Q2NS dev
ns-3 module
Loading...
Searching...
No Matches
q2ns-congestion-helper.cc
Go to the documentation of this file.
1/*-----------------------------------------------------------------------------
2 * Q2NS - Quantum Network Simulator
3 * Copyright (c) 2026 quantuminternet.it
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *---------------------------------------------------------------------------*/
9
10#include "ns3/q2ns-congestion-helper.h"
11
12#include "ns3/inet-socket-address.h"
13#include "ns3/ipv4.h"
14#include "ns3/log.h"
15#include "ns3/names.h"
16#include "ns3/node-list.h"
17#include "ns3/node.h"
18
19#include "ns3/application-container.h"
20#include "ns3/bulk-send-helper.h"
21#include "ns3/data-rate.h"
22#include "ns3/on-off-helper.h"
23#include "ns3/packet-sink-helper.h"
24#include "ns3/simulator.h"
25#include "ns3/string.h"
26#include "ns3/uinteger.h"
27
28#include <algorithm>
29#include <cctype>
30#include <cmath>
31#include <sstream>
32
33namespace q2ns {
34
35NS_LOG_COMPONENT_DEFINE("CongestionHelper");
36
37ns3::Ptr<ns3::Node> CongestionHelper::FindNodeByName(const std::string& name) {
38 if (name.empty())
39 return nullptr;
40 return ns3::Names::Find<ns3::Node>(name);
41}
42
43ns3::Ipv4Address CongestionHelper::FirstNonLoopback(ns3::Ptr<ns3::Node> node) {
44 auto ipv4 = node->GetObject<ns3::Ipv4>();
45 if (!ipv4)
46 return ns3::Ipv4Address::GetAny();
47 for (uint32_t i = 0; i < ipv4->GetNInterfaces(); ++i) {
48 for (uint32_t j = 0; j < ipv4->GetNAddresses(i); ++j) {
49 auto ifaddr = ipv4->GetAddress(i, j).GetLocal();
50 if (ifaddr != ns3::Ipv4Address("127.0.0.1") && ifaddr != ns3::Ipv4Address::GetZero()) {
51 return ifaddr;
52 }
53 }
54 }
55 return ns3::Ipv4Address::GetAny();
56}
57
58double CongestionHelper::ComputeTcpWarmup(double rateMbps, double rttSec, uint32_t mssBytes,
59 double initCwndPkts) {
60 // cwnd_needed (pkts) = (rate * RTT) / MSS
61 double cwndNeeded = (rateMbps * 1e6 * rttSec) / (double(mssBytes) * 8.0);
62 if (cwndNeeded <= 0.0)
63 return 0.0;
64 double nDoublings = std::ceil(std::log2(std::max(1.0, cwndNeeded / initCwndPkts)));
65 // Cushion of 3 RTTs for ACK-clock settling
66 return (nDoublings + 3.0) * rttSec;
67}
68
70 using namespace ns3;
71 NS_LOG_INFO("Installing " << spec.flows.size() << " congestion flows");
72
73 for (const auto& fraw : spec.flows) {
74 // Lowercase normalized copies
75 TrafficFlow f = fraw;
76 std::string proto = f.protocol;
77 std::string srcKind = f.source;
78 std::transform(proto.begin(), proto.end(), proto.begin(),
79 [](unsigned char c) { return std::tolower(c); });
80 std::transform(srcKind.begin(), srcKind.end(), srcKind.begin(),
81 [](unsigned char c) { return std::tolower(c); });
82
83 // Validate knobs
84 if (proto != "udp" && proto != "tcp") {
85 NS_LOG_WARN("Unknown protocol '" << f.protocol << "'; defaulting to UDP");
86 proto = "udp";
87 }
88 if (srcKind != "onoff" && srcKind != "bulk") {
89 NS_LOG_WARN("Unknown source '" << f.source << "'; defaulting to onoff");
90 srcKind = "onoff";
91 }
92 if (proto == "udp" && srcKind == "bulk") {
93 NS_LOG_WARN("UDP does not support BulkSend; falling back to OnOff for flow to port "
94 << f.dstPort);
95 srcKind = "onoff";
96 }
97
98 auto srcNode = FindNodeByName(f.src);
99 auto dstNode = FindNodeByName(f.dst);
100 if (!srcNode || !dstNode) {
101 NS_LOG_ERROR("TrafficFlow refers to unknown nodes: " << f.src << " -> " << f.dst);
102 continue;
103 }
104
105 // Install sink once per (dst,port,proto)
106 if (spec.autoCreateSinks) {
107 auto key = std::make_tuple(dstNode, f.dstPort, proto);
108 if (!m_installedSinks.count(key)) {
109 Address bind = InetSocketAddress(Ipv4Address::GetAny(), f.dstPort);
110 if (proto == "tcp") {
111 PacketSinkHelper sink("ns3::TcpSocketFactory", bind);
112 sink.Install(dstNode);
113 } else {
114 PacketSinkHelper sink("ns3::UdpSocketFactory", bind);
115 sink.Install(dstNode);
116 }
117 m_installedSinks.insert(key);
118 }
119 }
120
121 // Sender address/target
122 Ipv4Address dstAddr = FirstNonLoopback(dstNode);
123 InetSocketAddress dst(dstAddr, f.dstPort);
124
125 // Compute start/stop (start includes warm-up offset)
126 Time tStart = Seconds(std::max(0.0, f.start_s));
127 Time tStop = (f.stop_s > 0.0) ? Seconds(f.stop_s) : Time(); // 0 => run until sim stop
128
129 if (srcKind == "onoff") {
130 // App-paced traffic for either UDP or TCP
131 std::ostringstream rate;
132 rate << f.rateMbps << "Mbps";
133 const char* factory = (proto == "tcp") ? "ns3::TcpSocketFactory" : "ns3::UdpSocketFactory";
134 OnOffHelper onoff(factory, dst);
135 onoff.SetAttribute("DataRate", StringValue(rate.str()));
136 onoff.SetAttribute("PacketSize", UintegerValue(f.packetSize));
137 onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]"));
138 onoff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]"));
139
140 auto apps = onoff.Install(srcNode);
141 apps.Start(tStart);
142 if (f.stop_s > 0.0)
143 apps.Stop(tStop);
144
145 NS_LOG_INFO("Installed OnOff "
146 << proto << " " << f.src << " -> " << f.dst << ":" << f.dstPort
147 << " rate=" << f.rateMbps << "Mbps pkt=" << f.packetSize
148 << " start=" << tStart.GetSeconds() << "s"
149 << (f.stop_s > 0.0 ? (" stop=" + std::to_string(tStop.GetSeconds()) + "s") : ""));
150
151 } else { // "bulk" (TCP only)
152 BulkSendHelper bulk("ns3::TcpSocketFactory", dst);
153 bulk.SetAttribute("MaxBytes", UintegerValue(0)); // sustained firehose
154 bulk.SetAttribute("SendSize", UintegerValue(f.packetSize)); // segment size hint
155
156 auto apps = bulk.Install(srcNode);
157 apps.Start(tStart);
158 if (f.stop_s > 0.0)
159 apps.Stop(tStop);
160
161 NS_LOG_INFO("Installed BulkSend TCP "
162 << f.src << " -> " << f.dst << ":" << f.dstPort << " sendSize=" << f.packetSize
163 << " start=" << tStart.GetSeconds() << "s"
164 << (f.stop_s > 0.0 ? (" stop=" + std::to_string(tStop.GetSeconds()) + "s") : "")
165 << " (ignores rateMbps by design)");
166 }
167 }
168}
169
170} // namespace q2ns
void Install(const TrafficSpec &spec)
static ns3::Ipv4Address FirstNonLoopback(ns3::Ptr< ns3::Node > node)
static double ComputeTcpWarmup(double rateMbps, double rttSec, uint32_t mssBytes=1200, double initCwndPkts=10.0)
static ns3::Ptr< ns3::Node > FindNodeByName(const std::string &name)
std::set< std::tuple< ns3::Ptr< ns3::Node >, uint16_t, std::string > > m_installedSinks
std::vector< TrafficFlow > flows