import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.FluentFuture;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
+import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
import org.opendaylight.protocol.bgp.route.targetcontrain.spi.ClientRouteTargetContrainCache;
import org.opendaylight.protocol.bgp.route.targetcontrain.spi.RouteTargetMembeshipUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.Attributes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.Communities;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerRole;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.Route;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.Peer;
MplsLabeledVpnSubsequentAddressFamily.class);
private static final TablesKey IVP6_VPN_TABLE_KEY = new TablesKey(Ipv6AddressFamily.class,
MplsLabeledVpnSubsequentAddressFamily.class);
+ private static final ImmutableList<Communities> STALE_LLGR_COMMUNUTIES = ImmutableList.of(
+ StaleCommunities.STALE_LLGR);
+ private static final Attributes STALE_LLGR_ATTRIBUTES = new org.opendaylight.yang.gen.v1.urn.opendaylight.params
+ .xml.ns.yang.bgp.message.rev180329.path.attributes.AttributesBuilder()
+ .setCommunities(STALE_LLGR_COMMUNUTIES)
+ .build();
+
private final RIBSupportContextRegistry registry;
private final KeyedInstanceIdentifier<Peer, PeerKey> peerIId;
private final InstanceIdentifier<EffectiveRibIn> effRibTables;
switch (routeChanged.getModificationType()) {
case SUBTREE_MODIFIED:
case WRITE:
- writeRoutes(tx, tableKey, ribSupport, tablePath, routeKey, routeChanged.getDataAfter());
+ writeRoutes(tx, tableKey, ribSupport, tablePath, routeKey, routeChanged.getDataAfter(), false);
break;
case DELETE:
final InstanceIdentifier<R> routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey);
}
private <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
- R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>> void writeRoutes(
- final WriteTransaction tx, final TablesKey tk, final RIBSupport<C, S, R, I> ribSupport,
+ R extends Route & ChildOf<? super S> & Identifiable<I>, I extends Identifier<R>> void writeRoutes(
+ final WriteTransaction tx, final TablesKey tk, final RIBSupport<C, S, R, I> ribSupport,
final KeyedInstanceIdentifier<Tables, TablesKey> tablePath, final I routeKey,
- final R route) {
+ final R route, final boolean longLivedStale) {
final InstanceIdentifier<R> routeIID = ribSupport.createRouteIdentifier(tablePath, routeKey);
CountersUtil.increment(this.prefixesReceived.get(tk), tk);
- final Optional<Attributes> effAtt = this.ribPolicies
- .applyImportPolicies(this.peerImportParameters, route.getAttributes(),
- tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get());
- if (effAtt.isPresent()) {
- final Optional<RouteTarget> rtMembership = RouteTargetMembeshipUtil.getRT(route);
- if (rtMembership.isPresent()) {
- final RouteTarget rt = rtMembership.get();
- if(PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) {
- this.rtCache.cacheRoute(route);
- }
- this.rtMemberships.add(rt);
- this.rtMembershipsUpdated = true;
+
+ final Attributes routeAttrs = route.getAttributes();
+ final Optional<Attributes> optEffAtt;
+ // In case we want to add LLGR_STALE we do not process route through policies since it may be
+ // considered as received with LLGR_STALE from peer which is not true.
+ if (longLivedStale) {
+ // LLGR procedures are in effect. If the route is tagged with NO_LLGR, it needs to be removed.
+ final List<Communities> effCommunities = routeAttrs.getCommunities();
+ if (effCommunities != null && effCommunities.contains(CommunityUtil.NO_LLGR)) {
+ deleteRoutes(routeIID, route, tx);
+ return;
}
- CountersUtil.increment(this.prefixesInstalled.get(tk), tk);
- tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route);
- tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), effAtt.get());
+ optEffAtt = Optional.of(wrapLongLivedStale(routeAttrs));
} else {
+ optEffAtt = this.ribPolicies.applyImportPolicies(this.peerImportParameters, routeAttrs,
+ tableTypeRegistry.getAfiSafiType(ribSupport.getTablesKey()).get());
+ }
+ if (!optEffAtt.isPresent()) {
deleteRoutes(routeIID, route, tx);
+ return;
+ }
+ final Optional<RouteTarget> rtMembership = RouteTargetMembeshipUtil.getRT(route);
+ if (rtMembership.isPresent()) {
+ final RouteTarget rt = rtMembership.get();
+ if (PeerRole.Ebgp != this.peerImportParameters.getFromPeerRole()) {
+ this.rtCache.cacheRoute(route);
+ }
+ this.rtMemberships.add(rt);
+ this.rtMembershipsUpdated = true;
}
+ CountersUtil.increment(this.prefixesInstalled.get(tk), tk);
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeIID, route);
+ tx.put(LogicalDatastoreType.OPERATIONAL, routeIID.child(Attributes.class), optEffAtt.get());
+ }
+
+ private static Attributes wrapLongLivedStale(final Attributes attrs) {
+ if (attrs == null) {
+ return STALE_LLGR_ATTRIBUTES;
+ }
+
+ final List<Communities> oldCommunities = attrs.getCommunities();
+ final List<Communities> newCommunities;
+ if (oldCommunities != null) {
+ if (oldCommunities.contains(StaleCommunities.STALE_LLGR)) {
+ return attrs;
+ }
+ newCommunities = StaleCommunities.create(oldCommunities);
+ } else {
+ newCommunities = STALE_LLGR_COMMUNUTIES;
+ }
+
+ return new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329
+ .path.attributes.AttributesBuilder(attrs).setCommunities(newCommunities).build();
}
private <R extends Route> void deleteRoutes(final InstanceIdentifier<R> routeIID,
LOG.trace("Create Empty table at {}", tablePath);
if (table.getDataBefore() == null) {
tx.put(LogicalDatastoreType.OPERATIONAL, tablePath, new TablesBuilder()
- .setAfi(tableKey.getAfi()).setSafi(tableKey.getSafi())
+ .withKey(tableKey).setAfi(tableKey.getAfi()).setSafi(tableKey.getSafi())
.setAttributes(newTable.getAttributes()).build());
}
--- /dev/null
+/*
+ * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.bgp.rib.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.AbstractList;
+import java.util.List;
+import org.opendaylight.protocol.bgp.parser.impl.message.update.CommunityUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev180329.path.attributes.attributes.Communities;
+
+/**
+ * Utility class which prepends {@code LLGR_STALE} community in front of some other communities.
+ */
+class StaleCommunities extends AbstractList<Communities> {
+ private static final class RandomAccess extends StaleCommunities implements java.util.RandomAccess {
+ RandomAccess(final List<Communities> orig) {
+ super(orig);
+ }
+ }
+
+ static final Communities STALE_LLGR = (Communities) CommunityUtil.LLGR_STALE;
+
+ private final List<Communities> orig;
+
+ StaleCommunities(final List<Communities> orig) {
+ this.orig = requireNonNull(orig);
+ }
+
+ static StaleCommunities create(final List<Communities> orig) {
+ return orig instanceof java.util.RandomAccess ? new RandomAccess(orig) : new StaleCommunities(orig);
+ }
+
+ @Override
+ public final boolean contains(final Object obj) {
+ return STALE_LLGR.equals(obj) || orig.contains(obj);
+ }
+
+ @Override
+ public final Communities get(final int index) {
+ return index == 0 ? STALE_LLGR : orig.get(index - 1);
+ }
+
+ @Override
+ public final int size() {
+ return orig.size() + 1;
+ }
+}