Provide Add Path support for all AFI/SAFI
[bgpcep.git] / bgp / rib-impl / src / main / java / org / opendaylight / protocol / bgp / rib / impl / config / BgpDeployerImpl.java
index 9939b4667b971bea0fc3b8e3a6f577d8eef97b31..22482ac6af76d8df6db8287964c42cdbcc5dffd5 100644 (file)
@@ -8,39 +8,38 @@
 
 package org.opendaylight.protocol.bgp.rib.impl.config;
 
-import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceIdentifier;
-import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceName;
-import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getRibInstanceName;
+import static java.util.Objects.requireNonNull;
 
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import java.util.ArrayList;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Collection;
-import java.util.Dictionary;
 import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
 import javax.annotation.concurrent.GuardedBy;
 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
-import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
-import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
-import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroupKey;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
+import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
@@ -48,40 +47,51 @@ import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.re
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NetworkInstanceProtocol;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.blueprint.container.BlueprintContainer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public final class BgpDeployerImpl implements BgpDeployer, ClusteredDataTreeChangeListener<Bgp>, AutoCloseable {
+public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, PeerGroupConfigLoader,
+        AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
     private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
     private final BlueprintContainer container;
     private final BundleContext bundleContext;
     private final BGPTableTypeRegistryConsumer tableTypeRegistry;
-    private final ListenerRegistration<BgpDeployerImpl> registration;
-    @GuardedBy("this")
-    private final Map<InstanceIdentifier<Bgp>, RibImpl> ribs = new HashMap<>();
+    private final ClusterSingletonServiceProvider provider;
+    private final LoadingCache<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>> peerGroups = CacheBuilder.newBuilder()
+            .build(new CacheLoader<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>>() {
+                @Override
+                public Optional<PeerGroup> load(final InstanceIdentifier<PeerGroup> key)
+                        throws ExecutionException, InterruptedException {
+                    return loadPeerGroup(key);
+                }
+            });
+    private ListenerRegistration<BgpDeployerImpl> registration;
     @GuardedBy("this")
-    private final Map<InstanceIdentifier<Neighbor>, PeerBean> peers = new HashMap<>();
+    private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
     private final DataBroker dataBroker;
+    private final String networkInstanceName;
     @GuardedBy("this")
     private boolean closed;
 
-    public BgpDeployerImpl(final String networkInstanceName, final BlueprintContainer container,
-        final BundleContext bundleContext, final DataBroker dataBroker,
-        final BGPTableTypeRegistryConsumer mappingService) {
-        this.dataBroker = Preconditions.checkNotNull(dataBroker);
-        this.container = Preconditions.checkNotNull(container);
-        this.bundleContext = Preconditions.checkNotNull(bundleContext);
-        this.tableTypeRegistry = Preconditions.checkNotNull(mappingService);
+    public BgpDeployerImpl(final String networkInstanceName, final ClusterSingletonServiceProvider provider,
+            final BlueprintContainer container,
+            final BundleContext bundleContext, final DataBroker dataBroker,
+            final BGPTableTypeRegistryConsumer mappingService) {
+        this.dataBroker = requireNonNull(dataBroker);
+        this.provider = requireNonNull(provider);
+        this.networkInstanceName = requireNonNull(networkInstanceName);
+        this.container = requireNonNull(container);
+        this.bundleContext = requireNonNull(bundleContext);
+        this.tableTypeRegistry = requireNonNull(mappingService);
         this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
-            .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
+                .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
         Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
             @Override
             public void onSuccess(final Void result) {
@@ -92,11 +102,21 @@ public final class BgpDeployerImpl implements BgpDeployer, ClusteredDataTreeChan
             public void onFailure(final Throwable t) {
                 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
             }
-        });
-        this.registration = dataBroker.registerDataTreeChangeListener(
-            new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, this.networkInstanceIId.child(Protocols.class)
-                .child(Protocol.class).augmentation(Protocol1.class).child(Bgp.class)), this);
-        LOG.info("BGP Deployer {} started.", networkInstanceName);
+        }, MoreExecutors.directExecutor());
+    }
+
+    public synchronized void init() {
+        this.registration = this.dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
+                        this.networkInstanceIId.child(Protocols.class).child(Protocol.class)
+                                .augmentation(NetworkInstanceProtocol.class).child(Bgp.class)), this);
+        LOG.info("BGP Deployer {} started.", this.networkInstanceName);
+    }
+
+    private Optional<PeerGroup> loadPeerGroup(final InstanceIdentifier<PeerGroup> peerGroupIid)
+            throws ExecutionException, InterruptedException {
+        final ReadOnlyTransaction tr = this.dataBroker.newReadOnlyTransaction();
+        return tr.read(LogicalDatastoreType.CONFIGURATION, peerGroupIid).get().toJavaUtil();
     }
 
     @Override
@@ -109,233 +129,93 @@ public final class BgpDeployerImpl implements BgpDeployer, ClusteredDataTreeChan
             final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
             final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
             LOG.trace("BGP configuration has changed: {}", rootNode);
-            for (final DataObjectModification<? extends DataObject> dataObjectModification : rootNode.getModifiedChildren()) {
+            for (final DataObjectModification<? extends DataObject> dataObjectModification :
+                    rootNode.getModifiedChildren()) {
                 if (dataObjectModification.getDataType().equals(Global.class)) {
                     onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
                 } else if (dataObjectModification.getDataType().equals(Neighbors.class)) {
                     onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
+                } else if (dataObjectModification.getDataType().equals(PeerGroups.class)) {
+                    rebootNeighbors((DataObjectModification<PeerGroups>) dataObjectModification);
                 }
             }
         }
     }
 
-    @Override
-    public InstanceIdentifier<NetworkInstance> getInstanceIdentifier() {
-        return this.networkInstanceIId;
-    }
-
-    @Override
-    public synchronized void close() throws Exception {
-        LOG.info("Closing BGP Deployer.");
-        this.registration.close();
-        this.peers.values().forEach(PeerBean::close);
-        this.peers.clear();
-        this.ribs.values().forEach(RibImpl::close);
-        this.ribs.clear();
-        this.closed = true;
-    }
-
-    private static CheckedFuture<Void, TransactionCommitFailedException> initializeNetworkInstance(
-        final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
-        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
-        wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
-            new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
-                .setProtocols(new ProtocolsBuilder().build()).build());
-        return wTx.submit();
-    }
-
-    private synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
-        final InstanceIdentifier<Bgp> rootIdentifier) {
-        switch (dataObjectModification.getModificationType()) {
-        case DELETE:
-            onGlobalRemoved(rootIdentifier);
-            break;
-        case SUBTREE_MODIFIED:
-        case WRITE:
-            onGlobalModified(rootIdentifier, dataObjectModification.getDataAfter(), null);
-            break;
-        default:
-            break;
+    private synchronized void rebootNeighbors(final DataObjectModification<PeerGroups> dataObjectModification) {
+        PeerGroups peerGroups = dataObjectModification.getDataAfter();
+        if (peerGroups == null) {
+            peerGroups = dataObjectModification.getDataBefore();
         }
-    }
-
-    @Override
-    public synchronized void onGlobalModified(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
-        final WriteConfiguration configurationWriter) {
-        final RibImpl ribImpl = this.ribs.get(rootIdentifier);
-        if(ribImpl == null ) {
-            onGlobalCreated(rootIdentifier, global, configurationWriter);
-        } else if (!ribImpl.isGlobalEqual(global)) {
-            onGlobalUpdated(rootIdentifier, global, ribImpl, configurationWriter);
+        if (peerGroups == null) {
+            return;
+        }
+        for (final PeerGroup peerGroup: peerGroups.getPeerGroup()) {
+            this.bgpCss.values().forEach(css->css.restartNeighbors(peerGroup.getPeerGroupName()));
         }
-    }
-
-    private synchronized List<PeerBean> closeAllBindedPeers(final InstanceIdentifier<Bgp> rootIdentifier) {
-        final List<PeerBean> filtered = new ArrayList<>();
-        this.peers.entrySet().stream().filter(entry -> entry.getKey().firstIdentifierOf(Bgp.class)
-            .contains(rootIdentifier)).forEach(entry -> {final PeerBean peer = entry.getValue();
-            peer.close();
-            filtered.add(peer);
-        });
-        return filtered;
-    }
-
-    private synchronized void onGlobalCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
-        final WriteConfiguration configurationWriter) {
-        LOG.debug("Creating RIB instance with configuration: {}", global);
-        final RibImpl ribImpl = (RibImpl) this.container.getComponentInstance(InstanceType.RIB.getBeanName());
-        initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
-        this.ribs.put(rootIdentifier, ribImpl);
-        LOG.debug("RIB instance created: {}", ribImpl);
-    }
-
-    private synchronized void onGlobalUpdated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
-        final RibImpl ribImpl, final WriteConfiguration configurationWriter) {
-        LOG.debug("Modifying RIB instance with configuration: {}", global);
-        final List<PeerBean> closedPeers = closeAllBindedPeers(rootIdentifier);
-        ribImpl.close();
-        initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
-        closedPeers.forEach(peer -> peer.restart(ribImpl, this.tableTypeRegistry));
-        LOG.debug("RIB instance created: {}", ribImpl);
     }
 
     @Override
-    public synchronized void onGlobalRemoved(final InstanceIdentifier<Bgp> rootIdentifier) {
-        LOG.debug("Removing RIB instance: {}", rootIdentifier);
-        final RibImpl ribImpl = this.ribs.remove(rootIdentifier);
-        if (ribImpl != null) {
-            LOG.debug("RIB instance removed {}", ribImpl);
-            ribImpl.close();
+    public synchronized void close() {
+        LOG.info("Closing BGP Deployer.");
+        if (this.registration != null) {
+            this.registration.close();
+            this.registration = null;
         }
-    }
-
-    private synchronized void registerRibInstance(final RibImpl ribImpl, final String ribInstanceName) {
-        final Dictionary<String, String> properties = new Hashtable<>();
-        properties.put(InstanceType.RIB.getBeanName(), ribInstanceName);
-        final ServiceRegistration<?> serviceRegistration = this.bundleContext.registerService(
-            InstanceType.RIB.getServices(), ribImpl, properties);
-        ribImpl.setServiceRegistration(serviceRegistration);
-    }
-
-    private synchronized void initiateRibInstance(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
-        final RibImpl ribImpl, final WriteConfiguration configurationWriter) {
-        final String ribInstanceName = getRibInstanceName(rootIdentifier);
-        ribImpl.start(global, ribInstanceName, this.tableTypeRegistry, configurationWriter);
-        registerRibInstance(ribImpl, ribInstanceName);
-    }
+        this.closed = true;
 
-    private synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
-        final InstanceIdentifier<Bgp> rootIdentifier) {
-        for (final DataObjectModification<? extends DataObject> neighborModification : dataObjectModification.getModifiedChildren()) {
-            switch (neighborModification.getModificationType()) {
-            case DELETE:
-                onNeighborRemoved(rootIdentifier, (Neighbor) neighborModification.getDataBefore());
-                break;
-            case SUBTREE_MODIFIED:
-            case WRITE:
-                onNeighborModified(rootIdentifier, (Neighbor) neighborModification.getDataAfter(), null);
-                break;
-            default:
-                break;
+        this.bgpCss.values().iterator().forEachRemaining(service -> {
+            try {
+                service.close();
+            } catch (Exception e) {
+                LOG.warn("Failed to close BGP Cluster Singleton Service.");
             }
-        }
-    }
-
-    @Override
-    public synchronized void onNeighborModified(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor,
-        final WriteConfiguration configurationWriter) {
-        //restart peer instance with a new configuration
-        final PeerBean bgpPeer = this.peers.get(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
-        if (bgpPeer == null) {
-            onNeighborCreated(rootIdentifier, neighbor, configurationWriter);
-        } else if(!bgpPeer.containsEqualConfiguration(neighbor)){
-            onNeighborUpdated(bgpPeer, rootIdentifier, neighbor, configurationWriter);
-        }
-    }
+        });
 
-    private synchronized void onNeighborCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor,
-        final WriteConfiguration configurationWriter) {
-        LOG.debug("Creating Peer instance with configuration: {}", neighbor);
-        final PeerBean bgpPeer;
-        if (OpenConfigMappingUtil.isApplicationPeer(neighbor)) {
-            bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.APP_PEER.getBeanName());
-        } else {
-            bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.PEER.getBeanName());
-        }
-        final InstanceIdentifier<Neighbor> neighborInstanceIdentifier = getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey());
-        initiatePeerInstance(rootIdentifier, neighborInstanceIdentifier, neighbor, bgpPeer, configurationWriter);
-        this.peers.put(neighborInstanceIdentifier, bgpPeer);
-        LOG.debug("Peer instance created {}", bgpPeer);
     }
 
-    private synchronized void onNeighborUpdated(final PeerBean bgpPeer, final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor,
-            final WriteConfiguration configurationWriter) {
-        LOG.debug("Updating Peer instance with configuration: {}", neighbor);
-        bgpPeer.close();
-        final InstanceIdentifier<Neighbor> neighborInstanceIdentifier = getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey());
-        initiatePeerInstance(rootIdentifier, neighborInstanceIdentifier, neighbor, bgpPeer, configurationWriter);
-        LOG.debug("Peer instance updated {}", bgpPeer);
+    private static ListenableFuture<Void> initializeNetworkInstance(
+            final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
+        final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
+        wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
+                new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
+                        .setProtocols(new ProtocolsBuilder().build()).build());
+        return wTx.submit();
     }
 
-    @Override
-    public synchronized void onNeighborRemoved(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor) {
-        LOG.debug("Removing Peer instance: {}", rootIdentifier);
-        final PeerBean bgpPeer = this.peers.remove(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
-        if (bgpPeer != null) {
-            bgpPeer.close();
-            LOG.debug("Peer instance removed {}", bgpPeer);
+    @VisibleForTesting
+    synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
+            final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
+        BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
+        if (old == null) {
+            old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
+                    this.container, this.bundleContext, bgpInstanceIdentifier);
+            this.bgpCss.put(bgpInstanceIdentifier, old);
         }
+        old.onGlobalChanged(dataObjectModification);
     }
 
-    private synchronized void registerPeerInstance(final BgpPeer bgpPeer, final String peerInstanceName) {
-        final Dictionary<String, String> properties = new Hashtable<>();
-        properties.put(InstanceType.PEER.getBeanName(), peerInstanceName);
-        final ServiceRegistration<?> serviceRegistration = this.bundleContext
-            .registerService(InstanceType.PEER.getServices(), bgpPeer, properties);
-        bgpPeer.setServiceRegistration(serviceRegistration);
-    }
-
-    private synchronized void registerAppPeerInstance(final AppPeer appPeer, final String peerInstanceName) {
-        final Dictionary<String, String> properties = new Hashtable<>();
-        properties.put(InstanceType.PEER.getBeanName(), peerInstanceName);
-        final ServiceRegistration<?> serviceRegistration = this.bundleContext
-            .registerService(InstanceType.APP_PEER.getServices(), appPeer, properties);
-        appPeer.setServiceRegistration(serviceRegistration);
-    }
-
-    private synchronized void initiatePeerInstance(final InstanceIdentifier<Bgp> rootIdentifier,
-        final InstanceIdentifier<Neighbor> neighborIdentifier, final Neighbor neighbor,
-        final PeerBean bgpPeer, final WriteConfiguration configurationWriter) {
-        final String peerInstanceName = getNeighborInstanceName(neighborIdentifier);
-        final RibImpl rib = this.ribs.get(rootIdentifier);
-        if (rib != null) {
-            bgpPeer.start(rib, neighbor, this.tableTypeRegistry, configurationWriter);
-            if (bgpPeer instanceof BgpPeer) {
-                registerPeerInstance((BgpPeer) bgpPeer, peerInstanceName);
-            } else if(bgpPeer instanceof AppPeer) {
-                registerAppPeerInstance((AppPeer) bgpPeer, peerInstanceName);
-            }
+    @VisibleForTesting
+    synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
+            final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
+        BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
+        if (old == null) {
+            old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
+                    this.container, this.bundleContext, bgpInstanceIdentifier);
+            this.bgpCss.put(bgpInstanceIdentifier, old);
         }
+        old.onNeighborsChanged(dataObjectModification);
     }
 
-    @Override
-    public BGPTableTypeRegistryConsumer getTableTypeRegistry() {
+    @VisibleForTesting
+    BGPTableTypeRegistryConsumer getTableTypeRegistry() {
         return this.tableTypeRegistry;
     }
 
     @Override
-    public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data,
-        final InstanceIdentifier<T> identifier) {
-        final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
-        wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data, true);
-        return wTx.submit();
-    }
-
-    @Override
-    public <T extends DataObject> ListenableFuture<Void> removeConfiguration(
-        final InstanceIdentifier<T> identifier) {
-        final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
-        wTx.delete(LogicalDatastoreType.CONFIGURATION, identifier);
-        return wTx.submit();
+    public PeerGroup getPeerGroup(final InstanceIdentifier<Bgp> bgpIid, final String peerGroupName) {
+        final InstanceIdentifier<PeerGroup> peerGroupsIid =
+        bgpIid.child(PeerGroups.class).child(PeerGroup.class, new PeerGroupKey(peerGroupName));
+        return this.peerGroups.getUnchecked(peerGroupsIid).orElse(null);
     }
 }