2 * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.protocol.bgp.rib.impl.config;
11 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceIdentifier;
12 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getNeighborInstanceName;
13 import static org.opendaylight.protocol.bgp.rib.impl.config.OpenConfigMappingUtil.getRibInstanceName;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import com.google.common.util.concurrent.SettableFuture;
20 import java.util.ArrayList;
21 import java.util.Dictionary;
22 import java.util.HashMap;
23 import java.util.Hashtable;
24 import java.util.List;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.atomic.AtomicBoolean;
28 import java.util.stream.Collectors;
29 import javax.annotation.Nonnull;
30 import javax.annotation.concurrent.GuardedBy;
31 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
32 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonService;
33 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
34 import org.opendaylight.mdsal.singleton.common.api.ServiceGroupIdentifier;
35 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
36 import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
37 import org.opendaylight.protocol.bgp.rib.spi.util.ClusterSingletonServiceRegistrationHelper;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.osgi.framework.BundleContext;
45 import org.osgi.framework.ServiceRegistration;
46 import org.osgi.service.blueprint.container.BlueprintContainer;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public final class BGPClusterSingletonService implements ClusterSingletonService, AutoCloseable {
52 private static final Logger LOG = LoggerFactory.getLogger(BGPClusterSingletonService.class);
54 private static final long TIMEOUT_NS = TimeUnit.SECONDS.toNanos(5);
55 private final InstanceIdentifier<Bgp> bgpIid;
57 private final Map<InstanceIdentifier<Neighbor>, PeerBean> peers = new HashMap<>();
58 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
59 private final BlueprintContainer container;
60 private final BundleContext bundleContext;
61 private final ServiceGroupIdentifier serviceGroupIdentifier;
62 private final AtomicBoolean instantiated = new AtomicBoolean(false);
63 private RibImpl ribImpl;
65 BGPClusterSingletonService(
66 @Nonnull final ClusterSingletonServiceProvider provider,
67 @Nonnull final BGPTableTypeRegistryConsumer tableTypeRegistry,
68 @Nonnull final BlueprintContainer container,
69 @Nonnull final BundleContext bundleContext,
70 @Nonnull final InstanceIdentifier<Bgp> bgpIid) {
71 this.tableTypeRegistry = tableTypeRegistry;
72 this.container = container;
73 this.bundleContext = bundleContext;
75 final String ribInstanceName = getRibInstanceName(bgpIid);
76 this.serviceGroupIdentifier = ServiceGroupIdentifier.create(ribInstanceName + "-service-group");
77 LOG.info("BGPClusterSingletonService {} registered", this.serviceGroupIdentifier.getValue());
78 ClusterSingletonServiceRegistrationHelper
79 .registerSingletonService(provider, this);
83 public synchronized void instantiateServiceInstance() {
84 if (this.ribImpl != null) {
85 this.ribImpl.instantiateServiceInstance();
86 this.peers.values().forEach(PeerBean::instantiateServiceInstance);
88 this.instantiated.set(true);
89 LOG.info("BGPClusterSingletonService {} instantiated", this.serviceGroupIdentifier.getValue());
93 public synchronized ListenableFuture<Void> closeServiceInstance() {
94 LOG.info("BGPClusterSingletonService {} close service instance", this.serviceGroupIdentifier.getValue());
95 this.instantiated.set(false);
97 final List<ListenableFuture<Void>> futurePeerCloseList = this.peers.values().stream()
98 .map(PeerBean::closeServiceInstance).collect(Collectors.toList());
99 final SettableFuture<Void> done = SettableFuture.create();
100 Futures.addCallback(Futures.allAsList(futurePeerCloseList), new FutureCallback<List<Void>>() {
102 public void onSuccess(final List<Void> result) {
103 done.setFuture(BGPClusterSingletonService.this.ribImpl.closeServiceInstance());
107 public void onFailure(final Throwable throwable) {
108 LOG.warn("Failed removing peers {}", throwable);
110 }, MoreExecutors.directExecutor());
116 public ServiceGroupIdentifier getIdentifier() {
117 return this.serviceGroupIdentifier;
120 synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification) {
121 switch (dataObjectModification.getModificationType()) {
123 LOG.debug("Removing RIB instance: {}", this.bgpIid);
124 if (this.ribImpl != null) {
125 LOG.debug("RIB instance removed {}", this.ribImpl);
126 closeAllBindedPeers();
130 case SUBTREE_MODIFIED:
132 final Global global = dataObjectModification.getDataAfter();
133 if (this.ribImpl == null) {
134 onGlobalCreated(global);
135 } else if (!this.ribImpl.isGlobalEqual(global)) {
136 onGlobalUpdated(global);
144 private synchronized void onGlobalCreated(final Global global) {
145 LOG.debug("Creating RIB instance with configuration: {}", global);
146 this.ribImpl = (RibImpl) this.container.getComponentInstance(InstanceType.RIB.getBeanName());
147 initiateRibInstance(global, this.ribImpl);
148 LOG.debug("RIB instance created: {}", this.ribImpl);
151 private synchronized void onGlobalUpdated(final Global global) {
152 LOG.debug("Modifying RIB instance with configuration: {}", global);
153 final List<PeerBean> closedPeers = closeAllBindedPeers();
155 initiateRibInstance(global, this.ribImpl);
156 for(final PeerBean peer :closedPeers) {
157 peer.restart(this.ribImpl, this.tableTypeRegistry);
159 if (this.instantiated.get()) {
160 closedPeers.forEach(PeerBean::instantiateServiceInstance);
162 LOG.debug("RIB instance created: {}", this.ribImpl);
165 private void closeRibService() {
167 this.ribImpl.closeServiceInstance().get(TIMEOUT_NS, TimeUnit.NANOSECONDS);
168 } catch (final Exception e) {
169 LOG.error("RIB instance failed to close service instance", e);
171 this.ribImpl.close();
174 private synchronized void initiateRibInstance(final Global global, final RibImpl ribImpl) {
175 final String ribInstanceName = getRibInstanceName(this.bgpIid);
176 ribImpl.start(global, ribInstanceName, this.tableTypeRegistry);
177 registerRibInstance(ribImpl, ribInstanceName);
178 if (this.instantiated.get()) {
179 this.ribImpl.instantiateServiceInstance();
183 private synchronized List<PeerBean> closeAllBindedPeers() {
184 final List<PeerBean> filtered = new ArrayList<>();
185 this.peers.forEach((key, peer) -> {
187 peer.closeServiceInstance().get();
188 } catch (final Exception e) {
189 LOG.error("Peer instance failed to close service instance", e);
197 private synchronized void registerRibInstance(final RibImpl ribImpl, final String ribInstanceName) {
198 final Dictionary<String, String> properties = new Hashtable<>();
199 properties.put(InstanceType.RIB.getBeanName(), ribInstanceName);
200 final ServiceRegistration<?> serviceRegistration = this.bundleContext.registerService(
201 InstanceType.RIB.getServices(), ribImpl, properties);
202 ribImpl.setServiceRegistration(serviceRegistration);
206 public void close() throws Exception {
207 LOG.info("BGPClusterSingletonService {} close", this.serviceGroupIdentifier.getValue());
208 this.peers.values().iterator().forEachRemaining(PeerBean::close);
209 this.ribImpl.close();
214 synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification) {
215 for (final DataObjectModification<? extends DataObject> neighborModification :
216 dataObjectModification.getModifiedChildren()) {
217 switch (neighborModification.getModificationType()) {
219 onNeighborRemoved((Neighbor) neighborModification.getDataBefore());
221 case SUBTREE_MODIFIED:
223 onNeighborModified((Neighbor) neighborModification.getDataAfter());
231 private synchronized void onNeighborModified(final Neighbor neighbor) {
232 //restart peer instance with a new configuration
233 final PeerBean bgpPeer = this.peers.get(getNeighborInstanceIdentifier(this.bgpIid, neighbor.getKey()));
234 if (bgpPeer == null) {
235 onNeighborCreated(neighbor);
236 } else if (!bgpPeer.containsEqualConfiguration(neighbor)) {
237 onNeighborUpdated(bgpPeer, neighbor);
242 private synchronized void onNeighborCreated(final Neighbor neighbor) {
243 LOG.debug("Creating Peer instance with configuration: {}", neighbor);
244 final PeerBean bgpPeer;
245 if (OpenConfigMappingUtil.isApplicationPeer(neighbor)) {
246 bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.APP_PEER.getBeanName());
248 bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.PEER.getBeanName());
250 final InstanceIdentifier<Neighbor> neighborInstanceIdentifier =
251 getNeighborInstanceIdentifier(this.bgpIid, neighbor.getKey());
252 initiatePeerInstance(neighborInstanceIdentifier, neighbor, bgpPeer);
253 this.peers.put(neighborInstanceIdentifier, bgpPeer);
254 LOG.debug("Peer instance created {}", bgpPeer);
257 private synchronized void onNeighborUpdated(final PeerBean bgpPeer, final Neighbor neighbor) {
258 LOG.debug("Updating Peer instance with configuration: {}", neighbor);
261 final InstanceIdentifier<Neighbor> neighborInstanceIdentifier = getNeighborInstanceIdentifier(this.bgpIid,
263 initiatePeerInstance(neighborInstanceIdentifier, neighbor, bgpPeer);
264 LOG.debug("Peer instance updated {}", bgpPeer);
267 private void closePeer(final PeerBean bgpPeer) {
268 if (bgpPeer != null) {
270 bgpPeer.closeServiceInstance().get();
272 LOG.debug("Peer instance closed {}", bgpPeer);
273 } catch (final Exception e) {
274 LOG.error("Peer instance failed to close service instance", e);
279 private synchronized void onNeighborRemoved(final Neighbor neighbor) {
280 LOG.debug("Removing Peer instance: {}", neighbor);
281 final PeerBean bgpPeer = this.peers.remove(getNeighborInstanceIdentifier(this.bgpIid, neighbor.getKey()));
285 private synchronized void registerPeerInstance(final BgpPeer bgpPeer, final String peerInstanceName) {
286 final Dictionary<String, String> properties = new Hashtable<>();
287 properties.put(InstanceType.PEER.getBeanName(), peerInstanceName);
288 final ServiceRegistration<?> serviceRegistration = this.bundleContext
289 .registerService(InstanceType.PEER.getServices(), bgpPeer, properties);
290 bgpPeer.setServiceRegistration(serviceRegistration);
293 private synchronized void registerAppPeerInstance(final AppPeer appPeer, final String peerInstanceName) {
294 final Dictionary<String, String> properties = new Hashtable<>();
295 properties.put(InstanceType.PEER.getBeanName(), peerInstanceName);
296 final ServiceRegistration<?> serviceRegistration = this.bundleContext
297 .registerService(InstanceType.APP_PEER.getServices(), appPeer, properties);
298 appPeer.setServiceRegistration(serviceRegistration);
301 private synchronized void initiatePeerInstance(final InstanceIdentifier<Neighbor> neighborIdentifier,
302 final Neighbor neighbor, final PeerBean bgpPeer) {
303 final String peerInstanceName = getNeighborInstanceName(neighborIdentifier);
304 if (this.ribImpl != null) {
305 bgpPeer.start(this.ribImpl, neighbor, this.tableTypeRegistry);
306 if (bgpPeer instanceof BgpPeer) {
307 registerPeerInstance((BgpPeer) bgpPeer, peerInstanceName);
308 } else if (bgpPeer instanceof AppPeer) {
309 registerAppPeerInstance((AppPeer) bgpPeer, peerInstanceName);
312 if (this.instantiated.get()) {
313 bgpPeer.instantiateServiceInstance();