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
8 package org.opendaylight.protocol.bgp.rib.impl.config;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.VisibleForTesting;
13 import com.google.common.cache.CacheBuilder;
14 import com.google.common.cache.CacheLoader;
15 import com.google.common.cache.LoadingCache;
16 import com.google.common.util.concurrent.FluentFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.List;
24 import java.util.Optional;
25 import java.util.concurrent.ExecutionException;
26 import java.util.stream.Collectors;
27 import org.checkerframework.checker.lock.qual.GuardedBy;
28 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
29 import org.opendaylight.mdsal.binding.api.DataBroker;
30 import org.opendaylight.mdsal.binding.api.DataObjectModification;
31 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
32 import org.opendaylight.mdsal.binding.api.DataTreeModification;
33 import org.opendaylight.mdsal.binding.api.ReadTransaction;
34 import org.opendaylight.mdsal.binding.api.WriteTransaction;
35 import org.opendaylight.mdsal.common.api.CommitInfo;
36 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
37 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
38 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
39 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
40 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroupKey;
41 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
42 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
43 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
44 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
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.rev180329.NetworkInstanceProtocol;
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.service.blueprint.container.BlueprintContainer;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, PeerGroupConfigLoader,
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 BGPTableTypeRegistryConsumer tableTypeRegistry;
68 private final ClusterSingletonServiceProvider provider;
70 private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
71 private final DataBroker dataBroker;
72 private final LoadingCache<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>> peerGroups
73 = CacheBuilder.newBuilder()
74 .build(new CacheLoader<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>>() {
76 public Optional<PeerGroup> load(final InstanceIdentifier<PeerGroup> key)
77 throws ExecutionException, InterruptedException {
78 return loadPeerGroup(key);
81 private final String networkInstanceName;
82 private ListenerRegistration<BgpDeployerImpl> registration;
84 private boolean closed;
86 public BgpDeployerImpl(final String networkInstanceName,
87 final ClusterSingletonServiceProvider provider,
88 final BlueprintContainer container,
89 final BundleContext bundleContext,
90 final DataBroker dataBroker,
91 final BGPTableTypeRegistryConsumer mappingService) {
92 this.dataBroker = requireNonNull(dataBroker);
93 this.provider = requireNonNull(provider);
94 this.networkInstanceName = requireNonNull(networkInstanceName);
95 this.container = requireNonNull(container);
96 this.bundleContext = requireNonNull(bundleContext);
97 this.tableTypeRegistry = requireNonNull(mappingService);
98 this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
99 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
100 initializeNetworkInstance(dataBroker, this.networkInstanceIId).addCallback(new FutureCallback<CommitInfo>() {
102 public void onSuccess(final CommitInfo result) {
103 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
107 public void onFailure(final Throwable throwable) {
108 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, throwable);
110 }, MoreExecutors.directExecutor());
113 public synchronized void init() {
114 this.registration = this.dataBroker.registerDataTreeChangeListener(
115 DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
116 this.networkInstanceIId.child(Protocols.class).child(Protocol.class)
117 .augmentation(NetworkInstanceProtocol.class).child(Bgp.class)), this);
118 LOG.info("BGP Deployer {} started.", this.networkInstanceName);
121 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
122 justification = "https://github.com/spotbugs/spotbugs/issues/811")
123 private Optional<PeerGroup> loadPeerGroup(final InstanceIdentifier<PeerGroup> peerGroupIid)
124 throws ExecutionException, InterruptedException {
125 final ReadTransaction tr = this.dataBroker.newReadOnlyTransaction();
126 return tr.read(LogicalDatastoreType.CONFIGURATION, peerGroupIid).get();
130 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
132 LOG.trace("BGP Deployer was already closed, skipping changes.");
136 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
137 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
138 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
139 final List<DataObjectModification<? extends DataObject>> deletedConfig
140 = rootNode.getModifiedChildren().stream()
141 .filter(mod -> mod.getModificationType() == DataObjectModification.ModificationType.DELETE)
142 .collect(Collectors.toList());
143 final List<DataObjectModification<? extends DataObject>> changedConfig
144 = rootNode.getModifiedChildren().stream()
145 .filter(mod -> mod.getModificationType() != DataObjectModification.ModificationType.DELETE)
146 .collect(Collectors.toList());
147 handleDeletions(deletedConfig, rootIdentifier);
148 handleModifications(changedConfig, rootIdentifier);
152 private void handleModifications(final List<DataObjectModification<? extends DataObject>> changedConfig,
153 final InstanceIdentifier<Bgp> rootIdentifier) {
154 final List<DataObjectModification<? extends DataObject>> globalMod = changedConfig.stream()
155 .filter(mod -> mod.getDataType().equals(Global.class))
156 .collect(Collectors.toList());
157 final List<DataObjectModification<? extends DataObject>> peerMod = changedConfig.stream()
158 .filter(mod -> !mod.getDataType().equals(Global.class))
159 .collect(Collectors.toList());
160 if (!globalMod.isEmpty()) {
161 handleGlobalChange(globalMod, rootIdentifier);
163 if (!peerMod.isEmpty()) {
164 handlePeersChange(peerMod, rootIdentifier);
168 private void handleDeletions(final List<DataObjectModification<? extends DataObject>> deletedConfig,
169 final InstanceIdentifier<Bgp> rootIdentifier) {
170 final List<DataObjectModification<? extends DataObject>> globalMod = deletedConfig.stream()
171 .filter(mod -> mod.getDataType().equals(Global.class))
172 .collect(Collectors.toList());
173 final List<DataObjectModification<? extends DataObject>> peerMod = deletedConfig.stream()
174 .filter(mod -> !mod.getDataType().equals(Global.class))
175 .collect(Collectors.toList());
176 if (!globalMod.isEmpty()) {
177 handleGlobalChange(globalMod, rootIdentifier);
179 if (!peerMod.isEmpty()) {
180 handlePeersChange(peerMod, rootIdentifier);
184 private void handleGlobalChange(
185 final List<DataObjectModification<? extends DataObject>> config,
186 final InstanceIdentifier<Bgp> rootIdentifier) {
187 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
188 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
192 private void handlePeersChange(
193 final List<DataObjectModification<? extends DataObject>> config,
194 final InstanceIdentifier<Bgp> rootIdentifier) {
195 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
196 if (dataObjectModification.getDataType().equals(Neighbors.class)) {
197 onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
198 } else if (dataObjectModification.getDataType().equals(PeerGroups.class)) {
199 rebootNeighbors((DataObjectModification<PeerGroups>) dataObjectModification);
204 private synchronized void rebootNeighbors(final DataObjectModification<PeerGroups> dataObjectModification) {
205 PeerGroups extPeerGroups = dataObjectModification.getDataAfter();
206 if (extPeerGroups == null) {
207 extPeerGroups = dataObjectModification.getDataBefore();
209 if (extPeerGroups == null) {
212 for (final PeerGroup peerGroup : extPeerGroups.nonnullPeerGroup().values()) {
213 this.bgpCss.values().forEach(css -> css.restartNeighbors(peerGroup.getPeerGroupName()));
218 @SuppressWarnings("checkstyle:illegalCatch")
219 public synchronized void close() {
220 LOG.info("Closing BGP Deployer.");
221 if (this.registration != null) {
222 this.registration.close();
223 this.registration = null;
227 this.bgpCss.values().iterator().forEachRemaining(service -> {
230 } catch (Exception e) {
231 LOG.warn("Failed to close BGP Cluster Singleton Service.", e);
236 private static FluentFuture<? extends CommitInfo> initializeNetworkInstance(
237 final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
238 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
239 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
240 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
241 .setProtocols(new ProtocolsBuilder().build()).build());
246 synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
247 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
248 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
250 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
251 this.container, this.bundleContext, bgpInstanceIdentifier);
252 this.bgpCss.put(bgpInstanceIdentifier, old);
254 old.onGlobalChanged(dataObjectModification);
258 synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
259 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
260 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
262 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
263 this.container, this.bundleContext, bgpInstanceIdentifier);
264 this.bgpCss.put(bgpInstanceIdentifier, old);
266 old.onNeighborsChanged(dataObjectModification);
270 BGPTableTypeRegistryConsumer getTableTypeRegistry() {
271 return this.tableTypeRegistry;
275 public PeerGroup getPeerGroup(final InstanceIdentifier<Bgp> bgpIid, final String peerGroupName) {
276 final InstanceIdentifier<PeerGroup> peerGroupsIid = bgpIid.child(PeerGroups.class)
277 .child(PeerGroup.class, new PeerGroupKey(peerGroupName));
278 return this.peerGroups.getUnchecked(peerGroupsIid).orElse(null);