def _run(self, max_wait_open=10.0): try: if self.supervisor.processes.broken(self.neighbor.peer_address): # XXX: we should perhaps try to restart the process ?? raise Failure( 'ExaBGP lost the helper process for this peer - peer down') self.bgp = Protocol(self) self.bgp.connect() self._reset_skip() _open = self.bgp.new_open(self._restarted, self._asn4) logger.message(self.me('>> %s' % _open)) yield None start = time.time() while True: self.open = self.bgp.read_open(_open, self.neighbor.peer_address.ip) if time.time() - start > max_wait_open: logger.message( self. me('Waited for an OPEN for too long - killing the session' )) raise Notify( 1, 1, 'The client took over %s seconds to send the OPEN, closing' % str(max_wait_open)) # OPEN or NOP if self.open.TYPE == NOP.TYPE: yield None continue # This test is already done in read_open #if self.open.TYPE != Open.TYPE: # raise Notify(5,1,'We are expecting an OPEN message') logger.message(self.me('<< %s' % self.open)) if not self.open.capabilities.announced( Capabilities.FOUR_BYTES_ASN) and _open.asn.asn4(): self._asn4 = False raise Notify( 2, 0, 'peer does not speak ASN4 - restarting in compatibility mode' ) if _open.capabilities.announced(Capabilities.MULTISESSION_BGP): if not self.open.capabilities.announced( Capabilities.MULTISESSION_BGP): raise Notify(2, 7, 'peer does not support MULTISESSION') local_sessionid = set( _open.capabilities[Capabilities.MULTISESSION_BGP]) remote_sessionid = self.open.capabilities[ Capabilities.MULTISESSION_BGP] # Empty capability is the same as MultiProtocol (which is what we send) if not remote_sessionid: remote_sessionid.append( Capabilities.MULTIPROTOCOL_EXTENSIONS) remote_sessionid = set(remote_sessionid) # As we only send one MP per session, if the matching fails, we have nothing in common if local_sessionid.intersection( remote_sessionid) != local_sessionid: raise Notify( 2, 8, 'peer did not reply with the sessionid we sent') # We can not collide due to the way we generate the configuration yield None break message = self.bgp.new_keepalive(force=True) logger.message(self.me('>> KEEPALIVE (OPENCONFIRM)')) yield True while True: message = self.bgp.read_keepalive() # KEEPALIVE or NOP if message.TYPE == KeepAlive.TYPE: logger.message(self.me('<< KEEPALIVE (ESTABLISHED)')) break yield None try: for name in self.supervisor.processes.notify( self.neighbor.peer_address): self.supervisor.processes.write( name, 'neighbor %s up\n' % self.neighbor.peer_address) except ProcessError: # Can not find any better error code that 6,0 ! raise Notify(6, 0, 'ExaBGP Internal error, sorry.') count = 0 for count in self.bgp.new_announce(): yield True self._updates = self.bgp.buffered() if count: logger.message(self.me('>> %d UPDATE(s)' % count)) eor = False if self.neighbor.graceful_restart and \ self.open.capabilities.announced(Capabilities.MULTIPROTOCOL_EXTENSIONS) and \ self.open.capabilities.announced(Capabilities.GRACEFUL_RESTART): families = [] for family in self.open.capabilities[ Capabilities.GRACEFUL_RESTART].families(): if family in self.neighbor.families(): families.append(family) self.bgp.new_eors(families) if families: eor = True logger.message( self.me('>> EOR %s' % ', '.join([ '%s %s' % (str(afi), str(safi)) for (afi, safi) in families ]))) if not eor: # If we are not sending an EOR, send a keepalive as soon as when finished # So the other routers knows that we have no (more) routes to send ... # (is that behaviour documented somewhere ??) c, k = self.bgp.new_keepalive(True) if k: logger.message( self.me('>> KEEPALIVE (no more UPDATE and no EOR)')) seen_update = False while self._running: self._now = time.time() if self._now > self._next_info: self._next_info = self._now + self.update_time display_update = True else: display_update = False c, k = self.bgp.new_keepalive() if k: logger.message(self.me('>> KEEPALIVE')) if display_update: logger.timers( self.me('Sending Timer %d second(s) left' % c)) message = self.bgp.read_message() # let's read if we have keepalive before doing the timer check c = self.bgp.check_keepalive() if display_update: logger.timers( self.me('Receive Timer %d second(s) left' % c)) if message.TYPE == KeepAlive.TYPE: logger.message(self.me('<< KEEPALIVE')) elif message.TYPE == Update.TYPE: seen_update = True self._received_routes.extend(message.routes) if message.routes: logger.message(self.me('<< UPDATE')) self._route_parsed += len(message.routes) if self._route_parsed: for route in message.routes: logger.routes( LazyFormat(self.me(''), str, route)) else: logger.message(self.me('<< UPDATE (not parsed)')) elif message.TYPE not in (NOP.TYPE, ): logger.message(self.me('<< %d' % ord(message.TYPE))) if seen_update and display_update: logger.supervisor( self.me('processed %d routes' % self._route_parsed)) seen_update = False if self._updates: count = 0 for count in self.bgp.new_update(): yield True logger.message(self.me('>> UPDATE (%d)' % count)) self._updates = self.bgp.buffered() yield None if self.neighbor.graceful_restart and self.open.capabilities.announced( Capabilities.GRACEFUL_RESTART): logger.warning('Closing the connection without notification') self.bgp.close() return # User closing the connection raise Notify(6, 3) except NotConnected, e: logger.warning('we can not connect to the peer %s' % str(e)) self._more_skip() try: self.bgp.close() except Failure: pass return