BGPCEP-685: Add Peer Release session rpc
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / BGPPeer.java
index da0c276682e14b2d458277fb39e18ceca89ccacd..3c091107c7206a7ffa4636f0ae13ab74070fafd9 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.protocol.bgp.rib.impl;
 
+import static java.util.Objects.requireNonNull;
 import static org.opendaylight.protocol.bgp.rib.impl.AdjRibInWriter.isAnnounceNone;
 import static org.opendaylight.protocol.bgp.rib.impl.AdjRibInWriter.isLearnNone;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
-import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.net.InetAddresses;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -23,6 +26,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
 import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeMXBean;
 import org.opendaylight.controller.config.yang.bgp.rib.impl.BGPPeerRuntimeRegistration;
@@ -41,15 +45,26 @@ import org.opendaylight.protocol.bgp.parser.impl.message.update.LocalPreferenceA
 import org.opendaylight.protocol.bgp.parser.spi.MessageUtil;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIB;
 import org.opendaylight.protocol.bgp.rib.impl.spi.RIBSupportContext;
+import org.opendaylight.protocol.bgp.rib.impl.state.BGPPeerStateImpl;
+import org.opendaylight.protocol.bgp.rib.impl.state.BGPSessionStateProvider;
 import org.opendaylight.protocol.bgp.rib.impl.stats.peer.BGPPeerStats;
 import org.opendaylight.protocol.bgp.rib.impl.stats.peer.BGPPeerStatsImpl;
 import org.opendaylight.protocol.bgp.rib.impl.stats.peer.BGPSessionStats;
 import org.opendaylight.protocol.bgp.rib.spi.BGPSession;
 import org.opendaylight.protocol.bgp.rib.spi.BGPSessionListener;
 import org.opendaylight.protocol.bgp.rib.spi.BGPTerminationReason;
+import org.opendaylight.protocol.bgp.rib.spi.ExportPolicyPeerTracker;
 import org.opendaylight.protocol.bgp.rib.spi.IdentifierUtils;
 import org.opendaylight.protocol.bgp.rib.spi.Peer;
 import org.opendaylight.protocol.bgp.rib.spi.RouterIds;
+import org.opendaylight.protocol.bgp.rib.spi.state.BGPAfiSafiState;
+import org.opendaylight.protocol.bgp.rib.spi.state.BGPErrorHandlingState;
+import org.opendaylight.protocol.bgp.rib.spi.state.BGPSessionState;
+import org.opendaylight.protocol.bgp.rib.spi.state.BGPTimersState;
+import org.opendaylight.protocol.bgp.rib.spi.state.BGPTransportState;
+import org.opendaylight.protocol.concepts.AbstractRegistration;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.DestinationIpv4Builder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet.rev150305.ipv4.prefixes.destination.ipv4.Ipv4Prefixes;
@@ -58,7 +73,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.inet
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.Update;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.Attributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.path.attributes.AttributesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpAddPathTableType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.BgpTableType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.RouteRefresh;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.SendReceive;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.mp.capabilities.add.path.capability.AddressFamilies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.MpReachNlriBuilder;
@@ -66,8 +84,8 @@ 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.rev130919.update.attributes.MpUnreachNlriBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.reach.nlri.AdvertizedRoutesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.multiprotocol.rev130919.update.attributes.mp.unreach.nlri.WithdrawnRoutesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev160322.BgpPeerRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev160322.PeerContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev171027.BgpPeerRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.peer.rpc.rev171027.PeerContext;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.PeerRole;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.SimpleRoutingPolicy;
@@ -87,8 +105,8 @@ import org.slf4j.LoggerFactory;
  * Class representing a peer. We have a single instance for each peer, which provides translation from BGP events into
  * RIB actions.
  */
-public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeerRuntimeMXBean, TransactionChainListener {
-
+public class BGPPeer extends BGPPeerStateImpl implements BGPSessionListener, Peer, BGPPeerRuntimeMXBean,
+    TransactionChainListener {
     private static final Logger LOG = LoggerFactory.getLogger(BGPPeer.class);
 
     @GuardedBy("this")
@@ -108,38 +126,49 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
     private final String name;
     private BGPPeerRuntimeRegistrator registrator;
     private BGPPeerRuntimeRegistration runtimeReg;
-    private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap();
+    private final Map<TablesKey, AdjRibOutListener> adjRibOutListenerSet = new HashMap<>();
     private final RpcProviderRegistry rpcRegistry;
     private RoutedRpcRegistration<BgpPeerRpcService> rpcRegistration;
     private final PeerRole peerRole;
     private final Optional<SimpleRoutingPolicy> simpleRoutingPolicy;
     private final BGPPeerStats peerStats;
-
-    public BGPPeer(final String name, final RIB rib, final PeerRole role, final SimpleRoutingPolicy peerStatus, final RpcProviderRegistry rpcRegistry) {
+    private YangInstanceIdentifier peerIId;
+    private final Set<AbstractRegistration> tableRegistration = new HashSet<>();
+
+    public BGPPeer(final String name, final RIB rib, final PeerRole role, final SimpleRoutingPolicy peerStatus,
+        final RpcProviderRegistry rpcRegistry,
+        @Nonnull final Set<TablesKey> afiSafisAdvertized,
+        @Nonnull final Set<TablesKey> afiSafisGracefulAdvertized) {
+        //FIXME BUG-6971 Once Peer Group is implemented, pass it
+        super(rib.getInstanceIdentifier(), null, new IpAddress(new Ipv4Address(name)), afiSafisAdvertized,
+            afiSafisGracefulAdvertized);
         this.peerRole = role;
         this.simpleRoutingPolicy = Optional.ofNullable(peerStatus);
-        this.rib = Preconditions.checkNotNull(rib);
+        this.rib = requireNonNull(rib);
         this.name = name;
         this.rpcRegistry = rpcRegistry;
-        this.peerStats = new BGPPeerStatsImpl(this.name, this.tables);
-
-        // add current peer to "configured BGP peer" stats
-        this.rib.getRenderStats().getConfiguredPeerCounter().increaseCount();
+        this.peerStats = new BGPPeerStatsImpl(this.name, this.tables, this);
         this.chain = rib.createPeerChain(this);
     }
 
-    public BGPPeer(final String name, final RIB rib, final PeerRole role, final RpcProviderRegistry rpcRegistry) {
-        this(name, rib, role, null, rpcRegistry);
+    public BGPPeer(final String name, final RIB rib, final PeerRole role,
+        final RpcProviderRegistry rpcRegistry, @Nonnull final Set<TablesKey> afiSafisAdvertized,
+        @Nonnull final Set<TablesKey> afiSafisGracefulAdvertized) {
+        this(name, rib, role, null, rpcRegistry, afiSafisAdvertized, afiSafisGracefulAdvertized);
     }
 
     public void instantiateServiceInstance() {
-        this.ribWriter = AdjRibInWriter.create(rib.getYangRibId(), this.peerRole, this.simpleRoutingPolicy, this.chain);
+        // add current peer to "configured BGP peer" stats
+        this.rib.getRenderStats().getConfiguredPeerCounter().increment();
+        this.ribWriter = AdjRibInWriter.create(this.rib.getYangRibId(), this.peerRole, this.simpleRoutingPolicy, this.chain);
     }
 
+    // FIXME ListenableFuture<?> should be used once closeServiceInstance uses wildcard too
     @Override
-    public synchronized void close() {
-        releaseConnection();
+    public synchronized ListenableFuture<Void> close() {
+        final ListenableFuture<Void> future = releaseConnection();
         this.chain.close();
+        return future;
     }
 
     @Override
@@ -278,42 +307,62 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
 
     @Override
     public synchronized void onSessionUp(final BGPSession session) {
-        final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
-        LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name, addPathTablesType,
-                session.getAdvertisedAddPathTableTypes());
         this.session = session;
+        if (this.session instanceof BGPSessionStateProvider) {
+            ((BGPSessionStateProvider) this.session).registerMessagesCounter(this);
+        }
 
+        final List<AddressFamilies> addPathTablesType = session.getAdvertisedAddPathTableTypes();
+        final Set<BgpTableType> advertizedTableTypes = session.getAdvertisedTableTypes();
+        final List<BgpTableType> advertizedGracefulRestartTableTypes = session.getAdvertisedGracefulRestartTableTypes();
+        LOG.info("Session with peer {} went up with tables {} and Add Path tables {}", this.name, advertizedTableTypes, addPathTablesType);
         this.rawIdentifier = InetAddresses.forString(session.getBgpId().getValue()).getAddress();
         final PeerId peerId = RouterIds.createPeerId(session.getBgpId());
 
-        this.tables.addAll(this.session.getAdvertisedTableTypes().stream().map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
+        this.tables.addAll(advertizedTableTypes.stream().map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
+
+        setAdvertizedGracefulRestartTableTypes(advertizedGracefulRestartTableTypes.stream()
+            .map(t -> new TablesKey(t.getAfi(), t.getSafi())).collect(Collectors.toList()));
         final boolean announceNone = isAnnounceNone(this.simpleRoutingPolicy);
+        final Map<TablesKey, SendReceive> addPathTableMaps = mapTableTypesFamilies(addPathTablesType);
+        this.peerIId = this.rib.getYangRibId().node(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer.QNAME)
+            .node(IdentifierUtils.domPeerId(peerId));
+
         if(!announceNone) {
             createAdjRibOutListener(peerId);
         }
+        this.tables.forEach(tablesKey -> {
+            final ExportPolicyPeerTracker exportTracker = this.rib.getExportPolicyPeerTracker(tablesKey);
+            if (exportTracker != null) {
+                this.tableRegistration.add(exportTracker.registerPeer(peerId, addPathTableMaps.get(tablesKey), this.peerIId, this.peerRole,
+                    this.simpleRoutingPolicy));
+            }
+        });
         addBgp4Support(peerId, announceNone);
 
         if(!isLearnNone(this.simpleRoutingPolicy)) {
-            final YangInstanceIdentifier peerIId = this.rib.getYangRibId().node(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer.QNAME).node(IdentifierUtils.domPeerId(peerId));
-            this.effRibInWriter = EffectiveRibInWriter.create(this.rib.getService(), this.rib.createPeerChain(this), peerIId, this.rib.getImportPolicyPeerTracker(),
-                    this.rib.getRibSupportContext(), this.peerRole, this.peerStats.getEffectiveRibInRouteCounters(), this.peerStats.getAdjRibInRouteCounters());
+            this.effRibInWriter = EffectiveRibInWriter.create(this.rib.getService(), this.rib.createPeerChain(this),
+                this.peerIId, this.rib.getImportPolicyPeerTracker(), this.rib.getRibSupportContext(), this.peerRole,
+                this.peerStats.getAdjRibInRouteCounters(), this.tables);
+            registerPrefixesCounters(this.effRibInWriter, this.effRibInWriter);
         }
-        this.ribWriter = this.ribWriter.transform(peerId, this.rib.getRibSupportContext(), this.tables, addPathTablesType);
+        this.ribWriter = this.ribWriter.transform(peerId, this.rib.getRibSupportContext(), this.tables, addPathTableMaps);
 
         // register BGP Peer stats
-        this.peerStats.getSessionEstablishedCounter().increaseCount();
+        this.peerStats.getSessionEstablishedCounter().increment();
         if (this.registrator != null) {
             this.runtimeReg = this.registrator.register(this);
         }
 
         if (this.rpcRegistry != null) {
-            this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class, new BgpPeerRpc(session, this.tables));
+            this.rpcRegistration = this.rpcRegistry.addRoutedRpcImplementation(BgpPeerRpcService.class,
+                    new BgpPeerRpc(this, session, this.tables));
             final KeyedInstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer, PeerKey> path =
                     this.rib.getInstanceIdentifier().child(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.rib.rev130925.bgp.rib.rib.Peer.class, new PeerKey(peerId));
             this.rpcRegistration.registerPath(PeerContext.class, path);
         }
 
-        this.rib.getRenderStats().getConnectedPeerCounter().increaseCount();
+        this.rib.getRenderStats().getConnectedPeerCounter().increment();
     }
 
     private void createAdjRibOutListener(final PeerId peerId) {
@@ -333,22 +382,27 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
 
         // not particularly nice
         if (context != null && this.session instanceof BGPSessionImpl) {
-            this.adjRibOutListenerSet.put(key, AdjRibOutListener.create(peerId, key, this.rib.getYangRibId(), this.rib.getCodecsRegistry(),
-                    context.getRibSupport(), this.rib.getService(), ((BGPSessionImpl) this.session).getLimiter(), mpSupport, this.peerStats.getAdjRibOutRouteCounters().init(key)));
+            final ChannelOutputLimiter limiter = ((BGPSessionImpl) this.session).getLimiter();
+            final AdjRibOutListener adjRibOut = AdjRibOutListener.create(peerId, key,
+                this.rib.getYangRibId(), this.rib.getCodecsRegistry(), context.getRibSupport(),
+                this.rib.getService(), limiter, mpSupport, this.peerStats.getAdjRibOutRouteCounters().init(key));
+            this.adjRibOutListenerSet.put(key, adjRibOut);
+            registerPrefixesSentCounter(key, adjRibOut);
         }
     }
 
-    private void cleanup() {
+    private ListenableFuture<Void> cleanup() {
         // FIXME: BUG-196: support graceful
         this.adjRibOutListenerSet.values().forEach(AdjRibOutListener::close);
         this.adjRibOutListenerSet.clear();
         if (this.effRibInWriter != null) {
             this.effRibInWriter.close();
         }
-        if(this.ribWriter != null) {
-            this.ribWriter.removePeer();
-        }
         this.tables.clear();
+        if (this.ribWriter != null) {
+            return this.ribWriter.removePeer();
+        }
+        return Futures.immediateFuture(null);
     }
 
     @Override
@@ -384,20 +438,22 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
     }
 
     @Override
-    @GuardedBy("this")
-    public synchronized void releaseConnection() {
+    public synchronized ListenableFuture<Void> releaseConnection() {
         if (this.rpcRegistration != null) {
             this.rpcRegistration.close();
         }
-        addPeerToDisconnectedSharedList();
-        cleanup();
+        closeRegistration();
+        final ListenableFuture<Void> future = cleanup();
         dropConnection();
+        resetState();
+        return future;
     }
 
-    private void addPeerToDisconnectedSharedList() {
-        if(this.session != null) {
-            this.rib.getCacheDisconnectedPeers().insertDesconectedPeer(this.session.getBgpId());
+    private void closeRegistration() {
+        for (final AbstractRegistration tableCloseable : this.tableRegistration) {
+            tableCloseable.close();
         }
+        this.tableRegistration.clear();
     }
 
     private void dropConnection() {
@@ -413,7 +469,7 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
             }
             this.session = null;
 
-            this.rib.getRenderStats().getConnectedPeerCounter().decreaseCount();
+            this.rib.getRenderStats().getConnectedPeerCounter().decrement();
         }
     }
 
@@ -465,4 +521,43 @@ public class BGPPeer implements BGPSessionListener, Peer, AutoCloseable, BGPPeer
     public void markUptodate(final TablesKey tablesKey) {
         this.ribWriter.markTableUptodate(tablesKey);
     }
+
+    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)));
+    }
+
+    @Override
+    public BGPErrorHandlingState getBGPErrorHandlingState() {
+        return this;
+    }
+
+    @Override
+    public BGPAfiSafiState getBGPAfiSafiState() {
+        return this;
+    }
+
+    @Override
+    public BGPSessionState getBGPSessionState() {
+        if (this.session instanceof BGPSessionStateProvider) {
+            return ((BGPSessionStateProvider) this.session).getBGPSessionState();
+        }
+        return null;
+    }
+
+    @Override
+    public BGPTimersState getBGPTimersState() {
+        if (this.session instanceof BGPSessionStateProvider) {
+            return ((BGPSessionStateProvider) this.session).getBGPTimersState();
+        }
+        return null;
+    }
+
+    @Override
+    public BGPTransportState getBGPTransportState() {
+        if (this.session instanceof BGPSessionStateProvider) {
+            return ((BGPSessionStateProvider) this.session).getBGPTransportState();
+        }
+        return null;
+    }
 }