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.itm.cache.DpnTepStateCache;
20 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
21 import org.opendaylight.genius.itm.globals.ITMConstants;
22 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
23 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
24 import org.opendaylight.mdsal.binding.api.DataBroker;
25 import org.opendaylight.mdsal.binding.util.Datastore;
26 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
27 import org.opendaylight.mdsal.binding.util.Datastore.Operational;
28 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
29 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.Uint64;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class TunnelTopologyStateListener extends AbstractClusteredSyncDataTreeChangeListener<OvsdbBridgeAugmentation> {
55 private static final Logger LOG = LoggerFactory.getLogger(TunnelTopologyStateListener.class);
56 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
58 private final JobCoordinator coordinator;
59 private final ManagedNewTransactionRunner txRunner;
60 private final DirectTunnelUtils directTunnelUtils;
61 private final OvsBridgeEntryCache ovsBridgeEntryCache;
62 protected final DpnTepStateCache dpnTepStateCache;
64 public TunnelTopologyStateListener(final DataBroker dataBroker,
65 final JobCoordinator coordinator,
66 final DirectTunnelUtils directTunnelUtils,
67 final DpnTepStateCache dpnTepStateCache,
68 final OvsBridgeEntryCache ovsBridgeEntryCache) {
69 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
70 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
71 .augmentation(OvsdbBridgeAugmentation.class));
72 this.coordinator = coordinator;
73 this.dpnTepStateCache = dpnTepStateCache;
74 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
75 this.directTunnelUtils = directTunnelUtils;
76 this.ovsBridgeEntryCache = ovsBridgeEntryCache;
81 public void remove(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
82 @NonNull OvsdbBridgeAugmentation bridgeOld) {
83 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE DTCN received");
84 if (directTunnelUtils.isEntityOwner()) {
85 LOG.debug("Received Remove DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
86 identifier, bridgeOld);
87 TunnelRendererStateRemoveWorker rendererStateRemoveWorker =
88 new TunnelRendererStateRemoveWorker(identifier, bridgeOld);
89 coordinator.enqueueJob(bridgeOld.getBridgeName().getValue(), rendererStateRemoveWorker,
90 ITMConstants.JOB_MAX_RETRIES);
95 public void update(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
96 @NonNull OvsdbBridgeAugmentation bridgeOld, @NonNull OvsdbBridgeAugmentation bridgeNew) {
97 EVENT_LOGGER.debug("ITM-TunnelTopologyState, UPDATE DTCN received");
99 if (!directTunnelUtils.isEntityOwner()) {
102 LOG.debug("Received Update DataChange Notification for identifier: {}, + ovsdbBridgeAugmentation old: {},"
103 + " new: {}.", identifier, bridgeOld, bridgeNew);
105 DatapathId oldDpid = bridgeOld.getDatapathId();
106 DatapathId newDpid = bridgeNew.getDatapathId();
107 if (oldDpid == null && newDpid != null) {
108 TunnelRendererStateAddWorker rendererStateAddWorker =
109 new TunnelRendererStateAddWorker(identifier, bridgeNew);
110 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
111 ITMConstants.JOB_MAX_RETRIES);
112 } else if (oldDpid != null && !oldDpid.equals(newDpid)) {
113 TunnelRendererStateUpdateWorker rendererStateAddWorker =
114 new TunnelRendererStateUpdateWorker(identifier, bridgeNew, bridgeOld);
115 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
116 ITMConstants.JOB_MAX_RETRIES);
121 public void add(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
122 @NonNull OvsdbBridgeAugmentation bridgeNew) {
123 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD DTCN received");
124 if (directTunnelUtils.isEntityOwner()) {
125 LOG.debug("Received Add DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
126 identifier, bridgeNew);
127 TunnelRendererStateAddWorker rendererStateAddWorker =
128 new TunnelRendererStateAddWorker(identifier, bridgeNew);
129 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
130 ITMConstants.JOB_MAX_RETRIES);
135 * This code is used to handle only a dpnId change scenario for a particular change,
136 * which is not expected to happen in usual cases.
138 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
139 justification = "https://github.com/spotbugs/spotbugs/issues/811")
140 private List<? extends ListenableFuture<?>> updateOvsBridgeRefEntry(
141 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
142 OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
144 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL,
146 Uint64 dpnIdNew = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
147 Uint64 dpnIdOld = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
149 LOG.debug("updating bridge references for bridge: {}, dpnNew: {}, dpnOld: {}", bridgeNew,
151 //delete bridge reference entry for the old dpn in interface meta operational DS
152 deleteOvsBridgeRefEntry(dpnIdOld, tx);
154 // create bridge reference entry in interface meta operational DS
155 createOvsBridgeRefEntry(dpnIdNew, bridgeIid, tx);
157 // handle pre-provisioning of tunnels for the newly connected dpn
158 Optional<OvsBridgeEntry> bridgeEntry = null;
159 bridgeEntry = ovsBridgeEntryCache.get(dpnIdNew);
160 if (bridgeEntry.isPresent()) {
161 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
166 public List<? extends ListenableFuture<?>> removePortFromBridge(
167 InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid, OvsdbBridgeAugmentation bridgeOld) {
168 Uint64 dpnId = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
170 LOG.warn("Got Null DPID for Bridge: {}", bridgeOld);
171 return Collections.emptyList();
173 return List.of(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL, tx -> {
174 LOG.debug("removing bridge references for bridge: {}, dpn: {}", bridgeOld, dpnId);
175 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE {} completed", bridgeOld.getBridgeName().getValue());
176 //delete bridge reference entry in interface meta operational DS
177 deleteOvsBridgeRefEntry(dpnId, tx);
178 }), txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
179 // the bridge reference is copied to dpn-tunnel interfaces map, so that whenever a northbound delete
180 // happens when bridge is not connected, we need the bridge reference to clean up the topology config DS
181 addBridgeRefToBridgeTunnelEntry(dpnId, new OvsdbBridgeRef(bridgeIid), tx);
185 private void createOvsBridgeRefEntry(Uint64 dpnId, InstanceIdentifier<?> bridgeIid,
186 TypedWriteTransaction<@NonNull Operational> tx) {
187 LOG.debug("Creating bridge ref entry for dpn: {} bridge: {}", dpnId, bridgeIid);
188 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
189 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
190 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
191 OvsBridgeRefEntryBuilder tunnelDpnBridgeEntryBuilder =
192 new OvsBridgeRefEntryBuilder().withKey(bridgeRefEntryKey).setDpid(dpnId)
193 .setOvsBridgeReference(new OvsdbBridgeRef(bridgeIid));
194 tx.mergeParentStructurePut(bridgeEntryId, tunnelDpnBridgeEntryBuilder.build());
197 private void deleteOvsBridgeRefEntry(Uint64 dpnId, TypedWriteTransaction<@NonNull Operational> tx) {
198 LOG.debug("Deleting bridge ref entry for dpn: {}", dpnId);
199 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
200 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
201 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
202 tx.delete(bridgeEntryId);
205 private void addBridgeRefToBridgeTunnelEntry(Uint64 dpId, OvsdbBridgeRef ovsdbBridgeRef,
206 TypedWriteTransaction<@NonNull Configuration> tx) {
207 OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
208 InstanceIdentifier<OvsBridgeEntry> bridgeEntryInstanceIdentifier =
209 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
211 OvsBridgeEntryBuilder bridgeEntryBuilder = new OvsBridgeEntryBuilder().withKey(bridgeEntryKey)
212 .setOvsBridgeReference(ovsdbBridgeRef);
213 tx.mergeParentStructureMerge(bridgeEntryInstanceIdentifier, bridgeEntryBuilder.build());
217 * Add all tunnels ports corresponding to the bridge to the topology config
220 private void addAllPortsToBridge(OvsBridgeEntry bridgeEntry, InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
221 OvsdbBridgeAugmentation bridgeNew) {
222 String bridgeName = bridgeNew.getBridgeName().getValue();
223 LOG.debug("adding all ports to bridge: {}", bridgeName);
224 @Nullable Map<OvsBridgeTunnelEntryKey, OvsBridgeTunnelEntry> bridgeInterfaceEntries =
225 bridgeEntry.getOvsBridgeTunnelEntry();
226 if (bridgeInterfaceEntries != null) {
227 for (OvsBridgeTunnelEntry bridgeInterfaceEntry : bridgeInterfaceEntries.values()) {
228 String portName = bridgeInterfaceEntry.getTunnelName();
229 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
230 .ietf.interfaces.rev140508.interfaces.Interface iface =
231 dpnTepStateCache.getInterfaceFromCache(portName);
233 IfTunnel ifTunnel = iface.augmentation(IfTunnel.class);
234 if (ifTunnel != null) {
235 directTunnelUtils.addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName);
238 LOG.debug("Interface {} not found in config DS", portName);
241 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD port on {} completed", bridgeName);
245 private class TunnelRendererStateAddWorker implements Callable<List<? extends ListenableFuture<?>>> {
246 private final InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid;
247 private final OvsdbBridgeAugmentation bridgeNew;
249 TunnelRendererStateAddWorker(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
250 OvsdbBridgeAugmentation bridgeNew) {
251 this.bridgeIid = bridgeIid;
252 this.bridgeNew = bridgeNew;
256 public List<? extends ListenableFuture<?>> call() throws Exception {
257 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
258 // to call the respective helpers.
259 if (bridgeNew.getDatapathId() == null) {
260 LOG.info("DataPathId found as null for Bridge Augmentation: {}... returning...", bridgeNew);
261 return Collections.emptyList();
264 Uint64 dpnId = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
265 LOG.debug("adding bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
266 EVENT_LOGGER.debug("TunnelTopologyState, ADD bridge {} for {}", bridgeNew.getBridgeName(), dpnId);
268 // create bridge reference entry in interface meta operational DS
269 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.OPERATIONAL,
271 createOvsBridgeRefEntry(dpnId, bridgeIid, tx);
272 // handle pre-provisioning of tunnels for the newly connected dpn
273 Optional<OvsBridgeEntry> bridgeEntry = ovsBridgeEntryCache.get(dpnId);
274 if (!bridgeEntry.isPresent()) {
275 LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
277 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
283 private class TunnelRendererStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
284 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
285 private final OvsdbBridgeAugmentation bridgeNew;
287 TunnelRendererStateRemoveWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
288 OvsdbBridgeAugmentation bridgeNew) {
289 this.instanceIdentifier = instanceIdentifier;
290 this.bridgeNew = bridgeNew;
294 public List<? extends ListenableFuture<?>> call() throws Exception {
295 // If another renderer needs to be supported, check can be performed here
296 // to call the respective helpers.
297 return removePortFromBridge(instanceIdentifier, bridgeNew);
301 private class TunnelRendererStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
302 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
303 private final OvsdbBridgeAugmentation bridgeNew;
304 private final OvsdbBridgeAugmentation bridgeOld;
306 TunnelRendererStateUpdateWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
307 OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
308 this.instanceIdentifier = instanceIdentifier;
309 this.bridgeNew = bridgeNew;
310 this.bridgeOld = bridgeOld;
314 public List<? extends ListenableFuture<?>> call() throws Exception {
315 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
316 // to call the respective helpers.
317 return updateOvsBridgeRefEntry(instanceIdentifier, bridgeNew, bridgeOld);