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;
14 import java.util.Optional;
15 import java.util.concurrent.Callable;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
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.api.WriteTransaction;
26 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
27 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntryKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.DatapathId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.opendaylight.yangtools.yang.common.Uint64;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 public class TunnelTopologyStateListener extends AbstractClusteredSyncDataTreeChangeListener<OvsdbBridgeAugmentation> {
49 private static final Logger LOG = LoggerFactory.getLogger(TunnelTopologyStateListener.class);
50 private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
52 private final JobCoordinator coordinator;
53 private final ManagedNewTransactionRunner txRunner;
54 private final DirectTunnelUtils directTunnelUtils;
55 private final OvsBridgeEntryCache ovsBridgeEntryCache;
56 protected final DpnTepStateCache dpnTepStateCache;
58 public TunnelTopologyStateListener(final DataBroker dataBroker,
59 final JobCoordinator coordinator,
60 final DirectTunnelUtils directTunnelUtils,
61 final DpnTepStateCache dpnTepStateCache,
62 final OvsBridgeEntryCache ovsBridgeEntryCache) {
63 super(dataBroker, LogicalDatastoreType.OPERATIONAL,
64 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
65 .augmentation(OvsdbBridgeAugmentation.class));
66 this.coordinator = coordinator;
67 this.dpnTepStateCache = dpnTepStateCache;
68 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
69 this.directTunnelUtils = directTunnelUtils;
70 this.ovsBridgeEntryCache = ovsBridgeEntryCache;
75 public void remove(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
76 @NonNull OvsdbBridgeAugmentation bridgeOld) {
77 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE DTCN received");
78 if (directTunnelUtils.isEntityOwner()) {
79 LOG.debug("Received Remove DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
80 identifier, bridgeOld);
81 TunnelRendererStateRemoveWorker rendererStateRemoveWorker =
82 new TunnelRendererStateRemoveWorker(identifier, bridgeOld);
83 coordinator.enqueueJob(bridgeOld.getBridgeName().getValue(), rendererStateRemoveWorker,
84 ITMConstants.JOB_MAX_RETRIES);
89 public void update(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
90 @NonNull OvsdbBridgeAugmentation bridgeOld, @NonNull OvsdbBridgeAugmentation bridgeNew) {
91 EVENT_LOGGER.debug("ITM-TunnelTopologyState, UPDATE DTCN received");
93 if (!directTunnelUtils.isEntityOwner()) {
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 TunnelRendererStateAddWorker rendererStateAddWorker =
103 new TunnelRendererStateAddWorker(identifier, bridgeNew);
104 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
105 ITMConstants.JOB_MAX_RETRIES);
106 } else if (oldDpid != null && !oldDpid.equals(newDpid)) {
107 TunnelRendererStateUpdateWorker rendererStateAddWorker =
108 new TunnelRendererStateUpdateWorker(identifier, bridgeNew, bridgeOld);
109 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
110 ITMConstants.JOB_MAX_RETRIES);
115 public void add(@NonNull InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
116 @NonNull OvsdbBridgeAugmentation bridgeNew) {
117 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD DTCN received");
118 if (directTunnelUtils.isEntityOwner()) {
119 LOG.debug("Received Add DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
120 identifier, bridgeNew);
121 TunnelRendererStateAddWorker rendererStateAddWorker =
122 new TunnelRendererStateAddWorker(identifier, bridgeNew);
123 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
124 ITMConstants.JOB_MAX_RETRIES);
129 * This code is used to handle only a dpnId change scenario for a particular change,
130 * which is not expected to happen in usual cases.
132 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
133 justification = "https://github.com/spotbugs/spotbugs/issues/811")
134 private List<ListenableFuture<Void>> updateOvsBridgeRefEntry(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
135 OvsdbBridgeAugmentation bridgeNew,
136 OvsdbBridgeAugmentation bridgeOld) {
138 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
139 Uint64 dpnIdNew = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
140 Uint64 dpnIdOld = directTunnelUtils.getDpnId(bridgeOld.getDatapathId());
142 LOG.debug("updating bridge references for bridge: {}, dpnNew: {}, dpnOld: {}", bridgeNew,
144 //delete bridge reference entry for the old dpn in interface meta operational DS
145 deleteOvsBridgeRefEntry(dpnIdOld, tx);
147 // create bridge reference entry in interface meta operational DS
148 createOvsBridgeRefEntry(dpnIdNew, bridgeIid, tx);
150 // handle pre-provisioning of tunnels for the newly connected dpn
151 Optional<OvsBridgeEntry> bridgeEntry = null;
152 bridgeEntry = ovsBridgeEntryCache.get(dpnIdNew);
153 if (bridgeEntry.isPresent()) {
154 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
159 public List<ListenableFuture<Void>> removePortFromBridge(InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
160 OvsdbBridgeAugmentation bridgeOld) {
161 Uint64 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 EVENT_LOGGER.debug("ITM-TunnelTopologyState, REMOVE {} completed", bridgeOld.getBridgeName().getValue());
169 //delete bridge reference entry in interface meta operational DS
170 deleteOvsBridgeRefEntry(dpnId, tx);
172 // the bridge reference is copied to dpn-tunnel interfaces map, so that whenever a northbound delete
173 // happens when bridge is not connected, we need the bridge reference to clean up the topology config DS
174 addBridgeRefToBridgeTunnelEntry(dpnId, new OvsdbBridgeRef(bridgeIid), tx);
178 private void createOvsBridgeRefEntry(Uint64 dpnId, InstanceIdentifier<?> bridgeIid, 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().withKey(bridgeRefEntryKey).setDpid(dpnId)
186 .setOvsBridgeReference(new OvsdbBridgeRef(bridgeIid));
187 tx.put(LogicalDatastoreType.OPERATIONAL, bridgeEntryId, tunnelDpnBridgeEntryBuilder.build(), true);
190 private void deleteOvsBridgeRefEntry(Uint64 dpnId, WriteTransaction tx) {
191 LOG.debug("Deleting bridge ref entry for dpn: {}",
193 OvsBridgeRefEntryKey bridgeRefEntryKey = new OvsBridgeRefEntryKey(dpnId);
194 InstanceIdentifier<OvsBridgeRefEntry> bridgeEntryId =
195 DirectTunnelUtils.getOvsBridgeRefEntryIdentifier(bridgeRefEntryKey);
196 tx.delete(LogicalDatastoreType.OPERATIONAL, bridgeEntryId);
199 private void addBridgeRefToBridgeTunnelEntry(Uint64 dpId, OvsdbBridgeRef ovsdbBridgeRef, WriteTransaction tx) {
200 OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
201 InstanceIdentifier<OvsBridgeEntry> bridgeEntryInstanceIdentifier =
202 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
204 OvsBridgeEntryBuilder bridgeEntryBuilder = new OvsBridgeEntryBuilder().withKey(bridgeEntryKey)
205 .setOvsBridgeReference(ovsdbBridgeRef);
206 tx.merge(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, bridgeEntryBuilder.build(), true);
210 * Add all tunnels ports corresponding to the bridge to the topology config
213 private void addAllPortsToBridge(OvsBridgeEntry bridgeEntry, InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid,
214 OvsdbBridgeAugmentation bridgeNew) {
215 String bridgeName = bridgeNew.getBridgeName().getValue();
216 LOG.debug("adding all ports to bridge: {}", bridgeName);
217 List<OvsBridgeTunnelEntry> bridgeInterfaceEntries = bridgeEntry.getOvsBridgeTunnelEntry();
218 if (bridgeInterfaceEntries != null) {
219 for (OvsBridgeTunnelEntry bridgeInterfaceEntry : bridgeInterfaceEntries) {
220 String portName = bridgeInterfaceEntry.getTunnelName();
221 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
222 .ietf.interfaces.rev140508.interfaces.Interface iface =
223 dpnTepStateCache.getInterfaceFromCache(portName);
225 IfTunnel ifTunnel = iface.augmentation(IfTunnel.class);
226 if (ifTunnel != null) {
227 directTunnelUtils.addTunnelPortToBridge(ifTunnel, bridgeIid, iface, portName);
230 LOG.debug("Interface {} not found in config DS", portName);
233 EVENT_LOGGER.debug("ITM-TunnelTopologyState, ADD port on {} completed", bridgeName);
237 private class TunnelRendererStateAddWorker implements Callable<List<? extends ListenableFuture<?>>> {
238 private final InstanceIdentifier<OvsdbBridgeAugmentation> bridgeIid;
239 private final OvsdbBridgeAugmentation bridgeNew;
241 TunnelRendererStateAddWorker(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 Uint64 dpnId = directTunnelUtils.getDpnId(bridgeNew.getDatapathId());
257 LOG.debug("adding bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
258 EVENT_LOGGER.debug("TunnelTopologyState, ADD bridge {} for {}", bridgeNew.getBridgeName(), dpnId);
260 // create bridge reference entry in interface meta operational DS
261 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
262 createOvsBridgeRefEntry(dpnId, bridgeIid, tx);
263 // handle pre-provisioning of tunnels for the newly connected dpn
264 Optional<OvsBridgeEntry> bridgeEntry = ovsBridgeEntryCache.get(dpnId);
265 if (!bridgeEntry.isPresent()) {
266 LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
268 addAllPortsToBridge(bridgeEntry.get(), bridgeIid, bridgeNew);
274 private class TunnelRendererStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
275 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
276 private final OvsdbBridgeAugmentation bridgeNew;
278 TunnelRendererStateRemoveWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
279 OvsdbBridgeAugmentation bridgeNew) {
280 this.instanceIdentifier = instanceIdentifier;
281 this.bridgeNew = bridgeNew;
285 public List<ListenableFuture<Void>> call() throws Exception {
286 // If another renderer needs to be supported, check can be performed here
287 // to call the respective helpers.
288 return removePortFromBridge(instanceIdentifier, bridgeNew);
292 private class TunnelRendererStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
293 private final InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
294 private final OvsdbBridgeAugmentation bridgeNew;
295 private final OvsdbBridgeAugmentation bridgeOld;
297 TunnelRendererStateUpdateWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
298 OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
299 this.instanceIdentifier = instanceIdentifier;
300 this.bridgeNew = bridgeNew;
301 this.bridgeOld = bridgeOld;
305 public List<ListenableFuture<Void>> call() throws Exception {
306 // If another renderer(for eg : OVS) needs to be supported, check can be performed here
307 // to call the respective helpers.
308 return updateOvsBridgeRefEntry(instanceIdentifier, bridgeNew, bridgeOld);