Signed-off-by: YAMAMOTO Takashi <[email protected]>
---
 ryu/lib/packet/bgp.py             | 168 ++++++++++++++++++++++++++------------
 ryu/tests/unit/packet/test_bgp.py |   5 +-
 2 files changed, 120 insertions(+), 53 deletions(-)

diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index 716d1e3..b1bc2f2 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -121,13 +121,69 @@ class _IPAddrPrefix(StringifyMixin):
         return buf + bytes(bin_ip_addr)
 
 
-class BGPOptParam(StringifyMixin):
+class _Value(object):
+    _VALUE_PACK_STR = None
+
+    @classmethod
+    def parse_value(cls, buf):
+        (value,) = struct.unpack_from(cls._VALUE_PACK_STR, buffer(buf))
+        return {
+            'value': value
+        }
+
+    def serialize_value(self):
+        buf = bytearray()
+        msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.value)
+        return buf
+
+
+class _TypeDisp(object):
+    _TYPES = {}
+    _REV_TYPES = None
+    _UNKNOWN_TYPE = None
+
+    @classmethod
+    def register_unknown_type(cls):
+        def _register_type(subcls):
+            cls._UNKNOWN_TYPE = subcls
+            return subcls
+        return _register_type
+
+    @classmethod
+    def register_type(cls, type_):
+        cls._TYPES = cls._TYPES.copy()
+
+        def _register_type(subcls):
+            cls._TYPES[type_] = subcls
+            cls._REV_TYPES = None
+            return subcls
+        return _register_type
+
+    @classmethod
+    def _lookup_type(cls, type_):
+        try:
+            return cls._TYPES[type_]
+        except KeyError:
+            return cls._UNKNOWN_TYPE
+
+    @classmethod
+    def _rev_lookup_type(cls, targ_cls):
+        if cls._REV_TYPES is None:
+            rev = dict((v, k) for k, v in cls._TYPES.iteritems())
+            cls._REV_TYPES = rev
+        return cls._REV_TYPES[targ_cls]
+
+
+class _OptParam(StringifyMixin, _TypeDisp, _Value):
     _PACK_STR = '!BB'  # type, length
 
-    def __init__(self, type_, value, length=None):
+    def __init__(self, type_, value=None, length=None):
+        if type_ is None:
+            type_ = self._rev_lookup_type(self.__class__)
         self.type = type_
         self.length = length
-        self.value = value
+        if not value is None:
+            self.value = value
 
     @classmethod
     def parser(cls, buf):
@@ -135,35 +191,79 @@ class BGPOptParam(StringifyMixin):
         rest = buf[struct.calcsize(cls._PACK_STR):]
         value = bytes(rest[:length])
         rest = rest[length:]
-        return cls(type_=type_, length=length, value=value), rest
+        subcls = cls._lookup_type(type_)
+        kwargs = subcls.parse_value(value)
+        return subcls(type_=type_, length=length, **kwargs), rest
 
     def serialize(self):
         # fixup
-        self.length = len(self.value)
+        value = self.serialize_value()
+        self.length = len(value)
 
         buf = bytearray()
         msg_pack_into(self._PACK_STR, buf, 0, self.type, self.length)
-        return buf + bytes(self.value)
+        return buf + value
+
+
+@_OptParam.register_unknown_type()
+class BGPOptParamUnknown(_OptParam):
+    @classmethod
+    def parse_value(cls, buf):
+        return {
+            'value': buf
+        }
+
+    def serialize_value(self):
+        return self.value
+
+
+@_OptParam.register_type(BGP_OPT_CAPABILITY)
+class BGPOptParamCapability(_OptParam):
+    _CAP_HDR_PACK_STR = '!BB'
+
+    def __init__(self, cap_code, cap_value, cap_length=None,
+                 type_=None, length=None):
+        super(BGPOptParamCapability, self).__init__(type_=type_, length=length)
+        self.cap_code = cap_code
+        self.cap_length = cap_length
+        self.cap_value = cap_value
+
+    @classmethod
+    def parse_value(cls, buf):
+        (code, length) = struct.unpack_from(cls._CAP_HDR_PACK_STR, buffer(buf))
+        value = buf[struct.calcsize(cls._CAP_HDR_PACK_STR):]
+        assert len(value) == length
+        kwargs = {
+            'cap_code': code,
+            'cap_length': length,
+            'cap_value': value,
+        }
+        return kwargs
+
+    def serialize_value(self):
+        # fixup
+        cap_value = self.cap_value
+        self.cap_length = len(cap_value)
+
+        buf = bytearray()
+        msg_pack_into(self._CAP_HDR_PACK_STR, buf, 0, self.cap_code,
+                      self.cap_length)
+        return buf + cap_value
 
 
 class BGPWithdrawnRoute(_IPAddrPrefix):
     pass
 
 
-class _PathAttribute(StringifyMixin):
+class _PathAttribute(StringifyMixin, _TypeDisp, _Value):
     _PACK_STR = '!BB'  # flags, type
     _PACK_STR_LEN = '!B'  # length
     _PACK_STR_EXT_LEN = '!H'  # length w/ BGP_ATTR_FLAG_EXTENDED_LENGTH
-    _TYPES = {}
-    _REV_TYPES = None
     _ATTR_FLAGS = None
 
     def __init__(self, value=None, flags=0, type_=None, length=None):
         if type_ is None:
-            if self._REV_TYPES is None:
-                self._REV_TYPES = dict((v, k) for k, v in
-                                       self._TYPES.iteritems())
-            type_ = self._REV_TYPES[self.__class__]
+            type_ = self._rev_lookup_type(self.__class__)
         self.flags = flags
         self.type = type_
         self.length = length
@@ -171,21 +271,6 @@ class _PathAttribute(StringifyMixin):
             self.value = value
 
     @classmethod
-    def register_type(cls, type_):
-        def _register_type(subcls):
-            cls._TYPES[type_] = subcls
-            cls._REV_TYPES = None
-            return subcls
-        return _register_type
-
-    @classmethod
-    def _lookup_type(cls, type_):
-        try:
-            return cls._TYPES[type_]
-        except KeyError:
-            return BGPPathAttributeUnknown
-
-    @classmethod
     def parser(cls, buf):
         (flags, type_) = struct.unpack_from(cls._PACK_STR, buffer(buf))
         rest = buf[struct.calcsize(cls._PACK_STR):]
@@ -201,13 +286,6 @@ class _PathAttribute(StringifyMixin):
         return subcls(flags=flags, type_=type_, length=length,
                       **subcls.parse_value(value)), rest
 
-    @classmethod
-    def parse_value(cls, buf):
-        (value,) = struct.unpack_from(cls._VALUE_PACK_STR, buffer(buf))
-        return {
-            'value': value
-        }
-
     def serialize(self):
         # fixup
         if not self._ATTR_FLAGS is None:
@@ -228,12 +306,8 @@ class _PathAttribute(StringifyMixin):
         msg_pack_into(len_pack_str, buf, len(buf), self.length)
         return buf + value
 
-    def serialize_value(self):
-        buf = bytearray()
-        msg_pack_into(self._VALUE_PACK_STR, buf, 0, self.value)
-        return buf
-
 
+@_PathAttribute.register_unknown_type()
 class BGPPathAttributeUnknown(_PathAttribute):
     @classmethod
     def parse_value(cls, buf):
@@ -404,7 +478,7 @@ class BGPNLRI(_IPAddrPrefix):
     pass
 
 
-class BGPMessage(packet_base.PacketBase):
+class BGPMessage(packet_base.PacketBase, _TypeDisp):
     """Base class for BGP-4 messages.
 
     An instance has the following attributes at least.
@@ -423,14 +497,6 @@ class BGPMessage(packet_base.PacketBase):
 
     _HDR_PACK_STR = '!16sHB'  # marker, len, type
     _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
-    _TYPES = {}
-
-    @classmethod
-    def register_type(cls, type_):
-        def _register_type(subcls):
-            cls._TYPES[type_] = subcls
-            return subcls
-        return _register_type
 
     def __init__(self, type_, len_=None, marker=None):
         if marker is None:
@@ -453,7 +519,7 @@ class BGPMessage(packet_base.PacketBase):
                 '%d < %d' % (len(buf), msglen))
         binmsg = buf[cls._HDR_LEN:msglen]
         rest = buf[msglen:]
-        subcls = cls._TYPES[type_]
+        subcls = cls._lookup_type(type_)
         kwargs = subcls.parser(binmsg)
         return subcls(marker=marker, len_=len_, type_=type_, **kwargs), rest
 
@@ -525,7 +591,7 @@ class BGPOpen(BGPMessage):
         binopts = rest[:opt_param_len]
         opt_param = []
         while binopts:
-            opt, binopts = BGPOptParam.parser(binopts)
+            opt, binopts = _OptParam.parser(binopts)
             opt_param.append(opt)
         return {
             "version": version,
diff --git a/ryu/tests/unit/packet/test_bgp.py 
b/ryu/tests/unit/packet/test_bgp.py
index 17e88c0..99db218 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -40,9 +40,10 @@ class Test_bgp(unittest.TestCase):
         eq_(rest, '')
 
     def test_open2(self):
+        opt_param = [bgp.BGPOptParamCapability(cap_code=200, cap_value='hoge'),
+                     bgp.BGPOptParamUnknown(type_=99, value='fuga')]
         msg = bgp.BGPOpen(my_as=30000, bgp_identifier='192.0.2.2',
-                          opt_param=[bgp.BGPOptParam(type_=1, value='hooge'),
-                                     bgp.BGPOptParam(type_=2, value='fuga')])
+                          opt_param=opt_param)
         binmsg = msg.serialize()
         msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
-- 
1.8.3.1


------------------------------------------------------------------------------
October Webinars: Code for Performance
Free Intel webinars can help you accelerate application performance.
Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
the latest Intel processors and coprocessors. See abstracts and register >
http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to