732 lines
28 KiB
Python
732 lines
28 KiB
Python
# 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
|
|
"""
|
|
|
|
import struct
|
|
|
|
import six
|
|
|
|
from os_ken.lib import addrconv
|
|
from os_ken.lib.packet import packet_base
|
|
from os_ken.lib.packet import stream_parser
|
|
from os_ken.lib.packet.bgp import BGPMessage
|
|
from os_ken.lib.type_desc import TypeDisp
|
|
|
|
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 = 4
|
|
|
|
|
|
class BMPMessage(packet_base.PacketBase, TypeDisp):
|
|
r"""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,
|
|
six.binary_type(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):
|
|
r"""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,
|
|
six.binary_type(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(peer_address)
|
|
else:
|
|
peer_address = addrconv.ipv4.bin_to_text(peer_address[-4:])
|
|
|
|
peer_bgp_id = addrconv.ipv4.bin_to_text(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 = struct.pack(
|
|
'!12x4s', 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):
|
|
r"""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):
|
|
r"""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', six.binary_type(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,
|
|
six.binary_type(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', six.binary_type(value))
|
|
elif type_ == BMP_STAT_TYPE_ADJ_RIB_IN or \
|
|
type_ == BMP_STAT_TYPE_LOC_RIB:
|
|
value, = struct.unpack_from('!Q', six.binary_type(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(BMPPeerMessage):
|
|
r"""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, peer_type, is_post_policy,
|
|
peer_distinguisher, peer_address, peer_as, peer_bgp_id,
|
|
timestamp, version=VERSION,
|
|
type_=BMP_MSG_PEER_DOWN_NOTIFICATION, len_=None):
|
|
|
|
super(BMPPeerDownNotification,
|
|
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.reason = reason
|
|
self.data = data
|
|
|
|
@classmethod
|
|
def parser(cls, buf):
|
|
kwargs, buf = super(BMPPeerDownNotification, cls).parser(buf)
|
|
reason, = struct.unpack_from('!B', six.binary_type(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', six.binary_type(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['reason'] = reason
|
|
kwargs['data'] = data
|
|
|
|
return kwargs
|
|
|
|
def serialize_tail(self):
|
|
msg = super(BMPPeerDownNotification, self).serialize_tail()
|
|
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):
|
|
r"""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, six.binary_type(rest))
|
|
|
|
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 = struct.pack(
|
|
'!12x4s', 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):
|
|
r"""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,
|
|
six.binary_type(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):
|
|
r"""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,
|
|
six.binary_type(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', six.binary_type(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
|