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.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.Collections;
13 import java.util.List;
15 import java.util.Optional;
16 import java.util.concurrent.Callable;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
21 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
22 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
23 import org.opendaylight.genius.itm.globals.ITMConstants;
24 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
25 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.binding.api.WriteTransaction;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryKey;
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.opendaylight.yangtools.yang.common.Uint64;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 public class TunnelTopologyStateListener extends AbstractClusteredSyncDataTreeChangeListener<OvsdbBridgeAugmentation> {
52 private static final Logger LOG = LoggerFactory.getLogger(TunnelTopologyStateListener.class);
53 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
55 private final JobCoordinator coordinator;
56 private final ManagedNewTransactionRunner txRunner;
57 private final DirectTunnelUtils directTunnelUtils;
58 private final OvsBridgeEntryCache ovsBridgeEntryCache;
59 protected final DpnTepStateCache dpnTepStateCache;
61 public TunnelTopologyStateListener(final DataBroker dataBroker,
62 final JobCoordinator coordinator,
63 final DirectTunnelUtils directTunnelUtils,
64 final DpnTepStateCache dpnTepStateCache,
65 final OvsBridgeEntryCache ovsBridgeEntryCache) {
66 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
67 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
68 .augmentation(OvsdbBridgeAugmentation.class));
69 this.coordinator = coordinator;
70 this.dpnTepStateCache = dpnTepStateCache;
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) {
80 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE DTCN received");
81 if (directTunnelUtils.isEntityOwner()) {
82 LOG.debug("Received Remove DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
83 identifier, bridgeOld);
84 TunnelRendererStateRemoveWorker rendererStateRemoveWorker =
85 new TunnelRendererStateRemoveWorker(identifier, bridgeOld);
86 coordinator.enqueueJob(bridgeOld.getBridgeName().getValue(), rendererStateRemoveWorker,
87 ITMConstants.JOB_MAX_RETRIES);
92 public void update(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
93 @NonNull OvsdbBridgeAugmentation bridgeOld, @NonNull OvsdbBridgeAugmentation bridgeNew) {
94 EVENT_LOGGER.debug("ITM-TunnelTopologyState, UPDATE DTCN received");
96 if (!directTunnelUtils.isEntityOwner()) {
99 LOG.debug("Received Update DataChange Notification for identifier: {}, + ovsdbBridgeAugmentation old: {},"
100 + " new: {}.", identifier, bridgeOld, bridgeNew);
102 DatapathId oldDpid = bridgeOld.getDatapathId();
103 DatapathId newDpid = bridgeNew.getDatapathId();
104 if (oldDpid == null && newDpid != null) {
105 TunnelRendererStateAddWorker rendererStateAddWorker =
106 new TunnelRendererStateAddWorker(identifier, bridgeNew);
107 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
108 ITMConstants.JOB_MAX_RETRIES);
109 } else if (oldDpid != null && !oldDpid.equals(newDpid)) {
110 TunnelRendererStateUpdateWorker rendererStateAddWorker =
111 new TunnelRendererStateUpdateWorker(identifier, bridgeNew, bridgeOld);
112 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
113 ITMConstants.JOB_MAX_RETRIES);
118 public void add(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
119 @NonNull OvsdbBridgeAugmentation bridgeNew) {
120 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD DTCN received");
121 if (directTunnelUtils.isEntityOwner()) {
122 LOG.debug("Received Add DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
123 identifier, bridgeNew);
124 TunnelRendererStateAddWorker rendererStateAddWorker =
125 new TunnelRendererStateAddWorker(identifier, bridgeNew);
126 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
127 ITMConstants.JOB_MAX_RETRIES);
132 * This code is used to handle only a dpnId change scenario for a particular change,
133 * which is not expected to happen in usual cases.
135 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
136 justification = "https://github.com/spotbugs/spotbugs/issues/811")
137 private List<ListenableFuture<Void>> updateOvsBridgeRefEntry(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
138 OvsdbBridgeAugmentation bridgeNew,
139 OvsdbBridgeAugmentation bridgeOld) {
141 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
142 Uint64 dpnIdNew = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
143 Uint64 dpnIdOld = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
145 LOG.debug("updating bridge references for bridge: {}, dpnNew: {}, dpnOld: {}", bridgeNew,
147 //delete bridge reference entry for the old dpn in interface meta operational DS
148 deleteOvsBridgeRefEntry(dpnIdOld, tx);
150 // create bridge reference entry in interface meta operational DS
151 createOvsBridgeRefEntry(dpnIdNew, bridgeIid, tx);
153 // handle pre-provisioning of tunnels for the newly connected dpn
154 Optional<OvsBridgeEntry> bridgeEntry = null;
155 bridgeEntry = ovsBridgeEntryCache.get(dpnIdNew);
156 if (bridgeEntry.isPresent()) {
157 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
162 public List<ListenableFuture<Void>> removePortFromBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
163 OvsdbBridgeAugmentation bridgeOld) {
164 Uint64 dpnId = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
166 LOG.warn("Got Null DPID for Bridge: {}", bridgeOld);
167 return Collections.emptyList();
169 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
170 LOG.debug("removing bridge references for bridge: {}, dpn: {}", bridgeOld, dpnId);
171 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE {} completed", bridgeOld.getBridgeName().getValue());
172 //delete bridge reference entry in interface meta operational DS
173 deleteOvsBridgeRefEntry(dpnId, tx);
175 // the bridge reference is copied to dpn-tunnel interfaces map, so that whenever a northbound delete
176 // happens when bridge is not connected, we need the bridge reference to clean up the topology config DS
177 addBridgeRefToBridgeTunnelEntry(dpnId, new OvsdbBridgeRef(bridgeIid), tx);
181 private void createOvsBridgeRefEntry(Uint64 dpnId, InstanceIdentifier<?> bridgeIid, WriteTransaction tx) {
182 LOG.debug("Creating bridge ref entry for dpn: {} bridge: {}",
184 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
185 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
186 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
187 OvsBridgeRefEntryBuilder tunnelDpnBridgeEntryBuilder =
188 new OvsBridgeRefEntryBuilder().withKey(bridgeRefEntryKey).setDpid(dpnId)
189 .setOvsBridgeReference(new OvsdbBridgeRef(bridgeIid));
190 tx.mergeParentStructurePut(LogicalDatastoreType.OPERATIONAL, bridgeEntryId,
191 tunnelDpnBridgeEntryBuilder.build());
194 private void deleteOvsBridgeRefEntry(Uint64 dpnId, WriteTransaction tx) {
195 LOG.debug("Deleting bridge ref entry for dpn: {}",
197 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
198 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
199 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
200 tx.delete(LogicalDatastoreType.OPERATIONAL, bridgeEntryId);
203 private void addBridgeRefToBridgeTunnelEntry(Uint64 dpId, OvsdbBridgeRef ovsdbBridgeRef, WriteTransaction tx) {
204 OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
205 InstanceIdentifier<OvsBridgeEntry> bridgeEntryInstanceIdentifier =
206 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
208 OvsBridgeEntryBuilder bridgeEntryBuilder = new OvsBridgeEntryBuilder().withKey(bridgeEntryKey)
209 .setOvsBridgeReference(ovsdbBridgeRef);
210 tx.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier,
211 bridgeEntryBuilder.build());
215 * Add all tunnels ports corresponding to the bridge to the topology config
218 private void addAllPortsToBridge(OvsBridgeEntry bridgeEntry, InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
219 OvsdbBridgeAugmentation bridgeNew) {
220 String bridgeName = bridgeNew.getBridgeName().getValue();
221 LOG.debug("adding all ports to bridge: {}", bridgeName);
222 @Nullable Map<OvsBridgeTunnelEntryKey, OvsBridgeTunnelEntry> bridgeInterfaceEntries =
223 bridgeEntry.getOvsBridgeTunnelEntry();
224 if (bridgeInterfaceEntries != null) {
225 for (OvsBridgeTunnelEntry bridgeInterfaceEntry : bridgeInterfaceEntries.values()) {
226 String portName = bridgeInterfaceEntry.getTunnelName();
227 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
228 .ietf.interfaces.rev140508.interfaces.Interface iface =
229 dpnTepStateCache.getInterfaceFromCache(portName);
231 IfTunnel ifTunnel = iface.augmentation(IfTunnel.class);
232 if (ifTunnel != null) {
233 directTunnelUtils.addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName);
236 LOG.debug("Interface {} not found in config DS", portName);
239 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD port on {} completed", bridgeName);
243 private class TunnelRendererStateAddWorker implements Callable<List<? extends ListenableFuture<?>>> {
244 private final InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid;
245 private final OvsdbBridgeAugmentation bridgeNew;
247 TunnelRendererStateAddWorker(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
248 OvsdbBridgeAugmentation bridgeNew) {
249 this.bridgeIid = bridgeIid;
250 this.bridgeNew = bridgeNew;
254 public List<ListenableFuture<Void>> call() throws Exception {
255 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
256 // to call the respective helpers.
257 if (bridgeNew.getDatapathId() == null) {
258 LOG.info("DataPathId found as null for Bridge Augmentation: {}... returning...", bridgeNew);
259 return Collections.emptyList();
262 Uint64 dpnId = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
263 LOG.debug("adding bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
264 EVENT_LOGGER.debug("TunnelTopologyState, ADD bridge {} for {}", bridgeNew.getBridgeName(), dpnId);
266 // create bridge reference entry in interface meta operational DS
267 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
268 createOvsBridgeRefEntry(dpnId, bridgeIid, tx);
269 // handle pre-provisioning of tunnels for the newly connected dpn
270 Optional<OvsBridgeEntry> bridgeEntry = ovsBridgeEntryCache.get(dpnId);
271 if (!bridgeEntry.isPresent()) {
272 LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
274 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
280 private class TunnelRendererStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
281 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
282 private final OvsdbBridgeAugmentation bridgeNew;
284 TunnelRendererStateRemoveWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
285 OvsdbBridgeAugmentation bridgeNew) {
286 this.instanceIdentifier = instanceIdentifier;
287 this.bridgeNew = bridgeNew;
291 public List<ListenableFuture<Void>> call() throws Exception {
292 // If another renderer needs to be supported, check can be performed here
293 // to call the respective helpers.
294 return removePortFromBridge(instanceIdentifier, bridgeNew);
298 private class TunnelRendererStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
299 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
300 private final OvsdbBridgeAugmentation bridgeNew;
301 private final OvsdbBridgeAugmentation bridgeOld;
303 TunnelRendererStateUpdateWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
304 OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
305 this.instanceIdentifier = instanceIdentifier;
306 this.bridgeNew = bridgeNew;
307 this.bridgeOld = bridgeOld;
311 public List<ListenableFuture<Void>> call() throws Exception {
312 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
313 // to call the respective helpers.
314 return updateOvsBridgeRefEntry(instanceIdentifier, bridgeNew, bridgeOld);