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