def _accept (self): self._incoming.fsm.change(FSM.CONNECT) # we can do this as Protocol is a mutable object proto = self._incoming.proto # send OPEN message = Message.CODE.NOP for message in proto.new_open(self._restarted): if ord(message.TYPE) == Message.CODE.NOP: yield ACTION.NOW proto.negotiated.sent(message) self._incoming.fsm.change(FSM.OPENSENT) # Read OPEN wait = environment.settings().bgp.openwait opentimer = ReceiveTimer(self.me,wait,1,1,'waited for open too long, we do not like stuck in active') # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check without going to the other peer for message in proto.read_open(self.neighbor.peer_address.top()): opentimer.check_ka(message) if ord(message.TYPE) == Message.CODE.NOP: yield ACTION.LATER self._incoming.fsm.change(FSM.OPENCONFIRM) proto.negotiated.received(message) proto.validate_open() if self._outgoing.fsm == FSM.OPENCONFIRM: self.logger.network('incoming connection finds the outgoing connection is in openconfirm') local_id = self.neighbor.router_id.pack() remote_id = proto.negotiated.received_open.router_id.pack() if local_id < remote_id: self.logger.network('closing the outgoing connection') self._stop(self._outgoing,'collision local id < remote id') yield ACTION.LATER else: self.logger.network('aborting the incoming connection') raise Interrupted(self._incoming) # Send KEEPALIVE for message in self._incoming.proto.new_keepalive('OPENCONFIRM'): yield ACTION.NOW # Start keeping keepalive timer self.recv_timer = ReceiveTimer(self.me,proto.negotiated.holdtime,4,0) # Read KEEPALIVE for message in proto.read_keepalive(): self.recv_timer.check_ka(message) yield ACTION.NOW self._incoming.fsm.change(FSM.ESTABLISHED) # let the caller know that we were sucesfull yield ACTION.NOW
def _accept (self): # we can do this as Protocol is a mutable object proto = self._['in']['proto'] # send OPEN for message in proto.new_open(self._restarted): if ord(message.TYPE) == Message.ID.NOP: yield ACTION.immediate proto.negotiated.sent(message) self._['in']['state'] = STATE.opensent # Read OPEN wait = environment.settings().bgp.openwait opentimer = ReceiveTimer(self.me,wait,1,1,'waited for open too long, we do not like stuck in active') # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check without going to the other peer for message in proto.read_open(self.neighbor.peer_address.ip): opentimer.check_ka(message) if ord(message.TYPE) == Message.ID.NOP: yield ACTION.later self._['in']['state'] = STATE.openconfirm proto.negotiated.received(message) proto.validate_open() if self._['out']['state'] == STATE.openconfirm: self.logger.network('incoming connection finds the outgoing connection is in openconfirm') local_id = self.neighbor.router_id.packed remote_id = proto.negotiated.received_open.router_id.packed if local_id < remote_id: self.logger.network('closing the outgoing connection') self._stop('out','collision local id < remote id') yield ACTION.later else: self.logger.network('aborting the incoming connection') stop = Interrupted() stop.direction = 'in' raise stop # Send KEEPALIVE for message in self._['in']['proto'].new_keepalive('OPENCONFIRM'): yield ACTION.immediate # Start keeping keepalive timer self.recv_timer = ReceiveTimer(self.me,proto.negotiated.holdtime,4,0) # Read KEEPALIVE for message in proto.read_keepalive(): self.recv_timer.check_ka(message) yield ACTION.immediate self._['in']['state'] = STATE.established # let the caller know that we were sucesfull yield ACTION.immediate
def _establish(self): # try to establish the outgoing connection self.fsm.change(FSM.ACTIVE) if getenv().bgp.passive: while not self.proto: yield ACTION.LATER self.fsm.change(FSM.IDLE) if not self.proto: for action in self._connect(): if action in ACTION.ALL: yield action self.fsm.change(FSM.CONNECT) # normal sending of OPEN first ... if self.neighbor['local-as']: for sent_open in self._send_open(): if sent_open in ACTION.ALL: yield sent_open self.proto.negotiated.sent(sent_open) self.fsm.change(FSM.OPENSENT) # read the peer's open for received_open in self._read_open(): if received_open in ACTION.ALL: yield received_open self.proto.negotiated.received(received_open) self.proto.connection.msg_size = self.proto.negotiated.msg_size # if we mirror the ASN, we need to read first and send second if not self.neighbor['local-as']: for sent_open in self._send_open(): if sent_open in ACTION.ALL: yield sent_open self.proto.negotiated.sent(sent_open) self.fsm.change(FSM.OPENSENT) self.proto.validate_open() self.fsm.change(FSM.OPENCONFIRM) self.recv_timer = ReceiveTimer(self.proto.connection.session, self.proto.negotiated.holdtime, 4, 0) for action in self._send_ka(): yield action for action in self._read_ka(): yield action self.fsm.change(FSM.ESTABLISHED) self.stats['complete'] = time.time() # let the caller know that we were sucesfull yield ACTION.NOW
def _read_open (self): wait = environment.settings().bgp.openwait opentimer = ReceiveTimer(self.proto.connection.session,wait,1,1,'waited for open too long, we do not like stuck in active') # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check without going to the other peer for message in self.proto.read_open(self.neighbor.peer_address.top()): opentimer.check_ka(message) # XXX: FIXME: change the whole code to use the ord and not the chr version # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check if ordinal(message.TYPE) == Message.CODE.NOP: yield ACTION.NOW yield message
def _read_open (self): wait = environment.settings().bgp.openwait opentimer = ReceiveTimer(self.proto.connection.session,wait,1,1,'waited for open too long, we do not like stuck in active') # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check without going to the other peer for message in self.proto.read_open(self.neighbor.peer_address.top()): opentimer.check_ka(message) # XXX: FIXME: change the whole code to use the ord and not the chr version # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check if ordinal(message.TYPE) == Message.CODE.NOP: # If a peer does not reply to OPEN message, or not enough bytes # yielding ACTION.NOW can cause ExaBGP to busy spin trying to # read from peer. See GH #723 . yield ACTION.LATER yield message
def _connect (self): # try to establish the outgoing connection proto = Protocol(self) generator = proto.connect() connected = False try: while not connected: if self._teardown: raise StopIteration() connected = generator.next() # we want to come back as soon as possible yield ACTION.LATER except StopIteration: # Connection failed if not connected: proto.close('connection to peer failed',self._['in']['state'] != STATE.ESTABLISHED) # A connection arrived before we could establish ! if not connected or self._['in']['proto']: stop = Interrupted() stop.direction = 'out' yield ACTION.NOW raise stop self._['out']['state'] = STATE.CONNECT self._['out']['proto'] = proto # send OPEN # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to set the state without going to the other peer message = Message.CODE.NOP for message in proto.new_open(self._restarted): if ord(message.TYPE) == Message.CODE.NOP: yield ACTION.NOW proto.negotiated.sent(message) self._['out']['state'] = STATE.OPENSENT # Read OPEN wait = environment.settings().bgp.openwait opentimer = ReceiveTimer(self.me,wait,1,1,'waited for open too long, we do not like stuck in active') for message in self._['out']['proto'].read_open(self.neighbor.peer_address.ip): opentimer.check_ka(message) # XXX: FIXME: change the whole code to use the ord and not the chr version # Only yield if we have not the open, otherwise the reactor can run the other connection # which would be bad as we need to do the collission check if ord(message.TYPE) == Message.CODE.NOP: yield ACTION.LATER self._['out']['state'] = STATE.OPENCONFIRM proto.negotiated.received(message) proto.validate_open() if self._['in']['state'] == STATE.OPENCONFIRM: self.logger.network('outgoing connection finds the incoming connection is in openconfirm') local_id = self.neighbor.router_id.packed remote_id = proto.negotiated.received_open.router_id.packed if local_id < remote_id: self.logger.network('aborting the outgoing connection') stop = Interrupted() stop.direction = 'out' raise stop else: self.logger.network('closing the incoming connection') self._stop('in','collision local id < remote id') yield ACTION.LATER # Send KEEPALIVE for message in proto.new_keepalive('OPENCONFIRM'): yield ACTION.NOW # Start keeping keepalive timer self.recv_timer = ReceiveTimer(self.me,proto.negotiated.holdtime,4,0) # Read KEEPALIVE for message in self._['out']['proto'].read_keepalive(): self.recv_timer.check_ka(message) yield ACTION.NOW self._['out']['state'] = STATE.ESTABLISHED # let the caller know that we were sucesfull yield ACTION.NOW