From ea9567ee9965380853120d4995fb8291647a66c9 Mon Sep 17 00:00:00 2001 From: Vineet1101 Date: Mon, 23 Feb 2026 03:46:12 -0800 Subject: [PATCH 1/5] added dummy port for traffic manager update Signed-off-by: Vineet1101 --- model/dummy-switch-port.cc | 175 +++++++++++++++++++++++++++++++++++++ model/dummy-switch-port.h | 141 ++++++++++++++++++++++++++++++ 2 files changed, 316 insertions(+) create mode 100644 model/dummy-switch-port.cc create mode 100644 model/dummy-switch-port.h diff --git a/model/dummy-switch-port.cc b/model/dummy-switch-port.cc new file mode 100644 index 0000000..428800f --- /dev/null +++ b/model/dummy-switch-port.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#include "ns3/dummy-switch-port.h" + +#include "ns3/log.h" +#include "ns3/queue-disc.h" +#include "ns3/uinteger.h" + +namespace ns3 +{ + +NS_LOG_COMPONENT_DEFINE("DummySwitchPort"); +NS_OBJECT_ENSURE_REGISTERED(DummySwitchPort); + +TypeId +DummySwitchPort::GetTypeId() +{ + static TypeId tid = TypeId("ns3::DummySwitchPort") + .SetParent() + .SetGroupName("P4sim") + .AddConstructor(); + return tid; +} + +DummySwitchPort::DummySwitchPort() + : m_netDevice(nullptr), + m_portId(0), + m_egressTm(nullptr), + m_isUp(true) +{ + NS_LOG_FUNCTION(this); +} + +DummySwitchPort::~DummySwitchPort() +{ + NS_LOG_FUNCTION(this); +} + +void +DummySwitchPort::DoDispose() +{ + NS_LOG_FUNCTION(this); + m_netDevice = nullptr; + m_egressTm = nullptr; + Object::DoDispose(); +} + +void +DummySwitchPort::SetNetDevice(Ptr device) +{ + NS_LOG_FUNCTION(this << device); + m_netDevice = device; +} + +Ptr +DummySwitchPort::GetNetDevice() const +{ + return m_netDevice; +} + +void +DummySwitchPort::SetPortId(uint32_t portId) +{ + NS_LOG_FUNCTION(this << portId); + m_portId = portId; +} + +uint32_t +DummySwitchPort::GetPortId() const +{ + return m_portId; +} + +void +DummySwitchPort::SetTrafficManager(Ptr qdisc) +{ + NS_LOG_FUNCTION(this << qdisc); + m_egressTm = qdisc; + NS_LOG_INFO("Port " << m_portId << ": Traffic manager " + << (qdisc ? "attached" : "detached")); +} + +Ptr +DummySwitchPort::GetTrafficManager() const +{ + return m_egressTm; +} + +bool +DummySwitchPort::HasTrafficManager() const +{ + return (m_egressTm != nullptr); +} + +void +DummySwitchPort::SetPortUp(bool isUp) +{ + NS_LOG_FUNCTION(this << isUp); + m_isUp = isUp; +} + +bool +DummySwitchPort::IsPortUp() const +{ + return m_isUp; +} + +bool +DummySwitchPort::EnqueueEgress(Ptr packet, + const Address& dest, + uint16_t protocolNumber) +{ + NS_LOG_FUNCTION(this << packet << dest << protocolNumber); + + if (!m_isUp) + { + NS_LOG_DEBUG("Port " << m_portId << " is down, dropping packet"); + return false; + } + + if (!m_netDevice) + { + NS_LOG_ERROR("Port " << m_portId << " has no underlying NetDevice"); + return false; + } + + if (m_egressTm) + { + // Enqueue through the traffic manager + NS_LOG_DEBUG("Port " << m_portId << ": enqueueing packet (size " + << packet->GetSize() << ") into traffic manager"); + // NOTE: Full QueueDisc integration requires QueueDiscItem wrapping. + // For the skeleton, we bypass the TM and send directly, but log + // that the TM is present. + NS_LOG_INFO("Port " << m_portId << ": TM present (" + << m_egressTm->GetInstanceTypeId().GetName() + << "), forwarding packet directly for now"); + } + + // Send directly on the underlying NetDevice + NS_LOG_DEBUG("Port " << m_portId << ": sending packet (size " + << packet->GetSize() << ") on " + << m_netDevice->GetInstanceTypeId().GetName()); + + return m_netDevice->Send(packet, dest, protocolNumber); +} + +void +DummySwitchPort::TransmitFromQueue() +{ + NS_LOG_FUNCTION(this); + // Placeholder: will be used when full QueueDisc integration is implemented. + // The QueueDisc dequeue callback would invoke this method to actually + // transmit the packet on the underlying NetDevice. + NS_LOG_DEBUG("Port " << m_portId << ": TransmitFromQueue called (placeholder)"); +} + +} // namespace ns3 diff --git a/model/dummy-switch-port.h b/model/dummy-switch-port.h new file mode 100644 index 0000000..3dcc67a --- /dev/null +++ b/model/dummy-switch-port.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#ifndef DUMMY_SWITCH_PORT_H +#define DUMMY_SWITCH_PORT_H + +#include "ns3/net-device.h" +#include "ns3/object.h" +#include "ns3/packet.h" +#include "ns3/queue-disc.h" + +namespace ns3 +{ + +/** + * \ingroup p4sim + * \brief Represents a single port on a DummySwitchNetDevice. + * + * DummySwitchPort wraps an underlying ns-3 NetDevice (e.g. CsmaNetDevice, + * PointToPointNetDevice) and adds an optional egress Traffic Manager (QueueDisc) + * slot. When a QueueDisc is attached, egress packets are enqueued into it; + * otherwise they are forwarded directly to the underlying NetDevice. + */ +class DummySwitchPort : public Object +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + DummySwitchPort(); + ~DummySwitchPort() override; + + /** + * \brief Set the underlying NetDevice for this port. + * \param device the NetDevice to attach + */ + void SetNetDevice(Ptr device); + + /** + * \brief Get the underlying NetDevice. + * \return the NetDevice attached to this port + */ + Ptr GetNetDevice() const; + + /** + * \brief Set the port index. + * \param portId the port index on the switch + */ + void SetPortId(uint32_t portId); + + /** + * \brief Get the port index. + * \return the port index on the switch + */ + uint32_t GetPortId() const; + + /** + * \brief Attach a traffic manager (QueueDisc) to this egress port. + * \param qdisc the QueueDisc to use for egress traffic management + */ + void SetTrafficManager(Ptr qdisc); + + /** + * \brief Get the traffic manager attached to this port. + * \return the QueueDisc, or nullptr if none is attached + */ + Ptr GetTrafficManager() const; + + /** + * \brief Check whether this port has a traffic manager attached. + * \return true if a QueueDisc is attached + */ + bool HasTrafficManager() const; + + /** + * \brief Set the administrative up/down state of this port. + * \param isUp true to set port up, false to set port down + */ + void SetPortUp(bool isUp); + + /** + * \brief Check whether this port is administratively up. + * \return true if port is up + */ + bool IsPortUp() const; + + /** + * \brief Enqueue a packet for egress on this port. + * + * If a traffic manager is attached, the packet is enqueued into + * the QueueDisc. Otherwise, it is sent directly on the underlying + * NetDevice. + * + * \param packet the packet to send + * \param dest the destination address + * \param protocolNumber the protocol number + * \return true if successfully enqueued or sent + */ + bool EnqueueEgress(Ptr packet, + const Address& dest, + uint16_t protocolNumber); + + protected: + void DoDispose() override; + + private: + /** + * \brief Transmit a packet from the queue onto the underlying NetDevice. + * + * This is the callback invoked when the QueueDisc dequeues a packet. + */ + void TransmitFromQueue(); + + Ptr m_netDevice; //!< The underlying ns-3 NetDevice + uint32_t m_portId; //!< Port index on the switch + Ptr m_egressTm; //!< Optional egress traffic manager (QueueDisc) + bool m_isUp; //!< Administrative up/down state +}; + +} // namespace ns3 + +#endif /* DUMMY_SWITCH_PORT_H */ From 63238bdb8f2d9e8e6820bc1ddbd97fd83796ca48 Mon Sep 17 00:00:00 2001 From: Vineet1101 Date: Mon, 23 Feb 2026 03:47:19 -0800 Subject: [PATCH 2/5] added dummy switch net device for traffic manager update Signed-off-by: Vineet1101 --- model/dummy-switch-net-device.cc | 442 +++++++++++++++++++++++++++++++ model/dummy-switch-net-device.h | 203 ++++++++++++++ 2 files changed, 645 insertions(+) create mode 100644 model/dummy-switch-net-device.cc create mode 100644 model/dummy-switch-net-device.h diff --git a/model/dummy-switch-net-device.cc b/model/dummy-switch-net-device.cc new file mode 100644 index 0000000..eb80d67 --- /dev/null +++ b/model/dummy-switch-net-device.cc @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#include "ns3/dummy-switch-net-device.h" + +#include "ns3/boolean.h" +#include "ns3/channel.h" +#include "ns3/ethernet-header.h" +#include "ns3/log.h" +#include "ns3/node.h" +#include "ns3/packet.h" +#include "ns3/simulator.h" +#include "ns3/uinteger.h" + +namespace ns3 +{ + +NS_LOG_COMPONENT_DEFINE("DummySwitchNetDevice"); +NS_OBJECT_ENSURE_REGISTERED(DummySwitchNetDevice); + +TypeId +DummySwitchNetDevice::GetTypeId() +{ + static TypeId tid = + TypeId("ns3::DummySwitchNetDevice") + .SetParent() + .SetGroupName("P4sim") + .AddConstructor() + + .AddAttribute("Mtu", + "The MAC-level Maximum Transmission Unit", + UintegerValue(1500), + MakeUintegerAccessor(&DummySwitchNetDevice::SetMtu, + &DummySwitchNetDevice::GetMtu), + MakeUintegerChecker()) + + .AddTraceSource("Rx", + "A packet received by the dummy switch", + MakeTraceSourceAccessor(&DummySwitchNetDevice::m_rxTrace), + "ns3::Packet::TracedCallback") + + .AddTraceSource("Tx", + "A packet transmitted by the dummy switch", + MakeTraceSourceAccessor(&DummySwitchNetDevice::m_txTrace), + "ns3::Packet::TracedCallback"); + + return tid; +} + +DummySwitchNetDevice::DummySwitchNetDevice() + : m_node(nullptr), + m_ifIndex(0), + m_mtu(1500) +{ + NS_LOG_FUNCTION(this); + m_channel = CreateObject(); +} + +DummySwitchNetDevice::~DummySwitchNetDevice() +{ + NS_LOG_FUNCTION(this); +} + +void +DummySwitchNetDevice::DoInitialize() +{ + NS_LOG_FUNCTION(this); + NS_LOG_INFO("DummySwitchNetDevice initialized with " << m_ports.size() << " ports"); + NetDevice::DoInitialize(); +} + +void +DummySwitchNetDevice::DoDispose() +{ + NS_LOG_FUNCTION(this); + for (auto& port : m_ports) + { + port = nullptr; + } + m_ports.clear(); + m_channel = nullptr; + m_node = nullptr; + NetDevice::DoDispose(); +} + +// ============================================================================= +// Port management +// ============================================================================= + +uint32_t +DummySwitchNetDevice::AddPort(Ptr portDevice) +{ + NS_LOG_FUNCTION(this << portDevice); + NS_ASSERT(portDevice != this); + + if (!Mac48Address::IsMatchingType(portDevice->GetAddress())) + { + NS_FATAL_ERROR("Device does not support EUI-48 addresses: cannot be added to switch."); + } + if (!portDevice->SupportsSendFrom()) + { + NS_FATAL_ERROR("Device does not support SendFrom: cannot be added to switch."); + } + + // Adopt the MAC of the first port added + if (m_address == Mac48Address()) + { + m_address = Mac48Address::ConvertFrom(portDevice->GetAddress()); + } + + // Create the port wrapper + Ptr port = CreateObject(); + uint32_t portId = m_ports.size(); + port->SetPortId(portId); + port->SetNetDevice(portDevice); + + // Register protocol handler on the node + NS_LOG_DEBUG("Registering protocol handler for port " << portId + << " (" << portDevice->GetInstanceTypeId().GetName() << ")"); + + m_node->RegisterProtocolHandler( + MakeCallback(&DummySwitchNetDevice::ReceiveFromPort, this), + 0, + portDevice, + true); + + m_ports.push_back(port); + m_channel->AddChannel(portDevice->GetChannel()); + + NS_LOG_INFO("Added port " << portId << " to dummy switch (" + << portDevice->GetInstanceTypeId().GetName() << ")"); + return portId; +} + +uint32_t +DummySwitchNetDevice::GetNPorts() const +{ + return m_ports.size(); +} + +Ptr +DummySwitchNetDevice::GetPort(uint32_t portId) const +{ + if (portId >= m_ports.size()) + { + return nullptr; + } + return m_ports[portId]; +} + +int32_t +DummySwitchNetDevice::GetPortIdForDevice(Ptr device) const +{ + for (uint32_t i = 0; i < m_ports.size(); i++) + { + if (m_ports[i]->GetNetDevice() == device) + { + return static_cast(i); + } + } + return -1; +} + +// ============================================================================= +// Traffic manager configuration +// ============================================================================= + +bool +DummySwitchNetDevice::SetPortTrafficManager(uint32_t portId, Ptr qdisc) +{ + NS_LOG_FUNCTION(this << portId << qdisc); + if (portId >= m_ports.size()) + { + NS_LOG_ERROR("Port " << portId << " does not exist"); + return false; + } + m_ports[portId]->SetTrafficManager(qdisc); + return true; +} + +// ============================================================================= +// Forwarding +// ============================================================================= + +void +DummySwitchNetDevice::ReceiveFromPort(Ptr device, + Ptr packet, + uint16_t protocol, + const Address& source, + const Address& destination, + PacketType packetType) +{ + NS_LOG_FUNCTION(this << device << packet << protocol << source << destination << packetType); + + int32_t inPort = GetPortIdForDevice(device); + NS_LOG_INFO("Rx packet (uid=" << packet->GetUid() + << ", size=" << packet->GetSize() + << ") on port " << inPort); + + // Fire trace + m_rxTrace(packet); + + // Promiscuous callback + if (!m_promiscRxCallback.IsNull()) + { + m_promiscRxCallback(this, packet, protocol, source, destination, packetType); + } + + // Check if addressed to this switch + Mac48Address dst48 = Mac48Address::ConvertFrom(destination); + if (dst48 == m_address) + { + if (!m_rxCallback.IsNull()) + { + m_rxCallback(this, packet, protocol, source); + } + return; + } + + // === Skeleton forwarding: flood to all ports except ingress === + NS_LOG_DEBUG("Flooding packet to all ports except port " << inPort); + for (uint32_t i = 0; i < m_ports.size(); i++) + { + if (static_cast(i) == inPort) + { + continue; // skip ingress port + } + + Ptr pktCopy = packet->Copy(); + SendToPort(pktCopy, i, protocol, destination); + } +} + +void +DummySwitchNetDevice::SendToPort(Ptr packet, + uint32_t egressPort, + uint16_t protocolNumber, + const Address& destination) +{ + NS_LOG_FUNCTION(this << packet << egressPort << protocolNumber << destination); + + if (egressPort >= m_ports.size()) + { + NS_LOG_ERROR("Egress port " << egressPort << " out of range"); + return; + } + + Ptr port = m_ports[egressPort]; + if (!port->IsPortUp()) + { + NS_LOG_DEBUG("Egress port " << egressPort << " is down, dropping"); + return; + } + + NS_LOG_DEBUG("Tx packet (size=" << packet->GetSize() + << ") to port " << egressPort); + + // Fire trace + m_txTrace(packet); + + port->EnqueueEgress(packet, destination, protocolNumber); +} + +// ============================================================================= +// NetDevice interface +// ============================================================================= + +void +DummySwitchNetDevice::SetIfIndex(const uint32_t index) +{ + m_ifIndex = index; +} + +uint32_t +DummySwitchNetDevice::GetIfIndex() const +{ + return m_ifIndex; +} + +Ptr +DummySwitchNetDevice::GetChannel() const +{ + return m_channel; +} + +void +DummySwitchNetDevice::SetAddress(Address address) +{ + m_address = Mac48Address::ConvertFrom(address); +} + +Address +DummySwitchNetDevice::GetAddress() const +{ + return m_address; +} + +bool +DummySwitchNetDevice::SetMtu(const uint16_t mtu) +{ + m_mtu = mtu; + return true; +} + +uint16_t +DummySwitchNetDevice::GetMtu() const +{ + return m_mtu; +} + +bool +DummySwitchNetDevice::IsLinkUp() const +{ + return true; +} + +void +DummySwitchNetDevice::AddLinkChangeCallback(Callback callback) +{ + // Not implemented for skeleton +} + +bool +DummySwitchNetDevice::IsBroadcast() const +{ + return true; +} + +Address +DummySwitchNetDevice::GetBroadcast() const +{ + return Mac48Address::GetBroadcast(); +} + +bool +DummySwitchNetDevice::IsMulticast() const +{ + return true; +} + +Address +DummySwitchNetDevice::GetMulticast(Ipv4Address multicastGroup) const +{ + return Mac48Address::GetMulticast(multicastGroup); +} + +Address +DummySwitchNetDevice::GetMulticast(Ipv6Address addr) const +{ + return Mac48Address::GetMulticast(addr); +} + +bool +DummySwitchNetDevice::IsPointToPoint() const +{ + return false; +} + +bool +DummySwitchNetDevice::IsBridge() const +{ + return true; +} + +bool +DummySwitchNetDevice::Send(Ptr packet, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION(this << packet << dest << protocolNumber); + return SendFrom(packet, m_address, dest, protocolNumber); +} + +bool +DummySwitchNetDevice::SendFrom(Ptr packet, + const Address& source, + const Address& dest, + uint16_t protocolNumber) +{ + NS_LOG_FUNCTION(this << packet << source << dest << protocolNumber); + + // Flood to all ports + for (uint32_t i = 0; i < m_ports.size(); i++) + { + Ptr pktCopy = packet->Copy(); + Ptr portDev = m_ports[i]->GetNetDevice(); + portDev->SendFrom(pktCopy, source, dest, protocolNumber); + } + return true; +} + +Ptr +DummySwitchNetDevice::GetNode() const +{ + return m_node; +} + +void +DummySwitchNetDevice::SetNode(Ptr node) +{ + m_node = node; +} + +bool +DummySwitchNetDevice::NeedsArp() const +{ + return true; +} + +void +DummySwitchNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb) +{ + m_rxCallback = cb; +} + +void +DummySwitchNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) +{ + m_promiscRxCallback = cb; +} + +bool +DummySwitchNetDevice::SupportsSendFrom() const +{ + return true; +} + +} // namespace ns3 diff --git a/model/dummy-switch-net-device.h b/model/dummy-switch-net-device.h new file mode 100644 index 0000000..fdef3f2 --- /dev/null +++ b/model/dummy-switch-net-device.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#ifndef DUMMY_SWITCH_NET_DEVICE_H +#define DUMMY_SWITCH_NET_DEVICE_H + +#include "ns3/dummy-switch-port.h" +#include "ns3/mac48-address.h" +#include "ns3/net-device.h" +#include "ns3/p4-bridge-channel.h" +#include "ns3/traced-callback.h" + +#include +#include + +namespace ns3 +{ + +class Node; + +/** + * \ingroup p4sim + * \brief A skeleton dummy switch NetDevice for the P4sim Plan A architecture. + * + * DummySwitchNetDevice implements a minimal multi-port switch following the + * bridge pattern used by ns3::BridgeNetDevice and ns3::P4SwitchNetDevice. + * Each port is wrapped in a DummySwitchPort object that supports an optional + * egress Traffic Manager (QueueDisc). + * + * This skeleton does not contain any real packet processing logic — it + * performs simple learning-bridge-style forwarding (flood if destination + * unknown). It serves as the architectural starting point for the full + * P4 switch implementation. + */ +class DummySwitchNetDevice : public NetDevice +{ + public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId(); + + DummySwitchNetDevice(); + ~DummySwitchNetDevice() override; + + // Delete copy constructor and assignment operator + DummySwitchNetDevice(const DummySwitchNetDevice&) = delete; + DummySwitchNetDevice& operator=(const DummySwitchNetDevice&) = delete; + + // === Port management === + + /** + * \brief Add a port to the switch. + * + * Wraps the given NetDevice in a DummySwitchPort and registers + * a protocol handler to receive frames from it. + * + * \param portDevice the NetDevice to add as a switch port + * \return the port index assigned to this device + */ + uint32_t AddPort(Ptr portDevice); + + /** + * \brief Get the number of ports on this switch. + * \return the number of ports + */ + uint32_t GetNPorts() const; + + /** + * \brief Get a port by its index. + * \param portId the port index + * \return the DummySwitchPort, or nullptr if index out of range + */ + Ptr GetPort(uint32_t portId) const; + + /** + * \brief Get the port index for a given NetDevice. + * \param device the NetDevice to look up + * \return the port index, or -1 if not found + */ + int32_t GetPortIdForDevice(Ptr device) const; + + // === Traffic Manager configuration === + + /** + * \brief Attach a traffic manager (QueueDisc) to a specific egress port. + * \param portId the port index + * \param qdisc the QueueDisc to attach + * \return true if successfully attached + */ + bool SetPortTrafficManager(uint32_t portId, Ptr qdisc); + + // === Forwarding === + + /** + * \brief Send a packet out a specific port. + * + * Delegates to the port's EnqueueEgress method, which may + * pass through a traffic manager if one is attached. + * + * \param packet the packet to send + * \param egressPort the egress port index + * \param protocolNumber the protocol number + * \param destination the destination address + */ + void SendToPort(Ptr packet, + uint32_t egressPort, + uint16_t protocolNumber, + const Address& destination); + + // === NetDevice interface overrides === + void SetIfIndex(const uint32_t index) override; + uint32_t GetIfIndex() const override; + Ptr GetChannel() const override; + void SetAddress(Address address) override; + Address GetAddress() const override; + bool SetMtu(const uint16_t mtu) override; + uint16_t GetMtu() const override; + bool IsLinkUp() const override; + void AddLinkChangeCallback(Callback callback) override; + bool IsBroadcast() const override; + Address GetBroadcast() const override; + bool IsMulticast() const override; + Address GetMulticast(Ipv4Address multicastGroup) const override; + Address GetMulticast(Ipv6Address addr) const override; + bool IsPointToPoint() const override; + bool IsBridge() const override; + bool Send(Ptr packet, const Address& dest, uint16_t protocolNumber) override; + bool SendFrom(Ptr packet, + const Address& source, + const Address& dest, + uint16_t protocolNumber) override; + Ptr GetNode() const override; + void SetNode(Ptr node) override; + bool NeedsArp() const override; + void SetReceiveCallback(NetDevice::ReceiveCallback cb) override; + void SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) override; + bool SupportsSendFrom() const override; + + protected: + void DoInitialize() override; + void DoDispose() override; + + /** + * \brief Handle a packet received from one of the switch ports. + * + * In the skeleton, this performs simple flood-based forwarding: + * the packet is sent out all ports except the ingress port. + * + * \param device the originating port NetDevice + * \param packet the received packet + * \param protocol the packet protocol + * \param source the source address + * \param destination the destination address + * \param packetType the packet type + */ + void ReceiveFromPort(Ptr device, + Ptr packet, + uint16_t protocol, + const Address& source, + const Address& destination, + PacketType packetType); + + private: + // === Port storage === + std::vector> m_ports; //!< List of switch ports + + // === Network device information === + Mac48Address m_address; //!< MAC address of switch + Ptr m_node; //!< Node that owns this NetDevice + Ptr m_channel; //!< Virtual bridge channel + uint32_t m_ifIndex; //!< Interface index + uint16_t m_mtu; //!< MTU + + // === Callbacks === + NetDevice::ReceiveCallback m_rxCallback; //!< Receive callback + NetDevice::PromiscReceiveCallback m_promiscRxCallback; //!< Promiscuous receive callback + + // === Trace sources === + TracedCallback> m_rxTrace; //!< Rx trace + TracedCallback> m_txTrace; //!< Tx trace +}; + +} // namespace ns3 + +#endif /* DUMMY_SWITCH_NET_DEVICE_H */ From 2c31100e700916b1943b4dc53dfee38f8790e960 Mon Sep 17 00:00:00 2001 From: Vineet1101 Date: Mon, 23 Feb 2026 03:50:26 -0800 Subject: [PATCH 3/5] added dummy switch helper for traffic manager update Signed-off-by: Vineet1101 --- CMakeLists.txt | 6 +++ model/dummy-switch-helper.cc | 69 +++++++++++++++++++++++++++++++ model/dummy-switch-helper.h | 78 ++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 model/dummy-switch-helper.cc create mode 100644 model/dummy-switch-helper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fee84fa..ba3c93b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,10 +63,13 @@ build_lib( model/p4-switch-net-device.cc model/custom-p2p-net-device.cc model/p4-controller.cc + model/dummy-switch-port.cc + model/dummy-switch-net-device.cc helper/p4-helper.cc helper/p4-topology-reader-helper.cc helper/p4-p2p-helper.cc helper/build-flowtable-helper.cc + helper/dummy-switch-helper.cc HEADER_FILES # equivalent to headers.source utils/p4-queue.h utils/format-utils.h @@ -86,9 +89,12 @@ build_lib( model/p4-switch-net-device.h model/custom-p2p-net-device.h model/p4-controller.h + model/dummy-switch-port.h + model/dummy-switch-net-device.h helper/p4-helper.h helper/p4-topology-reader-helper.h helper/p4-p2p-helper.h + helper/dummy-switch-helper.h helper/build-flowtable-helper.h LIBRARIES_TO_LINK ${libcore} diff --git a/model/dummy-switch-helper.cc b/model/dummy-switch-helper.cc new file mode 100644 index 0000000..673edee --- /dev/null +++ b/model/dummy-switch-helper.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#include "ns3/dummy-switch-helper.h" + +#include "ns3/log.h" +#include "ns3/names.h" + +namespace ns3 +{ + +NS_LOG_COMPONENT_DEFINE("DummySwitchHelper"); + +DummySwitchHelper::DummySwitchHelper() +{ + NS_LOG_FUNCTION(this); + m_deviceFactory.SetTypeId("ns3::DummySwitchNetDevice"); +} + +void +DummySwitchHelper::SetDeviceAttribute(std::string n1, const AttributeValue& v1) +{ + NS_LOG_FUNCTION(this << n1); + m_deviceFactory.Set(n1, v1); +} + +Ptr +DummySwitchHelper::Install(Ptr node, NetDeviceContainer portDevices) +{ + NS_LOG_FUNCTION(this << node); + + Ptr dev = m_deviceFactory.Create(); + node->AddDevice(dev); + + for (uint32_t i = 0; i < portDevices.GetN(); i++) + { + dev->AddPort(portDevices.Get(i)); + } + + NS_LOG_INFO("Installed DummySwitchNetDevice on node " << node->GetId() + << " with " << portDevices.GetN() << " ports"); + return dev; +} + +Ptr +DummySwitchHelper::Install(std::string nodeName, NetDeviceContainer portDevices) +{ + NS_LOG_FUNCTION(this << nodeName); + Ptr node = Names::Find(nodeName); + return Install(node, portDevices); +} + +} // namespace ns3 diff --git a/model/dummy-switch-helper.h b/model/dummy-switch-helper.h new file mode 100644 index 0000000..1d5f8b5 --- /dev/null +++ b/model/dummy-switch-helper.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +#ifndef DUMMY_SWITCH_HELPER_H +#define DUMMY_SWITCH_HELPER_H + +#include "ns3/dummy-switch-net-device.h" +#include "ns3/net-device-container.h" +#include "ns3/node.h" +#include "ns3/object-factory.h" + +namespace ns3 +{ + +/** + * \ingroup p4sim + * \brief Helper to install DummySwitchNetDevice on nodes. + * + * DummySwitchHelper simplifies creating and configuring a DummySwitchNetDevice. + * It follows the same pattern as P4Helper and BridgeHelper. + */ +class DummySwitchHelper +{ + public: + DummySwitchHelper(); + + /** + * \brief Set an attribute on the DummySwitchNetDevice. + * \param n1 attribute name + * \param v1 attribute value + */ + void SetDeviceAttribute(std::string n1, const AttributeValue& v1); + + /** + * \brief Install a DummySwitchNetDevice on a node. + * + * Creates a DummySwitchNetDevice, adds each NetDevice in the container + * as a port, and installs the switch on the node. + * + * \param node the node to install on + * \param portDevices the NetDevices to add as switch ports + * \return the created DummySwitchNetDevice + */ + Ptr Install(Ptr node, + NetDeviceContainer portDevices); + + /** + * \brief Install a DummySwitchNetDevice on a node (by name). + * \param nodeName the name of the node + * \param portDevices the NetDevices to add as switch ports + * \return the created DummySwitchNetDevice + */ + Ptr Install(std::string nodeName, + NetDeviceContainer portDevices); + + private: + ObjectFactory m_deviceFactory; //!< Factory for creating DummySwitchNetDevice +}; + +} // namespace ns3 + +#endif /* DUMMY_SWITCH_HELPER_H */ From c1a5da4f3b9016e02d228c9477204c262fea6002 Mon Sep 17 00:00:00 2001 From: Vineet1101 Date: Mon, 23 Feb 2026 03:53:03 -0800 Subject: [PATCH 4/5] added dummy switch example for traffic manager update Signed-off-by: Vineet1101 --- examples/CMakeLists.txt | 11 +++ examples/dummy-switch-example.cc | 157 +++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 examples/dummy-switch-example.cc diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7aac84e..cbc3469 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -108,6 +108,17 @@ build_lib_example( SOURCE_FILES p4-ipv4-animation.cc LIBRARIES_TO_LINK ${P4SIM_CSMA_LIBS} ${libnetanim} ${libmobility} ) +build_lib_example( + NAME dummy-switch-example + SOURCE_FILES dummy-switch-example.cc + LIBRARIES_TO_LINK + ${libp4sim} + ${libinternet} + ${libapplications} + ${libnetwork} + ${libcsma} + ${libtraffic-control} +) # ========================= PSA Architecture =========================== diff --git a/examples/dummy-switch-example.cc b/examples/dummy-switch-example.cc new file mode 100644 index 0000000..aada0bf --- /dev/null +++ b/examples/dummy-switch-example.cc @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025 TU Dresden + * + * 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 + * + * Authors: P4sim Contributors + */ + +/** + * Dummy Switch Example + * + * Demonstrates the skeleton DummySwitchNetDevice with 3 hosts and 1 switch. + * Each host is connected via a CSMA link. An optional FifoQueueDisc traffic + * manager is attached to port 2 (egress toward host 2). + * + * Host0 ──┐ + * Host1 ──┼── DummySwitch + * Host2 ──┘ + * + * A UDP packet is sent from Host0 to Host2. The switch floods to all ports + * except the ingress, so Host1 and Host2 both receive the packet. The TM + * on port 2 is logged. + */ + +#include "ns3/applications-module.h" +#include "ns3/core-module.h" +#include "ns3/csma-helper.h" +#include "ns3/dummy-switch-helper.h" +#include "ns3/fifo-queue-disc.h" +#include "ns3/internet-module.h" +#include "ns3/network-module.h" +#include "ns3/traffic-control-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE("DummySwitchExample"); + +int +main(int argc, char* argv[]) +{ + LogComponentEnable("DummySwitchExample", LOG_LEVEL_INFO); + LogComponentEnable("DummySwitchNetDevice", LOG_LEVEL_INFO); + LogComponentEnable("DummySwitchPort", LOG_LEVEL_INFO); + + bool enableTm = true; + uint16_t pktSize = 512; + + CommandLine cmd; + cmd.AddValue("enableTm", "Enable traffic manager on port 2", enableTm); + cmd.AddValue("pktSize", "UDP packet size in bytes", pktSize); + cmd.Parse(argc, argv); + + // ======================== Create nodes ======================== + NS_LOG_INFO("Creating 3 hosts and 1 switch node..."); + NodeContainer hosts; + hosts.Create(3); + + NodeContainer switchNode; + switchNode.Create(1); + + // ======================== Create CSMA links ======================== + CsmaHelper csma; + csma.SetChannelAttribute("DataRate", StringValue("100Mbps")); + csma.SetChannelAttribute("Delay", TimeValue(NanoSeconds(6560))); + + // One link from each host to the switch + NetDeviceContainer switchPorts; + std::vector hostDevices(3); + + for (uint32_t i = 0; i < 3; i++) + { + NetDeviceContainer link = csma.Install( + NodeContainer(hosts.Get(i), switchNode.Get(0))); + hostDevices[i].Add(link.Get(0)); // host side + switchPorts.Add(link.Get(1)); // switch side + } + + // ======================== Install Internet stack ======================== + InternetStackHelper internet; + internet.Install(hosts); + + // Assign IP addresses to host devices + Ipv4AddressHelper ipv4; + ipv4.SetBase("10.1.1.0", "255.255.255.0"); + std::vector hostInterfaces(3); + for (uint32_t i = 0; i < 3; i++) + { + hostInterfaces[i] = ipv4.Assign(hostDevices[i]); + } + + // ======================== Install DummySwitch ======================== + NS_LOG_INFO("Installing DummySwitchNetDevice on switch node..."); + DummySwitchHelper dummySwitchHelper; + Ptr sw = dummySwitchHelper.Install(switchNode.Get(0), switchPorts); + + // ======================== Attach Traffic Manager ======================== + if (enableTm) + { + NS_LOG_INFO("Attaching FifoQueueDisc to port 2..."); + Ptr fifo = CreateObject(); + fifo->SetMaxSize(QueueSize("100p")); + sw->SetPortTrafficManager(2, fifo); + } + + // ======================== Print topology info ======================== + NS_LOG_INFO("Switch has " << sw->GetNPorts() << " ports:"); + for (uint32_t i = 0; i < sw->GetNPorts(); i++) + { + Ptr port = sw->GetPort(i); + NS_LOG_INFO(" Port " << i + << " -> " << port->GetNetDevice()->GetInstanceTypeId().GetName() + << " (TM: " << (port->HasTrafficManager() ? "yes" : "no") + << ", Up: " << (port->IsPortUp() ? "yes" : "no") << ")"); + } + + // ======================== Setup applications ======================== + // UDP echo server on host 2 + uint16_t port = 9; + UdpEchoServerHelper echoServer(port); + ApplicationContainer serverApp = echoServer.Install(hosts.Get(2)); + serverApp.Start(Seconds(1.0)); + serverApp.Stop(Seconds(10.0)); + + // UDP echo client on host 0 + Ipv4Address serverAddr = hostInterfaces[2].GetAddress(0); + UdpEchoClientHelper echoClient(serverAddr, port); + echoClient.SetAttribute("MaxPackets", UintegerValue(3)); + echoClient.SetAttribute("Interval", TimeValue(Seconds(1.0))); + echoClient.SetAttribute("PacketSize", UintegerValue(pktSize)); + + ApplicationContainer clientApp = echoClient.Install(hosts.Get(0)); + clientApp.Start(Seconds(2.0)); + clientApp.Stop(Seconds(10.0)); + + // ======================== Enable PCAP tracing ======================== + csma.EnablePcapAll("dummy-switch-example"); + + // ======================== Run simulation ======================== + NS_LOG_INFO("Running simulation..."); + Simulator::Stop(Seconds(11.0)); + Simulator::Run(); + Simulator::Destroy(); + + NS_LOG_INFO("Simulation complete."); + return 0; +} From 6e8adbf848bf6117dde579d5b4f3498191a5c309 Mon Sep 17 00:00:00 2001 From: Vineet1101 Date: Mon, 23 Feb 2026 03:56:35 -0800 Subject: [PATCH 5/5] fixed copyright message Signed-off-by: Vineet1101 --- examples/dummy-switch-example.cc | 2 +- model/dummy-switch-helper.cc | 2 +- model/dummy-switch-helper.h | 2 +- model/dummy-switch-net-device.cc | 2 +- model/dummy-switch-net-device.h | 2 +- model/dummy-switch-port.cc | 2 +- model/dummy-switch-port.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/dummy-switch-example.cc b/examples/dummy-switch-example.cc index aada0bf..fa65155 100644 --- a/examples/dummy-switch-example.cc +++ b/examples/dummy-switch-example.cc @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ /** diff --git a/model/dummy-switch-helper.cc b/model/dummy-switch-helper.cc index 673edee..9873e23 100644 --- a/model/dummy-switch-helper.cc +++ b/model/dummy-switch-helper.cc @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #include "ns3/dummy-switch-helper.h" diff --git a/model/dummy-switch-helper.h b/model/dummy-switch-helper.h index 1d5f8b5..cbc041f 100644 --- a/model/dummy-switch-helper.h +++ b/model/dummy-switch-helper.h @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #ifndef DUMMY_SWITCH_HELPER_H diff --git a/model/dummy-switch-net-device.cc b/model/dummy-switch-net-device.cc index eb80d67..169f3c6 100644 --- a/model/dummy-switch-net-device.cc +++ b/model/dummy-switch-net-device.cc @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #include "ns3/dummy-switch-net-device.h" diff --git a/model/dummy-switch-net-device.h b/model/dummy-switch-net-device.h index fdef3f2..660daca 100644 --- a/model/dummy-switch-net-device.h +++ b/model/dummy-switch-net-device.h @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #ifndef DUMMY_SWITCH_NET_DEVICE_H diff --git a/model/dummy-switch-port.cc b/model/dummy-switch-port.cc index 428800f..dd364de 100644 --- a/model/dummy-switch-port.cc +++ b/model/dummy-switch-port.cc @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #include "ns3/dummy-switch-port.h" diff --git a/model/dummy-switch-port.h b/model/dummy-switch-port.h index 3dcc67a..d6e3645 100644 --- a/model/dummy-switch-port.h +++ b/model/dummy-switch-port.h @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Authors: P4sim Contributors + * Authors: Mingyu Ma */ #ifndef DUMMY_SWITCH_PORT_H