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 java.util.Objects.requireNonNull;
13 import com.google.common.annotations.VisibleForTesting;
14 import com.google.common.cache.CacheBuilder;
15 import com.google.common.cache.CacheLoader;
16 import com.google.common.cache.LoadingCache;
17 import com.google.common.util.concurrent.FluentFuture;
18 import com.google.common.util.concurrent.FutureCallback;
19 import com.google.common.util.concurrent.MoreExecutors;
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 javax.annotation.concurrent.GuardedBy;
28 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
31 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
32 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
33 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
37 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
38 import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeFactory;
39 import org.opendaylight.mdsal.common.api.CommitInfo;
40 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
41 import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
42 import org.opendaylight.protocol.bgp.openconfig.routing.policy.spi.BGPRibRoutingPolicyFactory;
43 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
44 import org.opendaylight.protocol.bgp.rib.impl.spi.BGPDispatcher;
45 import org.opendaylight.protocol.bgp.rib.spi.RIBExtensionConsumerContext;
46 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroup;
47 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.peer.group.PeerGroupKey;
48 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.Bgp;
49 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Global;
50 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.Neighbors;
51 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.top.bgp.PeerGroups;
52 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.NetworkInstances;
53 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstance;
54 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceBuilder;
55 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.NetworkInstanceKey;
56 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.Protocols;
57 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.ProtocolsBuilder;
58 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.network.instance.rev151018.network.instance.top.network.instances.network.instance.protocols.Protocol;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev180329.NetworkInstanceProtocol;
60 import org.opendaylight.yangtools.concepts.ListenerRegistration;
61 import org.opendaylight.yangtools.yang.binding.DataObject;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
66 public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, PeerGroupConfigLoader,
68 private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
69 private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
70 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
71 private final ClusterSingletonServiceProvider provider;
73 private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
74 private final DataBroker dataBroker;
75 private final LoadingCache<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>> peerGroups
76 = CacheBuilder.newBuilder()
77 .build(new CacheLoader<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>>() {
79 public Optional<PeerGroup> load(final InstanceIdentifier<PeerGroup> key)
80 throws ExecutionException, InterruptedException {
81 return loadPeerGroup(key);
84 private final String networkInstanceName;
85 private ListenerRegistration<BgpDeployerImpl> registration;
87 private boolean closed;
88 private final RIBExtensionConsumerContext ribExtensionContext;
89 private final BGPDispatcher dispatcher;
90 private final BGPRibRoutingPolicyFactory policyFactory;
91 private final BindingCodecTreeFactory codecFactory;
92 private final DOMDataBroker domBroker;
93 private final DOMSchemaService schemaService;
94 private final RpcProviderRegistry rpcRegistry;
96 public BgpDeployerImpl(final String networkInstanceName,
97 final ClusterSingletonServiceProvider provider,
98 final DataBroker dataBroker,
99 final BGPTableTypeRegistryConsumer mappingService,
100 final RIBExtensionConsumerContext ribExtensionContext,
101 final BGPDispatcher dispatcher,
102 final BGPRibRoutingPolicyFactory policyFactory,
103 final BindingCodecTreeFactory codecFactory,
104 final DOMDataBroker domBroker,
105 final DOMSchemaService schemaService,
106 final RpcProviderRegistry rpcRegistry) {
107 this.dataBroker = requireNonNull(dataBroker);
108 this.provider = requireNonNull(provider);
109 this.networkInstanceName = requireNonNull(networkInstanceName);
110 this.tableTypeRegistry = requireNonNull(mappingService);
111 this.ribExtensionContext = requireNonNull(ribExtensionContext);
112 this.dispatcher = requireNonNull(dispatcher);
113 this.policyFactory = requireNonNull(policyFactory);
114 this.codecFactory = requireNonNull(codecFactory);
115 this.domBroker = requireNonNull(domBroker);
116 this.schemaService = requireNonNull(schemaService);
117 this.rpcRegistry = rpcRegistry;
118 this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
119 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
120 initializeNetworkInstance(dataBroker, this.networkInstanceIId).addCallback(new FutureCallback<CommitInfo>() {
122 public void onSuccess(final CommitInfo result) {
123 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
127 public void onFailure(final Throwable throwable) {
128 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, throwable);
130 }, MoreExecutors.directExecutor());
133 public synchronized void init() {
134 this.registration = this.dataBroker.registerDataTreeChangeListener(
135 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
136 this.networkInstanceIId.child(Protocols.class).child(Protocol.class)
137 .augmentation(NetworkInstanceProtocol.class).child(Bgp.class)), this);
138 LOG.info("BGP Deployer {} started.", this.networkInstanceName);
141 private Optional<PeerGroup> loadPeerGroup(final InstanceIdentifier<PeerGroup> peerGroupIid)
142 throws ExecutionException, InterruptedException {
143 final ReadOnlyTransaction tr = this.dataBroker.newReadOnlyTransaction();
144 return tr.read(LogicalDatastoreType.CONFIGURATION, peerGroupIid).get().toJavaUtil();
148 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
150 LOG.trace("BGP Deployer was already closed, skipping changes.");
154 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
155 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
156 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
157 final List<DataObjectModification<? extends DataObject>> deletedConfig
158 = rootNode.getModifiedChildren().stream()
159 .filter(mod -> mod.getModificationType() == DataObjectModification.ModificationType.DELETE)
160 .collect(Collectors.toList());
161 final List<DataObjectModification<? extends DataObject>> changedConfig
162 = rootNode.getModifiedChildren().stream()
163 .filter(mod -> mod.getModificationType() != DataObjectModification.ModificationType.DELETE)
164 .collect(Collectors.toList());
165 handleDeletions(deletedConfig, rootIdentifier);
166 handleModifications(changedConfig, rootIdentifier);
170 private void handleModifications(final List<DataObjectModification<? extends DataObject>> changedConfig,
171 final InstanceIdentifier<Bgp> rootIdentifier) {
172 final List<DataObjectModification<? extends DataObject>> globalMod = changedConfig.stream()
173 .filter(mod -> mod.getDataType().equals(Global.class))
174 .collect(Collectors.toList());
175 final List<DataObjectModification<? extends DataObject>> peerMod = changedConfig.stream()
176 .filter(mod -> !mod.getDataType().equals(Global.class))
177 .collect(Collectors.toList());
178 if (!globalMod.isEmpty()) {
179 handleGlobalChange(globalMod, rootIdentifier);
181 if (!peerMod.isEmpty()) {
182 handlePeersChange(peerMod, rootIdentifier);
186 private void handleDeletions(final List<DataObjectModification<? extends DataObject>> deletedConfig,
187 final InstanceIdentifier<Bgp> rootIdentifier) {
188 final List<DataObjectModification<? extends DataObject>> globalMod = deletedConfig.stream()
189 .filter(mod -> mod.getDataType().equals(Global.class))
190 .collect(Collectors.toList());
191 final List<DataObjectModification<? extends DataObject>> peerMod = deletedConfig.stream()
192 .filter(mod -> !mod.getDataType().equals(Global.class))
193 .collect(Collectors.toList());
194 if (!globalMod.isEmpty()) {
195 handleGlobalChange(globalMod, rootIdentifier);
197 if (!peerMod.isEmpty()) {
198 handlePeersChange(peerMod, rootIdentifier);
202 private void handleGlobalChange(
203 final List<DataObjectModification<? extends DataObject>> config,
204 final InstanceIdentifier<Bgp> rootIdentifier) {
205 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
206 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
210 private void handlePeersChange(
211 final List<DataObjectModification<? extends DataObject>> config,
212 final InstanceIdentifier<Bgp> rootIdentifier) {
213 for (final DataObjectModification<? extends DataObject> dataObjectModification : config) {
214 if (dataObjectModification.getDataType().equals(Neighbors.class)) {
215 onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
216 } else if (dataObjectModification.getDataType().equals(PeerGroups.class)) {
217 rebootNeighbors((DataObjectModification<PeerGroups>) dataObjectModification);
222 private synchronized void rebootNeighbors(final DataObjectModification<PeerGroups> dataObjectModification) {
223 PeerGroups peerGroups = dataObjectModification.getDataAfter();
224 if (peerGroups == null) {
225 peerGroups = dataObjectModification.getDataBefore();
227 if (peerGroups == null) {
230 for (final PeerGroup peerGroup : peerGroups.getPeerGroup()) {
231 this.bgpCss.values().forEach(css -> css.restartNeighbors(peerGroup.getPeerGroupName()));
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.");
254 private static FluentFuture<? extends CommitInfo> initializeNetworkInstance(
255 final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
256 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
257 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
258 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
259 .setProtocols(new ProtocolsBuilder().build()).build());
264 synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
265 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
266 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
268 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
269 bgpInstanceIdentifier, this.ribExtensionContext, this.dispatcher, this.policyFactory,
270 this.codecFactory, this.domBroker, this.dataBroker, this.schemaService, this.rpcRegistry);
271 this.bgpCss.put(bgpInstanceIdentifier, old);
273 old.onGlobalChanged(dataObjectModification);
277 synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
278 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
279 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
281 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
282 bgpInstanceIdentifier, this.ribExtensionContext, this.dispatcher, this.policyFactory,
283 this.codecFactory, this.domBroker, this.dataBroker, this.schemaService, this.rpcRegistry);
284 this.bgpCss.put(bgpInstanceIdentifier, old);
286 old.onNeighborsChanged(dataObjectModification);
290 BGPTableTypeRegistryConsumer getTableTypeRegistry() {
291 return this.tableTypeRegistry;
295 public PeerGroup getPeerGroup(final InstanceIdentifier<Bgp> bgpIid, final String peerGroupName) {
296 final InstanceIdentifier<PeerGroup> peerGroupsIid = bgpIid.child(PeerGroups.class)
297 .child(PeerGroup.class, new PeerGroupKey(peerGroupName));
298 return this.peerGroups.getUnchecked(peerGroupsIid).orElse(null);