2 * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. 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.genius.itm.itmdirecttunnels.listeners;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.concurrent.Callable;
16 import javax.annotation.Nonnull;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
23 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
24 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
25 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
26 import org.opendaylight.genius.itm.cache.UnprocessedNodeConnectorCache;
27 import org.opendaylight.genius.itm.globals.ITMConstants;
28 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
29 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
30 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 public class TunnelTopologyStateListener extends AbstractTunnelListenerBase<OvsdbBridgeAugmentation> {
51 private static final Logger LOG = LoggerFactory.getLogger(TunnelTopologyStateListener.class);
53 private final JobCoordinator coordinator;
54 private final ManagedNewTransactionRunner txRunner;
55 private final DirectTunnelUtils directTunnelUtils;
56 private final OvsBridgeEntryCache ovsBridgeEntryCache;
58 public TunnelTopologyStateListener(final DataBroker dataBroker,
59 final JobCoordinator coordinator,
60 final EntityOwnershipUtils entityOwnershipUtils,
61 final DirectTunnelUtils directTunnelUtils,
62 final DpnTepStateCache dpnTepStateCache,
63 final DPNTEPsInfoCache dpntePsInfoCache,
64 final OvsBridgeEntryCache ovsBridgeEntryCache,
65 final UnprocessedNodeConnectorCache unprocessedNodeConnectorCache) {
66 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
67 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
68 .augmentation(OvsdbBridgeAugmentation.class), dpnTepStateCache, dpntePsInfoCache,
69 unprocessedNodeConnectorCache, entityOwnershipUtils, directTunnelUtils);
70 this.coordinator = coordinator;
71 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
72 this.directTunnelUtils = directTunnelUtils;
73 this.ovsBridgeEntryCache = ovsBridgeEntryCache;
78 public void remove(@Nonnull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
79 @Nonnull OvsdbBridgeAugmentation bridgeOld) {
81 LOG.debug("Received Remove DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
82 identifier, bridgeOld);
83 RendererStateRemoveWorker rendererStateRemoveWorker = new RendererStateRemoveWorker(identifier, bridgeOld);
84 coordinator.enqueueJob(bridgeOld.getBridgeName().getValue(), rendererStateRemoveWorker,
85 ITMConstants.JOB_MAX_RETRIES);
90 public void update(@Nonnull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
91 @Nonnull OvsdbBridgeAugmentation bridgeOld, @Nonnull OvsdbBridgeAugmentation bridgeNew) {
96 LOG.debug("Received Update DataChange Notification for identifier: {}, + ovsdbBridgeAugmentation old: {},"
97 + " new: {}.", identifier, bridgeOld, bridgeNew);
99 DatapathId oldDpid = bridgeOld.getDatapathId();
100 DatapathId newDpid = bridgeNew.getDatapathId();
101 if (oldDpid == null && newDpid != null) {
102 RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, bridgeNew);
103 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
104 ITMConstants.JOB_MAX_RETRIES);
105 } else if (oldDpid != null && !oldDpid.equals(newDpid)) {
106 RendererStateUpdateWorker rendererStateAddWorker =
107 new RendererStateUpdateWorker(identifier, bridgeNew, bridgeOld);
108 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
109 ITMConstants.JOB_MAX_RETRIES);
114 public void add(@Nonnull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
115 @Nonnull OvsdbBridgeAugmentation bridgeNew) {
117 LOG.debug("Received Add DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
118 identifier, bridgeNew);
119 RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, bridgeNew);
120 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
121 ITMConstants.JOB_MAX_RETRIES);
126 * This code is used to handle only a dpnId change scenario for a particular change,
127 * which is not expected to happen in usual cases.
129 private List<ListenableFuture<Void>> updateOvsBridgeRefEntry(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
130 OvsdbBridgeAugmentation bridgeNew,
131 OvsdbBridgeAugmentation bridgeOld) {
133 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
134 BigInteger dpnIdNew = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
135 BigInteger dpnIdOld = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
137 LOG.debug("updating bridge references for bridge: {}, dpnNew: {}, dpnOld: {}", bridgeNew,
139 //delete bridge reference entry for the old dpn in interface meta operational DS
140 deleteOvsBridgeRefEntry(dpnIdOld, tx);
142 // create bridge reference entry in interface meta operational DS
143 createOvsBridgeRefEntry(dpnIdNew, bridgeIid, tx);
145 // handle pre-provisioning of tunnels for the newly connected dpn
146 Optional<OvsBridgeEntry> bridgeEntry = null;
148 bridgeEntry = ovsBridgeEntryCache.get(dpnIdNew);
149 if (bridgeEntry.isPresent()) {
150 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
152 } catch (ReadFailedException e) {
153 LOG.debug("OVSDB Bridge is not present for DPN {}", dpnIdNew);
158 public List<ListenableFuture<Void>> removePortFromBridge(InstanceIdentifier<OvsdbBridgeAugmentation>
160 OvsdbBridgeAugmentation bridgeOld) {
161 BigInteger dpnId = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
163 LOG.warn("Got Null DPID for Bridge: {}", bridgeOld);
164 return Collections.emptyList();
166 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
167 LOG.debug("removing bridge references for bridge: {}, dpn: {}", bridgeOld, dpnId);
168 //delete bridge reference entry in interface meta operational DS
169 deleteOvsBridgeRefEntry(dpnId, tx);
171 // the bridge reference is copied to dpn-tunnel interfaces map, so that whenever a northbound delete
172 // happens when bridge is not connected, we need the bridge reference to clean up the topology config DS
173 addBridgeRefToBridgeTunnelEntry(dpnId, new OvsdbBridgeRef(bridgeIid), tx);
177 private void createOvsBridgeRefEntry(BigInteger dpnId, InstanceIdentifier<?> bridgeIid,
178 WriteTransaction tx) {
179 LOG.debug("Creating bridge ref entry for dpn: {} bridge: {}",
181 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
182 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
183 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
184 OvsBridgeRefEntryBuilder tunnelDpnBridgeEntryBuilder =
185 new OvsBridgeRefEntryBuilder().setKey(bridgeRefEntryKey).setDpid(dpnId)
186 .setOvsBridgeReference(new OvsdbBridgeRef(bridgeIid));
187 tx.put(LogicalDatastoreType.OPERATIONAL, bridgeEntryId, tunnelDpnBridgeEntryBuilder.build(), true);
190 private void deleteOvsBridgeRefEntry(BigInteger dpnId,
191 WriteTransaction tx) {
192 LOG.debug("Deleting bridge ref entry for dpn: {}",
194 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
195 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
196 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
197 tx.delete(LogicalDatastoreType.OPERATIONAL, bridgeEntryId);
200 private void addBridgeRefToBridgeTunnelEntry(BigInteger dpId, OvsdbBridgeRef ovsdbBridgeRef, WriteTransaction tx) {
201 OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
202 InstanceIdentifier<OvsBridgeEntry> bridgeEntryInstanceIdentifier =
203 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
205 OvsBridgeEntryBuilder bridgeEntryBuilder = new OvsBridgeEntryBuilder().setKey(bridgeEntryKey)
206 .setOvsBridgeReference(ovsdbBridgeRef);
207 tx.merge(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, bridgeEntryBuilder.build(), true);
211 * Add all tunnels ports corresponding to the bridge to the topology config
214 private void addAllPortsToBridge(OvsBridgeEntry bridgeEntry, InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
215 OvsdbBridgeAugmentation bridgeNew) {
216 String bridgeName = bridgeNew.getBridgeName().getValue();
217 LOG.debug("adding all ports to bridge: {}", bridgeName);
218 List<OvsBridgeTunnelEntry> bridgeInterfaceEntries = bridgeEntry.getOvsBridgeTunnelEntry();
219 if (bridgeInterfaceEntries != null) {
220 for (OvsBridgeTunnelEntry bridgeInterfaceEntry : bridgeInterfaceEntries) {
221 String portName = bridgeInterfaceEntry.getTunnelName();
222 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
223 .ietf.interfaces.rev140508.interfaces.Interface iface =
224 dpnTepStateCache.getInterfaceFromCache(portName);
226 IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
227 if (ifTunnel != null) {
228 directTunnelUtils.addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName);
231 LOG.debug("Interface {} not found in config DS", portName);
237 private class RendererStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
238 private final InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid;
239 private final OvsdbBridgeAugmentation bridgeNew;
241 RendererStateAddWorker(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
242 OvsdbBridgeAugmentation bridgeNew) {
243 this.bridgeIid = bridgeIid;
244 this.bridgeNew = bridgeNew;
248 public List<ListenableFuture<Void>> call() throws Exception {
249 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
250 // to call the respective helpers.
251 if (bridgeNew.getDatapathId() == null) {
252 LOG.info("DataPathId found as null for Bridge Augmentation: {}... returning...", bridgeNew);
253 return Collections.emptyList();
256 BigInteger dpnId = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
257 LOG.debug("adding bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
259 // create bridge reference entry in interface meta operational DS
260 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
261 createOvsBridgeRefEntry(dpnId, bridgeIid, tx);
262 // handle pre-provisioning of tunnels for the newly connected dpn
263 Optional<OvsBridgeEntry> bridgeEntry = ovsBridgeEntryCache.get(dpnId);
264 if (!bridgeEntry.isPresent()) {
265 LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
267 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
273 private class RendererStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
274 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
275 private final OvsdbBridgeAugmentation bridgeNew;
277 RendererStateRemoveWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
278 OvsdbBridgeAugmentation bridgeNew) {
279 this.instanceIdentifier = instanceIdentifier;
280 this.bridgeNew = bridgeNew;
284 public List<ListenableFuture<Void>> call() throws Exception {
285 // If another renderer needs to be supported, check can be performed here
286 // to call the respective helpers.
287 return removePortFromBridge(instanceIdentifier, bridgeNew);
291 private class RendererStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
292 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
293 private final OvsdbBridgeAugmentation bridgeNew;
294 private final OvsdbBridgeAugmentation bridgeOld;
296 RendererStateUpdateWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
297 OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
298 this.instanceIdentifier = instanceIdentifier;
299 this.bridgeNew = bridgeNew;
300 this.bridgeOld = bridgeOld;
304 public List<ListenableFuture<Void>> call() throws Exception {
305 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
306 // to call the respective helpers.
307 return updateOvsBridgeRefEntry(instanceIdentifier, bridgeNew, bridgeOld);