def test_decoding_udpate_asn4 (self): try: for asn4,body in bodies: if not asn4: continue Update.unpack_message(''.join(chr(_) for _ in body),self.negotiated[asn4]) except Notify: self.assertEqual(1,0)
def check_update (neighbor, raw): from exabgp.logger import Logger logger = Logger() logger._parser = True logger.parser('\ndecoding routes in configuration') n = neighbor[neighbor.keys()[0]] p = Peer(n,None) path = {} for f in known_families(): if n.add_path: path[f] = n.add_path capa = Capabilities().new(n,False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = n.families() routerid_1 = str(n.router_id) routerid_2 = '.'.join(str((int(_)+1) % 250) for _ in str(n.router_id).split('.',-1)) o1 = Open(4,n.local_as,routerid_1,capa,180) o2 = Open(4,n.peer_as,routerid_2,capa,180) negotiated = Negotiated(n) 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','error') logger.parser(str(exc),'error') return False except Exception,exc: logger.parser('could not parse the message','error') logger.parser(str(exc),'error') return False
def check_update (neighbor, raw): from exabgp.logger import Logger logger = Logger() logger._parser = True logger.parser('\ndecoding routes in configuration') n = neighbor[neighbor.keys()[0]] p = Peer(n,None) path = {} for f in known_families(): if n.add_path: path[f] = n.add_path capa = Capabilities().new(n,False) capa[Capability.CODE.ADD_PATH] = path capa[Capability.CODE.MULTIPROTOCOL] = n.families() routerid_1 = str(n.router_id) routerid_2 = '.'.join(str((int(_)+1) % 250) for _ in str(n.router_id).split('.',-1)) o1 = Open(4,n.local_as,routerid_1,capa,180) o2 = Open(4,n.peer_as,routerid_2,capa,180) negotiated = Negotiated(n) 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 send(self, raw): if self.neighbor.api.get('send-%d' % ord(raw[19]), False): message = Update.unpack_message(raw[19:], self.negotiated) self._to_api('send', message, raw) for boolean in self.connection.writer(raw): yield boolean
def send (self,raw): if self.neighbor.api.get('send-%d' % ord(raw[19]),False): message = Update.unpack_message(raw[19:],self.negotiated) self._to_api('send',message,raw) for boolean in self.connection.writer(raw): yield boolean
def check_update(neighbor, raw): from exabgp.logger import Logger logger = Logger() logger._parser = True logger.parser("\ndecoding routes in configuration") n = neighbor[neighbor.keys()[0]] p = Peer(n, None) path = {} for f in known_families(): if n.add_path: path[f] = n.add_path capa = Capabilities().new(n, False) capa[Capability.ID.ADD_PATH] = path capa[Capability.ID.MULTIPROTOCOL_EXTENSIONS] = n.families() o1 = Open(4, n.local_as, str(n.local_address), capa, 180) o2 = Open(4, n.peer_as, str(n.peer_address), capa, 180) negotiated = Negotiated(n) 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, e: logger.parser("could not parse the message") logger.parser(str(e)) return False except Exception, e: logger.parser("could not parse the message") logger.parser(str(e)) return False
def _route(self, header): bgp_header = self._read_data(19) if bgp_header is None: self.close() return length = unpack('!H', bgp_header[16:18])[0] - 19 bgp_body = self._read_data(length) if bgp_body is None: self.close() return negotiated = FakeNegotiated(header, self.asn4) update = Update.unpack_message(bgp_body, negotiated) if self.use_json: print >> self.fd, self.json.bmp(self.ip, update) else: for route in update.routes: print >> self.fd, route.extensive()
def _route (self, header): bgp_header = self._read_data(19) if bgp_header is None: self.close() return length = unpack('!H',bgp_header[16:18])[0] - 19 bgp_body = self._read_data(length) if bgp_body is None: self.close() return negotiated = FakeNegotiated(header,self.asn4) update = Update.unpack_message(bgp_body,negotiated) if self.use_json: print >> self.fd, self.json.bmp(self.ip,update) else: for route in update.routes: print >> self.fd, route.extensive()
def check_neighbor (neighbors): from exabgp.logger import Logger 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 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,'127.0.0.2',capa,180) o2 = Open(4,neighbor.peer_as,'127.0.0.3',capa,180) negotiated = Negotiated(neighbor) negotiated.sent(o1) negotiated.received(o2) # grouped = False for message 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()
from exabgp.bgp.message.keepalive import new_KeepAlive from exabgp.bgp.message.update import Update from exabgp.bgp.message.update import Attributes from exabgp.rib.table import Table from exabgp.rib.delta import Delta from exabgp.reactor.protocol import Protocol from exabgp.bgp.neighbor import Neighbor from StringIO import StringIO class Network (StringIO): def pending (self): return True route1 = Update([],[to_NLRI('10.0.0.1','32')],Attributes()) route1.next_hop = '10.0.0.254' route2 = Update([],[to_NLRI('10.0.1.1','32')],Attributes()) route2.next_hop = '10.0.0.254' route3 = Update([],[to_NLRI('10.0.2.1','32')],Attributes()) route3.next_hop = '10.0.0.254' routes = [route1,route2,route3] routes.sort() class TestProtocol (unittest.TestCase): def setUp(self): self.table = Table()
def check_neighbor(neighbor): from exabgp.logger import Logger logger = Logger() logger._parser = True logger.parser('\ndecoding routes in configuration') n = neighbor[neighbor.keys()[0]] path = {} for f in known_families(): if n.add_path: path[f] = n.add_path capa = Capabilities().new(n, False) capa[Capability.ID.ADD_PATH] = path capa[Capability.ID.MULTIPROTOCOL] = n.families() o1 = Open(4, n.local_as, str(n.local_address), capa, 180) o2 = Open(4, n.peer_as, str(n.peer_address), capa, 180) negotiated = Negotiated(n) negotiated.sent(o1) negotiated.received(o2) #grouped = False for nei in neighbor.keys(): for message in neighbor[nei].rib.outgoing.updates(False): pass for change1 in neighbor[nei].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('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', '') 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('----------------------------------------') except Notify, e: logger.parser('----------------------------------------') logger.parser(str(e)) logger.parser('----------------------------------------') return False
def UpdateFactory(negotiated, data): logger = Logger() length = len(data) lw, withdrawn, data = defix(data) if len(withdrawn) != lw: raise Notify( 3, 1, 'invalid withdrawn routes length, not enough data available') la, attribute, announced = defix(data) if len(attribute) != la: raise Notify( 3, 1, 'invalid total path attribute length, not enough data available') if 2 + lw + 2 + la + len(announced) != length: raise Notify( 3, 1, 'error in BGP message length, not enough data for the size announced' ) attributes = AttributesFactory(NLRIFactory, negotiated, attribute) # Is the peer going to send us some Path Information with the route (AddPath) addpath = negotiated.addpath.receive(AFI(AFI.ipv4), SAFI(SAFI.unicast)) nho = attributes.get(AID.NEXT_HOP, None) nh = nho.packed if nho else None if not withdrawn: logger.parser(LazyFormat("parsed no withdraw nlri", od, '')) nlris = [] while withdrawn: length, nlri = NLRIFactory(AFI.ipv4, SAFI.unicast_multicast, withdrawn, addpath, nh, IN.withdrawn) logger.parser( LazyFormat("parsed withdraw nlri %s payload " % nlri, od, withdrawn[:len(nlri)])) withdrawn = withdrawn[length:] nlris.append(nlri) if not announced: logger.parser(LazyFormat("parsed no announced nlri", od, '')) while announced: length, nlri = NLRIFactory(AFI.ipv4, SAFI.unicast_multicast, announced, addpath, nh, IN.announced) logger.parser( LazyFormat("parsed announce nlri %s payload " % nlri, od, announced[:len(nlri)])) announced = announced[length:] nlris.append(nlri) for nlri in attributes.mp_withdraw: nlris.append(nlri) for nlri in attributes.mp_announce: nlris.append(nlri) return Update(nlris, attributes)
def test_decoding_udpate_asn4 (self): for asn4,body in bodies: if not asn4: continue Update.unpack_message(''.join(chr(_) for _ in body),self.negotiated[asn4])
def check_neighbor(neighbor): from exabgp.logger import Logger logger = Logger() logger._parser = True logger.parser("\ndecoding routes in configuration") n = neighbor[neighbor.keys()[0]] path = {} for f in known_families(): if n.add_path: path[f] = n.add_path capa = Capabilities().new(n, False) capa[Capability.ID.ADD_PATH] = path capa[Capability.ID.MULTIPROTOCOL_EXTENSIONS] = n.families() o1 = Open(4, n.local_as, str(n.local_address), capa, 180) o2 = Open(4, n.peer_as, str(n.peer_address), capa, 180) negotiated = Negotiated(n) negotiated.sent(o1) negotiated.received(o2) # grouped = False for nei in neighbor.keys(): for message in neighbor[nei].rib.outgoing.updates(False): pass for change1 in neighbor[nei].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("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", "") 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("----------------------------------------") except Notify, e: logger.parser("----------------------------------------") logger.parser(str(e)) logger.parser("----------------------------------------") return False
from exabgp.bgp.message.update import Update from exabgp.bgp.message.update import Attributes from exabgp.bgp.message.update import new_Update from exabgp.reactor.protocol import Protocol from exabgp.bgp.neighbor import Neighbor from StringIO import StringIO class Network(StringIO): def pending(self): return True route1 = Update([], [to_NLRI("10.0.0.1", "32")], Attributes()) route1.next_hop = "10.0.0.254" route2 = Update([], [to_NLRI("10.0.1.1", "32")], Attributes()) route2.next_hop = "10.0.0.254" route3 = Update([], [to_NLRI("10.0.2.1", "32")], Attributes()) route3.next_hop = "10.0.0.254" routes = [route1, route2, route3] routes.sort() class TestProtocol(unittest.TestCase): def setUp(self): self.neighbor = Neighbor()
def test_decoding_udpate_asn4(self): for asn4, body in bodies: if not asn4: continue Update.unpack_message(''.join(chr(_) for _ in body), self.negotiated[asn4])
from exabgp.bgp.message.update import Update from exabgp.bgp.message.update import EOR from exabgp.bgp.message.keepalive import KeepAlive from exabgp.bgp.message.notification import Notification from exabgp.bgp.message.notification import Notify from exabgp.bgp.message.operational import Operational from exabgp.reactor.api.processes import ProcessError from exabgp.logger import Logger from exabgp.logger import FakeLogger # This is the number of chuncked message we are willing to buffer, not the number of routes MAX_BACKLOG = 15000 _UPDATE = Update([], '') _OPERATIONAL = Operational(0x00) class Protocol(object): decode = True def __init__(self, peer): try: self.logger = Logger() except RuntimeError: self.logger = FakeLogger() self.peer = peer self.neighbor = peer.neighbor self.negotiated = Negotiated(self.neighbor) self.connection = None
def updates (self,grouped): if self._changes: dict_nlri = self._modify_nlri for family in self._seen: for change in self._seen[family].itervalues(): if change.index() not in self._modify_nlri: change.nlri.action = OUT.WITHDRAW self.insert_announced(change,True) for new in self._changes: self.insert_announced(new,True) self._changes = None # end of changes rr_announced = [] for afi,safi in self._enhanced_refresh_start: rr_announced.append((afi,safi)) yield RouteRefresh(afi,safi,RouteRefresh.start) dict_sorted = self._modify_sorted dict_nlri = self._modify_nlri dict_attr = self._cache_attribute for attr_index,full_dict_change in dict_sorted.items(): if self.cache: dict_change = {} for nlri_index,change in full_dict_change.iteritems(): family = change.nlri.family() announced = self._seen.get(family,{}) if change.nlri.action == OUT.ANNOUNCE: if nlri_index in announced: old_change = announced[nlri_index] # it is a duplicate route if old_change.attributes.index() == change.attributes.index(): continue elif change.nlri.action == OUT.WITHDRAW: if nlri_index not in announced: if dict_nlri[nlri_index].nlri.action == OUT.ANNOUNCE: continue dict_change[nlri_index] = change else: dict_change = full_dict_change if not dict_change: continue attributes = dict_attr[attr_index].attributes # we NEED the copy provided by list() here as insert_announced can be called while we iterate changed = list(dict_change.itervalues()) if grouped: update = Update([dict_nlri[nlri_index].nlri for nlri_index in dict_change],attributes) for change in changed: nlri_index = change.index() del dict_sorted[attr_index][nlri_index] del dict_nlri[nlri_index] # only yield once we have a consistent state, otherwise it will go wrong # as we will try to modify things we are using yield update else: updates = [] for change in changed: updates.append(Update([change.nlri,],attributes)) nlri_index = change.index() del dict_sorted[attr_index][nlri_index] del dict_nlri[nlri_index] # only yield once we have a consistent state, otherwise it will go wrong # as we will try to modify things we are using for update in updates: yield update if self.cache: announced = self._seen for change in changed: if change.nlri.action == OUT.ANNOUNCE: announced.setdefault(change.nlri.family(),{})[change.index()] = change else: family = change.nlri.family() if family in announced: announced[family].pop(change.index(),None) if rr_announced: for afi,safi in rr_announced: self._enhanced_refresh_start.remove((afi,safi)) yield RouteRefresh(afi,safi,RouteRefresh.end) for change in self._enhanced_refresh_delay: self.insert_announced(change,True) self.enhanced_refresh_delay = [] for update in self.updates(grouped): yield update
def check_neighbor (neighbors): from exabgp.logger import Logger logger = Logger() logger._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] neighbor.rib.clear() path = {} for f in 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() 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 message 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('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('----------------------------------------') except Notify,exc: logger.parser('----------------------------------------') logger.parser(str(exc)) logger.parser('----------------------------------------') return False
def updates(self, grouped): dict_sorted = self._modify_sorted dict_nlri = self._modify_nlri dict_attr = self._cache_attribute for attr_index, full_dict_change in list(dict_sorted.iteritems()): if self.cache: dict_change = {} for nlri_index, change in full_dict_change.iteritems(): family = change.nlri.family() announced = self._announced.get(family, {}) if change.nlri.action == OUT.announce: if nlri_index in announced: old_change = announced[nlri_index] # it is a duplicate route if old_change.attributes.index( ) == change.attributes.index(): continue elif change.nlri.action == OUT.withdraw: if nlri_index not in announced: continue dict_change[nlri_index] = change else: dict_change = full_dict_change if not dict_change: continue attributes = dict_attr[attr_index].attributes # we NEED the copy provided by list() here as clear_sent or insert_announced can be called while we iterate changed = list(dict_change.itervalues()) if grouped: update = Update( [dict_nlri[nlri_index].nlri for nlri_index in dict_change], attributes) for change in changed: nlri_index = change.nlri.index() del dict_change[nlri_index] del dict_nlri[nlri_index] # only yield once we have a consistent state, otherwise it will go wrong # as we will try to modify things we are using yield update else: updates = [ Update([ change.nlri, ], attributes) for change in changed ] for change in changed: nlri_index = change.nlri.index() del dict_change[nlri_index] del dict_nlri[nlri_index] # only yield once we have a consistent state, otherwise it will go wrong # as we will try to modify things we are using for update in updates: yield update if self.cache: announced = self._announced for change in changed: if change.nlri.action == OUT.announce: announced.setdefault(change.nlri.family(), {})[change.nlri.index()] = change else: family = change.nlri.family() if family in announced: announced[family].pop(change.nlri.index(), None)