Add adj-rib-in llgr-stale flag 79/78879/39
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 19 Dec 2018 18:47:51 +0000 (19:47 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 4 Feb 2019 11:24:15 +0000 (12:24 +0100)
Add the ability to signal tables to be LLGR-stale, so that
effective-rib-in can propagate this state properly towards
local rib.

This flag is picked up by before we are applying input policies,
so that routes are transiently marked as LLGR_STALE. The policy
can then decide whether to filter the route or modify its
attributes.

Once the policy has been applied and the flag is set, we check
if NO_LLGR flag is present, and if that is the case, we remove
that route.

This mechanics is required to correctly allow policies to
see LLGR_STALE routes as well as potentially remove the NO_LLGR
flag.

JIRA: BGPCEP-495
Change-Id: Iac9815b29e97aee99a81d015194cd16fb362387d
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
bgp/rib-api/src/main/yang/bgp-rib.yang
bgp/rib-impl/src/main/java/org/opendaylight/protocol/bgp/rib/impl/EffectiveRibInWriter.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBNodeIdentifiers.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBNormalizedNodes.java
bgp/rib-spi/src/main/java/org/opendaylight/protocol/bgp/rib/spi/RIBQNames.java

index a0dba9fd9810838348b9295314dfdd4179090905..b07f0630b990b26f3dfaa9eab9f1710f655488dc 100644 (file)
@@ -127,7 +127,16 @@ module bgp-rib {
                 }
                 container adj-rib-in {
                     description "Routes as we have received them from the peer.";
-                    uses rib;
+                    uses rib {
+                        augment tables/attributes {
+                            leaf llgr-stale {
+                                type empty;
+                                description "Presence indicates that all routes in this table
+                                             are to be treated as having LLGR_STALE community
+                                             attached to them";
+                            }
+                        }
+                    }
                 }
                 container effective-rib-in {
                     description "Routes as processed by inbound policy.";
index 0c78b7784fe39ce60811378cea72aab15adcca2a..aa0fdea0f4ff6aee4d563fec1784b89616206a4f 100644 (file)
@@ -9,11 +9,14 @@ package org.opendaylight.protocol.bgp.rib.impl;
 
 import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBIN_ATTRIBUTES_AID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBIN_NID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ATTRIBUTES_NID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.EFFRIBIN_NID;
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.LLGR_STALE_NID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ROUTES_NID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID;
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.UPTODATE_NID;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -47,6 +50,7 @@ import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContextRegistry;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RibOutRefresh;
 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesInstalledCounters;
 import org.opendaylight.protocol.bgp.rib.impl.state.peer.PrefixesReceivedCounters;
+import org.opendaylight.protocol.bgp.rib.spi.RIBNormalizedNodes;
 import org.opendaylight.protocol.bgp.rib.spi.RIBSupport;
 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
@@ -312,12 +316,21 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
             final YangInstanceIdentifier effectiveTablePath, final DataTreeCandidateNode table) {
         LOG.debug("Modify Effective Table {}", effectiveTablePath);
 
+        final boolean wasLongLivedStale = isLongLivedStaleTable(table.getDataBefore());
+        final boolean longLivedStale = isLongLivedStaleTable(table.getDataAfter());
+        if (wasLongLivedStale != longLivedStale) {
+            LOG.debug("LLGR_STALE flag flipped {}, overwriting table {}", longLivedStale ? "ON" : "OFF",
+                    effectiveTablePath);
+            writeTable(tx, ribContext, effectiveTablePath, table);
+            return;
+        }
+
         final DataTreeCandidateNode modifiedAttrs = table.getModifiedChild(ATTRIBUTES_NID);
         if (modifiedAttrs != null) {
-            final Optional<NormalizedNode<?, ?>> attrsAfter = modifiedAttrs.getDataAfter();
             final YangInstanceIdentifier effAttrsPath = effectiveTablePath.node(ATTRIBUTES_NID);
-            if (attrsAfter.isPresent()) {
-                tx.put(LogicalDatastoreType.OPERATIONAL, effAttrsPath, attrsAfter.get());
+            final Optional<NormalizedNode<?, ?>> optAttrsAfter = modifiedAttrs.getDataAfter();
+            if (optAttrsAfter.isPresent()) {
+                tx.put(LogicalDatastoreType.OPERATIONAL, effAttrsPath, effectiveAttributes(optAttrsAfter));
             } else {
                 tx.delete(LogicalDatastoreType.OPERATIONAL, effAttrsPath);
             }
@@ -332,7 +345,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
                     deleteRoutesBefore(tx, ribSupport, effectiveTablePath, modifiedRoutes);
                     // XXX: YANG Tools seems to have an issue stacking DELETE with child WRITE
                     tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ROUTES_NID), EMPTY_ROUTES);
-                    writeRoutesAfter(tx, ribSupport, effectiveTablePath, modifiedRoutes.getDataAfter());
+                    writeRoutesAfter(tx, ribSupport, effectiveTablePath, modifiedRoutes.getDataAfter(), longLivedStale);
                     break;
                 case DELETE:
                 case DISAPPEARED:
@@ -341,7 +354,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
                     break;
                 case SUBTREE_MODIFIED:
                     for (DataTreeCandidateNode modifiedRoute : ribSupport.changedRoutes(modifiedRoutes)) {
-                        processRoute(tx, ribSupport, effectiveTablePath, modifiedRoute);
+                        processRoute(tx, ribSupport, effectiveTablePath, modifiedRoute, longLivedStale);
                     }
                     break;
                 case UNMODIFIED:
@@ -365,13 +378,18 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
             ribContext.createEmptyTableStructure(tx, effectiveTablePath);
 
             final Optional<DataContainerChild<?, ?>> maybeAttrsAfter = tableAfter.getChild(ATTRIBUTES_NID);
+            final boolean longLivedStale;
             if (maybeAttrsAfter.isPresent()) {
                 final ContainerNode attrsAfter = extractContainer(maybeAttrsAfter);
-                tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ATTRIBUTES_NID), attrsAfter);
+                longLivedStale = isLongLivedStale(attrsAfter);
+                tx.put(LogicalDatastoreType.OPERATIONAL, effectiveTablePath.node(ATTRIBUTES_NID),
+                    effectiveAttributes(attrsAfter.getChild(UPTODATE_NID)));
+            } else {
+                longLivedStale = false;
             }
 
             writeRoutesAfter(tx, ribContext.getRibSupport(), effectiveTablePath,
-                NormalizedNodes.findNode(tableAfter, ROUTES_NID));
+                NormalizedNodes.findNode(tableAfter, ROUTES_NID), longLivedStale);
         }
     }
 
@@ -396,13 +414,15 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
     }
 
     private void writeRoutesAfter(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
-            final YangInstanceIdentifier effectiveTablePath, final Optional<NormalizedNode<?, ?>> routesAfter) {
+            final YangInstanceIdentifier effectiveTablePath, final Optional<NormalizedNode<?, ?>> routesAfter,
+            final boolean longLivedStale) {
         final Optional<NormalizedNode<?, ?>> maybeRoutesAfter = NormalizedNodes.findNode(routesAfter,
             ribSupport.relativeRoutesPath());
         if (maybeRoutesAfter.isPresent()) {
             final YangInstanceIdentifier routesPath = routeMapPath(ribSupport, effectiveTablePath);
             for (MapEntryNode routeAfter : extractMap(maybeRoutesAfter).getValue()) {
-                writeRoute(tx, ribSupport, routesPath.node(routeAfter.getIdentifier()), Optional.empty(), routeAfter);
+                writeRoute(tx, ribSupport, routesPath.node(routeAfter.getIdentifier()), Optional.empty(), routeAfter,
+                    longLivedStale);
             }
         }
     }
@@ -422,7 +442,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
     }
 
     private void processRoute(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
-            final YangInstanceIdentifier routesPath, final DataTreeCandidateNode route) {
+            final YangInstanceIdentifier routesPath, final DataTreeCandidateNode route, final boolean longLivedStale) {
         LOG.debug("Process route {}", route.getIdentifier());
         final YangInstanceIdentifier routePath = ribSupport.routePath(routesPath, route.getIdentifier());
         switch (route.getModificationType()) {
@@ -436,7 +456,8 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
             case APPEARED:
             case SUBTREE_MODIFIED:
             case WRITE:
-                writeRoute(tx, ribSupport, routePath, route.getDataBefore(), route.getDataAfter().get());
+                writeRoute(tx, ribSupport, routePath, route.getDataBefore(), route.getDataAfter().get(),
+                    longLivedStale);
             default:
                 LOG.warn("Ignoring unhandled route {}", route);
                 break;
@@ -454,7 +475,7 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
 
     private void writeRoute(final DOMDataWriteTransaction tx, final RIBSupport<?, ?, ?, ?> ribSupport,
             final YangInstanceIdentifier routePath, final Optional<NormalizedNode<?, ?>> routeBefore,
-            final NormalizedNode<?, ?> routeAfter) {
+            final NormalizedNode<?, ?> routeAfter, final boolean longLivedStale) {
         final TablesKey tablesKey = ribSupport.getTablesKey();
         CountersUtil.increment(this.prefixesReceived.get(tablesKey), tablesKey);
         // Lookup per-table attributes from RIBSupport
@@ -464,7 +485,6 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
         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.
-        final boolean longLivedStale = false;
         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();
@@ -591,4 +611,22 @@ final class EffectiveRibInWriter implements PrefixesReceivedCounters, PrefixesIn
         verify(node instanceof MapEntryNode, "Expected MapEntryNode, got %s", node);
         return (MapEntryNode) node;
     }
+
+    private static boolean isLongLivedStale(final ContainerNode attributes) {
+        return NormalizedNodes.findNode(attributes, ADJRIBIN_ATTRIBUTES_AID, LLGR_STALE_NID).isPresent();
+    }
+
+    private static boolean isLongLivedStaleTable(final Optional<NormalizedNode<?, ?>> optTable) {
+        final Optional<NormalizedNode<?, ?>> optAttributes = NormalizedNodes.findNode(optTable, ATTRIBUTES_NID);
+        return optAttributes.isPresent() ? isLongLivedStale(extractContainer(optAttributes)) : false;
+    }
+
+    private static ContainerNode effectiveAttributes(final Optional<? extends NormalizedNode<?, ?>> optUptodate) {
+        return optUptodate.map(leaf -> {
+            final Object value = leaf.getValue();
+            verify(value instanceof Boolean, "Expected boolean uptodate, got %s", value);
+            return ((Boolean) value).booleanValue() ? RIBNormalizedNodes.UPTODATE_ATTRIBUTES
+                    : RIBNormalizedNodes.NOT_UPTODATE_ATTRIBUTES;
+        }).orElse(RIBNormalizedNodes.NOT_UPTODATE_ATTRIBUTES);
+    }
 }
index 1ee16c312e91201ce1a56a49e82803a9d561b591..056253275f82f9ed723d3c434a953be522375c5c 100644 (file)
@@ -7,7 +7,10 @@
  */
 package org.opendaylight.protocol.bgp.rib.spi;
 
+import static org.opendaylight.protocol.bgp.rib.spi.RIBQNames.LLGR_STALE_QNAME;
+
 import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.BgpRib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.Rib;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.LocRib;
@@ -18,6 +21,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.Tables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Attributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 
 /**
@@ -37,7 +41,12 @@ public final class RIBNodeIdentifiers {
     public static final NodeIdentifier ROUTES_NID = NodeIdentifier.create(Routes.QNAME);
     public static final NodeIdentifier ATTRIBUTES_NID = NodeIdentifier.create(Attributes.QNAME);
 
+    // Unfortunate side-effect of how yang-data-api operates, we need to deal with the augmentation identifier
+    public static final AugmentationIdentifier ADJRIBIN_ATTRIBUTES_AID = new AugmentationIdentifier(
+        ImmutableSet.of(LLGR_STALE_QNAME));
+
     public static final NodeIdentifier UPTODATE_NID = NodeIdentifier.create(RIBQNames.UPTODATE_QNAME);
+    public static final NodeIdentifier LLGR_STALE_NID = NodeIdentifier.create(RIBQNames.LLGR_STALE_QNAME);
 
     private RIBNodeIdentifiers() {
 
index a10a3278925d246c54bdccee912648beb6084e5a..2cd86603067776887c7945be8d9b1ef583b2648c 100644 (file)
@@ -7,10 +7,13 @@
  */
 package org.opendaylight.protocol.bgp.rib.spi;
 
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ATTRIBUTES_NID;
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.UPTODATE_NID;
 
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 
 /**
@@ -22,6 +25,11 @@ public final class RIBNormalizedNodes {
     public static final LeafNode<Boolean> ATTRIBUTES_UPTODATE_TRUE = ImmutableNodes.leafNode(
         UPTODATE_NID, Boolean.TRUE);
 
+    public static final ContainerNode NOT_UPTODATE_ATTRIBUTES = Builders.containerBuilder()
+            .withNodeIdentifier(ATTRIBUTES_NID).withChild(ATTRIBUTES_UPTODATE_FALSE).build();
+    public static final ContainerNode UPTODATE_ATTRIBUTES = Builders.containerBuilder()
+            .withNodeIdentifier(ATTRIBUTES_NID).withChild(ATTRIBUTES_UPTODATE_TRUE).build();
+
     private RIBNormalizedNodes() {
 
     }
index fb4a236902243c7b469ae53da91c65150e237e64..d81633605c3a68611d897e3f87e75aa5fc3fdca2 100644 (file)
@@ -17,6 +17,7 @@ import org.opendaylight.yangtools.yang.common.QName;
 public final class RIBQNames {
     public static final QName UPTODATE_QNAME = QName.create(Attributes.QNAME, "uptodate").intern();
     public static final QName PEER_ID_QNAME = QName.create(Peer.QNAME, "peer-id").intern();
+    public static final QName LLGR_STALE_QNAME = QName.create(Attributes.QNAME, "llgr-stale").intern();
 
     private RIBQNames() {