def recv_bgpstream_updates(begin, until, collector, output_queue): logging.info ("CALL recv_bgpstream_updates") # wait for first RIB table dump to complete while (rib_ts < 0): time.sleep(RIB_TS_WAIT/10) time.sleep(RIB_TS_WAIT) # Create bgpstream stream = BGPStream() rec = BGPRecord() # set filtering stream.add_filter('collector', collector) stream.add_filter('record-type','updates') stream.add_interval_filter(rib_ts,until) # Start the stream stream.start() while (stream.get_next_record(rec)): if rec.status == 'valid': elem = rec.get_next_elem() else: logging.warn("stream record invalid, skipping ...") continue logging.info("Record TS: "+str(rec.time)) while (elem): logging.info(" -- Record Element Type: " + elem.type + ", TS: " + str(elem.time)) bgp_message = BGPmessage(elem.time, 'update') src_peer = dict() src_addr = elem.peer_address src_asn = elem.peer_asn src_peer['addr'] = src_addr src_peer['port'] = 0 src_peer['asn'] = src_asn bgp_message.set_source(src_peer) if elem.type.upper() == 'A': bgp_message.add_announce(elem.fields['prefix']) bgp_message.set_nexthop(elem.fields['next-hop']) aspath = elem.fields['as-path'].split() for a in aspath: if not '{' in a: # ignore AS-SETs bgp_message.add_as_to_path(a) output_queue.put(bgp_message) elif elem.type.upper() == 'W': bgp_message.add_withdraw(elem.fields['prefix']) output_queue.put(bgp_message) elem = rec.get_next_elem()
def recv_bgpstream_rib(begin, until, collector, output_queue): logging.info ("CALL recv_bgpstream_rib") # Create bgpstream stream = BGPStream() rec = BGPRecord() # set filtering stream.add_filter('collector', collector) stream.add_filter('record-type','updates') stream.add_interval_filter(begin,until) # Start the stream stream.start() while (stream.get_next_record(rec)): global rib_ts if rec.status == 'valid': elem = rec.get_next_elem() else: logging.warn("stream record invalid, skipping.") continue if (rib_ts > 0) and (rec.time > (rib_ts + RIB_TS_INTERVAL/2)): logging.info("received full RIB table dump.") break bgp_message = None while (elem): if (elem.type.upper() == 'A') or (elem.type.upper() == 'R'): rib_ts = elem.time bgp_message = BGPmessage(elem.time, 'update') bgp_message.set_nexthop(elem.fields['next-hop']) src_peer = dict() src_addr = elem.peer_address src_asn = elem.peer_asn src_peer['addr'] = src_addr src_peer['port'] = 0 src_peer['asn'] = src_asn bgp_message.set_source(src_peer) aspath = elem.fields['as-path'].split() for a in aspath: if not '{' in a: # ignore AS-SETs bgp_message.add_as_to_path(a) bgp_message.add_announce(elem.fields['prefix']) output_queue.put(bgp_message) elem = rec.get_next_elem()
def parse_bgp_message(xml): """Returns a dict of a parsed BGP XML update message""" logging.info("CALL parse_bgp_message") try: tree = ET.fromstring(xml) except: logging.exception ("Cannot parse XML: " + xml) return None logging.debug ("root: %s" % tree.tag) for child in tree: logging.debug (child.tag) # check if source exists, otherwise return src = tree.find('{urn:ietf:params:xml:ns:bgp_monitor}SOURCE') if src is None: logging.warning ("Invalid XML, no source!") return None src_peer = dict() src_peer['addr'] = src.find('{urn:ietf:params:xml:ns:bgp_monitor}ADDRESS').text src_peer['port'] = src.find('{urn:ietf:params:xml:ns:bgp_monitor}PORT').text src_peer['asn'] = src.find('{urn:ietf:params:xml:ns:bgp_monitor}ASN2').text # get timestamp dt = tree.find('{urn:ietf:params:xml:ns:bgp_monitor}OBSERVED_TIME') if dt is None: logging.warning ("Invalid XML, no source!") return None ts = dt.find('{urn:ietf:params:xml:ns:bgp_monitor}TIMESTAMP').text # check wether it is a keep alive message keep_alive = tree.find('{urn:ietf:params:xml:ns:xfb}KEEP_ALIVE') if keep_alive is not None: logging.debug ("BGP KEEP ALIVE %s (AS %s)" % (src_peer['addr'], src_peer['asn'])) return None # proceed with bgp update parsing update = tree.find('{urn:ietf:params:xml:ns:xfb}UPDATE') if update is None: logging.warning ("Invalid XML, no update!") return None # init return struct bgp_message = BGPmessage(ts,'update') bgp_message.set_source(src_peer) # add withdrawn prefixes withdraws = update.findall('.//{urn:ietf:params:xml:ns:xfb}WITHDRAW') for withdraw in withdraws: logging.debug ("BGP WITHDRAW %s by AS %s" % (withdraw.text,src_peer['asn'])) bgp_message.add_withdraw(withdraw.text) # add AS path asp = update.find('{urn:ietf:params:xml:ns:xfb}AS_PATH') if asp is not None: for asn in asp.findall('.//{urn:ietf:params:xml:ns:xfb}ASN2'): bgp_message.add_as_to_path(asn.text) # add next hop next_hop = update.find('{urn:ietf:params:xml:ns:xfb}NEXT_HOP') if next_hop is not None: bgp_message.set_nexthop(next_hop.text) # add announced prefixes prefixes = update.findall('.//{urn:ietf:params:xml:ns:xfb}NLRI') for prefix in prefixes: logging.debug ("BGP ANNOUNCE %s by AS %s" % (prefix.text,src_peer['asn'])) bgp_message.add_announce(prefix.text) return bgp_message