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 java.util.Collection;
20 import java.util.HashMap;
21 import java.util.List;
23 import java.util.Optional;
24 import java.util.concurrent.ExecutionException;
25 import java.util.stream.Collectors;
26 import org.checkerframework.checker.lock.qual.GuardedBy;
27 import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
28 import org.opendaylight.mdsal.binding.api.DataBroker;
29 import org.opendaylight.mdsal.binding.api.DataObjectModification;
30 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
31 import org.opendaylight.mdsal.binding.api.DataTreeModification;
32 import org.opendaylight.mdsal.binding.api.ReadTransaction;
33 import org.opendaylight.mdsal.binding.api.RpcProviderService;
34 import org.opendaylight.mdsal.binding.api.WriteTransaction;
35 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
36 import org.opendaylight.mdsal.common.api.CommitInfo;
37 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
38 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
39 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
40 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
41 import org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.BGPRibRoutingPolicyFactory;
42 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
43 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
44 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
45 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroupKey;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
52 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
53 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
54 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
55 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
56 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
57 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NetworkInstanceProtocol;
59 import org.opendaylight.yangtools.concepts.ListenerRegistration;
60 import org.opendaylight.yangtools.yang.binding.DataObject;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
65 public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, PeerGroupConfigLoader,
67 private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
68 private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
69 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
70 private final ClusterSingletonServiceProvider provider;
72 private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
73 private final DataBroker dataBroker;
74 private final LoadingCache<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>> peerGroups
75 = CacheBuilder.newBuilder()
76 .build(new CacheLoader<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>>() {
78 public Optional<PeerGroup> load(final InstanceIdentifier<PeerGroup> key)
79 throws ExecutionException, InterruptedException {
80 return loadPeerGroup(key);
83 private final String networkInstanceName;
84 private ListenerRegistration<BgpDeployerImpl> registration;
86 private boolean closed;
87 private final RIBExtensionConsumerContext ribExtensionContext;
88 private final BGPDispatcher dispatcher;
89 private final BGPRibRoutingPolicyFactory policyFactory;
90 private final BindingCodecTreeFactory codecFactory;
91 private final DOMDataBroker domBroker;
92 private final DOMSchemaService schemaService;
93 private final RpcProviderService rpcRegistry;
95 public BgpDeployerImpl(final String networkInstanceName,
96 final ClusterSingletonServiceProvider provider,
97 final DataBroker dataBroker,
98 final BGPTableTypeRegistryConsumer mappingService,
99 final RIBExtensionConsumerContext ribExtensionContext,
100 final BGPDispatcher dispatcher,
101 final BGPRibRoutingPolicyFactory policyFactory,
102 final BindingCodecTreeFactory codecFactory,
103 final DOMDataBroker domBroker,
104 final DOMSchemaService schemaService,
105 final RpcProviderService rpcRegistry) {
106 this.dataBroker = requireNonNull(dataBroker);
107 this.provider = requireNonNull(provider);
108 this.networkInstanceName = requireNonNull(networkInstanceName);
109 this.tableTypeRegistry = requireNonNull(mappingService);
110 this.ribExtensionContext = requireNonNull(ribExtensionContext);
111 this.dispatcher = requireNonNull(dispatcher);
112 this.policyFactory = requireNonNull(policyFactory);
113 this.codecFactory = requireNonNull(codecFactory);
114 this.domBroker = requireNonNull(domBroker);
115 this.schemaService = requireNonNull(schemaService);
116 this.rpcRegistry = rpcRegistry;
117 this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
118 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
119 initializeNetworkInstance(dataBroker, this.networkInstanceIId).addCallback(new FutureCallback<CommitInfo>() {
121 public void onSuccess(final CommitInfo result) {
122 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
126 public void onFailure(final Throwable throwable) {
127 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, throwable);
129 }, MoreExecutors.directExecutor());
132 public synchronized void init() {
133 this.registration = this.dataBroker.registerDataTreeChangeListener(
134 DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
135 this.networkInstanceIId.child(Protocols.class).child(Protocol.class)
136 .augmentation(NetworkInstanceProtocol.class).child(Bgp.class)), this);
137 LOG.info("BGP Deployer {} started.", this.networkInstanceName);
140 private Optional<PeerGroup> loadPeerGroup(final InstanceIdentifier<PeerGroup> peerGroupIid)
141 throws ExecutionException, InterruptedException {
142 final ReadTransaction tr = this.dataBroker.newReadOnlyTransaction();
143 return tr.read(LogicalDatastoreType.CONFIGURATION, peerGroupIid).get();
147 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
149 LOG.trace("BGP Deployer was already closed, skipping changes.");
153 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
154 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
155 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
156 final List<DataObjectModification<? extends DataObject>> deletedConfig
157 = rootNode.getModifiedChildren().stream()
158 .filter(mod -> mod.getModificationType() == DataObjectModification.ModificationType.DELETE)
159 .collect(Collectors.toList());
160 final List<DataObjectModification<? extends DataObject>> changedConfig
161 = rootNode.getModifiedChildren().stream()
162 .filter(mod -> mod.getModificationType() != DataObjectModification.ModificationType.DELETE)
163 .collect(Collectors.toList());
164 handleDeletions(deletedConfig, rootIdentifier);
165 handleModifications(changedConfig, rootIdentifier);
169 private void handleModifications(final List<DataObjectModification<? extends DataObject>> changedConfig,
170 final InstanceIdentifier<Bgp> rootIdentifier) {
171 final List<DataObjectModification<? extends DataObject>> globalMod = changedConfig.stream()
172 .filter(mod -> mod.getDataType().equals(Global.class))
173 .collect(Collectors.toList());
174 final List<DataObjectModification<? extends DataObject>> peerMod = changedConfig.stream()
175 .filter(mod -> !mod.getDataType().equals(Global.class))
176 .collect(Collectors.toList());
177 if (!globalMod.isEmpty()) {
178 handleGlobalChange(globalMod, rootIdentifier);
180 if (!peerMod.isEmpty()) {
181 handlePeersChange(peerMod, rootIdentifier);
185 private void handleDeletions(final List<DataObjectModification<? extends DataObject>> deletedConfig,
186 final InstanceIdentifier<Bgp> rootIdentifier) {
187 final List<DataObjectModification<? extends DataObject>> globalMod = deletedConfig.stream()
188 .filter(mod -> mod.getDataType().equals(Global.class))
189 .collect(Collectors.toList());
190 final List<DataObjectModification<? extends DataObject>> peerMod = deletedConfig.stream()
191 .filter(mod -> !mod.getDataType().equals(Global.class))
192 .collect(Collectors.toList());
193 if (!globalMod.isEmpty()) {
194 handleGlobalChange(globalMod, rootIdentifier);
196 if (!peerMod.isEmpty()) {
197 handlePeersChange(peerMod, rootIdentifier);
201 private void handleGlobalChange(
202 final List<DataObjectModification<? extends DataObject>> config,
203 final InstanceIdentifier<Bgp> rootIdentifier) {
204 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
205 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
209 private void handlePeersChange(
210 final List<DataObjectModification<? extends DataObject>> config,
211 final InstanceIdentifier<Bgp> rootIdentifier) {
212 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
213 if (dataObjectModification.getDataType().equals(Neighbors.class)) {
214 onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
215 } else if (dataObjectModification.getDataType().equals(PeerGroups.class)) {
216 rebootNeighbors((DataObjectModification<PeerGroups>) dataObjectModification);
221 private synchronized void rebootNeighbors(final DataObjectModification<PeerGroups> dataObjectModification) {
222 PeerGroups extPeerGroups = dataObjectModification.getDataAfter();
223 if (extPeerGroups == null) {
224 extPeerGroups = dataObjectModification.getDataBefore();
226 if (extPeerGroups == null) {
229 for (final PeerGroup peerGroup : extPeerGroups.getPeerGroup()) {
230 this.bgpCss.values().forEach(css -> css.restartNeighbors(peerGroup.getPeerGroupName()));
235 @SuppressWarnings("checkstyle:illegalCatch")
236 public synchronized void close() {
237 LOG.info("Closing BGP Deployer.");
238 if (this.registration != null) {
239 this.registration.close();
240 this.registration = null;
244 this.bgpCss.values().iterator().forEachRemaining(service -> {
247 } catch (Exception e) {
248 LOG.warn("Failed to close BGP Cluster Singleton Service.", e);
253 private static FluentFuture<? extends CommitInfo> initializeNetworkInstance(
254 final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
255 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
256 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
257 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
258 .setProtocols(new ProtocolsBuilder().build()).build());
263 synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
264 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
265 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
267 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
268 bgpInstanceIdentifier, this.ribExtensionContext, this.dispatcher, this.policyFactory,
269 this.codecFactory, this.domBroker, this.dataBroker, this.schemaService, this.rpcRegistry);
270 this.bgpCss.put(bgpInstanceIdentifier, old);
272 old.onGlobalChanged(dataObjectModification);
276 synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
277 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
278 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
280 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
281 bgpInstanceIdentifier, this.ribExtensionContext, this.dispatcher, this.policyFactory,
282 this.codecFactory, this.domBroker, this.dataBroker, this.schemaService, this.rpcRegistry);
283 this.bgpCss.put(bgpInstanceIdentifier, old);
285 old.onNeighborsChanged(dataObjectModification);
289 BGPTableTypeRegistryConsumer getTableTypeRegistry() {
290 return this.tableTypeRegistry;
294 public PeerGroup getPeerGroup(final InstanceIdentifier<Bgp> bgpIid, final String peerGroupName) {
295 final InstanceIdentifier<PeerGroup> peerGroupsIid = bgpIid.child(PeerGroups.class)
296 .child(PeerGroup.class, new PeerGroupKey(peerGroupName));
297 return this.peerGroups.getUnchecked(peerGroupsIid).orElse(null);