def _new_best_path(self, new_best_path): old_best_path = self._best_path self._best_path = new_best_path LOG.debug('New best path selected for destination %s' % (self)) # If old best path was withdrawn if (old_best_path and old_best_path not in self._known_path_list and self._sent_routes): # Have to clear sent_route list for this destination as # best path is removed. self._sent_routes = {} # Communicate that we have new best path to all qualifying # bgp-peers. pm = self._core_service.peer_manager pm.comm_new_best_to_bgp_peers(new_best_path) # withdraw old best path if old_best_path and self._sent_routes: for sent_route in self._sent_routes.values(): sent_path = sent_route.path withdraw_clone = sent_path.clone(for_withdrawal=True) outgoing_route = OutgoingRoute(withdraw_clone) sent_route.sent_peer.enque_outgoing_msg(outgoing_route) LOG.debug('Sending withdrawal to %s for %s' % (sent_route.sent_peer, outgoing_route)) self._sent_routes = {}
def _best_path_lost(self): self._best_path = None if self._sent_routes: # We have to send update-withdraw to all peers to whom old best # path was sent. for sent_route in self._sent_routes.values(): sent_path = sent_route.path withdraw_clone = sent_path.clone(for_withdrawal=True) outgoing_route = OutgoingRoute(withdraw_clone) sent_route.sent_peer.enque_outgoing_msg(outgoing_route) LOG.debug('Sending withdrawal to %s for %s' % (sent_route.sent_peer, outgoing_route)) # Have to clear sent_route list for this destination as # best path is removed. self._sent_routes = {}
def resend_sent(self, route_family, peer): """For given `peer` re-send sent paths. Parameters: - `route-family`: (RouteFamily) of the sent paths to re-send - `peer`: (Peer) peer for which we need to re-send sent paths """ if peer not in self._peers.values(): raise ValueError('Could not find given peer (%s)' % peer) if route_family not in SUPPORTED_GLOBAL_RF: raise ValueError( 'Given route family (%s) is not supported.' % route_family ) # Iterate over the global table for given afi, safi and enqueue # out-going routes. table = self._table_manager.get_global_table_by_route_family( route_family ) for destination in table.itervalues(): # Check if this destination's sent - routes include this peer. # i.e. check if this destinations was advertised and enqueue # the path only if it was. If the current best-path has not been # advertised before, it might already have a OutgoingRoute queued # to be sent to the peer. sent_routes = destination.sent_routes if sent_routes is None or len(sent_routes) == 0: continue for sent_route in sent_routes: if sent_route.sent_peer == peer: # update med - if previously med was set per neighbor or # wasn't set at all now it could have changed and we may # need to set new value there p = sent_route.path if p.med_set_by_target_neighbor or p.get_pattr( BGP_ATTR_TYPE_MULTI_EXIT_DISC) is None: sent_route.path = \ clone_path_and_update_med_for_target_neighbor( sent_route.path, peer.med ) ogr = OutgoingRoute(sent_route.path, for_route_refresh=True) peer.enque_outgoing_msg(ogr)
def withdraw_if_sent_to(self, peer): """Sends a withdraw for this destination to given `peer`. Check the records if we indeed advertise this destination to given peer and if so, creates a withdraw for advertised route and sends it to the peer. Parameter: - `peer`: (Peer) peer to send withdraw to """ from ryu.services.protocols.bgp.peer import Peer if not isinstance(peer, Peer): raise TypeError('Currently we only support sending withdrawal' ' to instance of peer') sent_route = self._sent_routes.pop(peer, None) if not sent_route: return False sent_path = sent_route.path withdraw_clone = sent_path.clone(for_withdrawal=True) outgoing_route = OutgoingRoute(withdraw_clone) sent_route.sent_peer.enque_outgoing_msg(outgoing_route) return True