diff --git a/examples/simple-error-model.cc b/examples/simple-error-model.cc new file mode 100644 index 000000000..04b627e62 --- /dev/null +++ b/examples/simple-error-model.cc @@ -0,0 +1,240 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * 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 + * + * ns-2 simple.tcl script (ported from ns-2) + * Originally authored by Steve McCanne, 12/19/1996 + */ + +// Port of ns-2/tcl/ex/simple.tcl to ns-3 +// +// Network topology +// +// n0 +// \ 5 Mb/s, 2ms +// \ 1.5Mb/s, 10ms +// n2 -------------------------n3 +// / +// / 5 Mb/s, 2ms +// n1 +// +// - all links are point-to-point links with indicated one-way BW/delay +// - CBR/UDP flows from n0 to n3, and from n3 to n1 +// - FTP/TCP flow from n0 to n3, starting at time 1.2 to time 1.35 sec. +// - UDP packet size of 210 bytes, with per-packet interval 0.00375 sec. +// (i.e., DataRate of 448,000 bps) +// - DropTail queues +// - Tracing of queues and packet receptions to file +// "simple-error-model.tr" + +#include "ns3/log.h" +#include "ns3/assert.h" +#include "ns3/command-line.h" +#include "ns3/default-value.h" +#include "ns3/ptr.h" + +#include "ns3/simulator.h" +#include "ns3/nstime.h" +#include "ns3/data-rate.h" + +#include "ns3/ascii-trace.h" +#include "ns3/pcap-trace.h" +#include "ns3/internet-node.h" +#include "ns3/default-value.h" +#include "ns3/component-manager.h" +#include "ns3/random-variable.h" +#include "ns3/point-to-point-channel.h" +#include "ns3/point-to-point-net-device.h" +#include "ns3/ipv4-address.h" +#include "ns3/inet-socket-address.h" +#include "ns3/ipv4.h" +#include "ns3/socket.h" +#include "ns3/ipv4-route.h" +#include "ns3/point-to-point-topology.h" +#include "ns3/onoff-application.h" +#include "ns3/packet-sink.h" +#include "ns3/error-model.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("SimpleErrorModelExample"); + +int +main (int argc, char *argv[]) +{ + // Users may find it convenient to turn on explicit debugging + // for selected modules; the below lines suggest how to do this +#if 0 + LogComponentEnable ("SimplePointToPointExample", LOG_LEVEL_INFO); +#endif + + // Set up some default values for the simulation. Use the Bind() + // technique to tell the system what subclass of ErrorModel to use + DefaultValue::Bind ("ErrorModel", "RateErrorModel"); + // Set a few parameters + DefaultValue::Bind ("RateErrorModelErrorRate", "0.01"); + DefaultValue::Bind ("RateErrorModelErrorUnit", "EU_PKT"); + + DefaultValue::Bind ("OnOffApplicationPacketSize", "210"); + DefaultValue::Bind ("OnOffApplicationDataRate", "448kb/s"); + + + // Allow the user to override any of the defaults and the above + // Bind()s at run-time, via command-line arguments + CommandLine::Parse (argc, argv); + + // Here, we will explicitly create four nodes. In more sophisticated + // topologies, we could configure a node factory. + NS_LOG_INFO ("Create nodes."); + Ptr n0 = Create (); + Ptr n1 = Create (); + Ptr n2 = Create (); + Ptr n3 = Create (); + + // We create the channels first without any IP addressing information + NS_LOG_INFO ("Create channels."); + Ptr channel0 = + PointToPointTopology::AddPointToPointLink ( + n0, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel1 = + PointToPointTopology::AddPointToPointLink ( + n1, n2, DataRate(5000000), MilliSeconds(2)); + + Ptr channel2 = + PointToPointTopology::AddPointToPointLink ( + n2, n3, DataRate(1500000), MilliSeconds(10)); + + // Later, we add IP addresses. + NS_LOG_INFO ("Assign IP Addresses."); + PointToPointTopology::AddIpv4Addresses ( + channel0, n0, Ipv4Address("10.1.1.1"), + n2, Ipv4Address("10.1.1.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel1, n1, Ipv4Address("10.1.2.1"), + n2, Ipv4Address("10.1.2.2")); + + PointToPointTopology::AddIpv4Addresses ( + channel2, n2, Ipv4Address("10.1.3.1"), + n3, Ipv4Address("10.1.3.2")); + + // Finally, we add static routes. These three steps (Channel and + // NetDevice creation, IP Address assignment, and routing) are + // separated because there may be a need to postpone IP Address + // assignment (emulation) or modify to use dynamic routing + NS_LOG_INFO ("Add Static Routes."); + PointToPointTopology::AddIpv4Routes(n0, n2, channel0); + PointToPointTopology::AddIpv4Routes(n1, n2, channel1); + PointToPointTopology::AddIpv4Routes(n2, n3, channel2); + + // Create the OnOff application to send UDP datagrams of size + // 210 bytes at a rate of 448 Kb/s + NS_LOG_INFO ("Create Applications."); + uint16_t port = 9; // Discard port (RFC 863) + Ptr ooff = Create ( + n0, + InetSocketAddress ("10.1.3.2", port), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.0)); + ooff->Stop (Seconds(10.0)); + + // Create an optional packet sink to receive these packets + Ptr sink = Create ( + n3, + InetSocketAddress (Ipv4Address::GetAny (), port), + "Udp"); + // Start the sink + sink->Start (Seconds (1.0)); + sink->Stop (Seconds (10.0)); + + // Create a similar flow from n3 to n1, starting at time 1.1 seconds + ooff = Create ( + n3, + InetSocketAddress ("10.1.2.1", port), + "Udp", + ConstantVariable(1), + ConstantVariable(0)); + // Start the application + ooff->Start(Seconds(1.1)); + ooff->Stop (Seconds(10.0)); + + // Create a packet sink to receive these packets + sink = Create ( + n1, + InetSocketAddress (Ipv4Address::GetAny (), port), + "Udp"); + // Start the sink + sink->Start (Seconds (1.1)); + sink->Stop (Seconds (10.0)); + + // Here, finish off packet routing configuration + // This will likely set by some global StaticRouting object in the future + NS_LOG_INFO ("Set Default Routes."); + Ptr ipv4; + ipv4 = n0->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.1.2"), 1); + ipv4 = n3->QueryInterface (Ipv4::iid); + ipv4->SetDefaultRoute (Ipv4Address ("10.1.3.1"), 1); + + // + // Error model + // + // We want to add an error model to node 3's NetDevice + // We can obtain a handle to the NetDevice via the channel and node + // pointers + Ptr nd3 = PointToPointTopology::GetNetDevice + (n3, channel2); + // Create an ErrorModel based on the implementation (constructor) + // specified by the default classId + Ptr em = ErrorModel::CreateDefault (); + NS_ASSERT (em != 0); + // Now, query interface on the resulting em pointer to see if a + // RateErrorModel interface exists. If so, set the packet error rate + Ptr bem = em->QueryInterface + (RateErrorModel::iid); + if (bem) + { + bem->SetRandomVariable (UniformVariable ()); + bem->SetRate (0.001); + } + nd3->AddReceiveErrorModel (em); + + // Now, let's use the ListErrorModel and explicitly force a loss + // of the packets with pkt-uids = 11 and 17 on node 2, device 0 + Ptr nd2 = PointToPointTopology::GetNetDevice + (n2, channel0); + std::list sampleList; + sampleList.push_back (11); + sampleList.push_back (17); + // This time, we'll explicitly create the error model we want + Ptr pem = Create (); + pem->SetList (sampleList); + nd2->AddReceiveErrorModel (pem); + + // Configure tracing of all enqueue, dequeue, and NetDevice receive events + // Trace output will be sent to the simple-error-model.tr file + NS_LOG_INFO ("Configure Tracing."); + AsciiTrace asciitrace ("simple-error-model.tr"); + asciitrace.TraceAllQueues (); + asciitrace.TraceAllNetDeviceRx (); + + NS_LOG_INFO ("Run Simulation."); + Simulator::Run (); + Simulator::Destroy (); + NS_LOG_INFO ("Done."); +} diff --git a/examples/wscript b/examples/wscript index f597225fb..e458fa057 100644 --- a/examples/wscript +++ b/examples/wscript @@ -14,6 +14,10 @@ def build(bld): ['point-to-point', 'internet-node']) obj.source = 'simple-point-to-point.cc' + obj = bld.create_ns3_program('simple-error-model', + ['point-to-point', 'internet-node']) + obj.source = 'simple-error-model.cc' + obj = bld.create_ns3_program('csma-one-subnet', ['csma', 'internet-node']) obj.source = 'csma-one-subnet.cc' diff --git a/src/common/error-model.cc b/src/common/error-model.cc new file mode 100644 index 000000000..938cced29 --- /dev/null +++ b/src/common/error-model.cc @@ -0,0 +1,300 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * + * 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 + * + * Author: Tom Henderson + * This code has been ported from ns-2 (queue/errmodel.{cc,h} + */ + +#include + +#include "error-model.h" + +#include "ns3/packet.h" +#include "ns3/assert.h" +#include "ns3/log.h" +#include "ns3/random-variable.h" +#include "ns3/default-value.h" + +NS_LOG_COMPONENT_DEFINE ("ErrorModel"); + +namespace ns3 { + +static ClassIdDefaultValue g_classIdErrorModelDefaultValue ("ErrorModel", + "Error Model", ErrorModel::iid, "RateErrorModel"); + +const InterfaceId ErrorModel::iid = + MakeInterfaceId ("ErrorModel", Object::iid); + +ErrorModel::ErrorModel () : + m_enable (true) +{ + NS_LOG_FUNCTION; + SetInterfaceId (ErrorModel::iid); +} + +ErrorModel::~ErrorModel () +{ + NS_LOG_FUNCTION; +} + +Ptr +ErrorModel::CreateDefault (void) +{ + NS_LOG_FUNCTION; + ClassId classId = g_classIdErrorModelDefaultValue.GetValue (); + Ptr em = ComponentManager::Create (classId, + ErrorModel::iid); + return em; +} + +bool +ErrorModel::IsCorrupt (Packet& p) +{ + NS_LOG_FUNCTION; + bool result; + // Insert any pre-conditions here + result = DoCorrupt (p); + // Insert any post-conditions here + return result; +} + +void +ErrorModel::Reset (void) +{ + NS_LOG_FUNCTION; + DoReset (); +} + +void +ErrorModel::Enable (void) +{ + NS_LOG_FUNCTION; + m_enable = true; +} + +void +ErrorModel::Disable (void) +{ + NS_LOG_FUNCTION; + m_enable = false; +} + +bool +ErrorModel::IsEnabled (void) const +{ + NS_LOG_FUNCTION; + return m_enable; +} + +// +// RateErrorModel +// + +const InterfaceId RateErrorModel::iid = + MakeInterfaceId ("RateErrorModel", ErrorModel::iid); + +const ClassId RateErrorModel::cid = + MakeClassId ("RateErrorModel", ErrorModel::iid, + RateErrorModel::iid); + +// Defaults for rate/size +static NumericDefaultValue g_defaultRateErrorModelErrorRate + ("RateErrorModelErrorRate", "The error rate for the error model", 0.0); + +static EnumDefaultValue + g_defaultRateErrorModelErrorUnit ("RateErrorModelErrorUnit", + "The error unit for this error model", + EU_BYTE, "EU_BYTE", + EU_PKT, "EU_PKT", + EU_BIT, "EU_BIT", + 0, (void*)0); + +RateErrorModel::RateErrorModel () : + m_unit (g_defaultRateErrorModelErrorUnit.GetValue() ), + m_rate (g_defaultRateErrorModelErrorRate.GetValue() ) +{ + NS_LOG_FUNCTION; + // Assume a uniform random variable if user does not specify + m_ranvar = new UniformVariable (); + SetInterfaceId (RateErrorModel::iid); +} + +RateErrorModel::~RateErrorModel () +{ + NS_LOG_FUNCTION; + delete m_ranvar; +} + +enum ErrorUnit +RateErrorModel::GetUnit (void) const +{ + NS_LOG_FUNCTION; + return m_unit; +} + +void +RateErrorModel::SetUnit (enum ErrorUnit error_unit) +{ + NS_LOG_FUNCTION; + m_unit = error_unit; +} + +double +RateErrorModel::GetRate (void) const +{ + NS_LOG_FUNCTION; + return m_rate; +} + +void +RateErrorModel::SetRate (double rate) +{ + NS_LOG_FUNCTION; + m_rate = rate; +} + +void +RateErrorModel::SetRandomVariable (const RandomVariable &ranvar) +{ + NS_LOG_FUNCTION; + delete m_ranvar; + m_ranvar = ranvar.Copy (); +} + +bool +RateErrorModel::DoCorrupt (Packet& p) +{ + NS_LOG_FUNCTION; + if (!m_enable) + { + return false; + } + switch (m_unit) + { + case EU_PKT: + return DoCorruptPkt (p); + case EU_BYTE: + return DoCorruptByte (p); + case EU_BIT: + return DoCorruptBit (p); + default: + NS_ASSERT_MSG (false, "m_unit not supported yet"); + break; + } + return false; +} + +bool +RateErrorModel::DoCorruptPkt (Packet& p) +{ + NS_LOG_FUNCTION; + return (m_ranvar->GetValue () < m_rate); +} + +bool +RateErrorModel::DoCorruptByte (Packet& p) +{ + NS_LOG_FUNCTION; + // compute pkt error rate, assume uniformly distributed byte error + double per = 1 - pow (1.0 - m_rate, p.GetSize ()); + return (m_ranvar->GetValue () < per); +} + +bool +RateErrorModel::DoCorruptBit(Packet& p) +{ + NS_LOG_FUNCTION; + // compute pkt error rate, assume uniformly distributed bit error + double per = 1 - pow (1.0 - m_rate, (8 * p.GetSize ()) ); + return (m_ranvar->GetValue () < per); +} + +void +RateErrorModel::DoReset (void) +{ + NS_LOG_FUNCTION; + /* re-initialize any state; no-op for now */ +} + +// +// ListErrorModel +// + +const InterfaceId ListErrorModel::iid = + MakeInterfaceId ("ListErrorModel", ErrorModel::iid); + +const ClassId ListErrorModel::cid = + MakeClassId ("ListErrorModel", ErrorModel::iid, + ListErrorModel::iid); + +ListErrorModel::ListErrorModel () +{ + NS_LOG_FUNCTION; + SetInterfaceId (ListErrorModel::iid); +} + +ListErrorModel::~ListErrorModel () +{ + NS_LOG_FUNCTION; +} + +std::list +ListErrorModel::GetList (void) const +{ + NS_LOG_FUNCTION; + return m_packetList; +} + +void +ListErrorModel::SetList (const std::list &packetlist) +{ + NS_LOG_FUNCTION; + m_packetList = packetlist; +} + +// When performance becomes a concern, the list provided could be +// converted to a dynamically-sized array of uint32_t to avoid +// list iteration below. +bool +ListErrorModel::DoCorrupt (Packet& p) +{ + NS_LOG_FUNCTION; + if (!m_enable) + { + return false; + } + uint32_t uid = p.GetUid (); + for (PacketListCI i = m_packetList.begin (); + i != m_packetList.end (); i++) + { + if (uid == *i) + { + return true; + } + } + return false; +} + +void +ListErrorModel::DoReset (void) +{ + NS_LOG_FUNCTION; + m_packetList.clear(); +} + + +} //namespace ns3 diff --git a/src/common/error-model.h b/src/common/error-model.h new file mode 100644 index 000000000..e386d2f94 --- /dev/null +++ b/src/common/error-model.h @@ -0,0 +1,236 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * + * 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 + * + * Author: Tom Henderson + * This code has been ported from ns-2 (queue/errmodel.{cc,h} + */ +#ifndef ERROR_MODEL_H +#define ERROR_MODEL_H + +#include +#include "ns3/object.h" +#include "ns3/component-manager.h" + +namespace ns3 { + +class Packet; +class RandomVariable; + +/** + * \brief General error model that can be used to corrupt packets + * + * This object is used to flag packets as being lost/errored or not. + * It is part of the Object framework and can be aggregated to + * other ns3 objects and handled by the Ptr class. + * + * The main method is IsCorrupt(Packet& p) which returns true if + * the packet is to be corrupted according to the underlying model. + * Depending on the error model, the packet itself may have its packet + * data buffer errored or not, or side information may be returned to + * the client in the form of a packet tag. + * The object can have state (resettable by Reset()). + * The object can also be enabled and disabled via two public member functions. + * + * Typical code (simplified) to use an ErrorModel may look something like + * this: + * \code + * Ptr rem = Create (); + * rem->SetRandomVariable (UniformVariable ()); + * rem->SetRate (0.001); + * ... + * Packet p; + * if (rem->IsCorrupt (p)) + * { + * dropTrace(p); + * } else { + * Forward (p); + * } + * \endcode + * + * Two practical error models, a ListErrorModel and a RateErrorModel, + * are currently implemented. + */ +class ErrorModel : public Object +{ +public: + static const InterfaceId iid; + /** + * A factory method to generate a preconfigured default ErrorModel for use + * \return an ErrorModel smart pointer that is the default ErrorModel + * type defined + */ + static Ptr CreateDefault (void); + + ErrorModel (); + virtual ~ErrorModel (); + + /** + * \returns true if the Packet is to be considered as errored/corrupted + * \param pkt Packet to apply error model to + */ + bool IsCorrupt (Packet& pkt); + /** + * Reset any state associated with the error model + */ + void Reset (void); + /** + * Enable the error model + */ + void Enable (void); + /** + * Disable the error model + */ + void Disable (void); + /** + * \return true if error model is enabled; false otherwise + */ + bool IsEnabled (void) const; + +protected: + bool m_enable; + +private: + /* + * These methods must be implemented by subclasses + */ + virtual bool DoCorrupt (Packet&) = 0; + virtual void DoReset (void) = 0; + +}; + +enum ErrorUnit + { + EU_BIT, + EU_BYTE, + EU_PKT + }; + +/** + * \brief Determine which packets are errored corresponding to an underlying + * distribution, rate, and unit. + * + * This object is used to flag packets as being lost/errored or not. + * The two parameters that govern the behavior are the rate (or + * equivalently, the mean duration/spacing between errors), and the + * unit (which may be per-bit, per-byte, and per-packet). + * Users can optionally provide a RandomVariable object; the default + * is to use a Uniform(0,1) distribution. + + * Reset() on this model will do nothing + * + * IsCorrupt() will not modify the packet data buffer + */ +class RateErrorModel : public ErrorModel +{ +public: + static const InterfaceId iid; + static const ClassId cid; + + RateErrorModel (); + virtual ~RateErrorModel (); + + /** + * \returns the ErrorUnit being used by the underlying model + */ + enum ErrorUnit GetUnit (void) const; + /** + * \param error_unit the ErrorUnit to be used by the underlying model + */ + void SetUnit (enum ErrorUnit error_unit); + + /** + * \returns the error rate being applied by the model + */ + double GetRate (void) const; + /** + * \param rate the error rate to be used by the model + */ + void SetRate (double rate); + + /** + * \param ranvar A random variable distribution to generate random variates + */ + void SetRandomVariable (const RandomVariable &ranvar); + +private: + virtual bool DoCorrupt (Packet& p); + virtual bool DoCorruptPkt (Packet& p); + virtual bool DoCorruptByte (Packet& p); + virtual bool DoCorruptBit (Packet& p); + virtual void DoReset (void); + + enum ErrorUnit m_unit; + double m_rate; + + RandomVariable* m_ranvar; +}; + +/** + * \brief Provide a list of Packet uids to corrupt + * + * This object is used to flag packets as being lost/errored or not. + * A note on performance: the list is assumed to be unordered, and + * in general, Packet uids received may be unordered. Therefore, + * each call to IsCorrupt() will result in a walk of the list with + * the present underlying implementation. + * + * Note also that if one wants to target multiple packets from looking + * at an (unerrored) trace file, the act of erroring a given packet may + * cause subsequent packet uids to change. For instance, suppose one wants + * to error packets 11 and 17 on a given device. It may be that erroring + * packet 11 will cause the subsequent uid stream to change and 17 may no + * longer correspond to the second packet that one wants to lose. Therefore, + * be advised that it might take some trial and error to select the + * right uids when multiple are provided. + * + * Reset() on this model will clear the list + * + * IsCorrupt() will not modify the packet data buffer + */ +class ListErrorModel : public ErrorModel +{ +public: + static const InterfaceId iid; + static const ClassId cid; + ListErrorModel (); + virtual ~ListErrorModel (); + + /** + * \return a copy of the underlying list + */ + std::list GetList (void) const; + /** + * \param packetlist The list of packet uids to error. + * + * This method overwrites any previously provided list. + */ + void SetList (const std::list &packetlist); + +private: + virtual bool DoCorrupt (Packet& p); + virtual void DoReset (void); + + typedef std::list PacketList; + typedef std::list::const_iterator PacketListCI; + + PacketList m_packetList; + +}; + + +} //namespace ns3 +#endif diff --git a/src/common/wscript b/src/common/wscript index 2472ecd1e..30589542a 100644 --- a/src/common/wscript +++ b/src/common/wscript @@ -13,6 +13,7 @@ def build(bld): 'tag-registry.cc', 'pcap-writer.cc', 'data-rate.cc', + 'error-model.cc', ] headers = bld.create_obj('ns3header') @@ -29,4 +30,5 @@ def build(bld): 'packet-metadata.h', 'pcap-writer.h', 'data-rate.h', + 'error-model.h', ] diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index e4fd05a1b..903bb6cb6 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -28,6 +28,7 @@ #include "ns3/ethernet-header.h" #include "ns3/ethernet-trailer.h" #include "ns3/llc-snap-header.h" +#include "ns3/error-model.h" NS_LOG_COMPONENT_DEFINE ("CsmaNetDevice"); @@ -82,7 +83,8 @@ CsmaTraceType::Get (void) const CsmaNetDevice::CsmaNetDevice (Ptr node) : NetDevice (node, Mac48Address::Allocate ()), - m_bps (DataRate (0xffffffff)) + m_bps (DataRate (0xffffffff)), + m_receiveErrorModel (0) { NS_LOG_FUNCTION; NS_LOG_PARAM ("(" << node << ")"); @@ -93,7 +95,8 @@ CsmaNetDevice::CsmaNetDevice (Ptr node) CsmaNetDevice::CsmaNetDevice (Ptr node, Mac48Address addr, CsmaEncapsulationMode encapMode) : NetDevice(node, addr), - m_bps (DataRate (0xffffffff)) + m_bps (DataRate (0xffffffff)), + m_receiveErrorModel (0) { NS_LOG_FUNCTION; NS_LOG_PARAM ("(" << node << ")"); @@ -531,6 +534,15 @@ CsmaNetDevice::AddQueue (Ptr q) m_queue = q; } +void CsmaNetDevice::AddReceiveErrorModel (Ptr em) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAM ("(" << em << ")"); + + m_receiveErrorModel = em; + AddInterface (em); +} + void CsmaNetDevice::Receive (const Packet& packet) { @@ -593,31 +605,41 @@ CsmaNetDevice::Receive (const Packet& packet) return; } - m_rxTrace (p); + if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (p) ) + { + NS_LOG_LOGIC ("Dropping pkt due to error model "); + m_dropTrace (packet); + // Do not forward up; let this packet go + } + else + { + m_rxTrace (p); // // protocol must be initialized to avoid a compiler warning in the RAW // case that breaks the optimized build. // - uint16_t protocol = 0; + uint16_t protocol = 0; - switch (m_encapMode) - { - case ETHERNET_V1: - case IP_ARP: - protocol = header.GetLengthType(); - break; - case LLC: { - LlcSnapHeader llc; - p.RemoveHeader (llc); - protocol = llc.GetType (); - } break; - case RAW: - NS_ASSERT (false); - break; + switch (m_encapMode) + { + case ETHERNET_V1: + case IP_ARP: + protocol = header.GetLengthType(); + break; + case LLC: + { + LlcSnapHeader llc; + p.RemoveHeader (llc); + protocol = llc.GetType (); + } + break; + case RAW: + NS_ASSERT (false); + break; + } + ForwardUp (p, protocol, header.GetSource ()); + return; } - - ForwardUp (p, protocol, header.GetSource ()); - return; } Address @@ -687,4 +709,5 @@ CsmaNetDevice::DoGetChannel(void) const return m_channel; } + } // namespace ns3 diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index bbe5259ed..1ce38d098 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -40,6 +40,7 @@ namespace ns3 { class Queue; class CsmaChannel; +class ErrorModel; /** * \brief hold in a TraceContext the type of trace source from a CsmaNetDevice @@ -192,6 +193,16 @@ enum CsmaEncapsulationMode { * ownership. */ void AddQueue (Ptr queue); + /** + * Attach a receive ErrorModel to the CsmaNetDevice. + * + * The CsmaNetDevice may optionally include an ErrorModel in + * the packet receive chain. + * + * @see ErrorModel + * @param em a pointer to the ErrorModel + */ + void AddReceiveErrorModel(Ptr em); /** * Receive a packet from a connected CsmaChannel. * @@ -453,6 +464,12 @@ private: * @see class DropTailQueue */ Ptr m_queue; + + /** + * Error model for receive packet events + */ + Ptr m_receiveErrorModel; + /** * NOT TESTED * The trace source for the packet reception events that the device can diff --git a/src/devices/point-to-point/point-to-point-net-device.cc b/src/devices/point-to-point/point-to-point-net-device.cc index ce3a253eb..66525b7a1 100644 --- a/src/devices/point-to-point/point-to-point-net-device.cc +++ b/src/devices/point-to-point/point-to-point-net-device.cc @@ -26,6 +26,7 @@ #include "ns3/composite-trace-resolver.h" #include "ns3/mac48-address.h" #include "ns3/llc-snap-header.h" +#include "ns3/error-model.h" #include "point-to-point-net-device.h" #include "point-to-point-channel.h" @@ -38,14 +39,28 @@ DataRateDefaultValue PointToPointNetDevice::g_defaultRate( "The default data rate for point to point links", DataRate ("10Mb/s")); -PointToPointTraceType::PointToPointTraceType () +PointToPointTraceType::PointToPointTraceType (enum Type type) + : m_type (type) { NS_LOG_FUNCTION; } +PointToPointTraceType::PointToPointTraceType () + : m_type (RX) +{ + NS_LOG_FUNCTION; +} + void PointToPointTraceType::Print (std::ostream &os) const { - os << "dev-rx"; + switch (m_type) { + case RX: + os << "dev-rx"; + break; + case DROP: + os << "dev-drop"; + break; + } } uint16_t @@ -63,6 +78,12 @@ PointToPointTraceType::GetTypeName (void) const return "ns3::PointToPointTraceType"; } +enum PointToPointTraceType::Type +PointToPointTraceType::Get (void) const +{ + NS_LOG_FUNCTION; + return m_type; +} PointToPointNetDevice::PointToPointNetDevice (Ptr node, const DataRate& rate) @@ -73,7 +94,9 @@ PointToPointNetDevice::PointToPointNetDevice (Ptr node, m_tInterframeGap (Seconds(0)), m_channel (0), m_queue (0), - m_rxTrace () + m_rxTrace (), + m_dropTrace (), + m_receiveErrorModel (0) { NS_LOG_FUNCTION; NS_LOG_PARAM ("(" << node << ")"); @@ -94,6 +117,7 @@ PointToPointNetDevice::~PointToPointNetDevice() { NS_LOG_FUNCTION; m_queue = 0; + m_receiveErrorModel = 0; } void @@ -221,7 +245,12 @@ PointToPointNetDevice::GetTraceResolver (void) const TraceDoc ("receive MAC packet", "const Packet &", "packet received"), m_rxTrace, - PointToPointTraceType ()); + PointToPointTraceType (PointToPointTraceType::RX)); + resolver->AddSource ("drop", + TraceDoc ("drop MAC packet", + "const Packet &", "packet dropped"), + m_dropTrace, + PointToPointTraceType (PointToPointTraceType::DROP)); resolver->SetParentResolver (NetDevice::GetTraceResolver ()); return resolver; } @@ -262,6 +291,15 @@ void PointToPointNetDevice::AddQueue (Ptr q) m_queue = q; } +void PointToPointNetDevice::AddReceiveErrorModel (Ptr em) +{ + NS_LOG_FUNCTION; + NS_LOG_PARAM ("(" << em << ")"); + + m_receiveErrorModel = em; + AddInterface (em); +} + void PointToPointNetDevice::Receive (Packet& p) { NS_LOG_FUNCTION; @@ -269,9 +307,17 @@ void PointToPointNetDevice::Receive (Packet& p) uint16_t protocol = 0; Packet packet = p; - m_rxTrace (packet); - ProcessHeader(packet, protocol); - ForwardUp (packet, protocol, GetBroadcast ()); + if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (p) ) + { + m_dropTrace (packet); + // Do not forward up; let this packet go + } + else + { + m_rxTrace (packet); + ProcessHeader(packet, protocol); + ForwardUp (packet, protocol, GetBroadcast ()); + } } Ptr PointToPointNetDevice::GetQueue(void) const diff --git a/src/devices/point-to-point/point-to-point-net-device.h b/src/devices/point-to-point/point-to-point-net-device.h index b85a2a66b..e597773ad 100644 --- a/src/devices/point-to-point/point-to-point-net-device.h +++ b/src/devices/point-to-point/point-to-point-net-device.h @@ -37,6 +37,7 @@ namespace ns3 { class Queue; class PointToPointChannel; +class ErrorModel; /** * \brief hold in a TraceContext the type of trace source from a PointToPointNetDevice @@ -44,10 +45,21 @@ class PointToPointChannel; class PointToPointTraceType : public TraceContextElement { public: + enum Type { + RX, + DROP + }; + PointToPointTraceType (enum Type type); PointToPointTraceType (); void Print (std::ostream &os) const; static uint16_t GetUid (void); std::string GetTypeName (void) const; + /** + * \returns the type of the trace source which generated an event. + */ + enum Type Get (void) const; +private: + enum Type m_type; }; /** @@ -133,6 +145,16 @@ public: * ownership. */ void AddQueue (Ptr queue); + /** + * Attach a receive ErrorModel to the PointToPointNetDevice. + * + * The PointToPointNetDevice may optionally include an ErrorModel in + * the packet receive chain. + * + * @see ErrorModel + * @param em a pointer to the ErrorModel + */ + void AddReceiveErrorModel(Ptr em); /** * Receive a packet from a connected PointToPointChannel. * @@ -288,11 +310,23 @@ private: * @see class TraceResolver */ CallbackTraceSource m_rxTrace; + /** + * The trace source for the packet drop events that the device can + * fire. + * + * @see class CallBackTraceSource + * @see class TraceResolver + */ + CallbackTraceSource m_dropTrace; /** * Default data rate. Used for all newly created p2p net devices */ static DataRateDefaultValue g_defaultRate; + /** + * Error model for receive packet events + */ + Ptr m_receiveErrorModel; }; }; // namespace ns3