summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2014-07-30 16:03:53 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-07-30 17:41:37 +0900
commit7d3b02cfabc30c382e59051f78536b0043040a6b (patch)
tree55e4c1215f047a1c48d61e8116d4f3ab31f9a952
parent40a70a9336bfad9c9953bb5fe4314f7b1bc5806b (diff)
packet lib: add bmp(BGP Monitoring Protocol)
implements I-D grow-bmp-07 Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/lib/packet/bmp.py746
1 files changed, 746 insertions, 0 deletions
diff --git a/ryu/lib/packet/bmp.py b/ryu/lib/packet/bmp.py
new file mode 100644
index 00000000..207ded84
--- /dev/null
+++ b/ryu/lib/packet/bmp.py
@@ -0,0 +1,746 @@
+# Copyright (C) 2014 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.
+
+"""
+BGP Monitoring Protocol draft-ietf-grow-bmp-07
+"""
+
+from ryu.lib.packet import packet_base
+from ryu.lib.packet import stream_parser
+from ryu.lib.packet.bgp import BGPMessage
+from ryu.lib import addrconv
+import struct
+
+VERSION = 3
+
+BMP_MSG_ROUTE_MONITORING = 0
+BMP_MSG_STATISTICS_REPORT = 1
+BMP_MSG_PEER_DOWN_NOTIFICATION = 2
+BMP_MSG_PEER_UP_NOTIFICATION = 3
+BMP_MSG_INITIATION = 4
+BMP_MSG_TERMINATION = 5
+
+BMP_PEER_TYPE_GLOBAL = 0
+BMP_PEER_TYPE_L3VPN = 1
+
+BMP_INIT_TYPE_STRING = 0
+BMP_INIT_TYPE_SYSDESCR = 1
+BMP_INIT_TYPE_SYSNAME = 2
+
+BMP_TERM_TYPE_STRING = 0
+BMP_TERM_TYPE_REASON = 1
+
+BMP_TERM_REASON_ADMIN = 0
+BMP_TERM_REASON_UNSPEC = 1
+BMP_TERM_REASON_OUT_OF_RESOURCE = 2
+BMP_TERM_REASON_REDUNDANT_CONNECTION = 3
+
+BMP_STAT_TYPE_REJECTED = 0
+BMP_STAT_TYPE_DUPLICATE_PREFIX = 1
+BMP_STAT_TYPE_DUPLICATE_WITHDRAW = 2
+BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP = 3
+BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP = 4
+BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID = 5
+BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP = 6
+BMP_STAT_TYPE_ADJ_RIB_IN = 7
+BMP_STAT_TYPE_LOC_RIB = 8
+
+BMP_PEER_DOWN_REASON_UNKNOWN = 0
+BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION = 1
+BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION = 2
+BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION = 3
+BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION = 3
+
+
+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 BMPMessage(packet_base.PacketBase, _TypeDisp):
+ """Base class for BGP Monitoring Protocol messages.
+
+ 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
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ ========================== ===============================================
+ """
+
+ _HDR_PACK_STR = '!BIB' # version, padding, len, type, padding
+ _HDR_LEN = struct.calcsize(_HDR_PACK_STR)
+
+ def __init__(self, type_, len_=None, version=VERSION):
+ self.version = version
+ self.len = len_
+ self.type = type_
+
+ @classmethod
+ def parse_header(cls, buf):
+ if len(buf) < cls._HDR_LEN:
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._HDR_LEN))
+ (version, len_, type_) = struct.unpack_from(cls._HDR_PACK_STR,
+ buffer(buf))
+
+ return version, len_, type_
+
+ @classmethod
+ def parser(cls, buf):
+ version, msglen, type_ = cls.parse_header(buf)
+
+ if version != VERSION:
+ raise ValueError("not supportted bmp version: %d" % version)
+
+ 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._lookup_type(type_)
+
+ if subcls == cls._UNKNOWN_TYPE:
+ raise ValueError("unknown bmp type: %d" % type_)
+
+ kwargs = subcls.parser(binmsg)
+ return subcls(len_=msglen,
+ type_=type_, version=version, **kwargs), rest
+
+ def serialize(self):
+ # fixup
+ tail = self.serialize_tail()
+ self.len = self._HDR_LEN + len(tail)
+
+ hdr = bytearray(struct.pack(self._HDR_PACK_STR, self.version,
+ self.len, self.type))
+ return hdr + tail
+
+ def __len__(self):
+ # XXX destructive
+ buf = self.serialize()
+ return len(buf)
+
+
+class BMPPeerMessage(BMPMessage):
+ """BMP Message with Per Peer Header
+
+ Following BMP Messages contain Per Peer Header after Common BMP Header.
+
+ - BMP_MSG_TYPE_ROUTE_MONITRING
+ - BMP_MSG_TYPE_STATISTICS_REPORT
+ - BMP_MSG_PEER_UP_NOTIFICATION
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ peer_type The type of the peer.
+ is_post_policy Indicate the message reflects the post-policy
+ Adj-RIB-In
+ peer_distinguisher Use for L3VPN router which can have multiple
+ instance.
+ peer_address The remote IP address associated with the TCP
+ session.
+ peer_as The Autonomous System number of the peer.
+ peer_bgp_id The BGP Identifier of the peer
+ timestamp The time when the encapsulated routes were
+ received.
+ ========================== ===============================================
+ """
+
+ _PEER_HDR_PACK_STR = '!BBQ16sI4sII'
+ _TYPE = {
+ 'ascii': [
+ 'peer_address',
+ 'peer_bgp_id'
+ ]
+ }
+
+ def __init__(self, peer_type, is_post_policy, peer_distinguisher,
+ peer_address, peer_as, peer_bgp_id, timestamp,
+ version=VERSION, type_=None, len_=None):
+ super(BMPPeerMessage, self).__init__(version=version,
+ len_=len_,
+ type_=type_)
+ self.peer_type = peer_type
+ self.is_post_policy = is_post_policy
+ self.peer_distinguisher = peer_distinguisher
+ self.peer_address = peer_address
+ self.peer_as = peer_as
+ self.peer_bgp_id = peer_bgp_id
+ self.timestamp = timestamp
+
+ @classmethod
+ def parser(cls, buf):
+ (peer_type, peer_flags, peer_distinguisher,
+ peer_address, peer_as, peer_bgp_id,
+ timestamp1, timestamp2) = struct.unpack_from(cls._PEER_HDR_PACK_STR,
+ buffer(buf))
+
+ rest = buf[struct.calcsize(cls._PEER_HDR_PACK_STR):]
+
+ if peer_flags & (1 << 6):
+ is_post_policy = True
+ else:
+ is_post_policy = False
+
+ if peer_flags & (1 << 7):
+ peer_address = addrconv.ipv6.bin_to_text(buffer(peer_address))
+ else:
+ peer_address = addrconv.ipv4.bin_to_text(buffer(peer_address[:4]))
+
+ peer_bgp_id = addrconv.ipv4.bin_to_text(buffer(peer_bgp_id))
+
+ timestamp = float(timestamp1) + timestamp2 * (10 ** -6)
+
+ return {
+ "peer_type": peer_type,
+ "is_post_policy": is_post_policy,
+ "peer_distinguisher": peer_distinguisher,
+ "peer_address": peer_address,
+ "peer_as": peer_as,
+ "peer_bgp_id": peer_bgp_id,
+ "timestamp": timestamp
+ }, rest
+
+ def serialize_tail(self):
+ flags = 0
+
+ if self.is_post_policy:
+ flags |= (1 << 6)
+
+ if ':' in self.peer_address:
+ flags |= (1 << 7)
+ peer_address = addrconv.ipv6.text_to_bin(self.peer_address)
+ else:
+ peer_address = addrconv.ipv4.text_to_bin(self.peer_address)
+
+ peer_bgp_id = addrconv.ipv4.text_to_bin(self.peer_bgp_id)
+
+ t1, t2 = [int(t) for t in ("%.6f" % self.timestamp).split('.')]
+
+ msg = bytearray(struct.pack(self._PEER_HDR_PACK_STR, self.peer_type,
+ flags, self.peer_distinguisher,
+ peer_address, self.peer_as,
+ peer_bgp_id, t1, t2))
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_ROUTE_MONITORING)
+class BMPRouteMonitoring(BMPPeerMessage):
+ """BMP Route Monitoring Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ peer_type The type of the peer.
+ peer_flags Provide more information about the peer.
+ peer_distinguisher Use for L3VPN router which can have multiple
+ instance.
+ peer_address The remote IP address associated with the TCP
+ session.
+ peer_as The Autonomous System number of the peer.
+ peer_bgp_id The BGP Identifier of the peer
+ timestamp The time when the encapsulated routes were
+ received.
+ bgp_update BGP Update PDU
+ ========================== ===============================================
+ """
+
+ def __init__(self, bgp_update, peer_type, is_post_policy,
+ peer_distinguisher, peer_address, peer_as, peer_bgp_id,
+ timestamp, version=VERSION, type_=BMP_MSG_ROUTE_MONITORING,
+ len_=None):
+ super(BMPRouteMonitoring,
+ self).__init__(peer_type=peer_type,
+ is_post_policy=is_post_policy,
+ peer_distinguisher=peer_distinguisher,
+ peer_address=peer_address,
+ peer_as=peer_as,
+ peer_bgp_id=peer_bgp_id,
+ timestamp=timestamp,
+ len_=len_,
+ type_=type_,
+ version=version)
+ self.bgp_update = bgp_update
+
+ @classmethod
+ def parser(cls, buf):
+ kwargs, buf = super(BMPRouteMonitoring, cls).parser(buf)
+
+ bgp_update, buf = BGPMessage.parser(buf)
+
+ kwargs['bgp_update'] = bgp_update
+
+ return kwargs
+
+ def serialize_tail(self):
+ msg = super(BMPRouteMonitoring, self).serialize_tail()
+ msg += self.bgp_update.serialize()
+
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_STATISTICS_REPORT)
+class BMPStatisticsReport(BMPPeerMessage):
+ """BMP Statistics Report Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ peer_type The type of the peer.
+ peer_flags Provide more information about the peer.
+ peer_distinguisher Use for L3VPN router which can have multiple
+ instance.
+ peer_address The remote IP address associated with the TCP
+ session.
+ peer_as The Autonomous System number of the peer.
+ peer_bgp_id The BGP Identifier of the peer
+ timestamp The time when the encapsulated routes were
+ received.
+ stats Statistics (one or more stats encoded as a TLV)
+ ========================== ===============================================
+ """
+
+ _TLV_PACK_STR = '!HH'
+ _MIN_LEN = struct.calcsize(_TLV_PACK_STR)
+
+ def __init__(self, stats, peer_type, is_post_policy, peer_distinguisher,
+ peer_address, peer_as, peer_bgp_id, timestamp,
+ version=VERSION, type_=BMP_MSG_STATISTICS_REPORT, len_=None):
+ super(BMPStatisticsReport,
+ self).__init__(peer_type=peer_type,
+ is_post_policy=is_post_policy,
+ peer_distinguisher=peer_distinguisher,
+ peer_address=peer_address,
+ peer_as=peer_as,
+ peer_bgp_id=peer_bgp_id,
+ timestamp=timestamp,
+ len_=len_,
+ type_=type_,
+ version=version)
+ self.stats = stats
+
+ @classmethod
+ def parser(cls, buf):
+ kwargs, rest = super(BMPStatisticsReport, cls).parser(buf)
+
+ stats_count, = struct.unpack_from('!I', buffer(rest))
+
+ buf = rest[struct.calcsize('!I'):]
+
+ stats = []
+
+ while len(buf):
+ if len(buf) < cls._MIN_LEN:
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN))
+ (type_, len_) = struct.unpack_from(cls._TLV_PACK_STR, buffer(buf))
+
+ if len(buf) < (cls._MIN_LEN + len_):
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN + len_))
+
+ value = buf[cls._MIN_LEN:cls._MIN_LEN + len_]
+
+ if type_ == BMP_STAT_TYPE_REJECTED or \
+ type_ == BMP_STAT_TYPE_DUPLICATE_PREFIX or \
+ type_ == BMP_STAT_TYPE_DUPLICATE_WITHDRAW or \
+ type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP or \
+ type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP or \
+ type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID or \
+ type_ == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP:
+ value, = struct.unpack_from('!I', buffer(value))
+ elif type_ == BMP_STAT_TYPE_ADJ_RIB_IN or \
+ type_ == BMP_STAT_TYPE_LOC_RIB:
+ value, = struct.unpack_from('!Q', buffer(value))
+
+ buf = buf[cls._MIN_LEN + len_:]
+
+ stats.append({'type': type_, 'len': len_, 'value': value})
+
+ kwargs['stats'] = stats
+
+ return kwargs
+
+ def serialize_tail(self):
+ msg = super(BMPStatisticsReport, self).serialize_tail()
+
+ stats_count = len(self.stats)
+
+ msg += bytearray(struct.pack('!I', stats_count))
+
+ for v in self.stats:
+ t = v['type']
+ if t == BMP_STAT_TYPE_REJECTED or \
+ t == BMP_STAT_TYPE_DUPLICATE_PREFIX or \
+ t == BMP_STAT_TYPE_DUPLICATE_WITHDRAW or \
+ t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP or \
+ t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP or \
+ t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID or \
+ t == BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP:
+ valuepackstr = 'I'
+ elif t == BMP_STAT_TYPE_ADJ_RIB_IN or \
+ t == BMP_STAT_TYPE_LOC_RIB:
+ valuepackstr = 'Q'
+ else:
+ continue
+
+ v['len'] = struct.calcsize(valuepackstr)
+ msg += bytearray(struct.pack(self._TLV_PACK_STR + valuepackstr,
+ t, v['len'], v['value']))
+
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_PEER_DOWN_NOTIFICATION)
+class BMPPeerDownNotification(BMPMessage):
+ """BMP Peer Down Notification Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ reason Reason indicates why the session was closed.
+ data vary by the reason.
+ ========================== ===============================================
+ """
+
+ def __init__(self, reason, data, type_=BMP_MSG_PEER_DOWN_NOTIFICATION,
+ len_=None, version=VERSION):
+ super(BMPPeerDownNotification, self).__init__(type_, len_, version)
+ self.reason = reason
+ self.data = data
+
+ @classmethod
+ def parser(cls, buf):
+ reason, = struct.unpack_from('!B', buffer(buf))
+ buf = buf[struct.calcsize('!B'):]
+
+ if reason == BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION:
+ data, rest = BGPMessage.parser(buf)
+ elif reason == BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION:
+ data = struct.unpack_from('!H', buffer(buf))
+ elif reason == BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION:
+ data, rest = BGPMessage.parser(buf)
+ elif reason == BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION:
+ data = None
+ else:
+ reason = BMP_PEER_DOWN_REASON_UNKNOWN
+ data = buf
+
+ kwargs = {}
+ kwargs['reason'] = reason
+ kwargs['data'] = data
+
+ return kwargs
+
+ def serialize_tail(self):
+ msg = struct.pack('!B', self.reason)
+
+ if self.reason == BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION:
+ msg += self.data.serialize()
+ elif self.reason == BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION:
+ msg += struct.pack('!H', self.data)
+ elif self.reason == BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION:
+ msg += self.data.serialize()
+ elif self.reason == BMP_PEER_DOWN_REASON_UNKNOWN:
+ msg += str(self.data)
+
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_PEER_UP_NOTIFICATION)
+class BMPPeerUpNotification(BMPPeerMessage):
+ """BMP Peer Up Notification Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ peer_type The type of the peer.
+ peer_flags Provide more information about the peer.
+ peer_distinguisher Use for L3VPN router which can have multiple
+ instance.
+ peer_address The remote IP address associated with the TCP
+ session.
+ peer_as The Autonomous System number of the peer.
+ peer_bgp_id The BGP Identifier of the peer
+ timestamp The time when the encapsulated routes were
+ received.
+ local_address The local IP address associated with the
+ peering TCP session.
+ local_port The local port number associated with the
+ peering TCP session.
+ remote_port The remote port number associated with the
+ peering TCP session.
+ sent_open_message The full OPEN message transmitted by the
+ monitored router to its peer.
+ received_open_message The full OPEN message received by the monitored
+ router from its peer.
+ ========================== ===============================================
+ """
+
+ _PACK_STR = '!16sHH'
+ _MIN_LEN = struct.calcsize(_PACK_STR)
+
+ def __init__(self, local_address, local_port, remote_port,
+ sent_open_message, received_open_message,
+ peer_type, is_post_policy, peer_distinguisher,
+ peer_address, peer_as, peer_bgp_id, timestamp,
+ version=VERSION, type_=BMP_MSG_PEER_UP_NOTIFICATION,
+ len_=None):
+ super(BMPPeerUpNotification,
+ self).__init__(peer_type=peer_type,
+ is_post_policy=is_post_policy,
+ peer_distinguisher=peer_distinguisher,
+ peer_address=peer_address,
+ peer_as=peer_as,
+ peer_bgp_id=peer_bgp_id,
+ timestamp=timestamp,
+ len_=len_,
+ type_=type_,
+ version=version)
+ self.local_address = local_address
+ self.local_port = local_port
+ self.remote_port = remote_port
+ self.sent_open_message = sent_open_message
+ self.received_open_message = received_open_message
+
+ @classmethod
+ def parser(cls, buf):
+ kwargs, rest = super(BMPPeerUpNotification, cls).parser(buf)
+
+ (local_address, local_port,
+ remote_port) = struct.unpack_from(cls._PACK_STR, buffer(rest))
+
+ local_address = buffer(local_address)
+
+ if '.' in kwargs['peer_address']:
+ local_address = addrconv.ipv4.bin_to_text(local_address[:4])
+ elif ':' in kwargs['peer_address']:
+ local_address = addrconv.ipv6.bin_to_text(local_address)
+ else:
+ raise ValueError("invalid local_address: %s" % local_address)
+
+ kwargs['local_address'] = local_address
+ kwargs['local_port'] = local_port
+ kwargs['remote_port'] = remote_port
+
+ rest = rest[cls._MIN_LEN:]
+
+ sent_open_msg, rest = BGPMessage.parser(rest)
+ received_open_msg, rest = BGPMessage.parser(rest)
+
+ kwargs['sent_open_message'] = sent_open_msg
+ kwargs['received_open_message'] = received_open_msg
+
+ return kwargs
+
+ def serialize_tail(self):
+ msg = super(BMPPeerUpNotification, self).serialize_tail()
+
+ if '.' in self.local_address:
+ local_address = addrconv.ipv4.text_to_bin(self.local_address)
+ elif ':' in self.local_address:
+ local_address = addrconv.ipv6.text_to_bin(self.local_address)
+ else:
+ raise ValueError("invalid local_address: %s" % self.local_address)
+
+ msg += struct.pack(self._PACK_STR, local_address,
+ self.local_port, self.remote_port)
+
+ msg += self.sent_open_message.serialize()
+ msg += self.received_open_message.serialize()
+
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_INITIATION)
+class BMPInitiation(BMPMessage):
+ """BMP Initiation Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ info One or more piece of information encoded as a
+ TLV
+ ========================== ===============================================
+ """
+
+ _TLV_PACK_STR = '!HH'
+ _MIN_LEN = struct.calcsize(_TLV_PACK_STR)
+
+ def __init__(self, info, type_=BMP_MSG_INITIATION, len_=None,
+ version=VERSION):
+ super(BMPInitiation, self).__init__(type_, len_, version)
+ self.info = info
+
+ @classmethod
+ def parser(cls, buf):
+ info = []
+ while len(buf):
+ if len(buf) < cls._MIN_LEN:
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN))
+ (type_, len_) = struct.unpack_from(cls._TLV_PACK_STR, buffer(buf))
+
+ if len(buf) < (cls._MIN_LEN + len_):
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN + len_))
+
+ value = buf[cls._MIN_LEN:cls._MIN_LEN + len_]
+
+ if type_ == BMP_INIT_TYPE_STRING:
+ value = value.decode('utf-8')
+
+ buf = buf[cls._MIN_LEN + len_:]
+
+ info.append({'type': type_, 'len': len_, 'value': value})
+
+ return {'info': info}
+
+ def serialize_tail(self):
+ msg = bytearray()
+
+ for v in self.info:
+ if v['type'] == BMP_INIT_TYPE_STRING:
+ value = v['value'].encode('utf-8')
+ else:
+ value = v['value']
+
+ v['len'] = len(value)
+ msg += struct.pack(self._TLV_PACK_STR, v['type'], v['len'])
+ msg += value
+
+ return msg
+
+
+@BMPMessage.register_type(BMP_MSG_TERMINATION)
+class BMPTermination(BMPMessage):
+ """BMP Termination Message
+
+ ========================== ===============================================
+ Attribute Description
+ ========================== ===============================================
+ version Version. this packet lib defines BMP ver. 3
+ len Length field. Ignored when encoding.
+ type Type field. one of BMP\_MSG\_ constants.
+ info One or more piece of information encoded as a
+ TLV
+ ========================== ===============================================
+ """
+
+ _TLV_PACK_STR = '!HH'
+ _MIN_LEN = struct.calcsize(_TLV_PACK_STR)
+
+ def __init__(self, info, type_=BMP_MSG_TERMINATION, len_=None,
+ version=VERSION):
+ super(BMPTermination, self).__init__(type_, len_, version)
+ self.info = info
+
+ @classmethod
+ def parser(cls, buf):
+ info = []
+ while len(buf):
+ if len(buf) < cls._MIN_LEN:
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN))
+ (type_, len_) = struct.unpack_from(cls._TLV_PACK_STR, buffer(buf))
+
+ if len(buf) < (cls._MIN_LEN + len_):
+ raise stream_parser.StreamParser.TooSmallException(
+ '%d < %d' % (len(buf), cls._MIN_LEN + len_))
+
+ value = buf[cls._MIN_LEN:cls._MIN_LEN + len_]
+ if type_ == BMP_TERM_TYPE_STRING:
+ value = value.decode('utf-8')
+ elif type_ == BMP_TERM_TYPE_REASON:
+ value, = struct.unpack_from('!H', buffer(value))
+
+ buf = buf[cls._MIN_LEN + len_:]
+
+ info.append({'type': type_, 'len': len_, 'value': value})
+
+ return {'info': info}
+
+ def serialize_tail(self):
+ msg = bytearray()
+
+ for v in self.info:
+ if v['type'] == BMP_TERM_TYPE_STRING:
+ value = v['value'].encode('utf-8')
+ elif v['type'] == BMP_TERM_TYPE_REASON:
+ value = struct.pack('!H', v['value'])
+ v['len'] = len(value)
+ msg += struct.pack(self._TLV_PACK_STR, v['type'], v['len'])
+ msg += value
+
+ return msg