implement BGP-4 streaming parser

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
YAMAMOTO Takashi 2013-09-25 11:59:49 +09:00 committed by FUJITA Tomonori
parent 011e19fd41
commit 1e3f88010f
2 changed files with 49 additions and 9 deletions

View File

@ -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)

View File

@ -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))