apply MTU/FrameSize treatment to point-to-point
authorcraigdo@ns-test
Fri, 05 Sep 2008 15:18:20 -0700
changeset 3632 aa1fb0f43571
parent 3631 d52cce4f1d6c
child 3633 fedc8b314171
apply MTU/FrameSize treatment to point-to-point
bindings/python/ns3_module_csma.py
bindings/python/ns3_module_helper.py
src/devices/csma/csma-net-device.cc
src/devices/csma/csma-net-device.h
src/devices/point-to-point/point-to-point-net-device.cc
src/devices/point-to-point/point-to-point-net-device.h
--- a/bindings/python/ns3_module_csma.py	Fri Sep 05 11:57:56 2008 -0700
+++ b/bindings/python/ns3_module_csma.py	Fri Sep 05 15:18:20 2008 -0700
@@ -14,7 +14,7 @@
     ## csma-net-device.h: ns3::CsmaNetDevice [class]
     module.add_class('CsmaNetDevice', parent=root_module['ns3::NetDevice'])
     ## csma-net-device.h: ns3::CsmaNetDevice::EncapsulationMode [enumeration]
-    module.add_enum('EncapsulationMode', ['ETHERNET_V1', 'IP_ARP', 'RAW', 'LLC'], outer_class=root_module['ns3::CsmaNetDevice'])
+    module.add_enum('EncapsulationMode', ['ILLEGAL', 'DIX', 'LLC'], outer_class=root_module['ns3::CsmaNetDevice'])
     
     ## Register a nested module for the namespace internal
     
@@ -256,21 +256,12 @@
     cls.add_method('SetAddress', 
                    'void', 
                    [param('ns3::Mac48Address', 'addr')])
-    ## csma-net-device.h: void ns3::CsmaNetDevice::SetMaxPayloadLength(uint16_t maxPayloadLength) [member function]
-    cls.add_method('SetMaxPayloadLength', 
+    ## csma-net-device.h: void ns3::CsmaNetDevice::SetFrameSize(uint16_t frameSize) [member function]
+    cls.add_method('SetFrameSize', 
                    'void', 
-                   [param('uint16_t', 'maxPayloadLength')])
-    ## csma-net-device.h: uint16_t ns3::CsmaNetDevice::GetMaxPayloadLength() const [member function]
-    cls.add_method('GetMaxPayloadLength', 
-                   'uint16_t', 
-                   [], 
-                   is_const=True)
-    ## csma-net-device.h: void ns3::CsmaNetDevice::SetMacMtu(uint16_t mtu) [member function]
-    cls.add_method('SetMacMtu', 
-                   'void', 
-                   [param('uint16_t', 'mtu')])
-    ## csma-net-device.h: uint16_t ns3::CsmaNetDevice::GetMacMtu() const [member function]
-    cls.add_method('GetMacMtu', 
+                   [param('uint16_t', 'frameSize')])
+    ## csma-net-device.h: uint16_t ns3::CsmaNetDevice::GetFrameSize() const [member function]
+    cls.add_method('GetFrameSize', 
                    'uint16_t', 
                    [], 
                    is_const=True)
--- a/bindings/python/ns3_module_helper.py	Fri Sep 05 11:57:56 2008 -0700
+++ b/bindings/python/ns3_module_helper.py	Fri Sep 05 15:18:20 2008 -0700
@@ -313,6 +313,10 @@
     cls.add_constructor([param('ns3::NetDeviceContainer const &', 'arg0')])
     ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer() [constructor]
     cls.add_constructor([])
+    ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer(ns3::Ptr<ns3::NetDevice> dev) [constructor]
+    cls.add_constructor([param('ns3::Ptr< ns3::NetDevice >', 'dev')])
+    ## net-device-container.h: ns3::NetDeviceContainer::NetDeviceContainer(ns3::NetDeviceContainer const & a, ns3::NetDeviceContainer const & b) [constructor]
+    cls.add_constructor([param('ns3::NetDeviceContainer const &', 'a'), param('ns3::NetDeviceContainer const &', 'b')])
     ## net-device-container.h: __gnu_cxx::__normal_iterator<const ns3::Ptr<ns3::NetDevice>*,std::vector<ns3::Ptr<ns3::NetDevice>, std::allocator<ns3::Ptr<ns3::NetDevice> > > > ns3::NetDeviceContainer::Begin() const [member function]
     cls.add_method('Begin', 
                    '__gnu_cxx::__normal_iterator< const ns3::Ptr< ns3::NetDevice >, std::vector< ns3::Ptr< ns3::NetDevice > > >', 
--- a/src/devices/csma/csma-net-device.cc	Fri Sep 05 11:57:56 2008 -0700
+++ b/src/devices/csma/csma-net-device.cc	Fri Sep 05 15:18:20 2008 -0700
@@ -50,7 +50,7 @@
                    Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
                    MakeMac48AddressAccessor (&CsmaNetDevice::m_address),
                    MakeMac48AddressChecker ())
-    .AddAttribute ("FrameLength", 
+    .AddAttribute ("FrameSize", 
                    "The maximum size of a packet sent over this device.",
                    UintegerValue (DEFAULT_FRAME_SIZE),
                    MakeUintegerAccessor (&CsmaNetDevice::SetFrameSize,
--- a/src/devices/csma/csma-net-device.h	Fri Sep 05 11:57:56 2008 -0700
+++ b/src/devices/csma/csma-net-device.h	Fri Sep 05 15:18:20 2008 -0700
@@ -685,26 +685,6 @@
 
   static const uint16_t DEFAULT_FRAME_SIZE = 1518;
   static const uint16_t ETHERNET_OVERHEAD = 18;
-  static const uint16_t DEFAULT_MTU = (DEFAULT_FRAME_SIZE - ETHERNET_OVERHEAD);
-
-  /**
-   * There are two MTU types that are used in this driver.  The MAC-level 
-   * MTU corresponds to the amount of data (payload) an upper layer can 
-   * send across the link.  The PHY-level MTU corresponds to the Type/Length
-   * field in the 802.3 header and corresponds to the maximum amount of data
-   * the underlying packet can accept.  These are not the same thing.  For 
-   * example, if you choose "Llc" as your encapsulation mode, the MAC-level
-   * MTU will be reduced by the eight bytes with respect to the PHY-level
-   * MTU which are consumed by the LLC/SNAP header.
-   *
-   * This method checks the current enacpuslation mode (and any other 
-   * relevent information) and determines if the provided frame size 
-   * and mtu are consistent.
-   *
-   * \param frameSize The proposed new frame size
-   * \param mtu The proposed new MTU
-   */
-  bool CheckMtuConsistency (uint16_t frameSize, uint16_t mtu);
 
   /**
    * The frame size/packet size.  This corresponds to the maximum 
--- a/src/devices/point-to-point/point-to-point-net-device.cc	Fri Sep 05 11:57:56 2008 -0700
+++ b/src/devices/point-to-point/point-to-point-net-device.cc	Fri Sep 05 15:18:20 2008 -0700
@@ -23,6 +23,7 @@
 #include "ns3/llc-snap-header.h"
 #include "ns3/error-model.h"
 #include "ns3/trace-source-accessor.h"
+#include "ns3/uinteger.h"
 #include "ns3/pointer.h"
 #include "point-to-point-net-device.h"
 #include "point-to-point-channel.h"
@@ -45,6 +46,12 @@
                    Mac48AddressValue (Mac48Address ("ff:ff:ff:ff:ff:ff")),
                    MakeMac48AddressAccessor (&PointToPointNetDevice::m_address),
                    MakeMac48AddressChecker ())
+    .AddAttribute ("FrameSize", 
+                   "The maximum size of a packet sent over this device.",
+                   UintegerValue (DEFAULT_FRAME_SIZE),
+                   MakeUintegerAccessor (&PointToPointNetDevice::SetFrameSize,
+                                         &PointToPointNetDevice::GetFrameSize),
+                   MakeUintegerChecker<uint16_t> ())
     .AddAttribute ("DataRate", 
                    "The default data rate for point to point links",
                    DataRateValue (DataRate ("32768b/s")),
@@ -83,10 +90,19 @@
   m_txMachineState (READY),
   m_channel (0), 
   m_name (""),
-  m_linkUp (false),
-  m_mtu (0xffff)
+  m_linkUp (false)
 {
   NS_LOG_FUNCTION (this);
+
+  //
+  // A quick sanity check to ensure consistent constants.
+  //
+  PppHeader ppp;
+  NS_ASSERT_MSG (PPP_OVERHEAD == ppp.GetSerializedSize (), 
+                 "PointToPointNetDevice::PointToPointNetDevice(): PPP_OVERHEAD inconsistent");
+
+  m_frameSize = DEFAULT_FRAME_SIZE;
+  m_mtu = MtuFromFrameSize (m_frameSize);
 }
 
 PointToPointNetDevice::~PointToPointNetDevice ()
@@ -314,19 +330,6 @@
 }
 
   bool 
-PointToPointNetDevice::SetMtu (const uint16_t mtu)
-{
-  m_mtu = mtu;
-  return true;
-}
-
-  uint16_t 
-PointToPointNetDevice::GetMtu (void) const
-{
-  return m_mtu;
-}
-
-  bool 
 PointToPointNetDevice::IsLinkUp (void) const
 {
   return m_linkUp;
@@ -501,4 +504,65 @@
   return Address ();
 }
 
+  uint16_t
+PointToPointNetDevice::MtuFromFrameSize (uint16_t frameSize)
+{
+  NS_LOG_FUNCTION (frameSize);
+
+  PppHeader ppp;
+
+  NS_ASSERT_MSG ((uint32_t)frameSize >= ppp.GetSerializedSize (), 
+                 "PointToPointNetDevice::MtuFromFrameSize(): Given frame size too small to support PPP");
+  return frameSize - ppp.GetSerializedSize ();
+}
+  
+  uint16_t
+PointToPointNetDevice::FrameSizeFromMtu (uint16_t mtu)
+{
+  NS_LOG_FUNCTION (mtu);
+
+  PppHeader ppp;
+  return mtu + ppp.GetSerializedSize ();
+}
+
+  void 
+PointToPointNetDevice::SetFrameSize (uint16_t frameSize)
+{
+  NS_LOG_FUNCTION (frameSize);
+
+  m_frameSize = frameSize;
+  m_mtu = MtuFromFrameSize (frameSize);
+
+  NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
+  NS_LOG_LOGIC ("m_mtu = " << m_mtu);
+}
+
+  uint16_t
+PointToPointNetDevice::GetFrameSize (void) const
+{
+  return m_frameSize;
+}
+
+  bool
+PointToPointNetDevice::SetMtu (uint16_t mtu)
+{
+  NS_LOG_FUNCTION (mtu);
+
+  m_frameSize = FrameSizeFromMtu (mtu);
+  m_mtu = mtu;
+
+  NS_LOG_LOGIC ("m_frameSize = " << m_frameSize);
+  NS_LOG_LOGIC ("m_mtu = " << m_mtu);
+
+  return true;
+}
+
+  uint16_t
+PointToPointNetDevice::GetMtu (void) const
+{
+  NS_LOG_FUNCTION_NOARGS ();
+  return m_mtu;
+}
+
+
 } // namespace ns3
--- a/src/devices/point-to-point/point-to-point-net-device.h	Fri Sep 05 11:57:56 2008 -0700
+++ b/src/devices/point-to-point/point-to-point-net-device.h	Fri Sep 05 15:18:20 2008 -0700
@@ -139,6 +139,93 @@
    */
   void SetAddress (Mac48Address addr);
 
+  /**
+   * Set The max frame size of packets sent over this device.
+   *
+   * Okay, that was easy to say, but the details are a bit thorny.  We have a MAC-level MTU that is the payload that higher 
+   * level protocols see.  We have a PHY-level MTU which is the maximum number of bytes we can send over the link 
+   * (cf. 1500 bytes for Ethernet).  We also have a frame size which is some total number of bytes in a packet which could
+   * or could not include any framing and overhead.  There can be a lot of inconsistency in definitions of these terms.  For
+   * example, RFC 1042 asserts that the terms maximum transmission unit and maximum packet size are equivalent.  RFC 791, 
+   * however, defines MTU as the maximum sized IP datagram that can be sent.  Packet size and frame size are sometimes
+   * used interchangeably.
+   *
+   * So, some careful definitions are in order to avoid confusion:
+   *
+   * In real serial channel (HDLC, for example), the wire idles (sends all ones) until the channel begins sending a packet.
+   * A frame on the wire starts with a flag character (01111110).  This is followed by what is usually called the packet: 
+   * address, control, payload, and a Frame Check Sequence (FCS).  This is followed by another flag character.  If the flag
+   * characters are used, then bit stuffing must be used to prevent flag characters from appearing in the packet and confusing
+   * the link.  Som to be strictly and pedantically correct the frame size is then necessarily larger than the packet size on 
+   * a real link.  But, this isn't a real link, it's a simulation of a device similar to a point-to-point device, and we have
+   * no good reason to add framing bits and therefore to do bit-stuffing.  So, in the case of the point-to-point device, the 
+   * frame size is equal to the packet size.  Since these two values are defined to be equal, there is no danger in assuming
+   * they are identical.  We define packet size to be equal to frame size and this excludes the flag characters.  We define a 
+   * single (MAC-level) MTU that coresponds to the payload size of the packet, which is the IP-centric view of the term as
+   * seen in RFC 791.
+   *
+   * To make this concrete, consider PPP framing on a synchronous link.  In this framing scheme, a real serial frame on the 
+   * wire starts with a flag character, address and control characters, then a 16-bit PPP protocol ID (0x21 = IP).  Then we 
+   * would see the actual payload we are supposed to send, presumably an IP datagram.  At then we see the FCS and finally 
+   * another flag character to end the frame.  We ignore the flag bits on this device since it they are not needed.  We 
+   * aren't really using HDLC to send frames across the link, so we don't need the address and control bits either.  In fact,
+   * to encapsulate using unframed PPP all we need to do is prepend the two-byte protocol ID.
+   *
+   * Typically the limiting factor in frame size is due to hardware limitations in the underlying HDLC controller receive 
+   * FIFO buffer size.  This number can vary widely.  For example, the Motorola MC92460 has a 64 KByte maximum frame size; 
+   * the Intel IXP4XX series has a 16 KByte size.  Older USARTs have a maximum frame size around 2KBytes, and typical PPP
+   * links on the Internet have their MTU set to 1500 bytes since this is what will typically be used on Ethernet segments
+   * and will avoid path MTU issues.  We choose to make the default MTU 1500 bytes which then fixes the maximum frame size
+   * as described below.
+   *
+   * So, there are really two related variables at work here.  There is the maximum frame size that can be sent over the
+   * link and there is the MTU.
+   *
+   * So, what do we do since these values must always be consistent in the driver?  We want to actually allow a user to change 
+   * these variables, but we want the results (even at intermediate stages of her ultimate change) to be consistent.  We 
+   * certainly don't want to require that users must understand the details of PPP encapsulation in order to set these 
+   * variables.
+   *
+   * Consider the following situation:  A user wants to set the maximum frame size to 16 KBytes.  This user shouldn't have to
+   * concern herself that the PPP encapsulation will consume six bytes.  She should not have to figure out that the MTU needs
+   * to be set to 16K - 2 bytes to make things consistent.
+   *
+   * Similarly, a user who is interested in setting the MTU to 1500 bytes should not be forced to understand that the frame 
+   * size will need to be set to 1502 bytes. 
+   *
+   * We could play games trying to figure out what the user wants to do, but that is typically a bad plan and programmers
+   * have a long and distinguished history of guessing wrong.  We'll avoid all of that and just define a flexible behavior
+   * that can be worked to get what you want.  Here it is:
+   *
+   * - If the user is changing the MTU, she is interested in getting that part of the system set, so the frame size
+   * will be changed to make it consistent;
+   *
+   * - If the user is changing the frame size, he is interested in getting that part of the system set, so the MTU
+   * will be changed to make it consistent;
+   *
+   * - You cannot define the MTU and frame size separately -- they are always tied together by the overhead of the PPP 
+   * encapsulation.  This is not a restriction.  Consider what this means.  Perhaps you want to set the frame size to some 
+   * large number and the MTU to some small number.  The largest packet you can send is going to be limited by the MTU, so it
+   * is not possible to send a frame larger than the MTU plus overhead.  Having the ability to set a  larger frame size is not
+   * useful.
+   * 
+   * So, if a user calls SetFrameSize, we assume that the maximum frame size is the interesting thing for that user and
+   * we just adjust the MTU to a new "correct value" based on the current encapsulation mode.  If a user calls SetMtu, we 
+   * assume that the MTU is the interesting property for that user, and we adjust the frame size to a new "correct value" 
+   * for the current encapsulation mode.  If a user calls SetEncapsulationMode, then we take the MTU as the free variable 
+   * and set its value to match the current frame size.
+   *
+   * \param frameSize The max frame size of packets sent over this device.
+   */
+  void SetFrameSize (uint16_t frameSize);
+
+  /**
+   * Get The max frame size of packets sent over this device.
+   *
+   * \returns The max frame size of packets sent over this device.
+   */
+  uint16_t GetFrameSize (void) const;
+
 //
 // Pure virtual methods inherited from NetDevice we must implement.
 //
@@ -196,10 +283,23 @@
 
 private:
   /**
+   * Calculate the value for the MTU that would result from 
+   * setting the frame size to the given value.
+   */
+  uint16_t MtuFromFrameSize (uint16_t frameSize);
+
+  /**
+   * Calculate the value for the frame size that would be required
+   * to be able to set the MTU to the given value.
+   */
+  uint16_t FrameSizeFromMtu (uint16_t mtu);
+
+  /**
    * \returns the address of the remote device connected to this device
    * through the point to point channel.
    */
   Address GetRemote (void) const;
+
   /**
    * Adds the necessary headers and trailers to a packet of data in order to
    * respect the protocol implemented by the agent.
@@ -314,7 +414,25 @@
   std::string m_name;
   bool m_linkUp;
   Callback<void> m_linkChangeCallback;
-  uint16_t m_mtu;
+
+  static const uint16_t DEFAULT_MTU = 1500;
+  static const uint16_t PPP_OVERHEAD = 2;
+  static const uint16_t DEFAULT_FRAME_SIZE = DEFAULT_MTU + PPP_OVERHEAD;
+
+  /**
+   * The frame size/packet size.  This corresponds to the maximum 
+   * number of bytes that can be transmitted as a packet without framing.
+   * This corresponds to the 1518 byte packet size often seen on Ethernet.
+   */
+  uint32_t m_frameSize;
+
+  /**
+   * The Maxmimum Transmission Unit.  This corresponds to the maximum 
+   * number of bytes that can be transmitted as seen from higher layers.
+   * This corresponds to the 1500 byte MTU size often seen on IP over 
+   * Ethernet.
+   */
+  uint32_t m_mtu;
 };
 
 } // namespace ns3