---
 ryu/lib/packet/bgp.py             | 26 +++++++++++++++++++++++---
 ryu/tests/unit/packet/test_bgp.py | 32 ++++++++++++++++++++++++++------
 2 files changed, 49 insertions(+), 9 deletions(-)

diff --git a/ryu/lib/packet/bgp.py b/ryu/lib/packet/bgp.py
index a6d5f4d..4c2119c 100644
--- a/ryu/lib/packet/bgp.py
+++ b/ryu/lib/packet/bgp.py
@@ -19,7 +19,6 @@ RFC 4271 BGP-4
 """
 
 # todo
-# - streaming parser
 # - notify data
 # - notify subcode constants
 # - RFC 1997 BGP Communities Attribute
@@ -35,6 +34,7 @@ import struct
 from ryu.ofproto.ofproto_parser import msg_pack_into
 from ryu.lib.stringify import StringifyMixin
 from ryu.lib.packet import packet_base
+from ryu.lib.packet import stream_parser
 from ryu.lib import addrconv
 
 
@@ -225,11 +225,20 @@ class BGPMessage(packet_base.PacketBase):
 
     @classmethod
     def parser(cls, buf):
+        if len(buf) < cls._HDR_LEN:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), cls._HDR_LEN))
         (marker, len_, type_) = struct.unpack_from(cls._HDR_PACK_STR,
                                                    buffer(buf))
+        msglen = len_
+        if len(buf) < msglen:
+            raise stream_parser.StreamParser.TooSmallException(
+                '%d < %d' % (len(buf), msglen))
+        binmsg = buf[cls._HDR_LEN:msglen]
+        rest = buf[msglen:]
         subcls = cls._TYPES[type_]
-        kwargs = subcls.parser(buf[cls._HDR_LEN:])
-        return subcls(marker=marker, len_=len_, type_=type_, **kwargs)
+        kwargs = subcls.parser(binmsg)
+        return subcls(marker=marker, len_=len_, type_=type_, **kwargs), rest
 
     def serialize(self):
         # fixup
@@ -517,3 +526,14 @@ class BGPNotification(BGPMessage):
                                     self.error_subcode))
         msg += self.data
         return msg
+
+
+class StreamParser(stream_parser.StreamParser):
+    """Streaming parser for BGP-4 messages.
+
+    This is a subclass of ryu.lib.packet.stream_parser.StreamParser.
+    Its parse method returns a list of BGPMessage subclass instances.
+    """
+
+    def try_parse(self, data):
+        return BGPMessage.parser(data)
diff --git a/ryu/tests/unit/packet/test_bgp.py 
b/ryu/tests/unit/packet/test_bgp.py
index db5319d..808b2db 100644
--- a/ryu/tests/unit/packet/test_bgp.py
+++ b/ryu/tests/unit/packet/test_bgp.py
@@ -34,25 +34,28 @@ class Test_bgp(unittest.TestCase):
     def test_open1(self):
         msg = bgp.BGPOpen(my_as=30000, bgp_identifier='192.0.2.1')
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         eq_(len(msg), 29)
+        eq_(rest, '')
 
     def test_open2(self):
         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')])
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         ok_(len(msg) > 29)
+        eq_(rest, '')
 
     def test_update1(self):
         msg = bgp.BGPUpdate()
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         eq_(len(msg), 23)
+        eq_(rest, '')
 
     def test_update2(self):
         withdrawn_routes = [bgp.BGPWithdrawnRoute(length=0,
@@ -76,21 +79,38 @@ class Test_bgp(unittest.TestCase):
                             path_attributes=path_attributes,
                             nlri=nlri)
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         ok_(len(msg) > 23)
+        eq_(rest, '')
 
     def test_keepalive(self):
         msg = bgp.BGPKeepAlive()
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         eq_(len(msg), 19)
+        eq_(rest, '')
 
     def test_notification(self):
         data = "hoge"
         msg = bgp.BGPNotification(error_code=1, error_subcode=2, data=data)
         binmsg = msg.serialize()
-        msg2 = bgp.BGPMessage.parser(binmsg)
+        msg2, rest = bgp.BGPMessage.parser(binmsg)
         eq_(str(msg), str(msg2))
         eq_(len(msg), 21 + len(data))
+        eq_(rest, '')
+
+    def test_stream_parser(self):
+        msgs = [
+            bgp.BGPNotification(error_code=1, error_subcode=2, data="foo"),
+            bgp.BGPNotification(error_code=3, error_subcode=4, data="bar"),
+            bgp.BGPNotification(error_code=5, error_subcode=6, data="baz"),
+        ]
+        binmsgs = ''.join([bytes(msg.serialize()) for msg in msgs])
+        sp = bgp.StreamParser()
+        results = []
+        for b in binmsgs:
+            for m in sp.parse(b):
+                results.append(m)
+        eq_(str(results), str(msgs))
-- 
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=60133471&iu=/4140/ostg.clktrk
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to