Skip to content

Repository files navigation

DOI

Live demo for automatic simulation using GPT-4o

(Full prompt and GPT-4o response for every case appear in the next section.)

Simulation and refinement results from the network-oriented LLMs with ns-3.

Architecture Diagram

Case Brief Summary Demo Video
B1 – LLM-Driven Automation From a single natural-language prompt, GPT-4o writes, compiles, and runs an ns-3 script that spawns a DynamicEmitter (exponential mean = 1 s), schedules ChangeRate(0.5) at 50 s, hooks a TimeProbe to the Interval trace source, and auto-generates the inter-arrival-time plot shown in panel (a) “C1 simulation results.” 🎥 B1 & B2 Demo
B2 – Iterative Tuning Building on B1’s script, the model edits just two parameters (initial mean and post-50 s mean), reruns the 100 s simulation, and returns the updated inter-arrival-time graph in panel (b) “C2 simulation results.” 🎥 B1 & B2 Demo
B3 – Code Conversion & Trace Analysis Given a C++ script path, GPT-4o translates it to Python, executes it, captures the PCAP, and opens the trace in a Wireshark-style view as shown in panel (c) “C3 PCAP trace in Wireshark.” 🎥 B3 Demo

Complete implementation scripts for B. Scenario 2: Packet-level Simulation with ns-3

B1. LLM-Driven Automation

Question:

Create a complete ns-3 simulation with a dynamic emitter class generating exponential interarrival times
(mean = 1.0 second) and using ChangeRate(double newRate) to adjust the mean to 0.5 seconds at 50 seconds;
connect a TimeProbe to the Interval trace source via log changes with TraceConnect function, and utilize
GnuplotHelper to create a PNG graph, while ensuring accurate trace source paths to prevent runtime errors.

Script:

#include "ns3/core-module.h"
#include "ns3/stats-module.h"
#include "ns3/gnuplot-helper.h"

using namespace ns3;

class DynamicEmitter : public Object
{
public:
  static TypeId GetTypeId()
  {
    static TypeId tid = TypeId("DynamicEmitter")
      .SetParent<Object>()
      .AddConstructor<DynamicEmitter>()
      .AddTraceSource("Interval",
                      "Interarrival time between events",
                      MakeTraceSourceAccessor(&DynamicEmitter::m_interval),
                      "ns3::Time::TracedValueCallback");
    return tid;
  }

  DynamicEmitter() : m_var(CreateObject<ExponentialRandomVariable>()) {}

  void Start()
  {
    m_var->SetAttribute("Mean", DoubleValue(1.0));
    Emit();
  }

  void ChangeRate(double newRate)
  {
    m_var->SetAttribute("Mean", DoubleValue(newRate));
  }

private:
  void Emit()
  {
    Time interval = Seconds(m_var->GetValue());
    m_interval = interval;
    Simulator::Schedule(interval, &DynamicEmitter::Emit, this);
  }

  TracedValue<Time> m_interval;
  Ptr<ExponentialRandomVariable> m_var;
};

int main(int argc, char *argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  Time::SetResolution(Time::NS);

  Ptr<DynamicEmitter> emitter = CreateObject<DynamicEmitter>();
  Names::Add("/Names/DynamicEmitter", emitter);

  Ptr<TimeProbe> timeProbe = CreateObject<TimeProbe>();
  bool connected = timeProbe->ConnectByObject("Interval", emitter);
  NS_ASSERT(connected);

  GnuplotHelper plotHelper;
  plotHelper.ConfigurePlot("dynamic-emitter-interarrival-time",
                           "Emitter Interarrival vs. Time with Rate Change",
                           "Time (Seconds)",
                           "Interarrival Time (Seconds)",
                           "png");

  plotHelper.PlotProbe("ns3::TimeProbe",
                       "/Names/DynamicEmitter/Interval",
                       "Output",
                       "Dynamic Emitter Interarrival Time",
                       GnuplotAggregator::KEY_INSIDE);

  Simulator::Schedule(Seconds(0.0), &DynamicEmitter::Start, emitter);
  Simulator::Schedule(Seconds(50.0), &DynamicEmitter::ChangeRate, emitter, 0.5);

  Simulator::Stop(Seconds(100.0));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

B2. Network Simulation Refinement through Multi-Round Interaction

Question:

What if we wanted to start with a mean interarrival time of 0.5 seconds, and at 50 seconds call ChangeRate
so the new mean becomes 0.4 seconds?

Script:

#include "ns3/core-module.h"
#include "ns3/stats-module.h"
#include "ns3/gnuplot-helper.h"

using namespace ns3;

class DynamicEmitter : public Object
{
public:
  static TypeId GetTypeId()
  {
    static TypeId tid = TypeId("DynamicEmitter")
      .SetParent<Object>()
      .AddConstructor<DynamicEmitter>()
      .AddTraceSource("Interval",
                      "Interarrival time between events",
                      MakeTraceSourceAccessor(&DynamicEmitter::m_interval),
                      "ns3::Time::TracedValueCallback");
    return tid;
  }

  DynamicEmitter() : m_var(CreateObject<ExponentialRandomVariable>()) {}

  void Start()
  {
    m_var->SetAttribute("Mean", DoubleValue(0.5));
    Emit();
  }

  void ChangeRate(double newRate)
  {
    m_var->SetAttribute("Mean", DoubleValue(newRate));
  }

private:
  void Emit()
  {
    Time interval = Seconds(m_var->GetValue());
    m_interval = interval;
    Simulator::Schedule(interval, &DynamicEmitter::Emit, this);
  }

  TracedValue<Time> m_interval;
  Ptr<ExponentialRandomVariable> m_var;
};

int main(int argc, char *argv[])
{
  CommandLine cmd;
  cmd.Parse(argc, argv);

  Time::SetResolution(Time::NS);

  Ptr<DynamicEmitter> emitter = CreateObject<DynamicEmitter>();
  Names::Add("/Names/DynamicEmitter", emitter);

  Ptr<TimeProbe> timeProbe = CreateObject<TimeProbe>();
  bool connected = timeProbe->ConnectByObject("Interval", emitter);
  NS_ASSERT(connected);

  GnuplotHelper plotHelper;
  plotHelper.ConfigurePlot("dynamic-emitter-interarrival-time",
                           "Emitter Interarrival vs. Time with Rate Change",
                           "Time (Seconds)",
                           "Interarrival Time (Seconds)",
                           "png");

  plotHelper.PlotProbe("ns3::TimeProbe",
                       "/Names/DynamicEmitter/Interval",
                       "Output",
                       "Dynamic Emitter Interarrival Time",
                       GnuplotAggregator::KEY_INSIDE);

  Simulator::Schedule(Seconds(0.0), &DynamicEmitter::Start, emitter);
  Simulator::Schedule(Seconds(50.0), &DynamicEmitter::ChangeRate, emitter, 0.4);

  Simulator::Stop(Seconds(100.0));
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

B3. Simulation Code Transition and Log Analysis

Question:

Please note: During the actual interaction, the user only needs to provide the path to the C++ file requiring conversion. Subsequent formatting will be handled automatically for question input.

Turn this ns-3 c++ script into its python version:

#include "ns3/applications-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"

using namespace ns3;

NS_LOG_COMPONENT_DEFINE("DEMO-2");

int
main(int argc, char* argv[])
{
  // Enable command-line argument parsing
  CommandLine cmd(__FILE__);
  cmd.Parse(argc, argv);

  // Set time resolution and enable some logging
  Time::SetResolution(Time::NS);
  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
  LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);

  // Create 3 nodes: n0, n1, n2
  NodeContainer allNodes;
  allNodes.Create(3);

  // 1) First link: n0 <--> n1
  NodeContainer nodes1;
  nodes1.Add(allNodes.Get(0)); // n0
  nodes1.Add(allNodes.Get(1)); // n1

  // 2) Second link: n1 <--> n2
  NodeContainer nodes2;
  nodes2.Add(allNodes.Get(1)); // n1
  nodes2.Add(allNodes.Get(2)); // n2

  // 3) Third link: n0 <--> n2
  NodeContainer nodes3;
  nodes3.Add(allNodes.Get(0)); // n0
  nodes3.Add(allNodes.Get(2)); // n2

  // Define PointToPoint helpers for each link
  PointToPointHelper p2p1, p2p2, p2p3;

  // p2p1: n0 <-> n1
  p2p1.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
  p2p1.SetChannelAttribute("Delay", StringValue("2ms"));

  // p2p2: n1 <-> n2
  p2p2.SetDeviceAttribute("DataRate", StringValue("3Mbps"));
  p2p2.SetChannelAttribute("Delay", StringValue("5ms"));

  // p2p3: n0 <-> n2
  p2p3.SetDeviceAttribute("DataRate", StringValue("2Mbps"));
  p2p3.SetChannelAttribute("Delay", StringValue("10ms"));

  // Install net devices for each link
  NetDeviceContainer devices1, devices2, devices3;
  devices1 = p2p1.Install(nodes1);
  devices2 = p2p2.Install(nodes2);
  devices3 = p2p3.Install(nodes3);

  // Enable ASCII and pcap tracing for each link
  AsciiTraceHelper ascii;
  p2p1.EnableAsciiAll(ascii.CreateFileStream("demo2-link1.tr"));
  p2p2.EnableAsciiAll(ascii.CreateFileStream("demo2-link2.tr"));
  p2p3.EnableAsciiAll(ascii.CreateFileStream("demo2-link3.tr"));

  p2p1.EnablePcapAll("demo2-link1");
  p2p2.EnablePcapAll("demo2-link2");
  p2p3.EnablePcapAll("demo2-link3");

  // Install the Internet stack on all nodes
  InternetStackHelper stack;
  stack.Install(allNodes);

  // Assign IPv4 addresses:
  //   p2p1 -> 10.1.1.0
  //   p2p2 -> 10.1.2.0
  //   p2p3 -> 10.1.3.0
  Ipv4AddressHelper address1, address2, address3;

  address1.SetBase("10.1.1.0", "255.255.255.0");
  Ipv4InterfaceContainer interfaces1 = address1.Assign(devices1);

  address2.SetBase("10.1.2.0", "255.255.255.0");
  Ipv4InterfaceContainer interfaces2 = address2.Assign(devices2);

  address3.SetBase("10.1.3.0", "255.255.255.0");
  Ipv4InterfaceContainer interfaces3 = address3.Assign(devices3);

  // Populate routing tables so that packets can find all routes
  Ipv4GlobalRoutingHelper::PopulateRoutingTables();

  // Create a UDP Echo Server on node n2 (port 9)
  UdpEchoServerHelper echoServer(9);
  ApplicationContainer serverApps = echoServer.Install(allNodes.Get(2));
  serverApps.Start(Seconds(1.0));
  serverApps.Stop(Seconds(10.0));

  // Create a UDP Echo Client on node n0, targeting the n2 server
  // The server is reachable at both 10.1.2.2 (via n1) and 10.1.3.2 (direct n0->n2 link).
  // We'll pick the direct link address (interfaces3.GetAddress(1)) for demonstration.
  UdpEchoClientHelper echoClient(interfaces3.GetAddress(1), 9);
  echoClient.SetAttribute("MaxPackets", UintegerValue(5));
  echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0)));
  echoClient.SetAttribute("PacketSize", UintegerValue(512));

  ApplicationContainer clientApps = echoClient.Install(allNodes.Get(0)); // n0
  clientApps.Start(Seconds(2.0));
  clientApps.Stop(Seconds(10.0));

  // Run the simulation
  Simulator::Run();
  Simulator::Destroy();

  return 0;
}

Script:

#
# SPDX-License-Identifier: GPL-2.0-only
#
# Converted from C++ to Python
#

try:
    from ns import ns
except ModuleNotFoundError:
    raise SystemExit(
        "Error: ns3 Python module not found;"
        " Python bindings may not be enabled"
        " or your PYTHONPATH might not be properly configured"
    )

import sys

# Enable logging for Echo applications
ns.LogComponentEnable("UdpEchoClientApplication", ns.LOG_LEVEL_INFO)
ns.LogComponentEnable("UdpEchoServerApplication", ns.LOG_LEVEL_INFO)

# Creating the nodes
allNodes = ns.NodeContainer()
allNodes.Create(3)

# Define n0 <-> n1 link
nodes1 = ns.NodeContainer()
nodes1.Add(allNodes.Get(0))
nodes1.Add(allNodes.Get(1))

# Define n1 <-> n2 link
nodes2 = ns.NodeContainer()
nodes2.Add(allNodes.Get(1))
nodes2.Add(allNodes.Get(2))

# Define n0 <-> n2 link
nodes3 = ns.NodeContainer()
nodes3.Add(allNodes.Get(0))
nodes3.Add(allNodes.Get(2))

# Configuring the point-to-point links
p2p1 = ns.PointToPointHelper()
p2p1.SetDeviceAttribute("DataRate", ns.StringValue("5Mbps"))
p2p1.SetChannelAttribute("Delay", ns.StringValue("2ms"))

p2p2 = ns.PointToPointHelper()
p2p2.SetDeviceAttribute("DataRate", ns.StringValue("3Mbps"))
p2p2.SetChannelAttribute("Delay", ns.StringValue("5ms"))

p2p3 = ns.PointToPointHelper()
p2p3.SetDeviceAttribute("DataRate", ns.StringValue("2Mbps"))
p2p3.SetChannelAttribute("Delay", ns.StringValue("10ms"))

# Installing the devices and links
devices1 = p2p1.Install(nodes1)
devices2 = p2p2.Install(nodes2)
devices3 = p2p3.Install(nodes3)

# Enable tracing
ascii = ns.AsciiTraceHelper()
p2p1.EnableAsciiAll(ascii.CreateFileStream("demo2-link1.tr"))
p2p2.EnableAsciiAll(ascii.CreateFileStream("demo2-link2.tr"))
p2p3.EnableAsciiAll(ascii.CreateFileStream("demo2-link3.tr"))

p2p1.EnablePcapAll("demo2-link1")
p2p2.EnablePcapAll("demo2-link2")
p2p3.EnablePcapAll("demo2-link3")

# Installing Internet stack on all nodes
stack = ns.InternetStackHelper()
stack.Install(allNodes)

# Assigning IP addresses
address1 = ns.Ipv4AddressHelper()
address1.SetBase(ns.Ipv4Address("10.1.1.0"), ns.Ipv4Mask("255.255.255.0"))
interfaces1 = address1.Assign(devices1)

address2 = ns.Ipv4AddressHelper()
address2.SetBase(ns.Ipv4Address("10.1.2.0"), ns.Ipv4Mask("255.255.255.0"))
interfaces2 = address2.Assign(devices2)

address3 = ns.Ipv4AddressHelper()
address3.SetBase(ns.Ipv4Address("10.1.3.0"), ns.Ipv4Mask("255.255.255.0"))
interfaces3 = address3.Assign(devices3)

# UdpEchoServer on node n2
echoServer = ns.UdpEchoServerHelper(9)
serverApps = echoServer.Install(allNodes.Get(2))
serverApps.Start(ns.Seconds(1.0))
serverApps.Stop(ns.Seconds(10.0))

# UdpEchoClient on node n0, targeting n2
echoClient = ns.UdpEchoClientHelper(interfaces3.GetAddress(1).ConvertTo(), 9)
echoClient.SetAttribute("MaxPackets", ns.UintegerValue(5))
echoClient.SetAttribute("Interval", ns.TimeValue(ns.Seconds(1.0)))
echoClient.SetAttribute("PacketSize", ns.UintegerValue(512))

clientApps = echoClient.Install(allNodes.Get(0))
clientApps.Start(ns.Seconds(2.0))
clientApps.Stop(ns.Seconds(10.0))

# Populating routing tables
ns.Ipv4GlobalRoutingHelper.PopulateRoutingTables()

# Run the simulation
ns.Simulator.Run()
ns.Simulator.Destroy()

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages