def send_route_refresh(self, afi, safi, res=0): """ Send bgp route refresh message :param afi: address family :param safi: sub address family :param res: reserve, default is 0 """ # check if the peer support route refresh if 'cisco_route_refresh' in cfg.CONF.bgp.running_config['capability'][ 'remote']: type_code = bgp_cons.MSG_CISCOROUTEREFRESH elif 'route_refresh' in cfg.CONF.bgp.running_config['capability'][ 'remote']: type_code = bgp_cons.MSG_ROUTEREFRESH else: return False # check if the peer support this address family if (afi, safi) not in cfg.CONF.bgp.running_config['capability'][ 'remote']['afi_safi']: return False # construct message msg_routerefresh = RouteRefresh(afi, safi, res).construct(type_code) # send message self.transport.write(msg_routerefresh) self.msg_sent_stat['RouteRefresh'] += 1 LOG.info("[%s]Send BGP RouteRefresh message to the peer.", self.factory.peer_addr) return True
def test_construct_cisco_route_refresh(self): msg = (1, 0, 128) msg_hex = RouteRefresh(afi=msg[0], res=msg[1], safi=msg[2]).construct(MSG_CISCOROUTEREFRESH) msg_hoped = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x17\x80\x00\x01\x00\x80' self.assertEqual(msg_hoped, msg_hex)
def parse_route_monitoring_msg(msg): """ Route Monitoring messages are used for initial synchronization of ADJ-RIBs-In. They are also used for ongoing monitoring of received advertisements and withdraws. Following the common BMP header and per-peer header is a BGP Update PDU. :param msg: :return: """ LOG.debug('decode route monitoring message') bgp_msg_type = struct.unpack('!B', msg[18])[0] LOG.debug('bgp message type=%s' % bgp_msg_type) msg = msg[bgp_cons.HDR_LEN:] if bgp_msg_type == 2: # decode update message results = Update().parse(None, msg, asn4=True) if results['sub_error']: LOG.error( 'error: decode update message error!, error code: %s' % results['sub_error']) LOG.error('Raw data: %s' % repr(results['hex'])) return None return_result = { 'attr': results['attr'], 'nlri': results['nlri'], 'withdraw': results['withdraw'] } LOG.debug('bgp update message: %s' % return_result) return bgp_msg_type, return_result elif bgp_msg_type == 5: bgp_route_refresh_msg = RouteRefresh().parse(msg=msg) LOG.debug('bgp route refresh message: afi=%s,res=%s,safi=%s' % (bgp_route_refresh_msg[0], bgp_route_refresh_msg[1], bgp_route_refresh_msg[2])) return bgp_msg_type, { 'afi': bgp_route_refresh_msg[0], 'sub_type': bgp_route_refresh_msg[1], 'safi': bgp_route_refresh_msg[2] }
def parse_route_mirroring_msg(msg): """ Route Mirroring messages are used for verbatim duplication of messages as received. Following the common BMP header and per-peer header is a set of TLVs that contain information about a message or set of messages. :param msg: :return: """ LOG.debug('decode route mirroring message') msg_dict = {} open_l = [] update = [] notification = [] route_refresh = [] while msg: mirror_type, length = struct.unpack('!HH', msg[0:4]) mirror_value = msg[4:4 + length] msg = msg[4 + length:] if mirror_type == 0: # BGP message type bgp_msg_type = struct.unpack('!B', mirror_value[18])[0] LOG.debug('bgp message type=%s' % bgp_msg_type) bgp_msg_body = mirror_value[bgp_cons.HDR_LEN:] if bgp_msg_type == 2: # Update message bgp_update_msg = Update().parse(None, bgp_msg_body, asn4=True) if bgp_update_msg['sub_error']: LOG.error( 'error: decode update message error!, error code: %s' % bgp_update_msg['sub_error']) LOG.error('Raw data: %s' % repr(bgp_update_msg['hex'])) else: update.append(bgp_update_msg) elif bgp_msg_type == 5: # Route Refresh message bgp_route_refresh_msg = RouteRefresh().parse( msg=bgp_msg_body) LOG.debug( 'bgp route refresh message: afi=%s,res=%s,safi=%s' % (bgp_route_refresh_msg[0], bgp_route_refresh_msg[1], bgp_route_refresh_msg[2])) route_refresh.append(bgp_route_refresh_msg) elif bgp_msg_type == 1: # Open message open_msg = Open().parse(bgp_msg_body) open_l.append(open_msg) elif bgp_msg_type == 3: # Notification message notification_msg = Notification().parse(bgp_msg_body) notification.append(notification_msg) elif mirror_type == 1: # Information type. # Amount of this TLV is not specified but we can assume # only one per mirroring message is present. info_code_type = struct.unpack('!H', mirror_value)[0] msg_dict['1'] = info_code_type else: msg_dict[mirror_type] = binascii.unhexlify( binascii.hexlify(mirror_value)) LOG.info('unknow mirroring type, type = %s' % mirror_type) msg_dict['0'] = { 'update': update, 'route_refresh': route_refresh, 'open': open_l, 'notification': notification } return msg_dict
def parse_buffer(self): """ Parse TCP buffer data. :return: True or False """ buf = self._receive_buffer if len(buf) < bgp_cons.HDR_LEN: # Every BGP message is at least 19 octets. Maybe the rest # hasn't arrived yet. return False # Check whether the first 16 octets of the buffer consist of # the BGP marker (all bits one) if buf[:16] != 16 * b'\xff': self.fsm.header_error(bgp_cons.ERR_MSG_HDR_CONN_NOT_SYNC) return False # Parse the BGP header try: marker, length, msg_type = struct.unpack('!16sHB', buf[:bgp_cons.HDR_LEN]) except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) self.fsm.header_error(bgp_cons.ERR_MSG_HDR_CONN_NOT_SYNC) return False # Check the length of the message, must be less than 4096, bigger than 19 if length < bgp_cons.HDR_LEN or length > bgp_cons.MAX_LEN: self.fsm.header_error(bgp_cons.ERR_MSG_HDR_BAD_MSG_LEN, struct.pack('!H', length)) # Check whether the entire message is already available if len(buf) < length: return False msg = buf[bgp_cons.HDR_LEN:length] t = time.time() # the time when received that packet. try: if msg_type == bgp_cons.MSG_OPEN: try: self._open_received(timestamp=t, msg=msg) except excep.MessageHeaderError as e: LOG.error(e) self.fsm.header_error(suberror=e.sub_error) return False except excep.OpenMessageError as e: LOG.error(e) self.fsm.open_message_error(suberror=e.sub_error) return False elif msg_type == bgp_cons.MSG_UPDATE: self._update_received(timestamp=t, msg=msg) elif msg_type == bgp_cons.MSG_NOTIFICATION: self._notification_received(Notification().parse(msg)) elif msg_type == bgp_cons.MSG_KEEPALIVE: try: self._keepalive_received(timestamp=t, msg=msg) except excep.MessageHeaderError as e: LOG.error(e) self.fsm.header_error(suberror=e.sub_error) return False elif msg_type in (bgp_cons.MSG_ROUTEREFRESH, bgp_cons.MSG_CISCOROUTEREFRESH): route_refresh_msg = RouteRefresh().parse(msg) self._route_refresh_received(msg=route_refresh_msg, msg_type=msg_type) else: # unknown message type self.fsm.header_error(bgp_cons.ERR_MSG_HDR_BAD_MSG_TYPE, struct.pack('!H', msg_type)) except Exception as e: LOG.error(e) error_str = traceback.format_exc() LOG.debug(error_str) self._receive_buffer = self._receive_buffer[length:] return True
def test_parse(self): msg_hex = b'\x00\x01\x00\x80' msg_parsed = RouteRefresh().parse(msg_hex) msg_hoped = (1, 0, 128) self.assertEqual(msg_hoped, msg_parsed)