Prepare EffRibInWriter for LLGR_STALE handling 76/78476/21
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 5 Dec 2018 18:18:57 +0000 (19:18 +0100)
committerMatej Perina <matej.perina@pantheon.tech>
Mon, 10 Dec 2018 19:36:50 +0000 (20:36 +0100)
When a peer configured with Long-Lived Graceful Restart goes down,
we need to process all tables which it advertised as LLGR-enabled
and mark all routes as being tagged with LLGR_STALE.

LLGR_STALE community must be added to routes behind import
policy processing since policies can also add this community.
This patch should provide procedures necessary to add LLGR_STALE
community to routes.

JIRA: BGPCEP-495
Change-Id: If921e378f998109b073c628f9913f395496b3139
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
Signed-off-by: Matej Perina <matej.perina@pantheon.tech>
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java [new file with mode: 0644]

index 932b1eeb14b9b23d1558fed99ebdbb4648ac9f5f..a7c6258b764f34b6626134aaee9a18e8ccaec84b 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.protocol.bgp.rib.impl;
 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;
@@ -35,6 +36,7 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 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;
@@ -46,6 +48,7 @@ import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameter
 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;
@@ -95,6 +98,13 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
             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;
@@ -260,7 +270,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
             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);
@@ -271,32 +281,66 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
     }
 
     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,
@@ -326,7 +370,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
         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());
         }
 
diff --git a/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java b/bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/StaleCommunities.java
new file mode 100644 (file)
index 0000000..e04738c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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;
+    }
+}