Remove Peer.getRawIdentifier()
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / AbstractPeer.java
index c0fc7fd219a2b0b6235a65694a3ad8fbf07ab371..7893470d4a1c327cfbbfae668ac4ada3b39a5f0a 100644 (file)
@@ -9,10 +9,10 @@ package org.opendaylight.protocol.bgp.rib.impl;
 
 import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.PEER_NID;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.MoreExecutors;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -21,11 +21,9 @@ import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.binding.api.TransactionChain;
-import org.opendaylight.mdsal.binding.api.TransactionChainListener;
-import org.opendaylight.mdsal.binding.api.WriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteOperations;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
@@ -43,49 +41,58 @@ import org.opendaylight.protocol.bgp.rib.spi.entry.AdvertizedRoute;
 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteEntryDependenciesContainer;
 import org.opendaylight.protocol.bgp.rib.spi.entry.RouteKeyIdentifier;
 import org.opendaylight.protocol.bgp.rib.spi.entry.StaleBestPathRoute;
-import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRibRoutingPolicy;
 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryExportParameters;
 import org.opendaylight.protocol.bgp.rib.spi.policy.BGPRouteEntryImportParameters;
 import org.opendaylight.protocol.bgp.rib.spi.state.BGPAfiSafiState;
 import org.opendaylight.protocol.bgp.rib.spi.state.BGPErrorHandlingState;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.AsNumber;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressNoZone;
-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.rev200120.path.attributes.Attributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.PeerId;
 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.rib.Tables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.TablesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.rib.tables.Routes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev180329.ClusterIdentifier;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.ClusterIdentifier;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.ChoiceIn;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.Identifiable;
-import org.opendaylight.yangtools.yang.binding.Identifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImportParameters, TransactionChainListener,
-        DOMTransactionChainListener, Peer, PeerTransactionChain {
+abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImportParameters, Peer,
+        PeerTransactionChain, DOMTransactionChainListener {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractPeer.class);
-    protected final RIB rib;
-    final String name;
-    final PeerRole peerRole;
+
+    final RTCClientRouteCache rtCache = new RTCClientRouteCache();
+    final RIB rib;
+
     private final ClusterIdentifier clusterId;
+    private final PeerRole peerRole;
     private final AsNumber localAs;
+    private final String name;
+
+    // FIXME: revisit locking here to improve concurrency:
+    //        -- identifiers, peerId are a shared resource
+    //        -- domChain seems to really be 'ribInChain', accessed from netty thread
+    //        -- ribOutChain is accessed from LocRibWriter
+    //        hence we want to use the two chains concurrently. The problem is their lifecycle in response to errors,
+    //        which needs figuring out.
     @GuardedBy("this")
     private DOMTransactionChain domChain;
     @GuardedBy("this")
-    TransactionChain bindingChain;
-    byte[] rawIdentifier;
-    @GuardedBy("this")
     PeerId peerId;
+
+    // These seem to be separate
+    @GuardedBy("this")
+    @VisibleForTesting
+    DOMTransactionChain ribOutChain;
+    @GuardedBy("this")
     private FluentFuture<? extends CommitInfo> submitted;
-    RTCClientRouteCache rtCache = new RTCClientRouteCache();
 
     AbstractPeer(
             final RIB rib,
@@ -155,11 +162,6 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
         return this.peerRole;
     }
 
-    @Override
-    public final synchronized byte[] getRawIdentifier() {
-        return Arrays.copyOf(this.rawIdentifier, this.rawIdentifier.length);
-    }
-
     @Override
     public final PeerRole getFromPeerRole() {
         return getRole();
@@ -180,11 +182,6 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
         LOG.debug("Transaction chain {} successful.", chain);
     }
 
-    @Override
-    public final void onTransactionChainSuccessful(final TransactionChain chain) {
-        LOG.debug("Transaction chain {} successful.", chain);
-    }
-
     @Override
     public final BGPErrorHandlingState getBGPErrorHandlingState() {
         return this;
@@ -228,47 +225,41 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
     }
 
     @Override
-    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
-            R extends Route & ChildOf<? super S> & Identifiable<I>,
-            I extends Identifier<R>> void initializeRibOut(final RouteEntryDependenciesContainer entryDep,
-                    final List<ActualBestPathRoutes<C, S, R, I>> routesToStore) {
-        if (this.bindingChain == null) {
+    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
+            void initializeRibOut(final RouteEntryDependenciesContainer entryDep,
+                    final List<ActualBestPathRoutes<C, S>> routesToStore) {
+        if (this.ribOutChain == null) {
             LOG.debug("Session closed, skip changes to peer AdjRibsOut {}", getPeerId());
             return;
         }
 
-        final RIBSupport<C, S, R, I> ribSupport = entryDep.getRIBSupport();
-        final TablesKey tk = entryDep.getRIBSupport().getTablesKey();
-        final boolean addPathSupported = supportsAddPathSupported(tk);
+        final RIBSupport<C, S> ribSupport = entryDep.getRIBSupport();
+        final YangInstanceIdentifier tableRibout = getRibOutIId(ribSupport.tablesKey());
+        final boolean addPathSupported = supportsAddPathSupported(ribSupport.getTablesKey());
 
-        final WriteTransaction tx = this.bindingChain.newWriteOnlyTransaction();
-        for (final ActualBestPathRoutes<C, S, R, I> initializingRoute : routesToStore) {
-            if (!supportsLLGR() && initializingRoute.isDepreferenced()) {
+        final DOMDataTreeWriteTransaction tx = this.ribOutChain.newWriteOnlyTransaction();
+        for (final ActualBestPathRoutes<C, S> initRoute : routesToStore) {
+            if (!supportsLLGR() && initRoute.isDepreferenced()) {
                 // Stale Long-lived Graceful Restart routes should not be propagated
                 continue;
             }
 
-            final PeerId fromPeerId = initializingRoute.getFromPeerId();
+            final PeerId fromPeerId = initRoute.getFromPeerId();
             if (!filterRoutes(fromPeerId, ribSupport.getTablesKey())) {
                 continue;
             }
 
-            final R route = initializingRoute.getRoute();
+            final MapEntryNode route = initRoute.getRoute();
             final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
             if (fromPeer == null) {
-                LOG.debug("Failed to acquire peer structure for {}, ignoring route {}", fromPeerId, initializingRoute);
+                LOG.debug("Failed to acquire peer structure for {}, ignoring route {}", fromPeerId, initRoute);
                 continue;
             }
 
-            final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
-                    this, route.getRouteKey(), this.rtCache);
-
-            final Optional<Attributes> effAttr = entryDep.getRoutingPolicies()
-                    .applyExportPolicies(routeEntry, initializingRoute.getAttributes(), entryDep.getAfiSafType());
-            final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
-
-            effAttr.ifPresent(attributes
-                -> storeRoute(ribSupport, addPathSupported, tableRibout, initializingRoute, route, attributes, tx));
+            final YangInstanceIdentifier routePath = createRoutePath(ribSupport, tableRibout, initRoute,
+                addPathSupported);
+            applyExportPolicy(entryDep, fromPeerId, route, routePath, initRoute.getAttributes()).ifPresent(
+                attributes -> storeRoute(ribSupport, initRoute, route, routePath, attributes, tx));
         }
 
         final FluentFuture<? extends CommitInfo> future = tx.commit();
@@ -287,16 +278,15 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
     }
 
     @Override
-    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
-            R extends Route & ChildOf<? super S> & Identifiable<I>,
-            I extends Identifier<R>> void refreshRibOut(final RouteEntryDependenciesContainer entryDep,
-            final List<StaleBestPathRoute<C, S, R, I>> staleRoutes, final List<AdvertizedRoute<C, S, R, I>> newRoutes) {
-        if (this.bindingChain == null) {
+    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
+            void refreshRibOut(final RouteEntryDependenciesContainer entryDep,
+                final List<StaleBestPathRoute> staleRoutes, final List<AdvertizedRoute<C, S>> newRoutes) {
+        if (this.ribOutChain == null) {
             LOG.debug("Session closed, skip changes to peer AdjRibsOut {}", getPeerId());
             return;
         }
-        final WriteTransaction tx = this.bindingChain.newWriteOnlyTransaction();
-        final RIBSupport<C, S, R, I> ribSupport = entryDep.getRIBSupport();
+        final DOMDataTreeWriteTransaction tx = this.ribOutChain.newWriteOnlyTransaction();
+        final RIBSupport<C, S> ribSupport = entryDep.getRIBSupport();
         deleteRouteRibOut(ribSupport, staleRoutes, tx);
         installRouteRibOut(entryDep, newRoutes, tx);
 
@@ -316,46 +306,40 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
     }
 
     @Override
-    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
-            R extends Route & ChildOf<? super S> & Identifiable<I>,
-            I extends Identifier<R>> void reEvaluateAdvertizement(
-            final RouteEntryDependenciesContainer entryDep,
-            final List<ActualBestPathRoutes<C, S, R, I>> routesToStore) {
-        if (this.bindingChain == null) {
+    public final synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
+            void reEvaluateAdvertizement(final RouteEntryDependenciesContainer entryDep,
+                final List<ActualBestPathRoutes<C, S>> routesToStore) {
+        if (this.ribOutChain == null) {
             LOG.debug("Session closed, skip changes to peer AdjRibsOut {}", getPeerId());
             return;
         }
 
-        final RIBSupport<C,S,R,I> ribSupport = entryDep.getRIBSupport();
-        final TablesKey tk = entryDep.getRIBSupport().getTablesKey();
-        final boolean addPathSupported = supportsAddPathSupported(tk);
+        final RIBSupport<C, S> ribSupport = entryDep.getRIBSupport();
+        final NodeIdentifierWithPredicates tk = ribSupport.tablesKey();
+        final boolean addPathSupported = supportsAddPathSupported(ribSupport.getTablesKey());
 
-        final WriteTransaction tx = this.bindingChain.newWriteOnlyTransaction();
-        for (final ActualBestPathRoutes<C, S, R, I> actualBestRoute : routesToStore) {
+        final DOMDataTreeWriteTransaction tx = this.ribOutChain.newWriteOnlyTransaction();
+        for (final ActualBestPathRoutes<C, S> actualBestRoute : routesToStore) {
             final PeerId fromPeerId = actualBestRoute.getFromPeerId();
             if (!filterRoutes(fromPeerId, ribSupport.getTablesKey())) {
                 continue;
             }
 
-            final R route = actualBestRoute.getRoute();
-            final Optional<Attributes> effAttr;
+            final YangInstanceIdentifier tableRibout = getRibOutIId(tk);
+            // Stale Long-lived Graceful Restart routes should not be propagated
             if (supportsLLGR() || !actualBestRoute.isDepreferenced()) {
-                final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
-                final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
-                    this, route.getRouteKey(), this.rtCache);
-                effAttr = entryDep.getRoutingPolicies()
-                        .applyExportPolicies(routeEntry, actualBestRoute.getAttributes(), entryDep.getAfiSafType());
-            } else {
-                // Stale Long-lived Graceful Restart routes should not be propagated
-                effAttr = Optional.empty();
+                final YangInstanceIdentifier routePath = createRoutePath(ribSupport, tableRibout, actualBestRoute,
+                    addPathSupported);
+                final MapEntryNode route = actualBestRoute.getRoute();
+                final Optional<ContainerNode> effAttr = applyExportPolicy(entryDep, fromPeerId, route, routePath,
+                    actualBestRoute.getAttributes());
+                if (effAttr.isPresent()) {
+                    storeRoute(ribSupport, actualBestRoute, route, routePath, effAttr.get(), tx);
+                    continue;
+                }
             }
 
-            final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
-            if (effAttr.isPresent()) {
-                storeRoute(ribSupport, addPathSupported, tableRibout, actualBestRoute, route, effAttr.get(), tx);
-            } else {
-                deleteRoute(ribSupport, addPathSupported, tableRibout, actualBestRoute, tx);
-            }
+            deleteRoute(ribSupport, addPathSupported, tableRibout, actualBestRoute, tx);
         }
 
         final FluentFuture<? extends CommitInfo> future = tx.commit();
@@ -373,18 +357,40 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
         }, MoreExecutors.directExecutor());
     }
 
-    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 installRouteRibOut(
-                    final RouteEntryDependenciesContainer entryDep, final List<AdvertizedRoute<C, S, R, I>> routes,
-                    final WriteTransaction tx) {
-        final TablesKey tk = entryDep.getRIBSupport().getTablesKey();
+    private Optional<ContainerNode> applyExportPolicy(final RouteEntryDependenciesContainer entryDep,
+            final PeerId fromPeerId, final MapEntryNode route, final YangInstanceIdentifier routePath,
+            final ContainerNode attrs) {
+        final Peer fromPeer = entryDep.getPeerTracker().getPeer(fromPeerId);
+        final RIBSupport<?, ?> ribSupport = entryDep.getRIBSupport();
+        final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer, this,
+            ribSupport.extractRouteKey(route.getIdentifier()), this.rtCache);
+
+        final Attributes bindingAttrs = ribSupport.attributeFromContainerNode(attrs);
+        final Optional<Attributes> optExportAttrs = entryDep.getRoutingPolicies().applyExportPolicies(routeEntry,
+            bindingAttrs, entryDep.getAfiSafType());
+        if (optExportAttrs.isEmpty()) {
+            // Discards route
+            return Optional.empty();
+        }
+        final Attributes exportAttrs = optExportAttrs.orElseThrow();
+
+        // If the same object is returned we can just reuse 'attrs' instead. Since we are in control of lifecycle here,
+        // we use identity comparison, as equality is too costly for the common case -- assuming export policy will not
+        // churn objects when it does not have to
+        return Optional.of(exportAttrs == bindingAttrs ? attrs
+            : ribSupport.attributeToContainerNode(routePath.node(ribSupport.routeAttributesIdentifier()), exportAttrs));
+    }
+
+    private <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>> void installRouteRibOut(
+            final RouteEntryDependenciesContainer entryDep, final List<AdvertizedRoute<C, S>> routes,
+            final DOMDataTreeWriteOperations tx) {
+        final RIBSupport<C, S> ribSupport = entryDep.getRIBSupport();
+        final TablesKey tk = ribSupport.getTablesKey();
         final BGPPeerTracker peerTracker = entryDep.getPeerTracker();
-        final RIBSupport<C, S, R, I> ribSupport = entryDep.getRIBSupport();
-        final BGPRibRoutingPolicy routingPolicies = entryDep.getRoutingPolicies();
         final boolean addPathSupported = supportsAddPathSupported(tk);
-        final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
+        final YangInstanceIdentifier tableRibout = getRibOutIId(ribSupport.tablesKey());
 
-        for (final AdvertizedRoute<C, S, R, I> advRoute : routes) {
+        for (final AdvertizedRoute<C, S> advRoute : routes) {
             final PeerId fromPeerId = advRoute.getFromPeerId();
             if (!filterRoutes(fromPeerId, tk) || !advRoute.isFirstBestPath() && !addPathSupported) {
                 continue;
@@ -401,63 +407,49 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
                 continue;
             }
 
-            final R route = advRoute.getRoute();
-            Optional<Attributes> effAttr = Optional.empty();
             final Peer fromPeer = peerTracker.getPeer(fromPeerId);
-            final Attributes attributes = advRoute.getAttributes();
+            final ContainerNode attributes = advRoute.getAttributes();
             if (fromPeer != null && attributes != null) {
-                final BGPRouteEntryExportParameters routeEntry = new BGPRouteEntryExportParametersImpl(fromPeer,
-                        this, route.getRouteKey(), this.rtCache);
-                effAttr = routingPolicies.applyExportPolicies(routeEntry, attributes, entryDep.getAfiSafType());
+                final YangInstanceIdentifier routePath = createRoutePath(ribSupport, tableRibout, advRoute,
+                    addPathSupported);
+                final MapEntryNode route = advRoute.getRoute();
+                applyExportPolicy(entryDep, fromPeerId, route, routePath, attributes).ifPresent(
+                    attrs -> storeRoute(ribSupport, advRoute, route, routePath, attrs, tx));
             }
-            effAttr.ifPresent(attributes1
-                -> storeRoute(ribSupport, addPathSupported, tableRibout, advRoute, route, attributes1, tx));
         }
     }
 
-    private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
-            R extends Route & ChildOf<? super S> & Identifiable<I>,
-            I extends Identifier<R>> void deleteRouteRibOut(
-            final RIBSupport<C, S, R, I> ribSupport,
-            final List<StaleBestPathRoute<C, S, R, I>> staleRoutesIid,
-            final WriteTransaction tx) {
-        final TablesKey tk = ribSupport.getTablesKey();
-        final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout = getRibOutIId(tk);
-        final boolean addPathSupported = supportsAddPathSupported(tk);
+    private static YangInstanceIdentifier createRoutePath(final RIBSupport<?, ?> ribSupport,
+            final YangInstanceIdentifier tableRibout, final RouteKeyIdentifier advRoute, final boolean withAddPath) {
+        return ribSupport.createRouteIdentifier(tableRibout,
+            withAddPath ? advRoute.getAddPathRouteKeyIdentifier() : advRoute.getNonAddPathRouteKeyIdentifier());
+    }
+
+    private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
+            void deleteRouteRibOut(final RIBSupport<C, S> ribSupport, final List<StaleBestPathRoute> staleRoutesIid,
+                final DOMDataTreeWriteOperations tx) {
+        final YangInstanceIdentifier tableRibout = getRibOutIId(ribSupport.tablesKey());
+        final boolean addPathSupported = supportsAddPathSupported(ribSupport.getTablesKey());
         staleRoutesIid.forEach(staleRouteIid
             -> removeRoute(ribSupport, addPathSupported, tableRibout, staleRouteIid, tx));
     }
 
-    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 storeRoute(
-                    final RIBSupport<C, S, R, I> ribSupport, final boolean addPathSupported,
-                    final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
-                    final RouteKeyIdentifier<R, I> advRoute, final R route, final Attributes effAttr,
-                    final WriteTransaction tx) {
-        final InstanceIdentifier<R> ribOut;
-        final I newKey;
-        if (!addPathSupported) {
-            ribOut = ribSupport.createRouteIdentifier(tableRibout, advRoute.getNonAddPathRouteKeyIdentifier());
-            newKey = ribSupport.createRouteListKey(route.getRouteKey());
-        } else {
-            ribOut = ribSupport.createRouteIdentifier(tableRibout, advRoute.getAddPathRouteKeyIdentifier());
-            newKey = ribSupport.createRouteListKey(route.getPathId(), route.getRouteKey());
-        }
-
-        final R newRoute = ribSupport.createRoute(route, newKey, effAttr);
+    private <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>> void storeRoute(
+            final RIBSupport<C, S> ribSupport, final RouteKeyIdentifier advRoute, final MapEntryNode route,
+            final YangInstanceIdentifier routePath, final ContainerNode effAttr, final DOMDataTreeWriteOperations tx) {
         LOG.debug("Write advRoute {} to peer AdjRibsOut {}", advRoute, getPeerId());
-        tx.put(LogicalDatastoreType.OPERATIONAL, ribOut, newRoute);
+        tx.put(LogicalDatastoreType.OPERATIONAL, routePath, ribSupport.createRoute(route,
+            (NodeIdentifierWithPredicates) routePath.getLastPathArgument(), effAttr));
     }
 
-    private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>,
-            R extends Route & ChildOf<? super S> & Identifiable<I>,
-            I extends Identifier<R>> void removeRoute(final RIBSupport<C, S, R, I> ribSupport,
-            final boolean addPathSupported, final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
-            final StaleBestPathRoute<C, S, R, I> staleRouteIid, final WriteTransaction tx) {
+    private synchronized <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>>
+            void removeRoute(final RIBSupport<C, S> ribSupport, final boolean addPathSupported,
+                final YangInstanceIdentifier tableRibout, final StaleBestPathRoute staleRouteIid,
+                final DOMDataTreeWriteOperations tx) {
         if (addPathSupported) {
-            List<I> staleRoutesIId = staleRouteIid.getAddPathRouteKeyIdentifiers();
-            for (final I id : staleRoutesIId) {
-                final InstanceIdentifier<R> ribOutTarget = ribSupport.createRouteIdentifier(tableRibout, id);
+            List<NodeIdentifierWithPredicates> staleRoutesIId = staleRouteIid.getAddPathRouteKeyIdentifiers();
+            for (final NodeIdentifierWithPredicates id : staleRoutesIId) {
+                final YangInstanceIdentifier ribOutTarget = ribSupport.createRouteIdentifier(tableRibout, id);
                 LOG.trace("Removing {} from transaction for peer {}", ribOutTarget, getPeerId());
                 tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutTarget);
             }
@@ -465,7 +457,7 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
             if (!staleRouteIid.isNonAddPathBestPathNew()) {
                 return;
             }
-            final InstanceIdentifier<R> ribOutTarget = ribSupport.createRouteIdentifier(tableRibout,
+            final YangInstanceIdentifier ribOutTarget = ribSupport.createRouteIdentifier(tableRibout,
                     staleRouteIid.getNonAddPathRouteKeyIdentifier());
             LOG.trace("Removing {} from transaction for peer {}", ribOutTarget, getPeerId());
             tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutTarget);
@@ -473,33 +465,31 @@ abstract class AbstractPeer extends BGPPeerStateImpl implements BGPRouteEntryImp
     }
 
     // FIXME: why is this different from removeRoute()?
-    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 deleteRoute(
-            final RIBSupport<C, S, R, I> ribSupport,  final boolean addPathSupported,
-            final KeyedInstanceIdentifier<Tables, TablesKey> tableRibout,
-            final AbstractAdvertizedRoute<C, S , R, I> advRoute, final WriteTransaction tx) {
-        final InstanceIdentifier<R> ribOutTarget = ribSupport.createRouteIdentifier(tableRibout,
+    private <C extends Routes & DataObject & ChoiceIn<Tables>, S extends ChildOf<? super C>> void deleteRoute(
+            final RIBSupport<C, S> ribSupport,  final boolean addPathSupported,
+            final YangInstanceIdentifier tableRibout, final AbstractAdvertizedRoute<C, S> advRoute,
+            final DOMDataTreeWriteOperations tx) {
+        final YangInstanceIdentifier ribOutTarget = ribSupport.createRouteIdentifier(tableRibout,
             addPathSupported ? advRoute.getAddPathRouteKeyIdentifier() : advRoute.getNonAddPathRouteKeyIdentifier());
         LOG.trace("Removing {} from transaction for peer {}", ribOutTarget, getPeerId());
         tx.delete(LogicalDatastoreType.OPERATIONAL, ribOutTarget);
     }
 
-    final synchronized void releaseBindingChain() {
-        if (this.submitted != null) {
-            try {
-                this.submitted.get();
-            } catch (final InterruptedException | ExecutionException throwable) {
-                LOG.error("Write routes failed", throwable);
+    final synchronized void releaseRibOutChain(final boolean isWaitForSubmitted) {
+        if (isWaitForSubmitted) {
+            if (this.submitted != null) {
+                try {
+                    this.submitted.get();
+                } catch (final InterruptedException | ExecutionException throwable) {
+                    LOG.error("Write routes failed", throwable);
+                }
             }
         }
-        closeBindingChain();
-    }
 
-    private synchronized void closeBindingChain() {
-        if (this.bindingChain != null) {
+        if (this.ribOutChain != null) {
             LOG.info("Closing peer chain {}", getPeerId());
-            this.bindingChain.close();
-            this.bindingChain = null;
+            this.ribOutChain.close();
+            this.ribOutChain = null;
         }
     }