def new_keepalive (self,comment=''): keepalive = KeepAlive() for _ in self.write(keepalive.message()): yield _NOP self.logger.message(self.me('>> KEEPALIVE%s' % (' (%s)' % comment if comment else ''))) yield keepalive
def test_2_selfparse_KeepAlive (self): ds = KeepAlive() txt = ds.message() network = Network(txt) bgp = Protocol(self.neighbor,network) message = bgp.read_message() self.assertEqual(message.TYPE,KeepAlive.TYPE)
def test_5_selfparse_update_announce_multi (self): o = Open(4,65000,'1.2.3.4',Capabilities().default(),30).message() k = KeepAlive().message() d = Delta(self.table) a = d.announce(65000,65000) self.table.update(routes[:-1]) u = d.update(65000,65000) network = Network(o+k+''.join(u)) bgp = Protocol(self.neighbor,network) bgp.follow = False self.assertEqual(bgp.read_message().TYPE,Open.TYPE) self.assertEqual(bgp.read_message().TYPE,KeepAlive.TYPE) updates = bgp.read_message() self.assertEqual(updates.TYPE,Update.TYPE) self.assertEqual(str(updates.added()[0]),'10.0.2.1/32')
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 port = os.environ.get('exabgp.tcp.port','') self.port = int(port) if port.isdigit() else 179 # XXX: FIXME: check the the -19 is correct (but it is harmless) # The message size is the whole BGP message _without_ headers self.message_size = Message.MAX_LEN-Message.HEADER_LEN # XXX: we use self.peer.neighbor.peer_address when we could use self.neighbor.peer_address def __del__ (self): self.close('automatic protocol cleanup') def me (self,message): return "Peer %15s ASN %-7s %s" % (self.peer.neighbor.peer_address,self.peer.neighbor.peer_as,message) def accept (self,incoming): self.connection = incoming if self.peer.neighbor.api.neighbor_changes: self.peer.reactor.processes.connected(self.peer.neighbor.peer_address) # very important - as we use this function on __init__ return self def connect (self): # allows to test the protocol code using modified StringIO with a extra 'pending' function if not self.connection: peer = self.neighbor.peer_address local = self.neighbor.local_address md5 = self.neighbor.md5 ttl = self.neighbor.ttl self.connection = Outgoing(peer.afi,peer.ip,local.ip,self.port,md5,ttl) connected = False try: generator = self.connection.establish() while True: connected = generator.next() if not connected: yield False continue if self.peer.neighbor.api.neighbor_changes: self.peer.reactor.processes.connected(self.peer.neighbor.peer_address) yield True return except StopIteration: # close called by the caller # self.close('could not connect to remote end') yield False return def close (self,reason='protocol closed, reason unspecified'): if self.connection: self.logger.network(self.me(reason)) # must be first otherwise we could have a loop caused by the raise in the below self.connection.close() self.connection = None try: if self.peer.neighbor.api.neighbor_changes: self.peer.reactor.processes.down(self.peer.neighbor.peer_address,reason) except ProcessError: self.logger.message(self.me('could not send notification of neighbor close to API')) def write (self,message): if self.neighbor.api.send_packets: self.peer.reactor.processes.send(self.peer.neighbor.peer_address,message[18],message[:19],message[19:]) for boolean in self.connection.writer(message): yield boolean # Read from network ....................................................... def read_message (self,comment=''): try: for length,msg,header,body in self.connection.reader(): if not length: yield _NOP except NotifyError,n: raise Notify(n.code,n.subcode,str(n)) if self.neighbor.api.receive_packets: self.peer.reactor.processes.receive(self.peer.neighbor.peer_address,msg,header,body) if msg == Message.Type.UPDATE: self.logger.message(self.me('<< UPDATE')) if length == 30 and body.startswith(EOR.PREFIX): update = EORFactory(body) if self.neighbor.api.receive_routes: self.peer.reactor.processes.update(self.peer.neighbor.peer_address,update) elif self.neighbor.api.receive_routes: update = UpdateFactory(self.negotiated,body) if self.neighbor.api.receive_routes: self.peer.reactor.processes.update(self.peer.neighbor.peer_address,update) else: update = _UPDATE yield update elif msg == Message.Type.KEEPALIVE: self.logger.message(self.me('<< KEEPALIVE%s' % (' (%s)' % comment if comment else ''))) yield KeepAlive() elif msg == Message.Type.NOTIFICATION: self.logger.message(self.me('<< NOTIFICATION')) yield NotificationFactory(body) elif msg == Message.Type.ROUTE_REFRESH: if self.negotiated.refresh != REFRESH.absent: self.logger.message(self.me('<< ROUTE-REFRESH')) refresh = RouteRefreshFactory(body) if self.neighbor.api.receive_routes: if refresh.reserved in (RouteRefresh.start,RouteRefresh.end): self.peer.reactor.processes.refresh(self.peer.neighbor.peer_address,refresh) else: # XXX: FIXME: really should raise, we are too nice self.logger.message(self.me('<< NOP (un-negotiated type %d)' % msg)) refresh = UnknownMessageFactory(body) yield refresh elif msg == Message.Type.OPERATIONAL: if self.peer.neighbor.operational: operational = OperationalFactory(body) what = OperationalGroup[operational.what][0] self.peer.reactor.processes.operational(self.peer.neighbor.peer_address,what,operational) else: operational = _OPERATIONAL yield operational elif msg == Message.Type.OPEN: yield OpenFactory(body) else: # XXX: FIXME: really should raise, we are too nice self.logger.message(self.me('<< NOP (unknow type %d)' % msg)) yield UnknownMessageFactory(msg)