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.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import java.util.Collection;
22 import java.util.HashMap;
24 import java.util.Optional;
25 import java.util.concurrent.ExecutionException;
26 import javax.annotation.concurrent.GuardedBy;
27 import org.apache.commons.lang3.StringUtils;
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.mdsal.singleton.common.api.ClusterSingletonServiceProvider;
37 import org.opendaylight.protocol.bgp.openconfig.spi.BGPTableTypeRegistryConsumer;
38 import org.opendaylight.yang.gen.v1.http.openconfig.net.yang.bgp.rev151009.bgp.neighbor.group.Config;
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.rev171207.Config2;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.openconfig.extensions.rev171207.Protocol1;
54 import org.opendaylight.yangtools.concepts.ListenerRegistration;
55 import org.opendaylight.yangtools.yang.binding.DataObject;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.osgi.framework.BundleContext;
58 import org.osgi.service.blueprint.container.BlueprintContainer;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
62 public final class BgpDeployerImpl implements ClusteredDataTreeChangeListener<Bgp>, PeerGroupConfigLoader,
64 private static final Logger LOG = LoggerFactory.getLogger(BgpDeployerImpl.class);
65 private final InstanceIdentifier<NetworkInstance> networkInstanceIId;
66 private final BlueprintContainer container;
67 private final BundleContext bundleContext;
68 private final BGPTableTypeRegistryConsumer tableTypeRegistry;
69 private final ClusterSingletonServiceProvider provider;
70 private final LoadingCache<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>> peerGroups = CacheBuilder.newBuilder()
71 .build(new CacheLoader<InstanceIdentifier<PeerGroup>, Optional<PeerGroup>>() {
73 public Optional<PeerGroup> load(final InstanceIdentifier<PeerGroup> key)
74 throws ExecutionException, InterruptedException {
75 return loadPeerGroup(key);
78 private ListenerRegistration<BgpDeployerImpl> registration;
80 private final Map<InstanceIdentifier<Bgp>, BGPClusterSingletonService> bgpCss = new HashMap<>();
81 private final DataBroker dataBroker;
82 private final String networkInstanceName;
84 private boolean closed;
86 public BgpDeployerImpl(final String networkInstanceName, final ClusterSingletonServiceProvider provider,
87 final BlueprintContainer container,
88 final BundleContext bundleContext, final DataBroker dataBroker,
89 final BGPTableTypeRegistryConsumer mappingService) {
90 this.dataBroker = requireNonNull(dataBroker);
91 this.provider = requireNonNull(provider);
92 this.networkInstanceName = requireNonNull(networkInstanceName);
93 this.container = requireNonNull(container);
94 this.bundleContext = requireNonNull(bundleContext);
95 this.tableTypeRegistry = requireNonNull(mappingService);
96 this.networkInstanceIId = InstanceIdentifier.create(NetworkInstances.class)
97 .child(NetworkInstance.class, new NetworkInstanceKey(networkInstanceName));
98 Futures.addCallback(initializeNetworkInstance(dataBroker, this.networkInstanceIId), new FutureCallback<Void>() {
100 public void onSuccess(final Void result) {
101 LOG.debug("Network Instance {} initialized successfully.", networkInstanceName);
105 public void onFailure(final Throwable t) {
106 LOG.error("Failed to initialize Network Instance {}.", networkInstanceName, t);
108 }, MoreExecutors.directExecutor());
111 public synchronized void init() {
112 this.registration = this.dataBroker.registerDataTreeChangeListener(
113 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
114 this.networkInstanceIId.child(Protocols.class)
115 .child(Protocol.class).augmentation(Protocol1.class).child(Bgp.class)), this);
116 LOG.info("BGP Deployer {} started.", this.networkInstanceName);
119 private Optional<PeerGroup> loadPeerGroup(final InstanceIdentifier<PeerGroup> peerGroupIid)
120 throws ExecutionException, InterruptedException {
121 final ReadOnlyTransaction tr = this.dataBroker.newReadOnlyTransaction();
122 final Optional<PeerGroup> result = tr.read(LogicalDatastoreType.CONFIGURATION, peerGroupIid).get().toJavaUtil();
127 public synchronized void onDataTreeChanged(final Collection<DataTreeModification<Bgp>> changes) {
129 LOG.trace("BGP Deployer was already closed, skipping changes.");
132 for (final DataTreeModification<Bgp> dataTreeModification : changes) {
133 final InstanceIdentifier<Bgp> rootIdentifier = dataTreeModification.getRootPath().getRootIdentifier();
134 final DataObjectModification<Bgp> rootNode = dataTreeModification.getRootNode();
135 LOG.trace("BGP configuration has changed: {}", rootNode);
136 for (final DataObjectModification<? extends DataObject> dataObjectModification :
137 rootNode.getModifiedChildren()) {
138 if (dataObjectModification.getDataType().equals(Global.class)) {
139 onGlobalChanged((DataObjectModification<Global>) dataObjectModification, rootIdentifier);
140 } else if (dataObjectModification.getDataType().equals(Neighbors.class)) {
141 onNeighborsChanged((DataObjectModification<Neighbors>) dataObjectModification, rootIdentifier);
142 } else if (dataObjectModification.getDataType().equals(PeerGroups.class)) {
143 rebootNeighbors((DataObjectModification<PeerGroups>) dataObjectModification);
149 private synchronized void rebootNeighbors(final DataObjectModification<PeerGroups> dataObjectModification) {
150 PeerGroups peerGroups = dataObjectModification.getDataAfter();
151 if (peerGroups == null) {
152 peerGroups = dataObjectModification.getDataBefore();
154 if (peerGroups == null) {
157 for (final PeerGroup peerGroup: peerGroups.getPeerGroup()) {
158 this.bgpCss.values().forEach(css->css.restartNeighbors(peerGroup.getPeerGroupName()));
163 public synchronized void close() {
164 LOG.info("Closing BGP Deployer.");
165 if (this.registration != null) {
166 this.registration.close();
167 this.registration = null;
171 this.bgpCss.values().iterator().forEachRemaining(service -> {
174 } catch (Exception e) {
175 LOG.warn("Failed to close BGP Cluster Singleton Service.");
181 private static ListenableFuture<Void> initializeNetworkInstance(
182 final DataBroker dataBroker, final InstanceIdentifier<NetworkInstance> networkInstance) {
183 final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction();
184 wTx.merge(LogicalDatastoreType.CONFIGURATION, networkInstance,
185 new NetworkInstanceBuilder().setName(networkInstance.firstKeyOf(NetworkInstance.class).getName())
186 .setProtocols(new ProtocolsBuilder().build()).build());
191 synchronized void onGlobalChanged(final DataObjectModification<Global> dataObjectModification,
192 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
193 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
195 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
196 this.container, this.bundleContext, bgpInstanceIdentifier);
197 this.bgpCss.put(bgpInstanceIdentifier, old);
199 old.onGlobalChanged(dataObjectModification);
203 synchronized void onNeighborsChanged(final DataObjectModification<Neighbors> dataObjectModification,
204 final InstanceIdentifier<Bgp> bgpInstanceIdentifier) {
205 BGPClusterSingletonService old = this.bgpCss.get(bgpInstanceIdentifier);
207 old = new BGPClusterSingletonService(this, this.provider, this.tableTypeRegistry,
208 this.container, this.bundleContext, bgpInstanceIdentifier);
209 this.bgpCss.put(bgpInstanceIdentifier, old);
211 old.onNeighborsChanged(dataObjectModification);
215 BGPTableTypeRegistryConsumer getTableTypeRegistry() {
216 return this.tableTypeRegistry;
220 public PeerGroup getPeerGroup(final InstanceIdentifier<Bgp> bgpIid, final Config config) {
221 if (config == null || config.getAugmentation(Config2.class) == null) {
225 final String setKey = StringUtils.substringBetween(config.getAugmentation(Config2.class)
226 .getPeerGroup(), "=\"", "\"");
228 final InstanceIdentifier<PeerGroup> peerGroupsIid =
229 bgpIid.child(PeerGroups.class).child(PeerGroup.class, new PeerGroupKey(setKey));
230 return this.peerGroups.getUnchecked(peerGroupsIid).orElse(null);