From f4ea04de0bc3185e90f314c4722c7ad058ead945 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 5 Sep 2008 15:18:20 -0700 Subject: [PATCH] apply MTU/FrameSize treatment to point-to-point --- bindings/python/ns3_module_csma.py | 21 +-- bindings/python/ns3_module_helper.py | 4 + src/devices/csma/csma-net-device.cc | 2 +- src/devices/csma/csma-net-device.h | 20 --- .../point-to-point-net-device.cc | 94 +++++++++++--- .../point-to-point-net-device.h | 120 +++++++++++++++++- 6 files changed, 209 insertions(+), 52 deletions(-) diff --git a/bindings/python/ns3_module_csma.py b/bindings/python/ns3_module_csma.py index 13b12f5da..6000fab38 100644 --- a/bindings/python/ns3_module_csma.py +++ b/bindings/python/ns3_module_csma.py @@ -14,7 +14,7 @@ def register_types(module): ## 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 @@ def register_Ns3CsmaNetDevice_methods(root_module, cls): 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) diff --git a/bindings/python/ns3_module_helper.py b/bindings/python/ns3_module_helper.py index 4c29797c2..d32bbb502 100644 --- a/bindings/python/ns3_module_helper.py +++ b/bindings/python/ns3_module_helper.py @@ -313,6 +313,10 @@ def register_Ns3NetDeviceContainer_methods(root_module, cls): 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 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*,std::vector, std::allocator > > > 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 > > >', diff --git a/src/devices/csma/csma-net-device.cc b/src/devices/csma/csma-net-device.cc index 8fca1119f..47536f215 100644 --- a/src/devices/csma/csma-net-device.cc +++ b/src/devices/csma/csma-net-device.cc @@ -50,7 +50,7 @@ CsmaNetDevice::GetTypeId (void) 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, diff --git a/src/devices/csma/csma-net-device.h b/src/devices/csma/csma-net-device.h index 367ab855d..8a8faafd3 100644 --- a/src/devices/csma/csma-net-device.h +++ b/src/devices/csma/csma-net-device.h @@ -685,26 +685,6 @@ private: 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 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 2daae6597..a68f72c2b 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 @@ -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 @@ PointToPointNetDevice::GetTypeId (void) 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 ()) .AddAttribute ("DataRate", "The default data rate for point to point links", DataRateValue (DataRate ("32768b/s")), @@ -83,10 +90,19 @@ PointToPointNetDevice::PointToPointNetDevice () 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 () @@ -313,19 +329,6 @@ PointToPointNetDevice::GetAddress (void) const return m_address; } - 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 { @@ -501,4 +504,65 @@ PointToPointNetDevice::GetRemote (void) const 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 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 4f336004a..a0c755cc9 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 @@ -139,6 +139,93 @@ public: */ 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. // @@ -195,11 +282,24 @@ private: Ptr GetQueue(void) const; 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 @@ private: std::string m_name; bool m_linkUp; Callback 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