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.getRibInstanceName;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.util.concurrent.CheckedFuture;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.Collection;
20 import java.util.Dictionary;
21 import java.util.HashMap;
22 import java.util.Hashtable;
24 import javax.annotation.concurrent.GuardedBy;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
27 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
29 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
30 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
35 import org.opendaylight.protocol.bgp.openconfig.spi.BGPOpenConfigMappingService;
36 import org.opendaylight.protocol.bgp.rib.impl.spi.BgpDeployer;
37 import org.opendaylight.protocol.bgp.rib.impl.spi.InstanceType;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev160614.Protocol1;
48 import org.opendaylight.yangtools.concepts.ListenerRegistration;
49 import org.opendaylight.yangtools.yang.binding.DataObject;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.osgi.framework.BundleContext;
52 import org.osgi.framework.ServiceRegistration;
53 import org.osgi.service.blueprint.container.BlueprintContainer;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 public final class BgpDeployerImpl implements BgpDeployer, DataTreeChangeListener<Bgp>, AutoCloseable {
59 private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
61 private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
62 private final BlueprintContainer container;
63 private final BundleContext bundleContext;
64 private final BGPOpenConfigMappingService mappingService;
65 private final ListenerRegistration<BgpDeployerImpl> registration;
67 private final Map<InstanceIdentifier<Bgp>, RibImpl> ribs = new HashMap<>();
69 private boolean closed;
71 private final DataBroker dataBroker;
73 public BgpDeployerImpl(final String networkInstanceName, final BlueprintContainer container, final BundleContext bundleContext, final DataBroker dataBroker,
74 final BGPOpenConfigMappingService mappingService) {
75 this.dataBroker = Preconditions.checkNotNull(dataBroker);
76 this.container = Preconditions.checkNotNull(container);
77 this.bundleContext = Preconditions.checkNotNull(bundleContext);
78 this.mappingService = Preconditions.checkNotNull(mappingService);
79 this.networkInstanceIId = InstanceIdentifier
80 .create(NetworkInstances.class)
81 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
82 Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
84 public void onSuccess(final Void result) {
85 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
88 public void onFailure(final Throwable t) {
89 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
92 this.registration = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, this.networkInstanceIId.child(Protocols.class)
93 .child(Protocol.class)
94 .augmentation(Protocol1.class)
95 .child(Bgp.class)), this);
96 LOG.info("BGP Deployer {} started.", networkInstanceName);
100 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
102 LOG.trace("BGP Deployer was already closed, skipping changes.");
105 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
106 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
107 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
108 LOG.trace("BGP configuration has changed: {}", rootNode);
109 for (final DataObjectModification<? extends DataObject> dataObjectModification : rootNode.getModifiedChildren()) {
110 if (dataObjectModification.getDataType().equals(Global.class)) {
111 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
118 public InstanceIdentifier<NetworkInstance> getInstanceIdentifier() {
119 return this.networkInstanceIId;
123 public synchronized void close() throws Exception {
124 this.registration.close();
125 this.ribs.values().forEach(rib -> rib.close());
130 private static CheckedFuture<Void, TransactionCommitFailedException> initializeNetworkInstance(final DataBroker dataBroker,
131 final InstanceIdentifier<NetworkInstance> networkInstance) {
132 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
133 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
134 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName()).setProtocols(new ProtocolsBuilder().build()).build());
138 private void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
139 final InstanceIdentifier<Bgp> rootIdentifier) {
140 switch (dataObjectModification.getModificationType()) {
142 onGlobalRemoved(rootIdentifier);
144 case SUBTREE_MODIFIED:
146 onGlobalModified(rootIdentifier, dataObjectModification.getDataAfter());
153 private void onGlobalModified(final InstanceIdentifier<Bgp> rootIdentifier, final Global global) {
154 LOG.debug("Modifing RIB instance with configuration: {}", global);
155 //restart existing rib instance with a new configuration
156 final RibImpl ribImpl = this.ribs.get(rootIdentifier);
157 if (ribImpl != null) {
159 initiateRibInstance(rootIdentifier, global, ribImpl);
161 //if not exists, create a new instance
162 onGlobalCreated(rootIdentifier, global);
164 LOG.debug("RIB instance modified {}", ribImpl);
167 private void onGlobalCreated(final InstanceIdentifier<Bgp> rootIdentifier, final Global global) {
168 //create, start and register rib instance
169 LOG.debug("Creating RIB instance with configuration: {}", global);
170 final RibImpl ribImpl = (RibImpl) this.container.getComponentInstance(InstanceType.RIB.getBeanName());
171 initiateRibInstance(rootIdentifier, global, ribImpl);
172 this.ribs.put(rootIdentifier, ribImpl);
173 LOG.debug("RIB instance created {}", ribImpl);
176 private void onGlobalRemoved(final InstanceIdentifier<Bgp> rootIdentifier) {
177 //destroy rib instance
178 LOG.debug("Removing RIB instance: {}", rootIdentifier);
179 final RibImpl ribImpl = this.ribs.remove(rootIdentifier);
180 if (ribImpl != null) {
182 LOG.debug("RIB instance removed {}", ribImpl);
186 private void registerRibInstance(final RibImpl ribImpl, final String ribInstanceName) {
187 final Dictionary<String, String> properties = new Hashtable<>();
188 properties.put(InstanceType.RIB.getBeanName(), ribInstanceName);
189 final ServiceRegistration<?> serviceRegistration = this.bundleContext.registerService(InstanceType.RIB.getServices(), ribImpl, properties);
190 ribImpl.setServiceRegistration(serviceRegistration);
193 private void initiateRibInstance(final InstanceIdentifier<Bgp> rootIdentifier, final Global global,
194 final RibImpl ribImpl) {
195 final String ribInstanceName = getRibInstanceName(rootIdentifier);
196 ribImpl.start(global, ribInstanceName, this.mappingService);
197 registerRibInstance(ribImpl, ribInstanceName);
201 public <T extends DataObject> ListenableFuture<Void> writeConfiguration(final T data,
202 final InstanceIdentifier<T> identifier) {
203 final ReadWriteTransaction wTx = this.dataBroker.newReadWriteTransaction();
204 final CheckedFuture<Optional<T>, ReadFailedException> readFuture = wTx.read(LogicalDatastoreType.CONFIGURATION, identifier);
205 Futures.addCallback(readFuture, new FutureCallback<Optional<T>>() {
207 public void onSuccess(final Optional<T> result) {
208 if (!result.isPresent()) {
209 wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
213 public void onFailure(final Throwable t) {
214 LOG.debug("Failed to ensure presence of {}, try to write configuration.", identifier, t);
215 wTx.put(LogicalDatastoreType.CONFIGURATION, identifier, data);
223 public <T extends DataObject> ListenableFuture<Void> removeConfiguration(
224 final InstanceIdentifier<T> identifier) {
225 final WriteTransaction wTx = this.dataBroker.newWriteOnlyTransaction();
226 wTx.delete(LogicalDatastoreType.CONFIGURATION, identifier);
231 public BGPOpenConfigMappingService getMappingService() {
232 return this.mappingService;