ifm changes for performance enhancements
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / listeners / InterfaceTopologyStateListener.java
1 /*
2  * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.genius.interfacemanager.listeners;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.Callable;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
24 import org.opendaylight.genius.interfacemanager.IfmConstants;
25 import org.opendaylight.genius.interfacemanager.IfmUtil;
26 import org.opendaylight.genius.interfacemanager.InterfacemgrProvider;
27 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
28 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
29 import org.opendaylight.genius.interfacemanager.recovery.impl.InterfaceServiceRecoveryHandler;
30 import org.opendaylight.genius.interfacemanager.recovery.listeners.RecoverableListener;
31 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceTopologyStateUpdateHelper;
32 import org.opendaylight.genius.interfacemanager.renderer.ovs.utilities.SouthboundUtils;
33 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
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.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 @Singleton
47 public class InterfaceTopologyStateListener
48         extends AsyncClusteredDataTreeChangeListenerBase<OvsdbBridgeAugmentation, InterfaceTopologyStateListener>
49         implements RecoverableListener {
50     private static final Logger LOG = LoggerFactory.getLogger(InterfaceTopologyStateListener.class);
51     private final DataBroker dataBroker;
52     private final InterfacemgrProvider interfaceMgrProvider;
53     private final EntityOwnershipUtils entityOwnershipUtils;
54     private final JobCoordinator coordinator;
55     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
56     private final OvsInterfaceTopologyStateUpdateHelper ovsInterfaceTopologyStateUpdateHelper;
57     private final InterfaceMetaUtils interfaceMetaUtils;
58     private final SouthboundUtils southboundUtils;
59
60     @Inject
61     public InterfaceTopologyStateListener(final DataBroker dataBroker, final InterfacemgrProvider interfaceMgrProvider,
62             final EntityOwnershipUtils entityOwnershipUtils, final JobCoordinator coordinator,
63             final InterfaceManagerCommonUtils interfaceManagerCommonUtils,
64             final OvsInterfaceTopologyStateUpdateHelper ovsInterfaceTopologyStateUpdateHelper,
65             final InterfaceMetaUtils interfaceMetaUtils, final SouthboundUtils southboundUtils,
66             final InterfaceServiceRecoveryHandler interfaceServiceRecoveryHandler) {
67         super(OvsdbBridgeAugmentation.class, InterfaceTopologyStateListener.class);
68         this.dataBroker = dataBroker;
69         this.interfaceMgrProvider = interfaceMgrProvider;
70         this.entityOwnershipUtils = entityOwnershipUtils;
71         this.coordinator = coordinator;
72         this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
73         this.ovsInterfaceTopologyStateUpdateHelper = ovsInterfaceTopologyStateUpdateHelper;
74         this.interfaceMetaUtils = interfaceMetaUtils;
75         this.southboundUtils = southboundUtils;
76         registerListener();
77         interfaceServiceRecoveryHandler.addRecoverableListener(this);
78     }
79
80     @Override
81     public void registerListener() {
82         this.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
83     }
84
85     @Override
86     public  void deregisterListener() {
87         close();
88     }
89
90     @Override
91     protected InstanceIdentifier<OvsdbBridgeAugmentation> getWildCardPath() {
92         return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class).child(Node.class)
93                 .augmentation(OvsdbBridgeAugmentation.class).build();
94     }
95
96     @Override
97     protected InterfaceTopologyStateListener getDataTreeChangeListener() {
98         return InterfaceTopologyStateListener.this;
99     }
100
101     private void runOnlyInOwnerNode(String jobDesc, Runnable job) {
102         entityOwnershipUtils.runOnlyInOwnerNode(IfmConstants.INTERFACE_CONFIG_ENTITY,
103                 IfmConstants.INTERFACE_CONFIG_ENTITY, coordinator, jobDesc, job);
104     }
105
106     @Override
107     protected void remove(InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
108                           OvsdbBridgeAugmentation bridgeOld) {
109         LOG.debug("Received Remove DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
110                 identifier, bridgeOld);
111
112         InstanceIdentifier<Node> nodeIid = identifier.firstIdentifierOf(Node.class);
113         interfaceMgrProvider.removeBridgeForNodeIid(nodeIid);
114
115         runOnlyInOwnerNode("OVSDB bridge removed", () -> {
116             RendererStateRemoveWorker rendererStateRemoveWorker =
117                     new RendererStateRemoveWorker(identifier, bridgeOld);
118             coordinator.enqueueJob(bridgeOld.getBridgeName().getValue(), rendererStateRemoveWorker,
119                 IfmConstants.JOB_MAX_RETRIES);
120         });
121     }
122
123     @Override
124     protected void update(InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
125                           OvsdbBridgeAugmentation bridgeOld,
126                           OvsdbBridgeAugmentation bridgeNew) {
127         LOG.debug(
128                 "Received Update DataChange Notification for identifier: {}, ovsdbBridgeAugmentation old: {}, new: {}.",
129                 identifier, bridgeOld, bridgeNew);
130
131         InstanceIdentifier<Node> nodeIid = identifier.firstIdentifierOf(Node.class);
132         interfaceMgrProvider.addBridgeForNodeIid(nodeIid, bridgeNew);
133
134         runOnlyInOwnerNode("OVSDB bridge updated", () -> {
135             DatapathId oldDpid = bridgeOld.getDatapathId();
136             DatapathId newDpid = bridgeNew.getDatapathId();
137             if (oldDpid == null && newDpid != null) {
138                 RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, bridgeNew);
139                 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
140                         IfmConstants.JOB_MAX_RETRIES);
141             } else if (oldDpid != null && !oldDpid.equals(newDpid)) {
142                 RendererStateUpdateWorker rendererStateAddWorker =
143                         new RendererStateUpdateWorker(identifier, bridgeNew, bridgeOld);
144                 coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
145                         IfmConstants.JOB_MAX_RETRIES);
146             }
147         });
148     }
149
150     @Override
151     protected void add(InstanceIdentifier<OvsdbBridgeAugmentation> identifier,
152                        OvsdbBridgeAugmentation bridgeNew) {
153         LOG.debug("Received Add DataChange Notification for identifier: {}, ovsdbBridgeAugmentation: {}",
154                 identifier, bridgeNew);
155
156         InstanceIdentifier<Node> nodeIid = identifier.firstIdentifierOf(Node.class);
157         interfaceMgrProvider.addBridgeForNodeIid(nodeIid, bridgeNew);
158
159         runOnlyInOwnerNode("OVSDB bridge added", () -> {
160             RendererStateAddWorker rendererStateAddWorker = new RendererStateAddWorker(identifier, bridgeNew);
161             coordinator.enqueueJob(bridgeNew.getBridgeName().getValue(), rendererStateAddWorker,
162                 IfmConstants.JOB_MAX_RETRIES);
163         });
164     }
165
166     private class RendererStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
167         InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
168         OvsdbBridgeAugmentation bridgeNew;
169
170         RendererStateAddWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
171                                OvsdbBridgeAugmentation bridgeNew) {
172             this.instanceIdentifier = instanceIdentifier;
173             this.bridgeNew = bridgeNew;
174         }
175
176         @Override
177         public List<ListenableFuture<Void>> call() {
178             List<ListenableFuture<Void>> futures = new ArrayList<>();
179
180             if (bridgeNew.getDatapathId() == null) {
181                 LOG.info("DataPathId found as null for Bridge Augmentation: {}... returning...", bridgeNew);
182                 return futures;
183             }
184             BigInteger dpnId = IfmUtil.getDpnId(bridgeNew.getDatapathId());
185             LOG.debug("adding bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
186             // create bridge reference entry in interface meta operational DS
187             WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
188             InterfaceMetaUtils.createBridgeRefEntry(dpnId, instanceIdentifier, writeTransaction);
189
190             // handle pre-provisioning of tunnels for the newly connected dpn
191             BridgeEntry bridgeEntry = interfaceMetaUtils.getBridgeEntryFromConfigDS(dpnId);
192             if (bridgeEntry == null) {
193                 LOG.debug("Bridge entry not found in config DS for dpn: {}", dpnId);
194                 futures.add(writeTransaction.submit());
195                 return futures;
196             }
197             futures.add(writeTransaction.submit());
198             southboundUtils
199                     .addAllPortsToBridge(bridgeEntry, interfaceManagerCommonUtils, instanceIdentifier, bridgeNew);
200             return futures;
201         }
202     }
203
204     private class RendererStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
205         InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
206         OvsdbBridgeAugmentation bridgeNew;
207
208         RendererStateRemoveWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
209                                   OvsdbBridgeAugmentation bridgeNew) {
210             this.instanceIdentifier = instanceIdentifier;
211             this.bridgeNew = bridgeNew;
212         }
213
214         @Override
215         public List<ListenableFuture<Void>> call() {
216             BigInteger dpnId = IfmUtil.getDpnId(bridgeNew.getDatapathId());
217
218             if (dpnId == null) {
219                 LOG.warn("Got Null DPID for Bridge: {}", bridgeNew);
220                 return Collections.emptyList();
221             }
222
223             WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
224             LOG.debug("removing bridge references for bridge: {}, dpn: {}", bridgeNew, dpnId);
225             // delete bridge reference entry in interface meta operational DS
226             InterfaceMetaUtils.deleteBridgeRefEntry(dpnId, transaction);
227
228             // the bridge reference is copied to dpn-tunnel interfaces map, so that
229             // whenever a northbound delete
230             // happens when bridge is not connected, we need the bridge reference to
231             // clean up the topology config DS
232             InterfaceMetaUtils.addBridgeRefToBridgeInterfaceEntry(dpnId, new OvsdbBridgeRef(instanceIdentifier),
233                     transaction);
234
235             return Collections.singletonList(transaction.submit());
236         }
237     }
238
239     private class RendererStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
240         InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier;
241         OvsdbBridgeAugmentation bridgeNew;
242         OvsdbBridgeAugmentation bridgeOld;
243
244         RendererStateUpdateWorker(InstanceIdentifier<OvsdbBridgeAugmentation> instanceIdentifier,
245                                   OvsdbBridgeAugmentation bridgeNew, OvsdbBridgeAugmentation bridgeOld) {
246             this.instanceIdentifier = instanceIdentifier;
247             this.bridgeNew = bridgeNew;
248             this.bridgeOld = bridgeOld;
249         }
250
251         @Override
252         public List<ListenableFuture<Void>> call() {
253             return ovsInterfaceTopologyStateUpdateHelper.updateBridgeRefEntry(instanceIdentifier, bridgeNew, bridgeOld);
254         }
255     }
256 }