packet lib: support Provider Backbone Bridges (PBB, IEEE 802.1ah)

Signed-off-by: Yuichi Ito <ito.yuichi0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Yuichi Ito 2013-10-29 11:28:37 +09:00 committed by FUJITA Tomonori
parent 0cc9c21ccc
commit 3ba951f403
5 changed files with 237 additions and 1 deletions

View File

@ -29,6 +29,9 @@ Protocol Header classes
.. automodule:: ryu.lib.packet.vlan
:members:
.. automodule:: ryu.lib.packet.pbb
:members:
.. automodule:: ryu.lib.packet.mpls
:members:

61
ryu/lib/packet/pbb.py Normal file
View File

@ -0,0 +1,61 @@
# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import struct
from ryu.lib.packet import packet_base
from ryu.ofproto import ether
class itag(packet_base.PacketBase):
"""I-TAG (IEEE 802.1ah-2008) 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
dei Drop Eligible Indication
uca Use Customer Address
sid Service Instance ID
============== ====================
"""
_PACK_STR = "!I"
_MIN_LEN = struct.calcsize(_PACK_STR)
def __init__(self, pcp=0, dei=0, uca=0, sid=0):
super(itag, self).__init__()
self.pcp = pcp
self.dei = dei
self.uca = uca
self.sid = sid
@classmethod
def parser(cls, buf):
(data, ) = struct.unpack_from(cls._PACK_STR, buf)
pcp = data >> 29
dei = data >> 28 & 1
uca = data >> 27 & 1
sid = data & 0x00ffffff
from ryu.lib.packet import ethernet
return (cls(pcp, dei, uca, sid), ethernet.ethernet,
buf[cls._MIN_LEN:])
def serialize(self, payload, prev):
data = self.pcp << 29 | self.dei << 28 | self.uca << 27 | self.sid
return struct.pack(self._PACK_STR, data)

View File

@ -22,6 +22,7 @@ from . import ipv6
from . import lldp
from . import slow
from . import llc
from . import pbb
from ryu.ofproto import ether
@ -98,7 +99,9 @@ class svlan(_vlan):
Attribute Description
============== ====================
pcp Priority Code Point
cfi Canonical Format Indicator
cfi Canonical Format Indicator.
In a case to be used as B-TAG,
this field means DEI(Drop Eligible Indication).
vid VLAN Identifier
ethertype EtherType
============== ====================
@ -120,3 +123,4 @@ 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)
svlan.register_packet_type(pbb.itag, ether.ETH_TYPE_8021AH)

View File

@ -22,4 +22,5 @@ ETH_TYPE_SLOW = 0x8809
ETH_TYPE_MPLS = 0x8847
ETH_TYPE_8021AD = 0x88a8
ETH_TYPE_LLDP = 0x88cc
ETH_TYPE_8021AH = 0x88e7
ETH_TYPE_IEEE802_3 = 0x05dc

View File

@ -0,0 +1,167 @@
# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import struct
import unittest
from nose.tools import eq_
from nose.tools import ok_
from nose.tools import raises
from ryu.ofproto import ether
from ryu.ofproto import inet
from ryu.lib.packet import ethernet
from ryu.lib.packet import packet
from ryu.lib.packet import ipv4
from ryu.lib.packet import vlan
from ryu.lib.packet import pbb
LOG = logging.getLogger(__name__)
class Test_itag(unittest.TestCase):
pcp = 3
dei = 0
uca = 1
sid = 16770000
data = pcp << 29 | dei << 28 | uca << 27 | sid
buf = struct.pack(pbb.itag._PACK_STR, data)
it = pbb.itag(pcp, dei, uca, sid)
def setUp(self):
pass
def tearDown(self):
pass
def test_init(self):
eq_(self.pcp, self.it.pcp)
eq_(self.dei, self.it.dei)
eq_(self.uca, self.it.uca)
eq_(self.sid, self.it.sid)
def test_parser(self):
_res = pbb.itag.parser(self.buf)
if type(_res) is tuple:
res = _res[0]
else:
res = _res
eq_(res.pcp, self.pcp)
eq_(res.dei, self.dei)
eq_(res.uca, self.uca)
eq_(res.sid, self.sid)
def test_serialize(self):
data = bytearray()
prev = None
buf = self.it.serialize(data, prev)
res = struct.unpack(pbb.itag._PACK_STR, buf)
eq_(res[0], self.data)
def _build_itag(self):
b_src_mac = '00:07:0d:af:f4:54'
b_dst_mac = '00:00:00:00:00:00'
b_ethertype = ether.ETH_TYPE_8021AD
e1 = ethernet.ethernet(b_dst_mac, b_src_mac, b_ethertype)
b_pcp = 0
b_cfi = 0
b_vid = 32
b_ethertype = ether.ETH_TYPE_8021Q
bt = vlan.svlan(b_pcp, b_cfi, b_vid, b_ethertype)
c_src_mac = '11:11:11:11:11:11'
c_dst_mac = 'aa:aa:aa:aa:aa:aa'
c_ethertype = ether.ETH_TYPE_8021AD
e2 = ethernet.ethernet(c_dst_mac, c_src_mac, c_ethertype)
s_pcp = 0
s_cfi = 0
s_vid = 32
s_ethertype = ether.ETH_TYPE_8021Q
st = vlan.svlan(s_pcp, s_cfi, s_vid, s_ethertype)
c_pcp = 0
c_cfi = 0
c_vid = 32
c_ethertype = ether.ETH_TYPE_IP
ct = vlan.vlan(c_pcp, c_cfi, c_vid, c_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.ipv4(version, header_length, tos, total_length,
identification, flags, offset, ttl, proto, csum,
src, dst, option)
p = packet.Packet()
p.add_protocol(e1)
p.add_protocol(bt)
p.add_protocol(self.it)
p.add_protocol(e2)
p.add_protocol(st)
p.add_protocol(ct)
p.add_protocol(ip)
p.serialize()
return p
def test_build_itag(self):
p = self._build_itag()
e = p.get_protocols(ethernet.ethernet)
ok_(e)
ok_(isinstance(e, list))
eq_(e[0].ethertype, ether.ETH_TYPE_8021AD)
eq_(e[1].ethertype, ether.ETH_TYPE_8021AD)
sv = p.get_protocols(vlan.svlan)
ok_(sv)
ok_(isinstance(sv, list))
eq_(sv[0].ethertype, ether.ETH_TYPE_8021Q)
eq_(sv[1].ethertype, ether.ETH_TYPE_8021Q)
it = p.get_protocol(pbb.itag)
ok_(it)
v = p.get_protocol(vlan.vlan)
ok_(v)
eq_(v.ethertype, ether.ETH_TYPE_IP)
ip = p.get_protocol(ipv4.ipv4)
ok_(ip)
eq_(it.pcp, self.pcp)
eq_(it.dei, self.dei)
eq_(it.uca, self.uca)
eq_(it.sid, self.sid)
@raises(Exception)
def test_malformed_itag(self):
m_short_buf = self.buf[1:pbb.itag._MIN_LEN]
pbb.itag.parser(m_short_buf)