ErwinLi opened issue #1066: Uid repeated in Callback $ns3::PacketSink/RxWithSeqTsSize at nsnam / ns-3-dev

ErwinLi
2024-04-13T19:14:33Z

I am using the $ns3::PacketSink/RxWithSeqTsSize callback to monitor and log packet information in my network simulation, which involves multiple UE nodes sending data to a single remote host through an LTE and point-to-point setup.

However, I am observing that the packet UIDs recorded by this callback seem to repeat in a loop, rather than being unique for each packet instance. This behavior is unexpected as I assumed that each packet should have a unique UID throughout the simulation.

Simulation Setup:

Multiple UE nodes (UE1, UE2, UE3) send UDP packets to a single remote host. Network setup includes eNodeB, PGW/SGW, and a remote host configured as a UDP server.

Observed Behavior:

The packet UIDs repeat for packets from different UE nodes across different time steps. For example, UIDs 24, 25, and 26 repeat every few simulation steps for packets sent from different UEs.

Expected Behavior:

Each packet should have a unique UID regardless of the source or the time of transmission.

Question: Why are packet UIDs repeating in the RxWithSeqTsSize callback output? Is this an intended behavior based on how UIDs are assigned in ns-3, or could this be indicative of an issue with how packet UIDs are logged or processed?

Additional Information:

NS-3 version: 3.4.0

I have attached a snippet of the recorded data and the relevant parts of the simulation setup code to help diagnose the issue. Any insights or suggestions would be appreciated.

# Network Structure
#
# +-------+ +----+ +------------------+
# | | |PGW |-------| Remote Host |
# | eNodeB|-------|SGW | | [UDP Server] |
# | | | | +------------------+
# +---+---+ +----+ |
# | | |
# | | |
# +-----+-------+ | +---------+----+
# | UE1 | +-----| P2P Internet |
# | [UDP Client]| +--------------+
# +-------------+
#
# +-------------+
# | UE2 |
# | [UDP Client]|
# +-------------+
#
# +-------------+
# | UE3 |
# | [UDP Client]|
# +-------------+

from ns import ns
import pandas as pd

pd.set_option('display.max_rows', None)
pd.set_option('display.expand_frame_repr', False)

port = 1234

tx_record_df = pd.DataFrame(columns=["uid", "size", "time", "step", "src", "dest", "seq_num"])
rx_record_df = pd.DataFrame(columns=["uid", "size", "time", "step", "src", "dest", "seq_num"])

step = 0

# Function used to make callback for Rx and Tx events of UDP
ns.cppyy.cppdef(
"""
#include<string>
using namespace ns3;

Callback<void, std::string, Ptr< const Packet >, const Address &, const Address &, const SeqTsSizeHeader &>
make_SeqTsSizeCallback(void(*func)(std::string, Ptr< const Packet >, const Address &, const Address &, const SeqTsSizeHeader &)){
return MakeCallback(func);
}

Callback<void, std::string, Ptr< const Packet >, const Address &, const Address &>
make_TwoAddressTracedCallback(void(*func)(std::string, Ptr< const Packet >, const Address &, const Address &)){
return MakeCallback(func);
}
""")

def RxWithSeqTsSize_callback(contex, packet, address_src, address_dest, SeqTsSizeHeader):
address_src = ns.InetSocketAddress.ConvertFrom(address_src)
address_dest = ns.InetSocketAddress.ConvertFrom(address_dest)
print(f"At {ns.Simulator.Now().GetSeconds():.5f}s ,{contex}, received {packet.__deref__().GetSize()} bytes data")
print(f"Packet ID: {packet.__deref__().GetUid()}")
print(f"Packet Size: {packet.__deref__().GetSize()}")
print(f"Sequence Number: {SeqTsSizeHeader.GetSeq()}")
print(f"Time Stamp: {SeqTsSizeHeader.GetTs()}")
print(f"Size: {SeqTsSizeHeader.GetSize()}")
rx_record_df.loc[len(rx_record_df)] = [packet.GetUid(), packet.__deref__().GetSize(), ns.Simulator.Now().GetSeconds(), step, f"{address_src.GetIpv4()}:{address_src.GetPort()}", f"{address_dest.GetIpv4()}:{address_dest.GetPort()}", SeqTsSizeHeader.GetSeq()]

def TxWithSeqTsSize_callback(contex, packet, address_src, address_dest, SeqTsSizeHeader):
address_src = ns.InetSocketAddress.ConvertFrom(address_src)
address_dest = ns.InetSocketAddress.ConvertFrom(address_dest)
print(f"At {ns.Simulator.Now().GetSeconds():.5f}s ,{contex}, sent {packet.__deref__().GetSize()} bytes data")
print(f"Packet ID: {packet.__deref__().GetUid()}")
print(f"Packet Size: {packet.__deref__().GetSize()}")
print(f"Sequence Number: {SeqTsSizeHeader.GetSeq()}")
print(f"Time Stamp: {SeqTsSizeHeader.GetTs()}")
print(f"Size: {SeqTsSizeHeader.GetSize()}")
tx_record_df.loc[len(tx_record_df)] = [packet.__deref__().GetUid(), packet.__deref__().GetSize(), ns.Simulator.Now().GetSeconds(), step, f"{address_src.GetIpv4()}:{address_src.GetPort()}", f"{address_dest.GetIpv4()}:{address_dest.GetPort()}", SeqTsSizeHeader.GetSeq()]

# Initialise LTE Helper
lte_helper = ns.CreateObject("LteHelper")

# Initialise EPC Helper and install it to LTE Help
epc_helper = ns.PointToPointEpcHelper()
lte_helper.SetEpcHelper(epc_helper)

# Initialise P2P link Helper
p2p_helper = ns.PointToPointHelper()

# Get PGW
pgw = epc_helper.GetPgwNode()

# ---------- initialise nodes ---------- #

# Set container for eNodeB
enb_nodes = ns.NodeContainer()
enb_nodes.Create(1)

# Set container for UE
ue_nodes = ns.NodeContainer()
ue_nodes.Create(3)

# Set remote host
remote_nodes = ns.NodeContainer()
remote_nodes.Create(1)

# ---------- Set mobility ---------- #

# Set mobility
mobilityhelper = ns.MobilityHelper()
mobilityhelper.SetMobilityModel("ns3::ConstantPositionMobilityModel")
mobilityhelper.Install(enb_nodes)
mobilityhelper.Install(ue_nodes)

# ---------- Initialise network ---------- #

# Install device to Node
enb_devices = lte_helper.InstallEnbDevice(enb_nodes)
ue_devices = lte_helper.InstallUeDevice(ue_nodes)

# Install network stack to UE and remote host
internet = ns.InternetStackHelper()
internet.Install(ue_nodes)
internet.Install(remote_nodes)
ue_ip_interface = epc_helper.AssignUeIpv4Address(ue_devices)

# Install p2p link between PGW and remote host
p2p_helper.SetDeviceAttribute("DataRate", ns.DataRateValue(ns.DataRate("100Gb/s")))
p2p_helper.SetDeviceAttribute("Mtu", ns.UintegerValue(1500))
# p2p_helper.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(10)))
p2p_link_device = p2p_helper.Install(pgw, remote_nodes.Get(0))

# Assign IP to PGW and remote host
ipv4_helper = ns.Ipv4AddressHelper()
ipv4_helper.SetBase("1.0.0.0", "255.0.0.0")
p2p_ip_interface = ipv4_helper.Assign(p2p_link_device)

# Create Routing
ipv4_routing_helper = ns.Ipv4StaticRoutingHelper()
remote_routing = ipv4_routing_helper.GetStaticRouting(remote_nodes.Get(0).GetObject["Ipv4"]())
remote_routing.AddNetworkRouteTo(ns.Ipv4Address("7.0.0.0"), ns.Ipv4Mask("255.0.0.0"), 1)

for i in range(ue_nodes.GetN()):
ue_node = ue_nodes.Get(i)
ue_routing = ipv4_routing_helper.GetStaticRouting(ue_node.GetObject["Ipv4"]())
ue_routing.SetDefaultRoute(epc_helper.GetUeDefaultGatewayAddress(), 1)

# Attach UEs to eNodeB
lte_helper.Attach(ue_devices)

# ---------- Install TCP server ---------- #

# Install Sink app to remote host
tcp_sink = ns.PacketSinkHelper("ns3::UdpSocketFactory", ns.InetSocketAddress(ns.Ipv4Address.GetAny(), port).ConvertTo())
tcp_sink.SetAttribute("EnableSeqTsSizeHeader", ns.BooleanValue(1))
tcp_sink_apps = tcp_sink.Install(remote_nodes.Get(0))
tcp_sink_apps.Start(ns.Seconds(0.1))
tcp_sink_apps.Stop(ns.Seconds(5.0))

# ---------- Install TCP clients ---------- #

# Install TCP client to UEs
tcp_client = ns.OnOffHelper("ns3::UdpSocketFactory", ns.InetSocketAddress(p2p_ip_interface.GetAddress(1), port).ConvertTo())
tcp_client.SetAttribute("OnTime", ns.StringValue("ns3::ConstantRandomVariable[Constant=1]"))
tcp_client.SetAttribute("OffTime", ns.StringValue("ns3::ConstantRandomVariable[Constant=0]"))
tcp_client.SetAttribute("DataRate", ns.StringValue("1Mbps"));
tcp_client.SetAttribute("PacketSize", ns.UintegerValue(1024))
tcp_client.SetAttribute("EnableSeqTsSizeHeader", ns.BooleanValue(1))
tcp_client_apps = tcp_client.Install(ue_nodes)
tcp_client_apps.Start(ns.Seconds(2))
tcp_client_apps.Stop(ns.Seconds(2.5))

# ---------- Enable UDP Traces ---------- #

# Enable OnOff Tx Traces
TxWithSeqTsSize_callback_cpp = ns.cppyy.gbl.make_SeqTsSizeCallback(TxWithSeqTsSize_callback)
ns.Config.Connect("/NodeList/*/ApplicationList/*/$ns3::OnOffApplication/TxWithSeqTsSize", TxWithSeqTsSize_callback_cpp)

# Enable Sink Rx Traces
RxWithSeqTsSize_callback_cpp = ns.cppyy.gbl.make_SeqTsSizeCallback(RxWithSeqTsSize_callback)
ns.Config.Connect("/NodeList/*/ApplicationList/*/$ns3::PacketSink/RxWithSeqTsSize", RxWithSeqTsSize_callback_cpp)

# ---------- Get configurations ---------- #

print("\n-------------------- eNodeB configurations --------------------\n")
enb_node = enb_nodes.Get(0)
enb_node_id = enb_node.GetId()
print(f"eNodeB Node ID: {enb_node_id}")

enb_net_device = enb_node.GetDevice(0).GetObject["LteEnbNetDevice"]()
print(f"eNodeB downlink Bandwidth:{enb_net_device.GetDlBandwidth()}")
print(f"eNodeB downlink Earfcn:{enb_net_device.GetDlEarfcn()}")
print(f"eNodeB uplink Bandwidth:{enb_net_device.GetUlBandwidth()}")
print(f"eNodeB uplink Earfcn:{enb_net_device.GetUlEarfcn()}")

# ---------- Run Simulation ---------- #

# Run simulation for 5s
ns.Simulator.Stop(ns.Seconds(5))
ns.Simulator.Run()

# print packet info
print(rx_record_df)
print(rx_record_df.dtypes)
print(tx_record_df)
print(tx_record_df.dtypes)

ns.Simulator.Destroy()

output:

# received packats
uid size time step src dest seq_num
0 24 1004 2.021930 0 7.0.0.2:49153 1.0.0.2:1234 0
1 25 1004 2.021931 0 7.0.0.3:49153 1.0.0.2:1234 0
2 26 1004 2.021932 0 7.0.0.4:49153 1.0.0.2:1234 0
3 24 1004 2.028930 0 7.0.0.2:49153 1.0.0.2:1234 1
4 25 1004 2.028931 0 7.0.0.3:49153 1.0.0.2:1234 1
5 26 1004 2.028932 0 7.0.0.4:49153 1.0.0.2:1234 1
6 24 1004 2.030930 0 7.0.0.2:49153 1.0.0.2:1234 2
7 25 1004 2.030931 0 7.0.0.3:49153 1.0.0.2:1234 2
8 26 1004 2.030932 0 7.0.0.4:49153 1.0.0.2:1234 2
9 24 1004 2.044930 0 7.0.0.2:49153 1.0.0.2:1234 3
10 25 1004 2.044931 0 7.0.0.3:49153 1.0.0.2:1234 3
11 26 1004 2.044932 0 7.0.0.4:49153 1.0.0.2:1234 3
12 24 1004 2.052930 0 7.0.0.2:49153 1.0.0.2:1234 4
13 25 1004 2.052931 0 7.0.0.3:49153 1.0.0.2:1234 4
14 26 1004 2.052932 0 7.0.0.4:49153 1.0.0.2:1234 4
15 24 1004 2.061930 0 7.0.0.2:49153 1.0.0.2:1234 5
16 25 1004 2.061931 0 7.0.0.3:49153 1.0.0.2:1234 5
17 26 1004 2.061932 0 7.0.0.4:49153 1.0.0.2:1234 5
...

# sent packets:
uid size time step src dest seq_num
0 12 1004 2.008192 0 0.0.0.0:49153 1.0.0.2:1234 0
1 13 1004 2.008192 0 0.0.0.0:49153 1.0.0.2:1234 0
2 14 1004 2.008192 0 0.0.0.0:49153 1.0.0.2:1234 0
3 18 1004 2.016384 0 0.0.0.0:49153 1.0.0.2:1234 1
4 19 1004 2.016384 0 0.0.0.0:49153 1.0.0.2:1234 1
5 20 1004 2.016384 0 0.0.0.0:49153 1.0.0.2:1234 1
6 30 1004 2.024576 0 0.0.0.0:49153 1.0.0.2:1234 2
7 31 1004 2.024576 0 0.0.0.0:49153 1.0.0.2:1234 2
8 32 1004 2.024576 0 0.0.0.0:49153 1.0.0.2:1234 2
9 39 1004 2.032768 0 0.0.0.0:49153 1.0.0.2:1234 3
10 40 1004 2.032768 0 0.0.0.0:49153 1.0.0.2:1234 3
11 41 1004 2.032768 0 0.0.0.0:49153 1.0.0.2:1234 3
12 48 1004 2.040960 0 0.0.0.0:49153 1.0.0.2:1234 4
13 49 1004 2.040960 0 0.0.0.0:49153 1.0.0.2:1234 4
14 50 1004 2.040960 0 0.0.0.0:49153 1.0.0.2:1234 4
15 57 1004 2.049152 0 0.0.0.0:49153 1.0.0.2:1234 5
16 58 1004 2.049152 0 0.0.0.0:49153 1.0.0.2:1234 5
17 59 1004 2.049152 0 0.0.0.0:49153 1.0.0.2:1234 5