use of org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path in project bgpcep by opendaylight.
the class PCEPTopologySessionListener method buildPath.
private static Path buildPath(final Reports report, final Srp srp, final Lsp lsp) {
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder pb = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.PathBuilder();
if (report.getPath() != null) {
pb.fieldsFrom(report.getPath());
}
// LSP is mandatory (if there is none, parser will throw an exception)
// this is to ensure a path will be created at any rate
final Path1Builder p1Builder = new Path1Builder();
p1Builder.setLsp(report.getLsp());
final PathSetupType pst;
if (srp != null && srp.getTlvs() != null && srp.getTlvs().getPathSetupType() != null) {
pst = srp.getTlvs().getPathSetupType();
p1Builder.setPathSetupType(pst);
} else {
pst = null;
}
pb.addAugmentation(p1Builder.build());
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.ietf.stateful.rev200720.lsp.object.lsp.Tlvs tlvs = report.getLsp().getTlvs();
if (tlvs != null) {
if (tlvs.getLspIdentifiers() != null) {
pb.setLspId(tlvs.getLspIdentifiers().getLspId());
} else if (!PSTUtil.isDefaultPST(pst)) {
pb.setLspId(new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.LspId(lsp.getPlspId().getValue()));
}
}
return pb.build();
}
use of org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path in project bgpcep by opendaylight.
the class AbstractTopologySessionListener method updateLsp.
/**
* Update an LSP in the data store.
*
* @param ctx Message context
* @param id Revision-specific LSP identifier
* @param lspName LSP name
* @param rlb Reported LSP builder
* @param solicited True if the update was solicited
* @param remove True if this is an LSP path removal
*/
protected final synchronized void updateLsp(final MessageContext ctx, final L id, final String lspName, final ReportedLspBuilder rlb, final boolean solicited, final boolean remove) {
final String name;
if (lspName == null) {
name = this.lsps.get(id);
if (name == null) {
LOG.error("PLSPID {} seen for the first time, not reporting the LSP", id);
return;
}
} else {
name = lspName;
}
LOG.debug("Saved LSP {} with name {}", id, name);
this.lsps.put(id, name);
final ReportedLsp previous = this.lspData.get(name);
// if no previous report about the lsp exist, just proceed
if (previous != null) {
final Map<PathKey, Path> updatedPaths = makeBeforeBreak(rlb, previous, name, remove);
// if all paths or the last path were deleted, delete whole tunnel
if (updatedPaths.isEmpty()) {
LOG.debug("All paths were removed, removing LSP with {}.", id);
removeLsp(ctx, id);
return;
}
rlb.setPath(updatedPaths);
}
rlb.withKey(new ReportedLspKey(name));
rlb.setName(name);
// If this is an unsolicited update. We need to make sure we retain the metadata already present
if (solicited) {
this.nodeState.setLspMetadata(name, rlb.getMetadata());
} else {
rlb.setMetadata(this.nodeState.getLspMetadata(name));
}
final ReportedLsp rl = rlb.build();
ctx.trans.put(LogicalDatastoreType.OPERATIONAL, this.pccIdentifier.child(ReportedLsp.class, rlb.key()), rl);
LOG.debug("LSP {} updated to MD-SAL", name);
this.lspData.put(name, rl);
}
use of org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path in project bgpcep by opendaylight.
the class AbstractTopologySessionListener method makeBeforeBreak.
private static Map<PathKey, Path> makeBeforeBreak(final ReportedLspBuilder rlb, final ReportedLsp previous, final String name, final boolean remove) {
// just one path should be reported
final Path path = Iterables.getOnlyElement(rlb.getPath().values());
final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.rsvp.rev150820.LspId reportedLspId = path.getLspId();
final List<Path> updatedPaths;
// remove existing tunnel's paths now, as explicit path remove will not come
if (!remove && reportedLspId.getValue().toJava() == 0) {
updatedPaths = new ArrayList<>();
LOG.debug("Remove previous paths {} to this lsp name {}", previous.getPath(), name);
} else {
// check previous report for existing paths
final Collection<Path> prev = previous.nonnullPath().values();
updatedPaths = new ArrayList<>(prev);
LOG.debug("Found previous paths {} to this lsp name {}", updatedPaths, name);
for (final Path prevPath : prev) {
// we found reported path in previous reports
if (prevPath.getLspId().getValue().toJava() == 0 || prevPath.getLspId().equals(reportedLspId)) {
LOG.debug("Match on lsp-id {}", prevPath.getLspId().getValue());
// path that was reported previously and does have the same lsp-id, path will be updated
final boolean r = updatedPaths.remove(prevPath);
LOG.trace("Request removed? {}", r);
}
}
}
// if the path does not exist in previous report, add it to path list, it's a new ERO
// only one path will be added
// lspId is 0 means confirmation message that shouldn't be added (because we have no means of deleting it later)
LOG.trace("Adding new path {} to {}", path, updatedPaths);
updatedPaths.add(path);
if (remove) {
if (reportedLspId.getValue().toJava() == 0) {
// if lsp-id also 0, remove all paths
LOG.debug("Removing all paths.");
updatedPaths.clear();
} else {
// path is marked to be removed
LOG.debug("Removing path {} from {}", path, updatedPaths);
final boolean r = updatedPaths.remove(path);
LOG.trace("Request removed? {}", r);
}
}
LOG.debug("Setting new paths {} to lsp {}", updatedPaths, name);
return Maps.uniqueIndex(updatedPaths, Path::key);
}
use of org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path in project bgpcep by opendaylight.
the class BGPPeer method onSessionUp.
@Override
public synchronized void onSessionUp(final BGPSession session) {
this.currentSession = session;
this.sessionUp = true;
this.ribOutChain = this.rib.createPeerDOMChain(new DOMTransactionChainListener() {
@Override
public void onTransactionChainSuccessful(final DOMTransactionChain chain) {
LOG.debug("RibOut transaction chain {} successful.", chain);
}
@Override
public void onTransactionChainFailed(final DOMTransactionChain chain, final DOMDataTreeTransaction transaction, final Throwable cause) {
onRibOutChainFailed(cause);
}
});
if (this.currentSession instanceof BGPSessionStateProvider) {
((BGPSessionStateProvider) this.currentSession).registerMessagesCounter(this);
}
final GracefulRestartCapability advertisedGracefulRestartCapability = session.getAdvertisedGracefulRestartCapability();
final var advertisedTables = advertisedGracefulRestartCapability.getTables();
final var advertisedLLTables = session.getAdvertisedLlGracefulRestartCapability().getTables();
final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
final Set<BgpTableType> advertizedTableTypes = session.getAdvertisedTableTypes();
LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", getName(), advertizedTableTypes, addPathTablesType);
final Set<TablesKey> setTables = advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toSet());
this.tables = ImmutableSet.copyOf(setTables);
this.addPathTableMaps = mapTableTypesFamilies(addPathTablesType);
final boolean restartingLocally = isLocalRestarting();
if (!restartingLocally) {
addBgp4Support();
}
if (!isRestartingGracefully()) {
this.peerId = RouterIds.createPeerId(session.getBgpId());
final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer, PeerKey> peerIId = getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId));
this.peerPath = createPeerPath(this.peerId);
this.peerRibOutIId = peerPath.node(ADJRIBOUT_NID);
this.trackerRegistration = this.rib.getPeerTracker().registerPeer(this);
createEffRibInWriter();
registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
this.effRibInWriter.init();
this.ribWriter = this.ribWriter.transform(this.peerId, this.peerPath, this.rib.getRibSupportContext(), this.tables, this.addPathTableMaps);
if (this.rpcRegistry != null) {
this.rpcRegistration = this.rpcRegistry.registerRpcImplementation(BgpPeerRpcService.class, new BgpPeerRpc(this, session, this.tables), ImmutableSet.of(this.rib.getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer.class, new PeerKey(this.peerId))));
}
} else {
final Set<TablesKey> forwardingTables;
if (advertisedTables == null) {
forwardingTables = Collections.emptySet();
} else {
forwardingTables = advertisedTables.values().stream().filter(table -> table.getAfiFlags() != null).filter(table -> table.getAfiFlags().getForwardingState()).map(table -> new TablesKey(table.getAfi(), table.getSafi())).collect(Collectors.toSet());
}
this.ribWriter.clearTables(Sets.difference(this.tables, forwardingTables));
if (restartingLocally) {
this.effRibInWriter.close();
this.peerRestartStopwatch = Stopwatch.createStarted();
handleSelectionReferralTimer();
this.missingEOT.addAll(this.tables);
}
}
if (advertisedTables == null || advertisedTables.isEmpty()) {
setAdvertizedGracefulRestartTableTypes(Collections.emptyList());
} else {
setAdvertizedGracefulRestartTableTypes(advertisedTables.values().stream().map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
}
setAfiSafiGracefulRestartState(advertisedGracefulRestartCapability.getRestartTime().toJava(), false, restartingLocally);
final Map<TablesKey, Integer> llTablesReceived;
if (advertisedLLTables != null) {
llTablesReceived = new HashMap<>();
for (var table : advertisedLLTables.values()) {
llTablesReceived.put(new TablesKey(table.getAfi(), table.getSafi()), table.getLongLivedStaleTime().getValue().intValue());
}
} else {
llTablesReceived = Collections.emptyMap();
}
setAdvertizedLlGracefulRestartTableTypes(llTablesReceived);
if (!llTablesReceived.isEmpty()) {
llgrSupport = true;
// FIXME: propagate preserved tables
} else {
// FIXME: clear preserved tables
llgrSupport = false;
}
if (!restartingLocally) {
if (!setTables.contains(IPV4_UCAST_TABLE_KEY)) {
createAdjRibOutListener(IPV4_UCAST_TABLE_KEY, false);
}
for (final TablesKey key : getAfiSafisAdvertized()) {
createAdjRibOutListener(key, true);
}
}
// SpotBugs does not grok Optional.ifPresent() and thinks we are using unsynchronized access
final Optional<RevisedErrorHandlingSupport> errorHandling = this.bgpPeer.getErrorHandling();
if (errorHandling.isPresent()) {
this.currentSession.addDecoderConstraint(RevisedErrorHandlingSupport.class, errorHandling.get());
}
}
use of org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.topology.pcep.rev200120.pcep.client.attributes.path.computation.client.reported.lsp.Path in project bgpcep by opendaylight.
the class AbstractBestPathSelector method isExistingPathBetter.
/**
* Chooses best route according to BGP best path selection.
*
* @param state attributes of the new route
* @return true if the existing path is better, false if the new path is better
*/
protected boolean isExistingPathBetter(@NonNull final BestPathState state) {
// 0. draft-uttaro-idr-bgp-persistence-04 defines "depreferenced" paths
final boolean stateDepref = state.isDepreferenced();
if (this.bestState.isDepreferenced() != stateDepref) {
return stateDepref;
}
// 1. prefer path with accessible nexthop
// - we assume that all nexthops are accessible
/*
* 2. prefer path with higher LOCAL_PREF
*
* FIXME: for eBGP cases (when the LOCAL_PREF is missing), we should assign a policy-based preference
* before we ever get here.
*/
final Uint32 bestLocal = this.bestState.getLocalPref();
final Uint32 stateLocal = state.getLocalPref();
if (stateLocal != null) {
if (bestLocal == null) {
return true;
}
final int cmp = stateLocal.compareTo(bestLocal);
if (cmp != 0) {
return cmp < 0;
}
} else if (bestLocal != null) {
return false;
}
// 4. prefer the path with the shortest AS_PATH.
if (this.bestState.getAsPathLength() != state.getAsPathLength()) {
return this.bestState.getAsPathLength() < state.getAsPathLength();
}
// - IGP is lower than Exterior Gateway Protocol (EGP), and EGP is lower than INCOMPLETE
if (!this.bestState.getOrigin().equals(state.getOrigin())) {
final BgpOrigin bo = this.bestState.getOrigin();
final BgpOrigin no = state.getOrigin();
// This trick relies on the order in which the values are declared in the model.
return no.ordinal() > bo.ordinal();
}
// FIXME: we should be able to cache the best AS
final long bestAs = this.bestState.getPeerAs();
final long newAs = state.getPeerAs();
/*
* Checks 6 and 7 are mutually-exclusive, as MEDs are comparable
* only when the routes originated from the same AS. On the other
* hand, when they are from the same AS, they are in the same iBGP/eBGP
* relationship.
*
*/
if (bestAs == newAs) {
// 6. prefer the path with the lowest multi-exit discriminator (MED)
final Boolean cmp = firstLower(this.bestState.getMultiExitDisc(), state.getMultiExitDisc());
if (cmp != null) {
return cmp;
}
} else {
/*
* 7. prefer eBGP over iBGP paths
*
* EBGP is peering between two different AS, whereas IBGP is between same AS (Autonomous System),
* so we just compare the AS numbers to our AS.
*
* FIXME: we should know this information from the peer directly.
*/
if (this.ourAs != bestAs && this.ourAs == newAs) {
return true;
}
}
/*
* 10. Prefer the route that comes from the BGP router with the lowest router ID.
*
* This is normally guaranteed by the iteration order of our caller, which runs selection
* in the order of increasing router ID, but RFC-4456 Route Reflection throws a wrench into that.
*
* With RFC-5004, this gets a bit easier, because it completely eliminates step f) and later :-)
*
* RFC-5004 states that this algorithm should end here and select existing path over new path in the
* best path selection process. Benefits are listed in the RFC: @see http://tools.ietf.org/html/rfc500
* - This algorithm SHOULD NOT be applied when either path is from a BGP Confederation peer.
* - not applicable, we don't deal with confederation peers
* - The algorithm SHOULD NOT be applied when both paths are from peers with an identical BGP identifier
* (i.e., there exist parallel BGP sessions between two BGP speakers).
* - not applicable, BUG-2631 prevents parallel sessions to be created.
*/
return true;
}
Aggregations