def setUp(self): self.negotiated = {} for asn4 in (True, False): neighbor = FakeNeighbor() neighbor.asn4 = asn4 capa = Capabilities().new(neighbor, False) capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # path = {} # for f in NLRI.known_families(): # if neighbor.add_path: # path[f] = neighbor.add_path # capa[Capability.CODE.ADD_PATH] = path o1 = Open(Version(4), ASN(neighbor.local_as), HoldTime(180), RouterID(neighbor.local_address.top()), capa) o2 = Open(Version(4), ASN(neighbor.peer_as), HoldTime(180), RouterID(neighbor.peer_address.top()), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) self.negotiated[asn4] = negotiated
def setUp(self): self.negotiated = {} for asn4 in (True, False): neighbor = FakeNeighbor() neighbor.asn4 = asn4 capa = Capabilities().new(neighbor, False) capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # path = {} # for f in NLRI.known_families(): # if neighbor.add_path: # path[f] = neighbor.add_path # capa[Capability.CODE.ADD_PATH] = path routerid_1 = str(neighbor.router_id) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor.router_id).split('.', -1)) o1 = Open(Version(4), ASN(neighbor.local_as), HoldTime(180), RouterID(routerid_1), capa) o2 = Open(Version(4), ASN(neighbor.peer_as), HoldTime(180), RouterID(routerid_2), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) self.negotiated[asn4] = negotiated
def _negotiated(neighbor): path = {} for f in NLRI.known_families(): if neighbor['capability']['add-path']: path[f] = neighbor['capability']['add-path'] capa = Capabilities().new(neighbor, False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # capa[Capability.CODE.FOUR_BYTES_ASN] = True routerid_1 = str(neighbor['router-id']) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor['router-id']).split('.', -1)) o1 = Open(Version(4), ASN(neighbor['local-as']), HoldTime(180), RouterID(routerid_1), capa) o2 = Open(Version(4), ASN(neighbor['peer-as']), HoldTime(180), RouterID(routerid_2), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False return negotiated
def test_2_open(self): capabilities = Capabilities() o = Open(Version(4), ASN(65500), HoldTime(180), RouterID('127.0.0.1'), capabilities) self.assertEqual(o.version, 4) self.assertEqual(o.asn, 65500) self.assertEqual(o.router_id, RouterID('127.0.0.1')) self.assertEqual(o.hold_time, 180) self.assertEqual(o.capabilities, {})
def test_2_open(self): capabilities = Capabilities() o = Open(4, 65500, '127.0.0.1', capabilities, 180) self.assertEqual(o.version, 4) self.assertEqual(o.asn, 65500) self.assertEqual(o.router_id, RouterID('127.0.0.1')) self.assertEqual(o.hold_time, 180) self.assertEqual(o.capabilities, {})
def new_open(self, restarted): sent_open = Open(Version(4), self.neighbor.local_as, self.neighbor.hold_time, self.neighbor.router_id, Capabilities().new(self.neighbor, restarted)) # we do not buffer open message in purpose for _ in self.write(sent_open): yield _NOP self.logger.message(self.me('>> %s' % sent_open)) yield sent_open
def check_open(neighbor, raw): import sys import traceback sys.excepthook = traceback.print_exception try: o = Open.unpack_message(raw, Direction.IN, _negotiated(neighbor)) print(o) except Exception as exc: print() print("we could not decode this open message") print("here is the traceback to help to figure out why") print() raise
def new_open(self): if self.neighbor.local_as: local_as = self.neighbor.local_as elif self.negotiated.received_open: local_as = self.negotiated.received_open.asn else: raise RuntimeError('no ASN available for the OPEN message') sent_open = Open( Version(4), local_as, self.neighbor.hold_time, self.neighbor.router_id, Capabilities().new(self.neighbor, self.peer._restarted)) # we do not buffer open message in purpose for _ in self.write(sent_open): yield _NOP self.logger.debug('>> %s' % sent_open, self.connection.session()) yield sent_open
def check_generation(neighbors): option.enabled['parser'] = True for name in neighbors.keys(): neighbor = copy.deepcopy(neighbors[name]) neighbor['local-as'] = neighbor['peer-as'] path = {} for f in NLRI.known_families(): if neighbor['capability']['add-path']: path[f] = neighbor['capability']['add-path'] capa = Capabilities().new(neighbor, False) if path: capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() routerid_1 = str(neighbor['router-id']) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor['router-id']).split('.', -1)) o1 = Open(Version(4), ASN(neighbor['local-as']), HoldTime(180), RouterID(routerid_1), capa) o2 = Open(Version(4), ASN(neighbor['peer-as']), HoldTime(180), RouterID(routerid_2), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False for _ in neighbor.rib.outgoing.updates(False): pass for change1 in neighbor.rib.outgoing.cached_changes(): str1 = change1.extensive() packed = list( Update([change1.nlri], change1.attributes).messages(negotiated)) pack1 = packed[0] log.debug('parsed route requires %d updates' % len(packed), 'parser') log.debug('update size is %d' % len(pack1), 'parser') log.debug('parsed route %s' % str1, 'parser') log.debug('parsed hex %s' % od(pack1), 'parser') # This does not take the BGP header - let's assume we will not break that :) try: log.debug('') # new line pack1s = pack1[19:] if pack1.startswith(b'\xFF' * 16) else pack1 update = Update.unpack_message(pack1s, negotiated) change2 = Change(update.nlris[0], update.attributes) str2 = change2.extensive() pack2 = list( Update([update.nlris[0]], update.attributes).messages(negotiated))[0] log.debug('recoded route %s' % str2, 'parser') log.debug('recoded hex %s' % od(pack2), 'parser') str1 = str1.replace('attribute [ 0x04 0x80 0x00000064 ]', 'med 100') str1r = (str1.lower().replace(' med 100', '').replace( ' local-preference 100', '').replace(' origin igp', '')) str2r = (str2.lower().replace(' med 100', '').replace( ' local-preference 100', '').replace(' origin igp', '')) str2r = str2r.replace( 'large-community [ 1:2:3 10:11:12 ]', 'attribute [ 0x20 0xc0 0x0000000100000002000000030000000a0000000b0000000c ]', ) if 'next-hop self' in str1r: if ':' in str1r: str1r = str1r.replace('next-hop self', 'next-hop ::1') else: str1r = str1r.replace( 'next-hop self', 'next-hop %s' % neighbor['local-address']) if ' name ' in str1r: parts = str1r.split(' ') pos = parts.index('name') str1r = ' '.join(parts[:pos] + parts[pos + 2:]) skip = False if str1r != str2r: if 'attribute [' in str1r and ' 0x00 ' in str1r: # we do not decode non-transitive attributes log.debug( 'skipping string check on update with non-transitive attribute(s)', 'parser') skip = True else: log.debug('strings are different:', 'parser') log.debug('[%s]' % (str1r), 'parser') log.debug('[%s]' % (str2r), 'parser') return False else: log.debug('strings are fine', 'parser') if skip: log.debug( 'skipping encoding for update with non-transitive attribute(s)', 'parser') elif pack1 != pack2: log.debug('encoding are different', 'parser') log.debug('[%s]' % (od(pack1)), 'parser') log.debug('[%s]' % (od(pack2)), 'parser') return False else: log.debug('encoding is fine', 'parser') log.debug('----------------------------------------', 'parser') log.debug('JSON nlri %s' % change1.nlri.json(), 'parser') log.debug('JSON attr %s' % change1.attributes.json(), 'parser') except Notify as exc: log.debug('----------------------------------------', 'parser') log.debug(str(exc), 'parser') log.debug('----------------------------------------', 'parser') return False neighbor.rib.clear() return True
def check_update(neighbor, raw): option.enabled['parser'] = True neighbor = neighbor[list(neighbor)[0]] path = {} for f in NLRI.known_families(): if neighbor['capability']['add-path']: path[f] = neighbor['capability']['add-path'] capa = Capabilities().new(neighbor, False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # capa[Capability.CODE.FOUR_BYTES_ASN] = True routerid_1 = str(neighbor['router-id']) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor['router-id']).split('.', -1)) o1 = Open(Version(4), ASN(neighbor['local-as']), HoldTime(180), RouterID(routerid_1), capa) o2 = Open(Version(4), ASN(neighbor['peer-as']), HoldTime(180), RouterID(routerid_2), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False while raw: if raw.startswith(b'\xff' * 16): kind = raw[18] size = (raw[16] << 16) + raw[17] injected, raw = raw[19:size], raw[size:] if kind == 2: log.debug('the message is an update', 'parser') decoding = 'update' else: log.debug( 'the message is not an update (%d) - aborting' % kind, 'parser') return False else: log.debug('header missing, assuming this message is ONE update', 'parser') decoding = 'update' injected, raw = raw, '' try: # This does not take the BGP header - let's assume we will not break that :) update = Update.unpack_message(injected, negotiated) except Notify: import traceback log.error('could not parse the message', 'parser') log.error(traceback.format_exc(), 'parser') return False except Exception: import traceback log.error('could not parse the message', 'parser') log.error(traceback.format_exc(), 'parser') return False log.debug('', 'parser') # new line for number in range(len(update.nlris)): change = Change(update.nlris[number], update.attributes) log.info( 'decoded %s %s %s' % (decoding, change.nlri.action, change.extensive()), 'parser') log.info( 'update json %s' % Response.JSON(json_version).update( neighbor, 'in', update, None, '', ''), 'parser') return True
def _from_json(self, string): try: parsed = json.loads(string) except ValueError: print >> sys.stderr, 'invalid JSON message' sys.exit(1) if parsed.get('exabgp', '0.0.0') != json_version: print >> sys.stderr, 'invalid json version', string sys.exit(1) content = parsed.get('type', '') if not content: print >> sys.stderr, 'invalid json content', string sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] raw = ''.join( chr(int(body[_:_ + 2], 16)) for _ in range(0, len(body), 2)) if content == 'open': message = Open.unpack_message(raw) self._open(direction, message) return self.encoder.open(neighbor, direction, message, header, body) if content == 'keapalive': return self.encoder.keepalive(neighbor, direction, header, body) if content == 'notification': message = Notification.unpack_message(raw) return self.encoder.notification(neighbor, direction, message, header, body) if not self.negotiated: print >> sys.stderr, 'invalid message sequence, open not exchange not complete', string sys.exit(1) message = Message.unpack(category, raw, self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, header, body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, header, body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, header, body) if content == 'operational': return self.json.refresh(neighbor, direction, message, header, body) raise RuntimeError( 'the programer is a monkey and forgot a JSON message type')
def check_update(neighbor, raw): logger = Logger() logger._option.parser = True logger.parser('\ndecoding routes in configuration') neighbor = neighbor[neighbor.keys()[0]] path = {} for f in NLRI.known_families(): if neighbor.add_path: path[f] = neighbor.add_path capa = Capabilities().new(neighbor, False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # capa[Capability.CODE.FOUR_BYTES_ASN] = True routerid_1 = str(neighbor.router_id) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor.router_id).split('.', -1)) o1 = Open(4, neighbor.local_as, routerid_1, capa, 180) o2 = Open(4, neighbor.peer_as, routerid_2, capa, 180) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False while raw: if raw.startswith('\xff' * 16): kind = ord(raw[18]) size = (ord(raw[16]) << 16) + (ord(raw[17])) injected, raw = raw[19:size], raw[size:] if kind == 2: logger.parser('the message is an update') decoding = 'update' else: logger.parser('the message is not an update (%d) - aborting' % kind) return False else: logger.parser( 'header missing, assuming this message is ONE update') decoding = 'update' injected, raw = raw, '' try: # This does not take the BGP header - let's assume we will not break that :) update = Update.unpack_message(injected, negotiated) except KeyboardInterrupt: raise except Notify, exc: logger.parser('could not parse the message') logger.parser(str(exc)) return False except Exception, exc: logger.parser('could not parse the message') logger.parser(str(exc)) return False
def _from_json (self, string): try: parsed = json.loads(string) except ValueError: print >> sys.stderr, 'invalid JSON message' sys.exit(1) if parsed.get('exabgp','0.0.0') != json_version: print >> sys.stderr, 'invalid json version', string sys.exit(1) content = parsed.get('type','') if not content: print >> sys.stderr, 'invalid json content', string sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] raw = ''.join(chr(int(body[_:_+2],16)) for _ in range(0,len(body),2)) if content == 'open': message = Open.unpack_message(raw) self._open(direction,message) return self.encoder.open(neighbor,direction,message,header,body) if content == 'keapalive': return self.encoder.keepalive(neighbor,direction,header,body) if content == 'notification': message = Notification.unpack_message(raw) return self.encoder.notification(neighbor,direction,message,header,body) if not self.negotiated: print >> sys.stderr, 'invalid message sequence, open not exchange not complete', string sys.exit(1) message = Message.unpack(category,raw,self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, header,body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, header,body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, header,body) if content == 'operational': return self.json.refresh(neighbor, direction, message, header,body) raise RuntimeError('the programer is a monkey and forgot a JSON message type')
def check_update(neighbor, raw): logger = Logger() logger._option.parser = True logger.parser('\ndecoding routes in configuration') neighbor = neighbor[neighbor.keys()[0]] path = {} for f in NLRI.known_families(): if neighbor.add_path: path[f] = neighbor.add_path capa = Capabilities().new(neighbor, False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() # capa[Capability.CODE.FOUR_BYTES_ASN] = True routerid_1 = str(neighbor.router_id) routerid_2 = '.'.join( str((int(_) + 1) % 250) for _ in str(neighbor.router_id).split('.', -1)) o1 = Open(Version(4), ASN(neighbor.local_as), HoldTime(180), RouterID(routerid_1), capa) o2 = Open(Version(4), ASN(neighbor.peer_as), HoldTime(180), RouterID(routerid_2), capa) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False while raw: if raw.startswith('\xff' * 16): kind = ord(raw[18]) size = (ord(raw[16]) << 16) + (ord(raw[17])) injected, raw = raw[19:size], raw[size:] if kind == 2: logger.parser('the message is an update') decoding = 'update' else: logger.parser('the message is not an update (%d) - aborting' % kind) return False else: logger.parser( 'header missing, assuming this message is ONE update') decoding = 'update' injected, raw = raw, '' try: # This does not take the BGP header - let's assume we will not break that :) update = Update.unpack_message(injected, negotiated) except KeyboardInterrupt: raise except Notify: logger.parser('could not parse the message', 'error') logger.parser(traceback.format_exc(), 'error') return False except StandardError: logger.parser('could not parse the message', 'error') logger.parser(traceback.format_exc(), 'error') return False logger.parser('') # new line for number in range(len(update.nlris)): change = Change(update.nlris[number], update.attributes) logger.parser('decoded %s %s %s' % (decoding, change.nlri.action, change.extensive())) logger.parser( 'update json %s' % Response.JSON(json_version).update(neighbor, 'in', update, '', '')) return True
def _from_json (self, json_string): try: parsed = json.loads(json_string) except ValueError: print('invalid JSON message', file=sys.stderr) sys.exit(1) if parsed.get('exabgp','0.0.0') != json_version: print('invalid json version', json_string, file=sys.stderr) sys.exit(1) content = parsed.get('type','') if not content: print('invalid json content', json_string, file=sys.stderr) sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return json_string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] data = concat_bytes_i(character(int(body[_:_+2],16)) for _ in range(0,len(body),2)) if content == 'open': message = Open.unpack_message(data) self._open(direction,message) return self.encoder.open(neighbor,direction,message,None,header,body) if content == 'keepalive': return self.encoder.keepalive(neighbor,direction,None,header,body) if content == 'notification': # XXX: Use the code of the Notifcation class here .. message = Notification.unpack_message(data) if (message.code, message.subcode) != (6, 2): message.data = data if not len([_ for _ in data if _ not in string.printable]) else hexstring(data) return self.encoder.notification(neighbor,direction,message,None,header,body) if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) message.data = '' return self.encoder.notification(neighbor,direction,message,None,header,body) # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = ordinal(data[0]) data = data[1:] if shutdown_length == 0: message.data = "empty Shutdown Communication." # move offset past length field return self.encoder.notification(neighbor,direction,message,None,header,body) if len(data) < shutdown_length: message.data = "invalid Shutdown Communication (buffer underrun) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) if shutdown_length > 128: message.data = "invalid Shutdown Communication (too large) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) try: message.data = 'Shutdown Communication: "%s"' % \ data[:shutdown_length].decode('utf-8').replace('\r',' ').replace('\n',' ') except UnicodeDecodeError: message.data = "invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % (shutdown_length, hexstring(data)) return self.encoder.notification(neighbor,direction,message,None,header,body) trailer = data[shutdown_length:] if trailer: message.data += ", trailing data: " + hexstring(trailer) return self.encoder.notification(neighbor,direction,message,None,header,body) if not self.negotiated: print('invalid message sequence, open not exchange not complete', json_string, file=sys.stderr) sys.exit(1) message = Message.unpack(category,data,self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, None, header,body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, None, header,body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, None, header,body) if content == 'operational': return self.json.refresh(neighbor, direction, message, None, header,body) raise RuntimeError('the programer is a monkey and forgot a JSON message type')
def _from_json(self, direction, json_string): try: parsed = json.loads(json_string) except ValueError: print('invalid JSON message', file=sys.stderr) sys.exit(1) if parsed.get('exabgp', '0.0.0') != json_version: print('invalid json version', json_string, file=sys.stderr) sys.exit(1) content = parsed.get('type', '') if not content: print('invalid json content', json_string, file=sys.stderr) sys.exit(1) neighbor = _FakeNeighbor( parsed['neighbor']['address']['local'], parsed['neighbor']['address']['peer'], parsed['neighbor']['asn']['local'], parsed['neighbor']['asn']['peer'], ) if content == 'state': self._state() return json_string direction = parsed['neighbor']['direction'] category = parsed['neighbor']['message']['category'] header = parsed['neighbor']['message']['header'] body = parsed['neighbor']['message']['body'] data = b''.join(bytes([int(body[_ : _ + 2], 16)]) for _ in range(0, len(body), 2)) if content == 'open': message = Open.unpack_message(data) self._open(direction, message) return self.encoder.open(neighbor, direction, message, None, header, body) if content == 'keepalive': return self.encoder.keepalive(neighbor, direction, None, header, body) if content == 'notification': # XXX: Use the code of the Notifcation class here .. message = Notification.unpack_message(data) if (message.code, message.subcode) != (6, 2): message.data = data if not len([_ for _ in data if _ not in string.printable]) else hexstring(data) return self.encoder.notification(neighbor, direction, message, None, header, body) if len(data) == 0: # shutdown without shutdown communication (the old fashioned way) message.data = '' return self.encoder.notification(neighbor, direction, message, None, header, body) # draft-ietf-idr-shutdown or the peer was using 6,2 with data shutdown_length = data[0] data = data[1:] if shutdown_length == 0: message.data = "empty Shutdown Communication." # move offset past length field return self.encoder.notification(neighbor, direction, message, None, header, body) if len(data) < shutdown_length: message.data = "invalid Shutdown Communication (buffer underrun) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) if shutdown_length > 128: message.data = "invalid Shutdown Communication (too large) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) try: message.data = 'Shutdown Communication: "%s"' % data[:shutdown_length].decode('utf-8').replace( '\r', ' ' ).replace('\n', ' ') except UnicodeDecodeError: message.data = "invalid Shutdown Communication (invalid UTF-8) length : %i [%s]" % ( shutdown_length, hexstring(data), ) return self.encoder.notification(neighbor, direction, message, None, header, body) trailer = data[shutdown_length:] if trailer: message.data += ", trailing data: " + hexstring(trailer) return self.encoder.notification(neighbor, direction, message, None, header, body) if not self.negotiated: print('invalid message sequence, open not exchange not complete', json_string, file=sys.stderr) sys.exit(1) message = Message.unpack(category, data, direction, self.negotiated) if content == 'update': return self.encoder.update(neighbor, direction, message, None, header, body) if content == 'eor': # XXX: Should not be required return self.encoder.update(neighbor, direction, message, None, header, body) if content == 'refresh': return self.json.refresh(neighbor, direction, message, None, header, body) if content == 'operational': return self.json.refresh(neighbor, direction, message, None, header, body) raise RuntimeError('the programer is a monkey and forgot a JSON message type')
def check_neighbor(neighbors): logger = Logger() logger._option.parser = True if not neighbors: logger.parser('\ncould not find neighbor(s) to check') return False logger.parser('\ndecoding routes in configuration') for name in neighbors.keys(): neighbor = neighbors[name] path = {} for f in NLRI.known_families(): if neighbor.add_path: path[f] = neighbor.add_path capa = Capabilities().new(neighbor, False) if path: capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = neighbor.families() o1 = Open(4, neighbor.local_as, str(neighbor.local_address), capa, 180) o2 = Open(4, neighbor.peer_as, str(neighbor.peer_address), capa, 180) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False for _ in neighbor.rib.outgoing.updates(False): pass for change1 in neighbor.rib.outgoing.sent_changes(): str1 = change1.extensive() packed = list( Update([change1.nlri], change1.attributes).messages(negotiated)) pack1 = packed[0] logger.parser('parsed route requires %d updates' % len(packed)) logger.parser('parsed route requires %d updates' % len(packed)) logger.parser('update size is %d' % len(pack1)) logger.parser('parsed route %s' % str1) logger.parser('parsed hex %s' % od(pack1)) # This does not take the BGP header - let's assume we will not break that :) try: logger.parser('') # new line pack1s = pack1[19:] if pack1.startswith('\xFF' * 16) else pack1 update = Update.unpack_message(pack1s, negotiated) change2 = Change(update.nlris[0], update.attributes) str2 = change2.extensive() pack2 = list( Update([update.nlris[0]], update.attributes).messages(negotiated))[0] logger.parser('recoded route %s' % str2) logger.parser('recoded hex %s' % od(pack2)) str1r = str1.replace(' med 100', '').replace( ' local-preference 100', '').replace(' origin igp', '') str2r = str2.replace(' med 100', '').replace( ' local-preference 100', '').replace(' origin igp', '') if ' name ' in str1r: parts = str1r.split(' ') pos = parts.index('name') str1r = ' '.join(parts[:pos] + parts[pos + 2:]) skip = False if str1r != str2r: if 'attribute [' in str1r and ' 0x00 ' in str1r: # we do not decode non-transitive attributes logger.parser( 'skipping string check on update with non-transitive attribute(s)' ) skip = True else: logger.parser('strings are different:') logger.parser('[%s]' % (str1r)) logger.parser('[%s]' % (str2r)) return False else: logger.parser('strings are fine') if skip: logger.parser( 'skipping encoding for update with non-transitive attribute(s)' ) elif pack1 != pack2: logger.parser('encoding are different') logger.parser('[%s]' % (od(pack1))) logger.parser('[%s]' % (od(pack2))) return False else: logger.parser('encoding is fine') logger.parser('----------------------------------------') logger.parser('JSON nlri %s' % change1.nlri.json()) logger.parser('JSON attr %s' % change1.attributes.json()) except Notify, exc: logger.parser('----------------------------------------') logger.parser(str(exc)) logger.parser('----------------------------------------') return False neighbor.rib.clear()