summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ryu/lib/packet/ethernet.py1
-rw-r--r--ryu/lib/packet/vlan.py76
-rw-r--r--ryu/ofproto/ether.py3
-rw-r--r--ryu/tests/unit/packet/test_vlan.py118
4 files changed, 178 insertions, 20 deletions
diff --git a/ryu/lib/packet/ethernet.py b/ryu/lib/packet/ethernet.py
index 349a352c..e63ffee8 100644
--- a/ryu/lib/packet/ethernet.py
+++ b/ryu/lib/packet/ethernet.py
@@ -76,4 +76,5 @@ class ethernet(packet_base.PacketBase):
# copy vlan _TYPES
ethernet._TYPES = vlan.vlan._TYPES
ethernet.register_packet_type(vlan.vlan, ether.ETH_TYPE_8021Q)
+ethernet.register_packet_type(vlan.svlan, ether.ETH_TYPE_8021AD)
ethernet.register_packet_type(mpls.mpls, ether.ETH_TYPE_MPLS)
diff --git a/ryu/lib/packet/vlan.py b/ryu/lib/packet/vlan.py
index 8930197b..2f0e2565 100644
--- a/ryu/lib/packet/vlan.py
+++ b/ryu/lib/packet/vlan.py
@@ -13,6 +13,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import abc
import struct
from . import packet_base
from . import arp
@@ -24,7 +25,35 @@ from . import llc
from ryu.ofproto import ether
-class vlan(packet_base.PacketBase):
+class _vlan(packet_base.PacketBase):
+
+ __metaclass__ = abc.ABCMeta
+ _PACK_STR = "!HH"
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ @abc.abstractmethod
+ def __init__(self, pcp, cfi, vid, ethertype):
+ super(_vlan, self).__init__()
+ self.pcp = pcp
+ self.cfi = cfi
+ self.vid = vid
+ self.ethertype = ethertype
+
+ @classmethod
+ def parser(cls, buf):
+ tci, ethertype = struct.unpack_from(cls._PACK_STR, buf)
+ pcp = tci >> 13
+ cfi = (tci >> 12) & 1
+ vid = tci & ((1 << 12) - 1)
+ return (cls(pcp, cfi, vid, ethertype),
+ vlan.get_packet_type(ethertype), buf[vlan._MIN_LEN:])
+
+ def serialize(self, payload, prev):
+ tci = self.pcp << 13 | self.cfi << 12 | self.vid
+ return struct.pack(vlan._PACK_STR, tci, self.ethertype)
+
+
+class vlan(_vlan):
"""VLAN (IEEE 802.1Q) header encoder/decoder class.
An instance has the following attributes at least.
@@ -41,15 +70,8 @@ class vlan(packet_base.PacketBase):
============== ====================
"""
- _PACK_STR = "!HH"
- _MIN_LEN = struct.calcsize(_PACK_STR)
-
def __init__(self, pcp=0, cfi=0, vid=0, ethertype=ether.ETH_TYPE_IP):
- super(vlan, self).__init__()
- self.pcp = pcp
- self.cfi = cfi
- self.vid = vid
- self.ethertype = ethertype
+ super(vlan, self).__init__(pcp, cfi, vid, ethertype)
@classmethod
def get_packet_type(cls, type_):
@@ -63,18 +85,32 @@ class vlan(packet_base.PacketBase):
type_ = ether.ETH_TYPE_IEEE802_3
return cls._TYPES.get(type_)
+
+class svlan(_vlan):
+ """S-VLAN (IEEE 802.1ad) header encoder/decoder class.
+
+
+ An instance has the following attributes at least.
+ Most of them are same to the on-wire counterparts but in host byte order.
+ __init__ takes the corresponding args in this order.
+
+ ============== ====================
+ Attribute Description
+ ============== ====================
+ pcp Priority Code Point
+ cfi Canonical Format Indicator
+ vid VLAN Identifier
+ ethertype EtherType
+ ============== ====================
+ """
+
+ def __init__(self, pcp=0, cfi=0, vid=0, ethertype=ether.ETH_TYPE_8021Q):
+ super(svlan, self).__init__(pcp, cfi, vid, ethertype)
+
@classmethod
- def parser(cls, buf):
- tci, ethertype = struct.unpack_from(cls._PACK_STR, buf)
- pcp = tci >> 13
- cfi = (tci >> 12) & 1
- vid = tci & ((1 << 12) - 1)
- return (cls(pcp, cfi, vid, ethertype),
- vlan.get_packet_type(ethertype), buf[vlan._MIN_LEN:])
+ def get_packet_type(cls, type_):
+ return cls._TYPES.get(type_)
- def serialize(self, payload, prev):
- tci = self.pcp << 13 | self.cfi << 12 | self.vid
- return struct.pack(vlan._PACK_STR, tci, self.ethertype)
vlan.register_packet_type(arp.arp, ether.ETH_TYPE_ARP)
vlan.register_packet_type(ipv4.ipv4, ether.ETH_TYPE_IP)
@@ -82,3 +118,5 @@ vlan.register_packet_type(ipv6.ipv6, ether.ETH_TYPE_IPV6)
vlan.register_packet_type(lldp.lldp, ether.ETH_TYPE_LLDP)
vlan.register_packet_type(slow.slow, ether.ETH_TYPE_SLOW)
vlan.register_packet_type(llc.llc, ether.ETH_TYPE_IEEE802_3)
+
+svlan.register_packet_type(vlan, ether.ETH_TYPE_8021Q)
diff --git a/ryu/ofproto/ether.py b/ryu/ofproto/ether.py
index f4883a39..9e1539c0 100644
--- a/ryu/ofproto/ether.py
+++ b/ryu/ofproto/ether.py
@@ -18,7 +18,8 @@ ETH_TYPE_IP = 0x0800
ETH_TYPE_ARP = 0x0806
ETH_TYPE_8021Q = 0x8100
ETH_TYPE_IPV6 = 0x86dd
-ETH_TYPE_MPLS = 0x8847
ETH_TYPE_SLOW = 0x8809
+ETH_TYPE_MPLS = 0x8847
+ETH_TYPE_8021AD = 0x88a8
ETH_TYPE_LLDP = 0x88cc
ETH_TYPE_IEEE802_3 = 0x05dc
diff --git a/ryu/tests/unit/packet/test_vlan.py b/ryu/tests/unit/packet/test_vlan.py
index 69835078..c9aa1862 100644
--- a/ryu/tests/unit/packet/test_vlan.py
+++ b/ryu/tests/unit/packet/test_vlan.py
@@ -26,6 +26,7 @@ from ryu.lib.packet.ethernet import ethernet
from ryu.lib.packet.packet import Packet
from ryu.lib.packet.ipv4 import ipv4
from ryu.lib.packet.vlan import vlan
+from ryu.lib.packet.vlan import svlan
LOG = logging.getLogger('test_vlan')
@@ -136,3 +137,120 @@ class Test_vlan(unittest.TestCase):
def test_malformed_vlan(self):
m_short_buf = self.buf[1:vlan._MIN_LEN]
vlan.parser(m_short_buf)
+
+
+class Test_svlan(unittest.TestCase):
+
+ pcp = 0
+ cfi = 0
+ vid = 32
+ tci = pcp << 15 | cfi << 12 | vid
+ ethertype = ether.ETH_TYPE_8021Q
+
+ buf = pack(svlan._PACK_STR, tci, ethertype)
+
+ sv = svlan(pcp, cfi, vid, ethertype)
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def find_protocol(self, pkt, name):
+ for p in pkt.protocols:
+ if p.protocol_name == name:
+ return p
+
+ def test_init(self):
+ eq_(self.pcp, self.sv.pcp)
+ eq_(self.cfi, self.sv.cfi)
+ eq_(self.vid, self.sv.vid)
+ eq_(self.ethertype, self.sv.ethertype)
+
+ def test_parser(self):
+ res, ptype, _ = self.sv.parser(self.buf)
+
+ eq_(res.pcp, self.pcp)
+ eq_(res.cfi, self.cfi)
+ eq_(res.vid, self.vid)
+ eq_(res.ethertype, self.ethertype)
+ eq_(ptype, vlan)
+
+ def test_serialize(self):
+ data = bytearray()
+ prev = None
+ buf = self.sv.serialize(data, prev)
+
+ fmt = svlan._PACK_STR
+ res = struct.unpack(fmt, buf)
+
+ eq_(res[0], self.tci)
+ eq_(res[1], self.ethertype)
+
+ def _build_svlan(self):
+ src_mac = '00:07:0d:af:f4:54'
+ dst_mac = '00:00:00:00:00:00'
+ ethertype = ether.ETH_TYPE_8021AD
+ e = ethernet(dst_mac, src_mac, ethertype)
+
+ pcp = 0
+ cfi = 0
+ vid = 32
+ tci = pcp << 15 | cfi << 12 | vid
+ ethertype = ether.ETH_TYPE_IP
+ v = vlan(pcp, cfi, vid, ethertype)
+
+ version = 4
+ header_length = 20
+ tos = 0
+ total_length = 24
+ identification = 0x8a5d
+ flags = 0
+ offset = 1480
+ ttl = 64
+ proto = inet.IPPROTO_ICMP
+ csum = 0xa7f2
+ src = '131.151.32.21'
+ dst = '131.151.32.129'
+ option = 'TEST'
+ ip = ipv4(version, header_length, tos, total_length, identification,
+ flags, offset, ttl, proto, csum, src, dst, option)
+
+ p = Packet()
+
+ p.add_protocol(e)
+ p.add_protocol(self.sv)
+ p.add_protocol(v)
+ p.add_protocol(ip)
+ p.serialize()
+
+ return p
+
+ def test_build_svlan(self):
+ p = self._build_svlan()
+
+ e = self.find_protocol(p, "ethernet")
+ ok_(e)
+ eq_(e.ethertype, ether.ETH_TYPE_8021AD)
+
+ sv = self.find_protocol(p, "svlan")
+ ok_(sv)
+ eq_(sv.ethertype, ether.ETH_TYPE_8021Q)
+
+ v = self.find_protocol(p, "vlan")
+ ok_(v)
+ eq_(v.ethertype, ether.ETH_TYPE_IP)
+
+ ip = self.find_protocol(p, "ipv4")
+ ok_(ip)
+
+ eq_(sv.pcp, self.pcp)
+ eq_(sv.cfi, self.cfi)
+ eq_(sv.vid, self.vid)
+ eq_(sv.ethertype, self.ethertype)
+
+ @raises(Exception)
+ def test_malformed_svlan(self):
+ m_short_buf = self.buf[1:svlan._MIN_LEN]
+ svlan.parser(m_short_buf)