In the Ethernet frame Spec (Both DIX EthernetII and IEEE 802.3),
the frame size must be at least 64 bytes long (not including the preamble).

  64 bytes = 14 bytes (Header) + 46 bytes (Payload) + 4 bytes (FCS)

This patch appends padding if the payload is less than 46 bytes long.

Reported-by: Kawai, Hiroaki <[email protected]>
Signed-off-by: IWASE Yusuke <[email protected]>
---
 ryu/lib/packet/ethernet.py           |  7 +++++++
 ryu/lib/packet/packet.py             |  5 +++--
 ryu/tests/unit/packet/test_lldp.py   | 11 ++++++++++-
 ryu/tests/unit/packet/test_packet.py | 22 +++++++++++++++++++---
 4 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/ryu/lib/packet/ethernet.py b/ryu/lib/packet/ethernet.py
index 33ef9c6..dd3a65c 100644
--- a/ryu/lib/packet/ethernet.py
+++ b/ryu/lib/packet/ethernet.py
@@ -19,6 +19,7 @@ from . import vlan
 from . import mpls
 from . import ether_types as ether
 from ryu.lib import addrconv
+from ryu.lib.pack_utils import msg_pack_into
 
 
 class ethernet(packet_base.PacketBase):
@@ -39,6 +40,7 @@ class ethernet(packet_base.PacketBase):
 
     _PACK_STR = '!6s6sH'
     _MIN_LEN = struct.calcsize(_PACK_STR)
+    _MIN_PAYLOAD_LEN = 46
     _TYPE = {
         'ascii': [
             'src', 'dst'
@@ -61,6 +63,11 @@ class ethernet(packet_base.PacketBase):
                 buf[ethernet._MIN_LEN:])
 
     def serialize(self, payload, prev):
+        # Append padding if the payload is less than 46 bytes long
+        pad_len = self._MIN_PAYLOAD_LEN - len(payload)
+        if pad_len > 0:
+            payload.extend(b'\x00' * pad_len)
+
         return struct.pack(ethernet._PACK_STR,
                            addrconv.mac.text_to_bin(self.dst),
                            addrconv.mac.text_to_bin(self.src),
diff --git a/ryu/lib/packet/packet.py b/ryu/lib/packet/packet.py
index 6f420cb..85e826f 100644
--- a/ryu/lib/packet/packet.py
+++ b/ryu/lib/packet/packet.py
@@ -54,7 +54,8 @@ class Packet(object):
                 break
             if proto:
                 self.protocols.append(proto)
-        if rest_data:
+        # If rest_data is all padding, we ignore rest_data
+        if rest_data and six.binary_type(rest_data).strip(b'\x00'):
             self.protocols.append(rest_data)
 
     def serialize(self):
@@ -74,7 +75,7 @@ class Packet(object):
                 data = p.serialize(self.data, prev)
             else:
                 data = six.binary_type(p)
-            self.data = data + self.data
+            self.data = bytearray(data + self.data)
 
     def add_protocol(self, proto):
         """Register a protocol *proto* for this packet.
diff --git a/ryu/tests/unit/packet/test_lldp.py 
b/ryu/tests/unit/packet/test_lldp.py
index 481ac09..d8d261c 100644
--- a/ryu/tests/unit/packet/test_lldp.py
+++ b/ryu/tests/unit/packet/test_lldp.py
@@ -121,7 +121,16 @@ class TestLLDPMandatoryTLV(unittest.TestCase):
         eq_(len(pkt.protocols), 2)
 
         pkt.serialize()
-        eq_(pkt.data, self.data)
+
+        # Note: If ethernet frame is less than 60 bytes length,
+        # ethernet.ethernet() appends padding to the payload.
+        # So, we splits the serialized data to compare.
+        data_len = len(self.data)
+        pkt_data_lldp = pkt.data[:data_len]
+        pkt_data_pad = pkt.data[data_len:]
+        eq_(b'\x00' * (60 - data_len), pkt_data_pad)
+
+        eq_(self.data, pkt_data_lldp)
 
     def test_to_string(self):
         chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_MAC_ADDRESS,
diff --git a/ryu/tests/unit/packet/test_packet.py 
b/ryu/tests/unit/packet/test_packet.py
index c48e372..b822976 100644
--- a/ryu/tests/unit/packet/test_packet.py
+++ b/ryu/tests/unit/packet/test_packet.py
@@ -93,6 +93,11 @@ class TestPacket(unittest.TestCase):
             + self.dst_ip_bin
 
         buf = e_buf + a_buf
+
+        # Append padding if ethernet frame is less than 60 bytes length
+        pad_len = 60 - len(buf)
+        if pad_len > 0:
+            buf += b'\x00' * pad_len
         eq_(buf, p.data)
 
         # parse
@@ -188,6 +193,11 @@ class TestPacket(unittest.TestCase):
             + self.dst_ip_bin
 
         buf = e_buf + v_buf + a_buf
+
+        # Append padding if ethernet frame is less than 60 bytes length
+        pad_len = 60 - len(buf)
+        if pad_len > 0:
+            buf += b'\x00' * pad_len
         eq_(buf, p.data)
 
         # parse
@@ -1407,9 +1417,9 @@ class TestPacket(unittest.TestCase):
                  b'\x00'
                  b'\x00'
                  b'\x00'
-                 b'\x80\x64\xaa\xaa\xaa\xaa\xaa\xaa'
-                 b'\x00\x00\x00\x04'
-                 b'\x80\x64\xbb\xbb\xbb\xbb\xbb\xbb'
+                 b'\x80\x00\xbb\xbb\xbb\xbb\xbb\xbb'
+                 b'\x00\x00\x00\x00'
+                 b'\x80\x00\xaa\xaa\xaa\xaa\xaa\xaa'
                  b'\x80\x04'
                  b'\x01\x00'
                  b'\x14\x00'
@@ -1418,6 +1428,12 @@ class TestPacket(unittest.TestCase):
 
         buf = e_buf + l_buf + b_buf
 
+        # Append padding if ethernet frame is less than 60 bytes length
+        pad_len = 60 - len(buf)
+        if pad_len > 0:
+            buf += b'\x00' * pad_len
+        eq_(buf, p.data)
+
         # parse
         pkt = packet.Packet(array.array('B', p.data))
         protocols = self.get_protocols(pkt)
-- 
2.7.4


------------------------------------------------------------------------------
Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San
Francisco, CA to explore cutting-edge tech and listen to tech luminaries
present their vision of the future. This family event has something for
everyone, including kids. Get more information and register today.
http://sdm.link/attshape
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to