From 4042681e83f0bcb038432ac2b228a3ce4891bc56 Mon Sep 17 00:00:00 2001 From: "George F. Riley" Date: Thu, 14 Jun 2007 10:41:47 +0200 Subject: [PATCH] Simplification to p2p-net-device and p2p-channel (work in progress) --- src/devices/p2p/p2p-channel.cc | 6 +- src/devices/p2p/p2p-net-device.cc | 150 +++++++----------------------- src/devices/p2p/p2p-net-device.h | 59 ++++++------ src/node/mac-address.cc | 21 +++++ src/node/mac-address.h | 15 +++ 5 files changed, 104 insertions(+), 147 deletions(-) diff --git a/src/devices/p2p/p2p-channel.cc b/src/devices/p2p/p2p-channel.cc index 2833c8bb1..be4851553 100644 --- a/src/devices/p2p/p2p-channel.cc +++ b/src/devices/p2p/p2p-channel.cc @@ -135,12 +135,14 @@ PointToPointChannel::TransmitEnd(Packet& p, Ptr src) // The sender is going to free the packet as soon as it has been transmitted. // We need to copy it to get a reference so it won't e deleted. // - Packet packet = p; +// Above is not correct (GFR). The event scheduler makes a copy +// of the packet +// Packet packet = p; NS_DEBUG ("PointToPointChannel::TransmitEnd (): Schedule event in " << m_delay.GetSeconds () << "sec"); Simulator::Schedule (m_delay, &PointToPointChannel::PropagationCompleteEvent, - this, packet, src); + this, p, src); return true; } diff --git a/src/devices/p2p/p2p-net-device.cc b/src/devices/p2p/p2p-net-device.cc index 9542d951b..2667e388f 100644 --- a/src/devices/p2p/p2p-net-device.cc +++ b/src/devices/p2p/p2p-net-device.cc @@ -16,7 +16,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Author: Mathieu Lacage + * Author: Craig Dowell + * Revised: George Riley */ #include @@ -32,11 +33,17 @@ NS_DEBUG_COMPONENT_DEFINE ("PointToPointNetDevice"); namespace ns3 { -PointToPointNetDevice::PointToPointNetDevice (Ptr node) +DataRateDefaultValue PointToPointNetDevice::g_defaultRate( + "PointToPointLinkDataRate", + "The default data rate for point to point links", + DataRate ("10Mb/s")); + + PointToPointNetDevice::PointToPointNetDevice (Ptr node, + const DataRate& rate) : - NetDevice(node, MacAddress ("00:00:00:00:00:00")), + NetDevice(node, MacAddress (6)), m_txMachineState (READY), - m_bps (DataRate (0xffffffff)), + m_bps (rate), m_tInterframeGap (Seconds(0)), m_channel (0), m_queue (0), @@ -101,26 +108,25 @@ void PointToPointNetDevice::DoDispose() // // Assignment operator for PointToPointNetDevice. // -// This uses the non-obvious trick of taking the source net device passed by -// value instead of by reference. This causes the copy constructor to be -// invoked (where the real work is done -- see above). All we have to do -// here is to return the newly constructed net device. // - PointToPointNetDevice& -PointToPointNetDevice::operator= (const PointToPointNetDevice nd) +PointToPointNetDevice& +PointToPointNetDevice::operator= (const PointToPointNetDevice& nd) { NS_DEBUG ("PointToPointNetDevice::operator= (" << &nd << ")"); + // FIXME. Not sure what to do here + // GFR Note. I would suggest dis-allowing netdevice assignment, + // as well as pass-by-value (ie. copy constructor). return *this; } void -PointToPointNetDevice::SetDataRate(DataRate bps) +PointToPointNetDevice::SetDataRate(const DataRate& bps) { m_bps = bps; } void -PointToPointNetDevice::SetInterframeGap(Time t) +PointToPointNetDevice::SetInterframeGap(const Time& t) { m_tInterframeGap = t; } @@ -133,68 +139,23 @@ PointToPointNetDevice::SendTo (Packet& p, const MacAddress& dest) NS_ASSERT (IsLinkUp ()); -#ifdef NOTYET - struct NetDevicePacketDestAddress tag; - tag.address = address; - p.AddTag (tag); -#endif - // // This class simulates a point to point device. In the case of a serial // link, this means that we're simulating something like a UART. This is // not a requirement for a point-to-point link, but it's a typical model for // the device. // -// Generally, a real device will have a list of pending packets to transmit. -// An on-device CPU frees the main CPU(s) of the details of what is happening -// in the device and feeds the USART. The main CPU basically just sees the -// list of packets -- it puts packets into the list, and the device frees the -// packets when they are transmitted. -// -// In the case of our virtual device here, the queue pointed to by m_queue -// corresponds to this list. The main CPU adds packets to the list by -// calling this method and when the device completes a send, the packets are -// freed in an "interrupt" service routine. -// -// We're going to do the same thing here. So first of all, the incoming packet -// goes onto our queue if possible. If the queue can't handle it, there's -// nothing to be done. -// - if (m_queue->Enqueue(p) == false ) - { - return false; - } -// -// If there's a transmission in progress, the "interrupt" will keep the -// transmission process going. If the device is idle, we need to start a -// transmission. -// -// In the real world, the USART runs until it finishes sending bits, and then -// pulls on the device's transmit complete interrupt wire. At the same time, -// the electrons from the last wiggle of the wire are busy propagating down -// the wire. In the case of a long speed-of-light delay in the wire, we could -// conceivably start transmitting the next packet before the end of the -// previously sent data has even reached the end of the wire. This situation -// is usually avoided (like the plague) and an "interframe gap" is introduced. -// This is usually the round-trip delay on the channel plus some hard-to- -// quantify receiver turn-around time (the time required for the receiver -// to process the last frame and prepare for reception of the next). -// -// So, if the transmit machine is ready, we need to schedule a transmit -// complete event (at which time we tell the channel we're no longer sending -// bits). A separate transmit ready event (at which time the transmitter -// becomes ready to start sending bits again is scheduled there). Finally, -// we tell the channel (via TransmitStart ()) that we've started wiggling the -// wire and bits are coming out. -// -// If the transmit machine is not ready, we just leave and the transmit ready -// event we know is coming will kick-start the transmit process. // +// If there's a transmission in progress, we enque the packet for later +// trnsmission; otherwise we send it now. if (m_txMachineState == READY) { return TransmitStart (p); } - return true; + else + { + return m_queue->Enqueue(p); + } } bool @@ -206,25 +167,25 @@ PointToPointNetDevice::TransmitStart (Packet &p) // // This function is called to start the process of transmitting a packet. // We need to tell the channel that we've started wiggling the wire and -// schedule an event that will be executed when it's time to tell the -// channel that we're done wiggling the wire. +// schedule an event that will be executed when the transmission is complete. // NS_ASSERT_MSG(m_txMachineState == READY, "Must be READY to transmit"); m_txMachineState = BUSY; - Time tEvent = Seconds (m_bps.CalculateTxTime(p.GetSize())); + Time txCompleteTime = Seconds (m_bps.CalculateTxTime(p.GetSize())) + + m_tInterframeGap; NS_DEBUG ("PointToPointNetDevice::TransmitStart (): " << "Schedule TransmitCompleteEvent in " << - tEvent.GetSeconds () << "sec"); - - Simulator::Schedule (tEvent, - &PointToPointNetDevice::TransmitCompleteEvent, + txCompleteTime.GetSeconds () << "sec"); + // Schedule the tx complete event + Simulator::Schedule (txCompleteTime, + &PointToPointNetDevice::TransmitComplete, this); - return m_channel->TransmitStart (p, this); + return m_channel->TransmitStart(p, this); } void -PointToPointNetDevice::TransmitCompleteEvent (void) +PointToPointNetDevice::TransmitComplete (void) { NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent ()"); // @@ -234,49 +195,10 @@ PointToPointNetDevice::TransmitCompleteEvent (void) // the transmitter after the interframe gap. // NS_ASSERT_MSG(m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = GAP; - Packet p; - bool found; - found = m_queue->Dequeue (p); - NS_ASSERT_MSG(found, "Packet must be on queue if transmitted"); - NS_DEBUG ("PointToPointNetDevice::TransmitCompleteEvent (): Pkt UID is " << - p.GetUid () << ")"); - m_channel->TransmitEnd (p, this); - - NS_DEBUG ( - "PointToPointNetDevice::TransmitCompleteEvent (): " << - "Schedule TransmitReadyEvent in " - << m_tInterframeGap.GetSeconds () << "sec"); - - Simulator::Schedule (m_tInterframeGap, - &PointToPointNetDevice::TransmitReadyEvent, - this); -} - - void -PointToPointNetDevice::TransmitReadyEvent (void) -{ - NS_DEBUG ("PointToPointNetDevice::TransmitReadyEvent ()"); -// -// This function is called to enable the transmitter after the interframe -// gap has passed. If there are pending transmissions, we use this opportunity -// to start the next transmit. -// - NS_ASSERT_MSG(m_txMachineState == GAP, "Must be in interframe gap"); m_txMachineState = READY; - - if (m_queue->IsEmpty()) - { - return; - } - else - { - Packet p; - bool found; - found = m_queue->Peek (p); - NS_ASSERT_MSG(found, "IsEmpty false but no Packet on queue?"); - TransmitStart (p); - } + Packet p; + if (!m_queue->Dequeue(p)) return; // Nothing to do at this point + TransmitStart(p); } TraceResolver * diff --git a/src/devices/p2p/p2p-net-device.h b/src/devices/p2p/p2p-net-device.h index e1eb8a666..5fb3e8016 100644 --- a/src/devices/p2p/p2p-net-device.h +++ b/src/devices/p2p/p2p-net-device.h @@ -30,6 +30,7 @@ #include "ns3/callback-trace-source.h" #include "ns3/nstime.h" #include "ns3/data-rate.h" +#include "ns3/default-value.h" #include "ns3/ptr.h" namespace ns3 { @@ -80,7 +81,8 @@ public: * @see PointToPointTopology::AddPointToPointLink () * @param node the Node to which this device is connected. */ - PointToPointNetDevice (Ptr node); + PointToPointNetDevice (Ptr node, + const DataRate& = g_defaultRate.GetValue()); /** * Copy Construct a PointToPointNetDevice * @@ -105,7 +107,7 @@ public: * * @param nd the object to be copied */ - PointToPointNetDevice& operator= (PointToPointNetDevice nd); + PointToPointNetDevice& operator= (const PointToPointNetDevice& nd); /** * Set the Data Rate used for transmission of packets. The data rate is * set in the Attach () method from the corresponding field in the channel @@ -114,7 +116,7 @@ public: * @see Attach () * @param bps the data rate at which this object operates */ - void SetDataRate(DataRate bps); + void SetDataRate(const DataRate& bps); /** * Set the inteframe gap used to separate packets. The interframe gap * defines the minimum space required between packets sent by this device. @@ -125,7 +127,7 @@ public: * @see Attach () * @param t the interframe gap time */ - void SetInterframeGap(Time t); + void SetInterframeGap(const Time& t); /** * Attach the device to a channel. * @@ -190,6 +192,19 @@ protected: * @returns a pointer to the channel */ virtual Ptr DoGetChannel(void) const; + /** + * Set a new default data rate + * @param Data rate to set for new default + */ + static void SetDefaultRate(const DataRate&); + + /** + * Get the current default rate. + * @returns a const reference to current default + */ + + static const DataRate& GetDefaultRate(); + private: /** * Send a Packet Down the Wire. @@ -223,33 +238,11 @@ private: /** * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. * - * The TransmitCompleteEvent method is used internally to finish the process - * of sending a packet out on the channel. During execution of this method - * the TransmitEnd method is called on the channel to let it know that the - * physical device this class represents has virually finished sending - * signals. The channel uses this event to begin its speed of light delay - * timer after which it notifies the Net Device at the other end of the - * link that the bits have arrived. During this method, the net device - * also schedules the TransmitReadyEvent at which time the transmitter - * becomes ready to send the next packet. + * The TransmitComplete method is used internally to finish the process + * of sending a packet out on the channel. * - * @see PointToPointChannel::TransmitEnd () - * @see TransmitReadyEvent () - * @returns true if success, false on failure */ - void TransmitCompleteEvent (void); - /** - * Cause the Transmitter to Become Ready to Send Another Packet. - * - * The TransmitReadyEvent method is used internally to re-enable the - * transmit machine of the net device. It is scheduled after a suitable - * interframe gap after the completion of the previous transmission. - * The queue is checked at this time, and if there is a packet waiting on - * the queue, the transmission process is begun. - * - * @see TransmitStart () - */ - void TransmitReadyEvent (void); + void TransmitComplete(void); /** * Create a Trace Resolver for events in the net device. * @@ -263,8 +256,7 @@ private: enum TxMachineState { READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY, /**< The transmitter is busy transmitting a packet */ - GAP /**< The transmitter is in the interframe gap time */ + BUSY /**< The transmitter is busy transmitting a packet */ }; /** * The state of the Net Device transmit state machine. @@ -305,6 +297,11 @@ private: * @see class TraceResolver */ CallbackTraceSource m_rxTrace; + /** + * Default data rate. Used for all newly created p2p net devices + */ + static DataRateDefaultValue g_defaultRate; + }; }; // namespace ns3 diff --git a/src/node/mac-address.cc b/src/node/mac-address.cc index be455a8a3..9dcf9bdd6 100644 --- a/src/node/mac-address.cc +++ b/src/node/mac-address.cc @@ -33,6 +33,9 @@ namespace ns3 { +// Static variables +uint8_t MacAddress::g_nextAddress[MacAddress::MAX_LEN]; + static char AsciiToLowCase (char c) { @@ -54,6 +57,13 @@ MacAddress::MacAddress () : m_len(0) } } +MacAddress::MacAddress(uint8_t len) : m_len(len) +{ + NS_ASSERT (len <= MacAddress::MAX_LEN); + AdvanceAddress(); + memcpy(m_address, g_nextAddress, len); +} + MacAddress::MacAddress (uint8_t const *address, uint8_t len) { NS_ASSERT (len <= MacAddress::MAX_LEN); @@ -148,6 +158,17 @@ MacAddress::Set (uint8_t const ad[MacAddress::MAX_LEN], uint8_t len) m_len = len; } +// Static methods +void MacAddress::AdvanceAddress() + { + // Advance to next address, little end first + for(size_t i = 0; i < MAX_LEN; ++i) + { + if (++g_nextAddress[i] != 0) break; + } + } + +// Non-member operators bool operator == (MacAddress const&a, MacAddress const&b) { return a.IsEqual (b); diff --git a/src/node/mac-address.h b/src/node/mac-address.h index 75a80b700..76c5a6ae0 100644 --- a/src/node/mac-address.h +++ b/src/node/mac-address.h @@ -46,6 +46,13 @@ public: * This MacAddress has length of zero, and is internally all zeros */ MacAddress (void); + /** + * \brief Construct a MacAddress using the next available + * address. + * \see MacAddres::Next + * \param len length, in bytes, of the desired address + */ + MacAddress(uint8_t len); /** * \brief Construct a MacAddress from a byte-array * @@ -97,6 +104,14 @@ public: */ void Set (uint8_t const ad[MAX_LEN], uint8_t len); + // Static methods/members + /** + * + * Advance the global to the next available mac address. + */ + static void AdvanceAddress(); + static uint8_t g_nextAddress[MAX_LEN]; + private: uint8_t m_address[MAX_LEN]; uint8_t m_len;