#include "switch-net-device.h" #include "ns3/boolean.h" #include "ns3/channel.h" #include "ns3/log.h" #include "ns3/node.h" #include "ns3/packet.h" #include "ns3/uinteger.h" #include "ns3/names.h" #include "ns3/random-variable-stream.h" #include "ns3/ethernet-header2.h" #include "ns3/net-device.h" /** * \file * \ingroup ethernet * ns3::SwitchNetDevice implementation. */ namespace ns3 { NS_LOG_COMPONENT_DEFINE("SwitchNetDevice"); NS_OBJECT_ENSURE_REGISTERED(SwitchNetDevice); TypeId SwitchNetDevice::GetTypeId() { static TypeId tid = TypeId("ns3::SwitchNetDevice") .SetParent() .SetGroupName("Ethernet") .AddConstructor() .AddAttribute("Mtu", "The MAC-level Maximum Transmission Unit", UintegerValue(1500), MakeUintegerAccessor(&SwitchNetDevice::SetMtu, &SwitchNetDevice::GetMtu), MakeUintegerChecker()) .AddAttribute("MinForwardingLatency", "The minimum latency experienced by the packet during forwarding", TimeValue(Seconds(0)), MakeTimeAccessor(&SwitchNetDevice::m_minForwardingLatency), MakeTimeChecker()) .AddAttribute("MaxForwardingLatency", "The maximun latency experienced by the packet during forwarding", TimeValue(Seconds(0)), MakeTimeAccessor(&SwitchNetDevice::m_maxForwardingLatency), MakeTimeChecker()) .AddAttribute("MaxPortNumber", "The maximum number of port", UintegerValue(65535), MakeUintegerAccessor(&SwitchNetDevice::m_maxPortNumber), MakeUintegerChecker()) .AddAttribute("MaxFdbEntryNumber", "The maximum number of entry in the forwarding database", UintegerValue(65535), MakeUintegerAccessor(&SwitchNetDevice::m_maxFdbEntryNumber), MakeUintegerChecker()); return tid; } SwitchNetDevice::SwitchNetDevice() : m_node(nullptr), m_ifIndex(0) { NS_LOG_FUNCTION_NOARGS(); m_channel = CreateObject(); } SwitchNetDevice::~SwitchNetDevice() { NS_LOG_FUNCTION_NOARGS(); } void SwitchNetDevice::DoDispose() { NS_LOG_FUNCTION_NOARGS(); for (auto iter = m_ports.begin(); iter != m_ports.end(); iter++) { *iter = nullptr; } m_ports.clear(); m_forwardingTable.clear(); m_channel = nullptr; m_node = nullptr; NetDevice::DoDispose(); } void SwitchNetDevice::ReceiveFromDevice(Ptr incomingPort, Ptr packet, uint16_t protocol, const Address& src, const Address& dst, PacketType packetType) { NS_LOG_FUNCTION_NOARGS(); NS_LOG_DEBUG("UID is " << packet->GetUid()); Mac48Address src48 = Mac48Address::ConvertFrom(src); Mac48Address dst48 = Mac48Address::ConvertFrom(dst); if (!m_promiscRxCallback.IsNull()) { m_promiscRxCallback(this, packet, protocol, src, dst, packetType); } switch (packetType) { case PACKET_HOST: if (dst48 == m_address) { m_rxCallback(this, packet, protocol, src); } break; case PACKET_MULTICAST: case PACKET_BROADCAST: m_rxCallback(this, packet, protocol, src); ForwardBroadcast(incomingPort, packet, protocol, src48, dst48); break; case PACKET_OTHERHOST: if (dst48 == m_address) { m_rxCallback(this, packet, protocol, src); } else { Forward(incomingPort, packet, protocol, src48, dst48); } break; } } void SwitchNetDevice::Forward(Ptr incomingPort, Ptr packet, uint16_t protocol, Mac48Address src, Mac48Address dst) { NS_LOG_FUNCTION_NOARGS(); Ptr originalPacket = packet->Copy(); EthernetHeader2 header; originalPacket->RemoveHeader(header); uint16_t vid = header.GetVid(); //NS_LOG_INFO(Names::FindName(this) << " Look in forwarding table for Pkt #" << packet->GetUid()); std::vector> outPorts = GetOutputPortsFromForwardingTable(dst, vid); EventId e; int s = outPorts.size(); for(int i=0; i < s; i++){ //Avoid sending on the incomingPort if(outPorts[i] != incomingPort){ Ptr randVar = CreateObject(); Time forwardingLatency = NanoSeconds(randVar->GetValue(m_minForwardingLatency.GetNanoSeconds(), m_maxForwardingLatency.GetNanoSeconds())); Simulator::Schedule(forwardingLatency, &NetDevice::SendFrom, outPorts[i], packet->Copy(), src, dst, protocol); } } } void SwitchNetDevice::ForwardBroadcast(Ptr incomingPort, Ptr packet, uint16_t protocol, Mac48Address src, Mac48Address dst) { NS_LOG_FUNCTION_NOARGS(); Forward(incomingPort, packet, protocol, src, dst); } std::vector> SwitchNetDevice::GetOutputPortsFromForwardingTable(Mac48Address dest, uint16_t vid) { NS_LOG_FUNCTION(this); int s = m_forwardingTable.size(); for(int i=0; i < s; i++){ if(m_forwardingTable[i].dest == dest and m_forwardingTable[i].vid==vid){ // NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : Match on vid "<< vid << " for " << m_forwardingTable[i].associatedPorts.size() << " output port(s) "); return m_forwardingTable[i].associatedPorts; } } // NS_LOG_INFO(Names::FindName(this) << " Forwarding Table : No Match on vid "<< vid); return {}; } void SwitchNetDevice::AddForwardingTableEntry(Mac48Address dest, uint16_t vid, std::vector> outPorts) { NS_LOG_FUNCTION(this); NS_ASSERT_MSG(m_forwardingTable.size() < m_maxFdbEntryNumber, "Trying to add more forwarding database entry than the " << m_maxFdbEntryNumber << " available."); PortsToVidAssociation entry = {dest, vid, outPorts}; m_forwardingTable.insert(m_forwardingTable.end(), entry); } uint32_t SwitchNetDevice::GetNSwitchPorts() const { NS_LOG_FUNCTION_NOARGS(); return m_ports.size(); } Ptr SwitchNetDevice::GetSwitchPort(uint32_t n) const { NS_LOG_FUNCTION_NOARGS(); return m_ports[n]; } void SwitchNetDevice::AddSwitchPort(Ptr switchPort) { NS_LOG_FUNCTION_NOARGS(); NS_ASSERT_MSG(m_ports.size() < m_maxPortNumber, "Trying to add more switch port than the " << m_maxPortNumber << " available."); //NS_ASSERT(switchPort != this); if (!Mac48Address::IsMatchingType(switchPort->GetAddress())) { NS_FATAL_ERROR("Device does not support eui 48 addresses: cannot be added to switch."); } if (!switchPort->SupportsSendFrom()) { NS_FATAL_ERROR("Device does not support SendFrom: cannot be added to switch."); } if (m_address == Mac48Address()) { m_address = Mac48Address::ConvertFrom(switchPort->GetAddress()); } NS_LOG_DEBUG("RegisterProtocolHandler for " << switchPort->GetInstanceTypeId().GetName()); m_node->RegisterProtocolHandler(MakeCallback(&SwitchNetDevice::ReceiveFromDevice, this), 0, switchPort, true); m_ports.push_back(switchPort); m_channel->AddChannel(switchPort->GetChannel()); } void SwitchNetDevice::SetIfIndex(const uint32_t index) { NS_LOG_FUNCTION_NOARGS(); m_ifIndex = index; } uint32_t SwitchNetDevice::GetIfIndex() const { NS_LOG_FUNCTION_NOARGS(); return m_ifIndex; } Ptr SwitchNetDevice::GetChannel() const { NS_LOG_FUNCTION_NOARGS(); return m_channel; } void SwitchNetDevice::SetAddress(Address address) { NS_LOG_FUNCTION_NOARGS(); m_address = Mac48Address::ConvertFrom(address); } Address SwitchNetDevice::GetAddress() const { NS_LOG_FUNCTION_NOARGS(); return m_address; } bool SwitchNetDevice::SetMtu(const uint16_t mtu) { NS_LOG_FUNCTION_NOARGS(); m_mtu = mtu; return true; } uint16_t SwitchNetDevice::GetMtu() const { NS_LOG_FUNCTION_NOARGS(); return m_mtu; } bool SwitchNetDevice::IsLinkUp() const { NS_LOG_FUNCTION_NOARGS(); return true; } void SwitchNetDevice::AddLinkChangeCallback(Callback callback) { } bool SwitchNetDevice::IsBroadcast() const { NS_LOG_FUNCTION_NOARGS(); return true; } Address SwitchNetDevice::GetBroadcast() const { NS_LOG_FUNCTION_NOARGS(); return Mac48Address("ff:ff:ff:ff:ff:ff"); } bool SwitchNetDevice::IsMulticast() const { NS_LOG_FUNCTION_NOARGS(); return true; } Address SwitchNetDevice::GetMulticast(Ipv4Address multicastGroup) const { NS_LOG_FUNCTION(this << multicastGroup); Mac48Address multicast = Mac48Address::GetMulticast(multicastGroup); return multicast; } bool SwitchNetDevice::IsPointToPoint() const { NS_LOG_FUNCTION_NOARGS(); return false; } bool SwitchNetDevice::IsBridge() const { NS_LOG_FUNCTION_NOARGS(); return true; } bool SwitchNetDevice::Send(Ptr packet, const Address& dest, uint16_t protocolNumber) { NS_LOG_FUNCTION_NOARGS(); return SendFrom(packet, m_address, dest, protocolNumber); } bool SwitchNetDevice::SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) { NS_LOG_FUNCTION_NOARGS(); Mac48Address src = Mac48Address::ConvertFrom(source); Mac48Address dst = Mac48Address::ConvertFrom(dest); Ptr originalPacket = packet->Copy(); EthernetHeader2 header; originalPacket->RemoveHeader(header); uint16_t vid = header.GetVid(); std::vector> outPorts = GetOutputPortsFromForwardingTable(dst, vid); int s = outPorts.size(); for(int i=0; i < s; i++){ outPorts[i]->SendFrom(packet->Copy(), src, dst, protocolNumber); } return true; } Ptr SwitchNetDevice::GetNode() const { NS_LOG_FUNCTION_NOARGS(); return m_node; } void SwitchNetDevice::SetNode(Ptr node) { NS_LOG_FUNCTION_NOARGS(); m_node = node; } bool SwitchNetDevice::NeedsArp() const { NS_LOG_FUNCTION_NOARGS(); return true; } void SwitchNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb) { NS_LOG_FUNCTION_NOARGS(); m_rxCallback = cb; } void SwitchNetDevice::SetPromiscReceiveCallback(NetDevice::PromiscReceiveCallback cb) { NS_LOG_FUNCTION_NOARGS(); m_promiscRxCallback = cb; } bool SwitchNetDevice::SupportsSendFrom() const { NS_LOG_FUNCTION_NOARGS(); return true; } Address SwitchNetDevice::GetMulticast(Ipv6Address addr) const { NS_LOG_FUNCTION(this << addr); return Mac48Address::GetMulticast(addr); } } // namespace ns3