Files
unison/src/network/utils/simple-net-device.cc
2024-09-06 19:32:31 +00:00

558 lines
12 KiB
C++

/*
* Copyright (c) 2008 INRIA
*
* SPDX-License-Identifier: GPL-2.0-only
*
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
*/
#include "simple-net-device.h"
#include "error-model.h"
#include "queue.h"
#include "simple-channel.h"
#include "ns3/boolean.h"
#include "ns3/log.h"
#include "ns3/node.h"
#include "ns3/packet.h"
#include "ns3/pointer.h"
#include "ns3/simulator.h"
#include "ns3/string.h"
#include "ns3/tag.h"
#include "ns3/trace-source-accessor.h"
namespace ns3
{
NS_LOG_COMPONENT_DEFINE("SimpleNetDevice");
/**
* \brief SimpleNetDevice tag to store source, destination and protocol of each packet.
*/
class SimpleTag : public Tag
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId();
TypeId GetInstanceTypeId() const override;
uint32_t GetSerializedSize() const override;
void Serialize(TagBuffer i) const override;
void Deserialize(TagBuffer i) override;
/**
* Set the source address
* \param src source address
*/
void SetSrc(Mac48Address src);
/**
* Get the source address
* \return the source address
*/
Mac48Address GetSrc() const;
/**
* Set the destination address
* \param dst destination address
*/
void SetDst(Mac48Address dst);
/**
* Get the destination address
* \return the destination address
*/
Mac48Address GetDst() const;
/**
* Set the protocol number
* \param proto protocol number
*/
void SetProto(uint16_t proto);
/**
* Get the protocol number
* \return the protocol number
*/
uint16_t GetProto() const;
void Print(std::ostream& os) const override;
private:
Mac48Address m_src; //!< source address
Mac48Address m_dst; //!< destination address
uint16_t m_protocolNumber; //!< protocol number
};
NS_OBJECT_ENSURE_REGISTERED(SimpleTag);
TypeId
SimpleTag::GetTypeId()
{
static TypeId tid = TypeId("ns3::SimpleTag")
.SetParent<Tag>()
.SetGroupName("Network")
.AddConstructor<SimpleTag>();
return tid;
}
TypeId
SimpleTag::GetInstanceTypeId() const
{
return GetTypeId();
}
uint32_t
SimpleTag::GetSerializedSize() const
{
return 8 + 8 + 2;
}
void
SimpleTag::Serialize(TagBuffer i) const
{
uint8_t mac[6];
m_src.CopyTo(mac);
i.Write(mac, 6);
m_dst.CopyTo(mac);
i.Write(mac, 6);
i.WriteU16(m_protocolNumber);
}
void
SimpleTag::Deserialize(TagBuffer i)
{
uint8_t mac[6];
i.Read(mac, 6);
m_src.CopyFrom(mac);
i.Read(mac, 6);
m_dst.CopyFrom(mac);
m_protocolNumber = i.ReadU16();
}
void
SimpleTag::SetSrc(Mac48Address src)
{
m_src = src;
}
Mac48Address
SimpleTag::GetSrc() const
{
return m_src;
}
void
SimpleTag::SetDst(Mac48Address dst)
{
m_dst = dst;
}
Mac48Address
SimpleTag::GetDst() const
{
return m_dst;
}
void
SimpleTag::SetProto(uint16_t proto)
{
m_protocolNumber = proto;
}
uint16_t
SimpleTag::GetProto() const
{
return m_protocolNumber;
}
void
SimpleTag::Print(std::ostream& os) const
{
os << "src=" << m_src << " dst=" << m_dst << " proto=" << m_protocolNumber;
}
NS_OBJECT_ENSURE_REGISTERED(SimpleNetDevice);
TypeId
SimpleNetDevice::GetTypeId()
{
static TypeId tid =
TypeId("ns3::SimpleNetDevice")
.SetParent<NetDevice>()
.SetGroupName("Network")
.AddConstructor<SimpleNetDevice>()
.AddAttribute("ReceiveErrorModel",
"The receiver error model used to simulate packet loss",
PointerValue(),
MakePointerAccessor(&SimpleNetDevice::m_receiveErrorModel),
MakePointerChecker<ErrorModel>())
.AddAttribute("PointToPointMode",
"The device is configured in Point to Point mode",
BooleanValue(false),
MakeBooleanAccessor(&SimpleNetDevice::m_pointToPointMode),
MakeBooleanChecker())
.AddAttribute("TxQueue",
"A queue to use as the transmit queue in the device.",
StringValue("ns3::DropTailQueue<Packet>"),
MakePointerAccessor(&SimpleNetDevice::m_queue),
MakePointerChecker<Queue<Packet>>())
.AddAttribute("DataRate",
"The default data rate for point to point links. Zero means infinite",
DataRateValue(DataRate("0b/s")),
MakeDataRateAccessor(&SimpleNetDevice::m_bps),
MakeDataRateChecker())
.AddTraceSource("PhyRxDrop",
"Trace source indicating a packet has been dropped "
"by the device during reception",
MakeTraceSourceAccessor(&SimpleNetDevice::m_phyRxDropTrace),
"ns3::Packet::TracedCallback");
return tid;
}
SimpleNetDevice::SimpleNetDevice()
: m_channel(nullptr),
m_node(nullptr),
m_mtu(0xffff),
m_ifIndex(0),
m_linkUp(false)
{
NS_LOG_FUNCTION(this);
}
void
SimpleNetDevice::Receive(Ptr<Packet> packet, uint16_t protocol, Mac48Address to, Mac48Address from)
{
NS_LOG_FUNCTION(this << packet << protocol << to << from);
NetDevice::PacketType packetType;
if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt(packet))
{
m_phyRxDropTrace(packet);
return;
}
if (to == m_address)
{
packetType = NetDevice::PACKET_HOST;
}
else if (to.IsBroadcast())
{
packetType = NetDevice::PACKET_BROADCAST;
}
else if (to.IsGroup())
{
packetType = NetDevice::PACKET_MULTICAST;
}
else
{
packetType = NetDevice::PACKET_OTHERHOST;
}
if (packetType != NetDevice::PACKET_OTHERHOST)
{
m_rxCallback(this, packet, protocol, from);
}
if (!m_promiscCallback.IsNull())
{
m_promiscCallback(this, packet, protocol, from, to, packetType);
}
}
void
SimpleNetDevice::SetChannel(Ptr<SimpleChannel> channel)
{
NS_LOG_FUNCTION(this << channel);
m_channel = channel;
m_channel->Add(this);
m_linkUp = true;
m_linkChangeCallbacks();
}
Ptr<Queue<Packet>>
SimpleNetDevice::GetQueue() const
{
NS_LOG_FUNCTION(this);
return m_queue;
}
void
SimpleNetDevice::SetQueue(Ptr<Queue<Packet>> q)
{
NS_LOG_FUNCTION(this << q);
m_queue = q;
}
void
SimpleNetDevice::SetReceiveErrorModel(Ptr<ErrorModel> em)
{
NS_LOG_FUNCTION(this << em);
m_receiveErrorModel = em;
}
void
SimpleNetDevice::SetIfIndex(const uint32_t index)
{
NS_LOG_FUNCTION(this << index);
m_ifIndex = index;
}
uint32_t
SimpleNetDevice::GetIfIndex() const
{
NS_LOG_FUNCTION(this);
return m_ifIndex;
}
Ptr<Channel>
SimpleNetDevice::GetChannel() const
{
NS_LOG_FUNCTION(this);
return m_channel;
}
void
SimpleNetDevice::SetAddress(Address address)
{
NS_LOG_FUNCTION(this << address);
m_address = Mac48Address::ConvertFrom(address);
}
Address
SimpleNetDevice::GetAddress() const
{
//
// Implicit conversion from Mac48Address to Address
//
NS_LOG_FUNCTION(this);
return m_address;
}
bool
SimpleNetDevice::SetMtu(const uint16_t mtu)
{
NS_LOG_FUNCTION(this << mtu);
m_mtu = mtu;
return true;
}
uint16_t
SimpleNetDevice::GetMtu() const
{
NS_LOG_FUNCTION(this);
return m_mtu;
}
bool
SimpleNetDevice::IsLinkUp() const
{
NS_LOG_FUNCTION(this);
return m_linkUp;
}
void
SimpleNetDevice::AddLinkChangeCallback(Callback<void> callback)
{
NS_LOG_FUNCTION(this << &callback);
m_linkChangeCallbacks.ConnectWithoutContext(callback);
}
bool
SimpleNetDevice::IsBroadcast() const
{
NS_LOG_FUNCTION(this);
return !m_pointToPointMode;
}
Address
SimpleNetDevice::GetBroadcast() const
{
NS_LOG_FUNCTION(this);
return Mac48Address::GetBroadcast();
}
bool
SimpleNetDevice::IsMulticast() const
{
NS_LOG_FUNCTION(this);
return !m_pointToPointMode;
}
Address
SimpleNetDevice::GetMulticast(Ipv4Address multicastGroup) const
{
NS_LOG_FUNCTION(this << multicastGroup);
return Mac48Address::GetMulticast(multicastGroup);
}
Address
SimpleNetDevice::GetMulticast(Ipv6Address addr) const
{
NS_LOG_FUNCTION(this << addr);
return Mac48Address::GetMulticast(addr);
}
bool
SimpleNetDevice::IsPointToPoint() const
{
NS_LOG_FUNCTION(this);
return m_pointToPointMode;
}
bool
SimpleNetDevice::IsBridge() const
{
NS_LOG_FUNCTION(this);
return false;
}
bool
SimpleNetDevice::Send(Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber)
{
NS_LOG_FUNCTION(this << packet << dest << protocolNumber);
return SendFrom(packet, m_address, dest, protocolNumber);
}
bool
SimpleNetDevice::SendFrom(Ptr<Packet> p,
const Address& source,
const Address& dest,
uint16_t protocolNumber)
{
NS_LOG_FUNCTION(this << p << source << dest << protocolNumber);
if (p->GetSize() > GetMtu())
{
return false;
}
Mac48Address to = Mac48Address::ConvertFrom(dest);
Mac48Address from = Mac48Address::ConvertFrom(source);
SimpleTag tag;
tag.SetSrc(from);
tag.SetDst(to);
tag.SetProto(protocolNumber);
p->AddPacketTag(tag);
if (m_queue->Enqueue(p))
{
if (m_queue->GetNPackets() == 1 && !FinishTransmissionEvent.IsPending())
{
StartTransmission();
}
return true;
}
return false;
}
void
SimpleNetDevice::StartTransmission()
{
if (m_queue->GetNPackets() == 0)
{
return;
}
NS_ASSERT_MSG(!FinishTransmissionEvent.IsPending(),
"Tried to transmit a packet while another transmission was in progress");
Ptr<Packet> packet = m_queue->Dequeue();
/**
* SimpleChannel will deliver the packet to the far end(s) of the link as soon as Send is called
* (or after its fixed delay, if one is configured). So we have to handle the rate of the link
* here, which we do by scheduling FinishTransmission (packetSize / linkRate) time in the
* future. While that event is running, the transmit path of this NetDevice is busy, so we can't
* send other packets.
*
* SimpleChannel doesn't have a locking mechanism, and doesn't check for collisions, so there's
* nothing we need to do with the channel until the transmission has "completed" from the
* perspective of this NetDevice.
*/
Time txTime = Time(0);
if (m_bps > DataRate(0))
{
txTime = m_bps.CalculateBytesTxTime(packet->GetSize());
}
FinishTransmissionEvent =
Simulator::Schedule(txTime, &SimpleNetDevice::FinishTransmission, this, packet);
}
void
SimpleNetDevice::FinishTransmission(Ptr<Packet> packet)
{
NS_LOG_FUNCTION(this);
SimpleTag tag;
packet->RemovePacketTag(tag);
Mac48Address src = tag.GetSrc();
Mac48Address dst = tag.GetDst();
uint16_t proto = tag.GetProto();
m_channel->Send(packet, proto, dst, src, this);
StartTransmission();
}
Ptr<Node>
SimpleNetDevice::GetNode() const
{
NS_LOG_FUNCTION(this);
return m_node;
}
void
SimpleNetDevice::SetNode(Ptr<Node> node)
{
NS_LOG_FUNCTION(this << node);
m_node = node;
}
bool
SimpleNetDevice::NeedsArp() const
{
NS_LOG_FUNCTION(this);
return !m_pointToPointMode;
}
void
SimpleNetDevice::SetReceiveCallback(NetDevice::ReceiveCallback cb)
{
NS_LOG_FUNCTION(this << &cb);
m_rxCallback = cb;
}
void
SimpleNetDevice::DoDispose()
{
NS_LOG_FUNCTION(this);
m_channel = nullptr;
m_node = nullptr;
m_receiveErrorModel = nullptr;
m_queue->Dispose();
if (FinishTransmissionEvent.IsPending())
{
FinishTransmissionEvent.Cancel();
}
NetDevice::DoDispose();
}
void
SimpleNetDevice::SetPromiscReceiveCallback(PromiscReceiveCallback cb)
{
NS_LOG_FUNCTION(this << &cb);
m_promiscCallback = cb;
}
bool
SimpleNetDevice::SupportsSendFrom() const
{
NS_LOG_FUNCTION(this);
return true;
}
} // namespace ns3