2 * Copyright (c) 2016 Cisco Systems, Inc. and others. 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.base.Preconditions;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Dictionary;
23 import java.util.HashMap;
24 import java.util.Hashtable;
25 import java.util.List;
27 import java.util.Map.Entry;
28 import javax.annotation.concurrent.GuardedBy;
29 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
32 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
33 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
34 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
38 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
39 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
40 import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbors.Neighbor;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
53 import org.opendaylight.yangtools.concepts.ListenerRegistration;
54 import org.opendaylight.yangtools.yang.binding.DataObject;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.osgi.framework.BundleContext;
57 import org.osgi.framework.ServiceRegistration;
58 import org.osgi.service.blueprint.container.BlueprintContainer;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 public final class BgpDeployerImpl implements BgpDeployer, ClusteredDataTreeChangeListener<Bgp>, AutoCloseable {
63 private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
64 private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
65 private final BlueprintContainer container;
66 private final BundleContext bundleContext;
67 private final BGPOpenConfigMappingService mappingService;
68 private final ListenerRegistration<BgpDeployerImpl> registration;
70 private final Map<InstanceIdentifier<Bgp>, RibImpl> ribs = new HashMap<>();
72 private final Map<InstanceIdentifier<Neighbor>, PeerBean> peers = new HashMap<>();
73 private final DataBroker dataBroker;
75 private boolean closed;
77 public BgpDeployerImpl(final String networkInstanceName, final BlueprintContainer container, final BundleContext bundleContext, final DataBroker dataBroker,
78 final BGPOpenConfigMappingService mappingService) {
79 this.dataBroker = Preconditions.checkNotNull(dataBroker);
80 this.container = Preconditions.checkNotNull(container);
81 this.bundleContext = Preconditions.checkNotNull(bundleContext);
82 this.mappingService = Preconditions.checkNotNull(mappingService);
83 this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
84 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
85 Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
87 public void onSuccess(final Void result) {
88 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
92 public void onFailure(final Throwable t) {
93 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
96 this.registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
97 this.networkInstanceIId.child(Protocols.class).child(Protocol.class).augmentation(Protocol1.class).child(Bgp.class)), this);
98 LOG.info("BGP Deployer {} started.", networkInstanceName);
102 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
104 LOG.trace("BGP Deployer was already closed, skipping changes.");
107 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
108 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
109 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
110 LOG.trace("BGP configuration has changed: {}", rootNode);
111 for (final DataObjectModification<? extends DataObject> dataObjectModification : rootNode.getModifiedChildren()) {
112 if (dataObjectModification.getDataType().equals(Global.class)) {
113 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
114 } else if (dataObjectModification.getDataType().equals(Neighbors.class)) {
115 onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
122 public InstanceIdentifier<NetworkInstance> getInstanceIdentifier() {
123 return this.networkInstanceIId;
127 public synchronized void close() throws Exception {
128 this.registration.close();
129 this.peers.values().forEach(PeerBean::close);
131 this.ribs.values().forEach(RibImpl::close);
136 private static CheckedFuture<Void, TransactionCommitFailedException> initializeNetworkInstance(final DataBroker dataBroker,
137 final InstanceIdentifier<NetworkInstance> networkInstance) {
138 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
139 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
140 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName()).setProtocols(new ProtocolsBuilder().build()).build());
144 private void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
145 final InstanceIdentifier<Bgp> rootIdentifier) {
146 switch (dataObjectModification.getModificationType()) {
148 onGlobalRemoved(rootIdentifier);
150 case SUBTREE_MODIFIED:
152 onGlobalModified(rootIdentifier, dataObjectModification.getDataAfter(), null);
160 public synchronized void onGlobalModified(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
161 final WriteConfiguration configurationWriter) {
162 LOG.debug("Modifying RIB instance with configuration: {}", global);
163 //restart existing rib instance with a new configuration
164 final RibImpl ribImpl = this.ribs.get(rootIdentifier);
165 if(ribImpl == null ) {
166 onGlobalCreated(rootIdentifier, global, configurationWriter);
167 } else if (!ribImpl.isGlobalEqual(global)) {
168 final List<PeerBean> closedPeers = closeAllBindedPeers(rootIdentifier);
170 initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
171 closedPeers.forEach(peer -> peer.restart(ribImpl, this.mappingService));
173 LOG.debug("RIB instance modified {}", ribImpl);
176 private List<PeerBean> closeAllBindedPeers(final InstanceIdentifier<Bgp> rootIdentifier) {
177 final List<PeerBean> filtered = new ArrayList<>();
178 for (final Entry<InstanceIdentifier<Neighbor>, PeerBean> entry : this.peers.entrySet()) {
179 if (entry.getKey().contains(rootIdentifier)) {
180 final PeerBean peer = entry.getValue();
188 private synchronized void onGlobalCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
189 final WriteConfiguration configurationWriter) {
190 LOG.debug("Creating RIB instance with configuration: {}", global);
191 final RibImpl ribImpl = (RibImpl) this.container.getComponentInstance(InstanceType.RIB.getBeanName());
192 initiateRibInstance(rootIdentifier, global, ribImpl, configurationWriter);
193 this.ribs.put(rootIdentifier, ribImpl);
194 LOG.debug("RIB instance created {}", ribImpl);
198 public synchronized void onGlobalRemoved(final InstanceIdentifier<Bgp> rootIdentifier) {
199 LOG.debug("Removing RIB instance: {}", rootIdentifier);
200 final RibImpl ribImpl = this.ribs.remove(rootIdentifier);
201 if (ribImpl != null) {
203 LOG.debug("RIB instance removed {}", ribImpl);
207 private void registerRibInstance(final RibImpl ribImpl, final String ribInstanceName) {
208 final Dictionary<String, String> properties = new Hashtable<>();
209 properties.put(InstanceType.RIB.getBeanName(), ribInstanceName);
210 final ServiceRegistration<?> serviceRegistration = this.bundleContext.registerService(InstanceType.RIB.getServices(), ribImpl, properties);
211 ribImpl.setServiceRegistration(serviceRegistration);
214 private void initiateRibInstance(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
215 final RibImpl ribImpl, final WriteConfiguration configurationWriter) {
216 final String ribInstanceName = getRibInstanceName(rootIdentifier);
217 ribImpl.start(global, ribInstanceName, this.mappingService, configurationWriter);
218 registerRibInstance(ribImpl, ribInstanceName);
221 private void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
222 final InstanceIdentifier<Bgp> rootIdentifier) {
223 for (final DataObjectModification<? extends DataObject> neighborModification : dataObjectModification.getModifiedChildren()) {
224 switch (neighborModification.getModificationType()) {
226 onNeighborRemoved(rootIdentifier, (Neighbor) neighborModification.getDataBefore());
228 case SUBTREE_MODIFIED:
230 onNeighborModified(rootIdentifier, (Neighbor) neighborModification.getDataAfter(), null);
239 public synchronized void onNeighborModified(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor,
240 final WriteConfiguration configurationWriter) {
241 LOG.debug("Modifying Peer instance with configuration: {}", neighbor);
242 //restart peer instance with a new configuration
243 final PeerBean bgpPeer = this.peers.get(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
244 if (bgpPeer == null) {
245 onNeighborCreated(rootIdentifier, neighbor, configurationWriter);
246 } else if(!bgpPeer.containsEqualConfiguration(neighbor)){
248 final InstanceIdentifier<Neighbor> neighborInstanceIdentifier = getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey());
249 initiatePeerInstance(rootIdentifier, neighborInstanceIdentifier, neighbor, bgpPeer, configurationWriter);
251 LOG.debug("Peer instance modified {}", bgpPeer);
254 private synchronized void onNeighborCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor,
255 final WriteConfiguration configurationWriter) {
256 LOG.debug("Creating Peer instance with configuration: {}", neighbor);
257 final PeerBean bgpPeer;
258 if (this.mappingService.isApplicationPeer(neighbor)) {
259 bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.APP_PEER.getBeanName());
261 bgpPeer = (PeerBean) this.container.getComponentInstance(InstanceType.PEER.getBeanName());
263 final InstanceIdentifier<Neighbor> neighborInstanceIdentifier = getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey());
264 initiatePeerInstance(rootIdentifier, neighborInstanceIdentifier, neighbor, bgpPeer, configurationWriter);
265 this.peers.put(neighborInstanceIdentifier, bgpPeer);
266 LOG.debug("Peer instance created {}", bgpPeer);
270 public synchronized void onNeighborRemoved(final InstanceIdentifier<Bgp> rootIdentifier, final Neighbor neighbor) {
271 LOG.debug("Removing Peer instance: {}", rootIdentifier);
272 final PeerBean bgpPeer = this.peers.remove(getNeighborInstanceIdentifier(rootIdentifier, neighbor.getKey()));
273 if (bgpPeer != null) {
275 LOG.debug("Peer instance removed {}", bgpPeer);
279 private void registerPeerInstance(final BgpPeer bgpPeer, final String peerInstanceName) {
280 final Dictionary<String, String> properties = new Hashtable<>();
281 properties.put(InstanceType.PEER.getBeanName(), peerInstanceName);
282 final ServiceRegistration<?> serviceRegistration = this.bundleContext.registerService(InstanceType.PEER.getServices(), bgpPeer, properties);
283 bgpPeer.setServiceRegistration(serviceRegistration);
286 private void initiatePeerInstance(final InstanceIdentifier<Bgp> rootIdentifier, final InstanceIdentifier<Neighbor> neighborIdentifier, final Neighbor neighbor,
287 final PeerBean bgpPeer, final WriteConfiguration configurationWriter) {
288 final String peerInstanceName = getNeighborInstanceName(neighborIdentifier);
289 final RibImpl rib = this.ribs.get(rootIdentifier);
291 bgpPeer.start(rib, neighbor, this.mappingService, configurationWriter);
292 if (bgpPeer instanceof BgpPeer) {
293 registerPeerInstance((BgpPeer) bgpPeer, peerInstanceName);
299 public BGPOpenConfigMappingService getMappingService() {
300 return this.mappingService;
304 public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data, final InstanceIdentifier<T> identifier) {
305 final ReadWriteTransaction wTx = this.dataBroker.newReadWriteTransaction();
306 wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
311 public <T extends DataObject> ListenableFuture<Void> removeConfiguration(
312 final InstanceIdentifier<T> identifier) {
313 final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
314 wTx.delete(LogicalDatastoreType.CONFIGURATION, identifier);