--- a/examples/udp-echo.cc Sun Aug 03 21:55:49 2008 -0700
+++ b/examples/udp-echo.cc Mon Aug 04 17:32:32 2008 -0700
@@ -89,6 +89,7 @@
CsmaHelper csma;
csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000)));
csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+ csma.SetDeviceAttribute ("MTU", UintegerValue (1400));
NetDeviceContainer d = csma.Install (n);
Ipv4AddressHelper ipv4;
--- a/src/devices/csma/csma-net-device.cc Sun Aug 03 21:55:49 2008 -0700
+++ b/src/devices/csma/csma-net-device.cc Mon Aug 04 17:32:32 2008 -0700
@@ -52,18 +52,20 @@
MakeMac48AddressChecker ())
.AddAttribute ("PayloadLength",
"The max PHY-level payload length of packets sent over this device.",
- UintegerValue (DEFAULT_FRAME_LENGTH),
- MakeUintegerAccessor (&CsmaNetDevice::m_maxPayloadLength),
+ UintegerValue (DEFAULT_PAYLOAD_LENGTH),
+ MakeUintegerAccessor (&CsmaNetDevice::SetMaxPayloadLength,
+ &CsmaNetDevice::GetMaxPayloadLength),
MakeUintegerChecker<uint16_t> ())
.AddAttribute ("MTU",
"The MAC-level MTU (client payload) of packets sent over this device.",
UintegerValue (DEFAULT_MTU),
- MakeUintegerAccessor (&CsmaNetDevice::m_mtu),
+ MakeUintegerAccessor (&CsmaNetDevice::SetMacMtu,
+ &CsmaNetDevice::GetMacMtu),
MakeUintegerChecker<uint16_t> ())
.AddAttribute ("EncapsulationMode",
"The link-layer encapsulation type to use.",
EnumValue (LLC),
- MakeEnumAccessor (&CsmaNetDevice::m_encapMode),
+ MakeEnumAccessor (&CsmaNetDevice::SetEncapsulationMode),
MakeEnumChecker (ETHERNET_V1, "EthernetV1",
IP_ARP, "IpArp",
RAW, "Raw",
@@ -106,6 +108,14 @@
m_txMachineState = READY;
m_tInterframeGap = Seconds (0);
m_channel = 0;
+
+ m_encapMode = LLC;
+ m_maxPayloadLength = DEFAULT_PAYLOAD_LENGTH;
+ m_mtu = MacMtuFromPayload (m_maxPayloadLength);
+
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+ NS_LOG_LOGIC ("m_maxPayloadLength = " << m_maxPayloadLength);
+ NS_LOG_LOGIC ("m_mtu = " << m_mtu);
}
CsmaNetDevice::~CsmaNetDevice()
@@ -123,6 +133,133 @@
NetDevice::DoDispose ();
}
+ uint16_t
+CsmaNetDevice::MacMtuFromPayload (uint16_t payloadLength)
+{
+ NS_LOG_FUNCTION (payloadLength);
+
+ switch (m_encapMode)
+ {
+ case RAW:
+ case IP_ARP:
+ case ETHERNET_V1:
+ return payloadLength;
+ case LLC:
+ {
+ LlcSnapHeader llc;
+
+ NS_ASSERT_MSG (payloadLength >= llc.GetSerializedSize (), "CsmaNetDevice::MacMtuFromPayload(): "
+ "Given payload too small to support LLC mode");
+ return payloadLength - llc.GetSerializedSize ();
+ }
+ }
+
+ NS_ASSERT_MSG (false, "CsmaNetDevice::MacMtuFromPayload(): Unexpected encapsulation mode");
+ return 0;
+}
+
+ uint16_t
+CsmaNetDevice::PayloadFromMacMtu (uint16_t mtu)
+{
+ NS_LOG_FUNCTION (mtu);
+
+ switch (m_encapMode)
+ {
+ case RAW:
+ case IP_ARP:
+ case ETHERNET_V1:
+ return mtu;
+ case LLC:
+ {
+ LlcSnapHeader llc;
+ return mtu + llc.GetSerializedSize ();
+ }
+ }
+
+ NS_ASSERT_MSG (false, "CsmaNetDevice::PayloadFromMacMtu(): Unexpected encapsulation mode");
+ return 0;
+}
+
+ void
+CsmaNetDevice::SetEncapsulationMode (enum EncapsulationMode mode)
+{
+ NS_LOG_FUNCTION (mode);
+
+ m_encapMode = mode;
+ m_mtu = MacMtuFromPayload (m_maxPayloadLength);
+
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+ NS_LOG_LOGIC ("m_maxPayloadLength = " << m_maxPayloadLength);
+ NS_LOG_LOGIC ("m_mtu = " << m_mtu);
+}
+
+ CsmaNetDevice::EncapsulationMode
+CsmaNetDevice::GetEncapsulationMode (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_encapMode;
+}
+
+ void
+CsmaNetDevice::SetMacMtu (uint16_t mtu)
+{
+ NS_LOG_FUNCTION (mtu);
+
+ m_maxPayloadLength = PayloadFromMacMtu (mtu);
+ m_mtu = mtu;
+
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+ NS_LOG_LOGIC ("m_maxPayloadLength = " << m_maxPayloadLength);
+ NS_LOG_LOGIC ("m_mtu = " << m_mtu);
+}
+
+ uint16_t
+CsmaNetDevice::GetMacMtu (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return m_mtu;
+}
+
+//
+// The SetMtu method in the net device base class always refers to the MAC-level MTU by definition.
+//
+ bool
+CsmaNetDevice::SetMtu (const uint16_t mtu)
+{
+ NS_LOG_FUNCTION (mtu);
+ SetMacMtu (mtu);
+ return true;
+}
+
+//
+// The GetMtu method in the net device base class always refers to the MAC-level MTU by definition.
+//
+ uint16_t
+CsmaNetDevice::GetMtu (void) const
+{
+ NS_LOG_FUNCTION_NOARGS ();
+ return GetMacMtu ();
+}
+
+ void
+CsmaNetDevice::SetMaxPayloadLength (uint16_t maxPayloadLength)
+{
+ NS_LOG_FUNCTION (maxPayloadLength);
+
+ m_maxPayloadLength = maxPayloadLength;
+ m_mtu = MacMtuFromPayload (maxPayloadLength);
+
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
+ NS_LOG_LOGIC ("m_maxPayloadLength = " << m_maxPayloadLength);
+ NS_LOG_LOGIC ("m_mtu = " << m_mtu);
+}
+
+ uint16_t
+CsmaNetDevice::GetMaxPayloadLength (void) const
+{
+ return m_maxPayloadLength;
+}
+
void
CsmaNetDevice::SetAddress (Mac48Address self)
{
@@ -193,6 +330,7 @@
EthernetTrailer trailer;
NS_LOG_LOGIC ("p->GetSize () = " << p->GetSize ());
+ NS_LOG_LOGIC ("m_encapMode = " << m_encapMode);
NS_LOG_LOGIC ("m_mtu = " << m_mtu);
NS_LOG_LOGIC ("m_maxPayloadLength = " << m_maxPayloadLength);
@@ -238,8 +376,7 @@
}
break;
case RAW:
- NS_LOG_LOGIC ("Encapsulating packet as RAW");
- NS_ASSERT (false);
+ NS_ASSERT_MSG (false, "CsmaNetDevice::AddHeader(): RAW packet encapsulation not supported");
break;
}
@@ -680,21 +817,6 @@
}
bool
-CsmaNetDevice::SetMtu (const uint16_t mtu)
-{
- NS_LOG_FUNCTION (mtu);
- m_mtu = mtu;
- return true;
-}
-
- uint16_t
-CsmaNetDevice::GetMtu (void) const
-{
- NS_LOG_FUNCTION_NOARGS ();
- return m_mtu;
-}
-
- bool
CsmaNetDevice::IsLinkUp (void) const
{
NS_LOG_FUNCTION_NOARGS ();
--- a/src/devices/csma/csma-net-device.h Sun Aug 03 21:55:49 2008 -0700
+++ b/src/devices/csma/csma-net-device.h Mon Aug 04 17:32:32 2008 -0700
@@ -65,11 +65,12 @@
{
public:
static TypeId GetTypeId (void);
+
/**
* Enumeration of the types of packets supported in the class.
*
*/
- enum CsmaEncapsulationMode {
+ enum EncapsulationMode {
ETHERNET_V1, /**< Version one ethernet packet, length field */
IP_ARP, /**< Ethernet packet encapsulates IP/ARP packet */
RAW, /**< Packet that contains no headers */
@@ -197,17 +198,108 @@
*/
void SetAddress (Mac48Address addr);
-//
-// The following methods are inherited from NetDevice base class.
-//
+ /**
+ * Set The max PHY-level payload length of packets sent over this device.
+ *
+ * Okay, that was easy to say, but the details are a bit thorny. We have a MAC-level 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). The value that determines the relationship between these two values is the link
+ * encapsulation mode. The link encapsulation defines the number of bytes of overhead that are required for the particular
+ * MAC protocol used. For example, if the LLC/SNAP encapsulation is used, eight bytes of LLC/SNAP header are consumed and
+ * therefore the MAC-level MTU must be set and reported as eight bytes less than the PHY-level MTU (which we call the
+ * payload length to try and avoid confusion).
+ *
+ * So, what do we do since there must be three values which must always be consistent in the driver? Which values to we
+ * allow to be changed and how do we ensure the other two are consistent? We want to actually enable a user to change
+ * these two payload lengths in flexible ways, but we want the results (even at intermediate stages) to be consistent.
+ * We certainly don't want to require that users must understand the various requirements of an enapsulation mode in order
+ * to set these variables.
+ *
+ * Consider the following situation: A user wants to set the physical layer MTU to 1400 bytes instead of 1500. This
+ * user shouldn't have to concern herself that the current encapuslation mode is LLC and this will consume eight bytes.
+ * She should not have to also set the MAC MTU to 1392 bytes, and she should certainly not have to do this before setting
+ * the PHY MTU.
+ *
+ * A user who is interested in setting the MAC-level MTU to 1400 bytes should not be forced to understand that in certain
+ * cases the PHY-level MTU must be set to eight bytes more than what he wants in certain cases and zero bytes in others.
+ *
+ * Now, consider a user who is only interested in changing the encapsulation mode from LLC/SNAP to ETHERNET_V1. This
+ * is going to change the relationship between the MAC MTU and the PHY MTU. We've may have to come up with a new value
+ * for at least one of the MTUs? Which one?
+ *
+ * We could play games trying to figure out what the user wants to do, but that is typically a bad plan. So we're going
+ * to just define a flexible behavior. Here it is:
+ *
+ * - If the user is changing the encapsulation mode, the PHY MTU will remain fixed and the MAC MTU will change, if required,
+ * to make the three values consistent;
+ *
+ * - If the user is changing the MAC MTU, she is interested in getting that part of the system set, so the PHY MTU
+ * will be changed to make the three values consistent;
+ *
+ * - If the user is changing the PHY MTU, he is interested in getting that part of the system set, so the MAC MTU
+ * will be changed to make the three values consistent.
+ *
+ * So, if a user calls SetMaxPayloadLength, we assume that the PHY-level MTU is the interesting thing for that user and
+ * we just adjust the MAC-level MTU to "the correct value" based on the current encapsulation mode. If a user calls
+ * SetMacMtu, we assume that the MAC-level MTU is the interesting property for that user, and we adjust the PHY-level MTU
+ * to "the correct value" for the current encapsulation mode. If a user calls SetEncapsulationMode, then we take the
+ * MAC-level MTU as the free variable and set its value to match the current PHY-level MTU.
+ *
+ * \param mayPayloadLength The max PHY-level payload length of packets sent over this device.
+ */
+ void SetMaxPayloadLength (uint16_t maxPayloadLength);
+
+ /**
+ * Get The max PHY-level payload length of packets sent over this device.
+ *
+ * \returns The max PHY-level payload length of packets sent over this device.
+ */
+ uint16_t GetMaxPayloadLength (void) const;
+
+ /**
+ * Set The MAC-level MTU (client payload) of packets sent over this device.
+ *
+ * \param mtu The MAC-level MTU (client payload) of packets sent over this device.
+ *
+ * \see SetMaxPayloadLength
+ */
+ void SetMacMtu (uint16_t mtu);
+
+ /**
+ * Get The MAC-level MTU (client payload) of packets sent over this device.
+ *
+ * \returns The MAC-level MTU (client payload) of packets sent over this device.
+ */
+ uint16_t GetMacMtu (void) const;
+
+
+ /**
+ * Set the encapsulation mode of this device.
+ *
+ * \param mode The encapsulation mode of this device.
+ *
+ * \see SetMaxPayloadLength
+ */
+ void SetEncapsulationMode (CsmaNetDevice::EncapsulationMode mode);
+
+ /**
+ * Get the encapsulation mode of this device.
+ *
+ * \returns The encapsulation mode of this device.
+ */
+ CsmaNetDevice::EncapsulationMode GetEncapsulationMode (void);
+
+ //
+ // The following methods are inherited from NetDevice base class.
+ //
virtual void SetName (const std::string name);
virtual std::string GetName (void) const;
virtual void SetIfIndex (const uint32_t index);
virtual uint32_t GetIfIndex (void) const;
virtual Ptr<Channel> GetChannel (void) const;
- virtual Address GetAddress (void) const;
virtual bool SetMtu (const uint16_t mtu);
virtual uint16_t GetMtu (void) const;
+ virtual Address GetAddress (void) const;
virtual bool IsLinkUp (void) const;
virtual void SetLinkChangeCallback (Callback<void> callback);
virtual bool IsBroadcast (void) const;
@@ -333,9 +425,6 @@
private:
- static const uint16_t DEFAULT_FRAME_LENGTH = 1500;
- static const uint16_t DEFAULT_MTU = 1492;
-
/**
* Operator = is declared but not implemented. This disables the assigment
* operator for CsmaNetDevice objects.
@@ -355,6 +444,18 @@
void Init (bool sendEnable, bool receiveEnable);
/**
+ * Calculate the value for the MAC-level MTU that would result from
+ * setting the PHY-level MTU to the given value.
+ */
+ uint16_t MacMtuFromPayload (uint16_t payloadLength);
+
+ /**
+ * Calculate the value for the PHY-level MTU that would be required
+ * to be able to set the MAC-level MTU to the given value.
+ */
+ uint16_t PayloadFromMacMtu (uint16_t mtu);
+
+ /**
* Start Sending a Packet Down the Wire.
*
* The TransmitStart method is the method that is used internally in
@@ -460,7 +561,7 @@
* function and that should be processed by the ProcessHeader
* function.
*/
- CsmaEncapsulationMode m_encapMode;
+ EncapsulationMode m_encapMode;
/**
* The data rate that the Net Device uses to simulate packet transmission
@@ -568,6 +669,28 @@
*/
Callback<void> m_linkChangeCallback;
+ static const uint16_t DEFAULT_PAYLOAD_LENGTH = 1500;
+ static const uint16_t DEFAULT_MTU = 1492;
+
+ /**
+ * 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 payloadLength
+ * (PHY-level MTU) and mtu (MAC-level MTU) are consistent.
+ *
+ * \param payloadLength The proposed PHY-level MTU
+ * \param mtu The proposed MAC-level MTU
+ */
+ bool CheckMtuConsistency (uint16_t payloadLength, uint16_t mtu);
+
/**
* The MAC-level maximum transmission unit allowed to be sent or received by
* this network device. This corresponds to the maximum payload the device