Bump MRI upstreams
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / BGPPeer.java
index 344805f3843dca3dfeb76291ced4788474aa3247..eb7a3aa71aef61d87d4c53c3ad23505ff51ad3ef 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.protocol.bgp.rib.impl;
 
 import static java.util.Objects.requireNonNull;
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.ADJRIBOUT_NID;
+import static org.opendaylight.protocol.bgp.rib.spi.RIBNodeIdentifiers.TABLES_NID;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Stopwatch;
@@ -17,7 +19,6 @@ import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
-import com.google.common.net.InetAddresses;
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -35,12 +36,12 @@ import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.checkerframework.checker.lock.qual.Holding;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
-import org.opendaylight.mdsal.binding.api.Transaction;
-import org.opendaylight.mdsal.binding.api.TransactionChain;
 import org.opendaylight.mdsal.common.api.CommitInfo;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
 import org.opendaylight.protocol.bgp.parser.BGPDocumentedException;
 import org.opendaylight.protocol.bgp.parser.BGPError;
@@ -76,19 +77,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.mult
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.RouteRefresh;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.SendReceive;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.MpReachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.reach.mp.reach.nlri.AdvertizedRoutesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.MpUnreachNlriBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.attributes.unreach.mp.unreach.nlri.WithdrawnRoutesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.GracefulRestartCapability;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.mp.capabilities.add.path.capability.AddressFamilies;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpReachNlriBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.MpUnreachNlriBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev180329.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev180329.BgpPeerRpcService;
 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.bgp.rib.rib.PeerKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev180329.bgp.rib.rib.peer.AdjRibOut;
-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.types.rev200120.AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.ClusterIdentifier;
@@ -98,10 +97,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.UnicastSubsequentAddressFamily;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -114,26 +113,31 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
     private static final TablesKey IPV4_UCAST_TABLE_KEY = new TablesKey(Ipv4AddressFamily.class,
         UnicastSubsequentAddressFamily.class);
 
-    private ImmutableSet<TablesKey> tables = ImmutableSet.of();
     private final RIB rib;
+
+    // FIXME: Alright, this right here is a ton of state which has intertwined initialization and dependencies Split
+    //        these out into separate behavior objects. This also has relationship with state in AbstractPeer -- which
+    //        hints at an obvious layer of indirection. Yeah, yeah, we can always add one of those, but the point
+    //        is that this class is a mutable meeting point, whereas the behaviour has captured invariants.
+    private final LoadingCache<NodeIdentifierWithPredicates, YangInstanceIdentifier> tablesIId =
+        CacheBuilder.newBuilder().build(new CacheLoader<NodeIdentifierWithPredicates, YangInstanceIdentifier>() {
+            @Override
+            public YangInstanceIdentifier load(final NodeIdentifierWithPredicates key) {
+                return peerRibOutIId.node(TABLES_NID).node(key).toOptimized();
+            }
+        });
+
+    private ImmutableSet<TablesKey> tables = ImmutableSet.of();
     private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap<>();
     private final List<RouteTarget> rtMemberships = new ArrayList<>();
     private final RpcProviderService rpcRegistry;
     private final BGPTableTypeRegistryConsumer tableTypeRegistry;
     private final BgpPeer bgpPeer;
-    private InstanceIdentifier<AdjRibOut> peerRibOutIId;
-    private KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib
-            .rev180329.bgp.rib.rib.Peer, PeerKey> peerIId;
+
+    // FIXME: This should be a constant co-located with ApplicationPeer.peerId
+    private YangInstanceIdentifier peerRibOutIId;
     @GuardedBy("this")
     private Registration trackerRegistration;
-    private final LoadingCache<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>> tablesIId
-            = CacheBuilder.newBuilder()
-            .build(new CacheLoader<TablesKey, KeyedInstanceIdentifier<Tables, TablesKey>>() {
-                @Override
-                public KeyedInstanceIdentifier<Tables, TablesKey> load(final TablesKey tablesKey) {
-                    return BGPPeer.this.peerRibOutIId.child(Tables.class, tablesKey);
-                }
-            });
 
     @GuardedBy("this")
     private BGPSession currentSession;
@@ -143,7 +147,9 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
     private EffectiveRibInWriter effRibInWriter;
     private ObjectRegistration<BgpPeerRpcService> rpcRegistration;
     private Map<TablesKey, SendReceive> addPathTableMaps = Collections.emptyMap();
+    // FIXME: This should be a constant co-located with ApplicationPeer.peerId
     private YangInstanceIdentifier peerPath;
+    // FIXME: This is for supportsTable() -- a trivial behavior thing, where 'peer-down' type states always return false
     private boolean sessionUp;
     private boolean llgrSupport;
     private Stopwatch peerRestartStopwatch;
@@ -192,7 +198,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
                 .collect(Collectors.toList());
         final MpReachNlriBuilder b = new MpReachNlriBuilder().setAfi(Ipv4AddressFamily.class).setSafi(
                 UnicastSubsequentAddressFamily.class).setAdvertizedRoutes(
-                new AdvertizedRoutesBuilder().setDestinationType(
+                    new AdvertizedRoutesBuilder().setDestinationType(
                         new DestinationIpv4CaseBuilder().setDestinationIpv4(
                                 new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build());
         if (message.getAttributes() != null) {
@@ -226,23 +232,23 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
                 .setWithdrawnRoutes(new WithdrawnRoutesBuilder().setDestinationType(new org.opendaylight.yang.gen.v1
                         .urn.opendaylight.params.xml.ns.yang.bgp.inet.rev180329.update.attributes.mp.unreach.nlri
                         .withdrawn.routes.destination.type.DestinationIpv4CaseBuilder().setDestinationIpv4(
-                        new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
+                            new DestinationIpv4Builder().setIpv4Prefixes(prefixes).build()).build()).build()).build();
     }
 
     private static Map<TablesKey, SendReceive> mapTableTypesFamilies(final List<AddressFamilies> addPathTablesType) {
-        return ImmutableMap.copyOf(addPathTablesType.stream().collect(Collectors.toMap(af -> new TablesKey(af.getAfi(),
-                        af.getSafi()), BgpAddPathTableType::getSendReceive)));
+        return addPathTablesType.stream().collect(ImmutableMap.toImmutableMap(
+            af -> new TablesKey(af.getAfi(), af.getSafi()), BgpAddPathTableType::getSendReceive));
     }
 
     public synchronized void instantiateServiceInstance() {
         createDomChain();
-        this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this);
+        this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), getRole(), this);
         setActive(true);
     }
 
     @Override
     public synchronized FluentFuture<? extends CommitInfo> close() {
-        final FluentFuture<? extends CommitInfo> future = releaseConnection();
+        final FluentFuture<? extends CommitInfo> future = releaseConnection(true);
         closeDomChain();
         setActive(false);
         return future;
@@ -283,7 +289,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
     private void checkMandatoryAttributesPresence(final Update message) throws BGPDocumentedException {
         if (MessageUtil.isAnyNlriPresent(message)) {
             final Attributes attrs = message.getAttributes();
-            if (this.peerRole == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
+            if (getRole() == PeerRole.Ibgp && (attrs == null || attrs.getLocalPref() == null)) {
                 throw new BGPDocumentedException(BGPError.MANDATORY_ATTR_MISSING_MSG + "LOCAL_PREF",
                         BGPError.WELL_KNOWN_ATTR_MISSING,
                         new byte[]{LocalPreferenceAttributeParser.TYPE});
@@ -355,7 +361,20 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
     public synchronized void onSessionUp(final BGPSession session) {
         this.currentSession = session;
         this.sessionUp = true;
-        this.bindingChain = this.rib.createPeerChain(this);
+
+        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);
         }
@@ -366,7 +385,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
 
         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 {}", this.name,
+        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());
@@ -378,12 +397,14 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
             addBgp4Support();
         }
         if (!isRestartingGracefully()) {
-            this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
             this.peerId = RouterIds.createPeerId(session.getBgpId());
-            this.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.peerRibOutIId = peerIId.child(AdjRibOut.class);
+
+            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);
@@ -405,7 +426,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
             } else {
                 forwardingTables = advertisedTables.values().stream()
                         .filter(table -> table.getAfiFlags() != null)
-                        .filter(table -> table.getAfiFlags().isForwardingState())
+                        .filter(table -> table.getAfiFlags().getForwardingState())
                         .map(table -> new TablesKey(table.getAfi(), table.getSafi()))
                         .collect(Collectors.toSet());
             }
@@ -486,7 +507,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
 
     @Holding("this")
     private void createAdjRibOutListener(final TablesKey key, final boolean mpSupport) {
-        final RIBSupport<?, ?, ?, ?> ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
+        final RIBSupport<?, ?> ribSupport = this.rib.getRibSupportContext().getRIBSupport(key);
 
         // not particularly nice
         if (ribSupport != null && this.currentSession instanceof BGPSessionImpl) {
@@ -502,34 +523,45 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
     @Override
     public synchronized void onSessionDown(final BGPSession session, final Exception exc) {
         if (exc.getMessage().equals(BGPSessionImpl.END_OF_INPUT)) {
-            LOG.info("Session with peer {} went down", this.name);
+            LOG.info("Session with peer {} went down", getName());
         } else {
-            LOG.info("Session with peer {} went down", this.name, exc);
+            LOG.info("Session with peer {} went down", getName(), exc);
         }
         releaseConnectionGracefully();
     }
 
     @Override
     public synchronized void onSessionTerminated(final BGPSession session, final BGPTerminationReason cause) {
-        LOG.info("Session with peer {} terminated: {}", this.name, cause);
+        LOG.info("Session with peer {} terminated: {}", getName(), cause);
         releaseConnectionGracefully();
     }
 
     @Override
     public String toString() {
-        return MoreObjects.toStringHelper(this).add("name", this.name).add("tables", this.tables).toString();
+        return MoreObjects.toStringHelper(this).add("name", getName()).add("tables", this.tables).toString();
     }
 
     @Override
     public synchronized FluentFuture<? extends CommitInfo> releaseConnection() {
+        return releaseConnection(true);
+    }
+
+    /**
+     * On transaction chain failure, we don't want to wait for future.
+     *
+     * @param isWaitForSubmitted if true, wait for submitted future before closing binding chain. if false, don't wait.
+     */
+    @Holding("this")
+    private @NonNull FluentFuture<? extends CommitInfo> releaseConnection(final boolean isWaitForSubmitted) {
         LOG.info("Closing session with peer");
         this.sessionUp = false;
         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
         this.adjRibOutListenerSet.clear();
         final FluentFuture<? extends CommitInfo> future;
-        if (!isRestartingGracefully()) {
-            future = terminateConnection();
-        } else {
+        // FIXME: this is a typical example of something which should be handled by a behavior into which we have
+        //        transitioned way before this method is called. This really begs to be an abstract base class with
+        //        a 'clearTables' or similar callout
+        if (isRestartingGracefully()) {
             final Set<TablesKey> gracefulTables = getGracefulTables();
             this.ribWriter.storeStaleRoutes(gracefulTables);
             future = this.ribWriter.clearTables(Sets.difference(this.tables, gracefulTables));
@@ -537,8 +569,10 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
                 this.peerRestartStopwatch = Stopwatch.createStarted();
                 handleRestartTimer();
             }
+        } else {
+            future = terminateConnection();
         }
-        releaseBindingChain();
+        releaseRibOutChain(isWaitForSubmitted);
 
         closeSession();
         return future;
@@ -623,11 +657,12 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
             TimeUnit.NANOSECONDS);
     }
 
+    @Holding("this")
     private void releaseConnectionGracefully() {
         if (getPeerRestartTime() > 0) {
             setRestartingState();
         }
-        releaseConnection();
+        releaseConnection(true);
     }
 
     @SuppressFBWarnings("IS2_INCONSISTENT_SYNC")
@@ -638,26 +673,26 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
 
     @Override
     public boolean supportsTable(final TablesKey tableKey) {
-        return this.sessionUp && getAfiSafisAdvertized().contains(tableKey);
+        return this.sessionUp && getAfiSafisAdvertized().contains(tableKey) && this.tables.contains(tableKey);
     }
 
     @Override
-    public KeyedInstanceIdentifier<Tables, TablesKey> getRibOutIId(final TablesKey tablesKey) {
-        return this.tablesIId.getUnchecked(tablesKey);
+    public YangInstanceIdentifier getRibOutIId(final NodeIdentifierWithPredicates tablekey) {
+        return this.tablesIId.getUnchecked(tablekey);
     }
 
     @Override
     public synchronized void onTransactionChainFailed(final DOMTransactionChain chain,
             final DOMDataTreeTransaction transaction, final Throwable cause) {
         LOG.error("Transaction domChain failed.", cause);
-        releaseConnection();
+        releaseConnection(true);
     }
 
-    @Override
-    public synchronized void onTransactionChainFailed(final TransactionChain chain, final Transaction transaction,
-            final Throwable cause) {
-        LOG.error("Transaction domChain failed.", cause);
-        releaseConnection();
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+        justification = "https://github.com/spotbugs/spotbugs/issues/811")
+    private synchronized void onRibOutChainFailed(final Throwable cause) {
+        LOG.error("RibOut transaction chain failed.", cause);
+        releaseConnection(false);
     }
 
     @Override
@@ -705,7 +740,7 @@ public class BGPPeer extends AbstractPeer implements BGPSessionListener {
         setGracefulPreferences(true, tablesToPreserve);
         this.currentSelectionDeferralTimerSeconds = selectionDeferralTimerSeconds;
         setLocalRestartingState(true);
-        return releaseConnection();
+        return releaseConnection(true);
     }
 
     @Override