7dfd368abc440f5e07065152de682f37d1f64baa
[ovsdb.git] / hwvtepsouthbound / hwvtepsouthbound-impl / src / main / java / org / opendaylight / ovsdb / hwvtepsouthbound / HwvtepDeviceInfo.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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
10
11 import com.google.common.collect.Sets;
12
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.Map;
17 import java.util.Set;
18
19 import java.util.concurrent.ConcurrentHashMap;
20 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependencyQueue;
21 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.DependentJob;
22 import org.opendaylight.ovsdb.hwvtepsouthbound.transact.TransactCommand;
23 import org.opendaylight.ovsdb.lib.notation.UUID;
24 import org.opendaylight.ovsdb.schema.hardwarevtep.LogicalSwitch;
25 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalLocator;
26 import org.opendaylight.ovsdb.schema.hardwarevtep.PhysicalSwitch;
27 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionHistory;
28 import org.opendaylight.ovsdb.utils.mdsal.utils.TransactionType;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
33 import org.opendaylight.yangtools.yang.binding.Identifiable;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /*
39  * HwvtepDeviceInfo is used to store some of the table entries received
40  * in updates from a Hwvtep device. There will be one instance of this per
41  * Hwvtep device connected. Table entries are stored in a map keyed by
42  * uuids of respective rows.
43  *
44  * Purpose of this class is to provide data present in tables which
45  * were updated in a previous transaction and are not available in
46  * current updatedRows. This allows us to handle updates for Tables
47  * which reference other tables and need information in those tables
48  * to add data to Operational data store.
49  *
50  * e.g. Mac-entries in data store use logical-switch-ref as one of the
51  * keys. Mac-entry updates from switch rarely contain Logical_Switch
52  * table entries. To add mac-entries we need table entries from
53  * Logical_Switch table which were created in an earlier update.
54  *
55  */
56 public class HwvtepDeviceInfo {
57
58     private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceInfo.class);
59
60     public enum DeviceDataStatus {
61         IN_TRANSIT,
62         UNAVAILABLE,
63         AVAILABLE
64     }
65
66     public static class DeviceData {
67         private final InstanceIdentifier key;
68         private final UUID uuid;
69         private final Object data;
70         private final DeviceDataStatus status;
71         private long intransitTimeStamp;
72
73         DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
74             this.data = data;
75             this.key = key;
76             this.status = status;
77             this.uuid = uuid;
78             if (status == DeviceDataStatus.IN_TRANSIT) {
79                 intransitTimeStamp = System.currentTimeMillis();
80             }
81         }
82
83         public Object getData() {
84             return data;
85         }
86
87         public DeviceDataStatus getStatus() {
88             return status;
89         }
90
91         public UUID getUuid() {
92             return uuid;
93         }
94
95         public InstanceIdentifier getKey() {
96             return key;
97         }
98
99         public boolean isIntransitTimeExpired() {
100             return System.currentTimeMillis()
101                     > intransitTimeStamp + HwvtepSouthboundConstants.IN_TRANSIT_STATE_EXPIRY_TIME_MILLIS;
102         }
103
104         public boolean isInTransitState() {
105             return status == DeviceDataStatus.IN_TRANSIT;
106         }
107     }
108
109     private final Map<InstanceIdentifier<?>, Set<InstanceIdentifier>> tepIdReferences = new ConcurrentHashMap<>();
110     private final Map<InstanceIdentifier<LogicalSwitches>, Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs>>
111             logicalSwitchVsUcasts = new ConcurrentHashMap<>();
112     private final Map<InstanceIdentifier<LogicalSwitches>, Map<InstanceIdentifier<RemoteMcastMacs>, RemoteMcastMacs>>
113             logicalSwitchVsMcasts = new ConcurrentHashMap<>();
114     private final Map<UUID, PhysicalSwitch> physicalSwitches = new ConcurrentHashMap<>();
115     private final Map<UUID, UUID> mapTunnelToPhysicalSwitch = new ConcurrentHashMap<>();
116
117     private final HwvtepConnectionInstance connectionInstance;
118
119     private Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> configKeyVsData =
120             new ConcurrentHashMap<>();
121     private final Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> opKeyVsData =
122             new ConcurrentHashMap<>();
123     private final Map<Class<? extends Identifiable>, Map<UUID, DeviceData>> uuidVsData = new ConcurrentHashMap<>();
124     private final DependencyQueue dependencyQueue;
125     private TransactionHistory controllerTxHistory;
126     private TransactionHistory deviceUpdateHistory;
127
128
129     public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
130         this.connectionInstance = hwvtepConnectionInstance;
131         this.dependencyQueue = new DependencyQueue(this);
132     }
133
134     public LogicalSwitch getLogicalSwitch(UUID uuid) {
135         DeviceData deviceData = getDeviceOperData(LogicalSwitches.class, uuid);
136         if (deviceData != null && deviceData.getData() != null) {
137             return (LogicalSwitch) deviceData.getData();
138         }
139         return null;
140     }
141
142     public Map<UUID, LogicalSwitch> getLogicalSwitches() {
143         Map<UUID, DeviceData> switches = uuidVsData.get(LogicalSwitches.class);
144         Map<UUID, LogicalSwitch> result = new HashMap<>();
145         if (switches != null) {
146             for (Map.Entry<UUID, DeviceData> entry : switches.entrySet()) {
147                 result.put(entry.getKey(), (LogicalSwitch) entry.getValue().getData());
148             }
149         }
150         return result;
151     }
152
153     public void putPhysicalSwitch(UUID uuid, PhysicalSwitch physicalSwitch) {
154         physicalSwitches.put(uuid, physicalSwitch);
155     }
156
157     public PhysicalSwitch getPhysicalSwitch(UUID uuid) {
158         return physicalSwitches.get(uuid);
159     }
160
161     public PhysicalSwitch removePhysicalSwitch(UUID uuid) {
162         return physicalSwitches.remove(uuid);
163     }
164
165     public Map<UUID, PhysicalSwitch> getPhysicalSwitches() {
166         return physicalSwitches;
167     }
168
169     public PhysicalLocator getPhysicalLocator(UUID uuid) {
170         DeviceData deviceData = getDeviceOperData(TerminationPoint.class, uuid);
171         if (deviceData != null && deviceData.getData() != null) {
172             return (PhysicalLocator) deviceData.getData();
173         }
174         return null;
175     }
176
177     public Map<UUID, PhysicalLocator> getPhysicalLocators() {
178         Map<UUID, DeviceData> locators = uuidVsData.get(TerminationPoint.class);
179         Map<UUID, PhysicalLocator> result = new HashMap<>();
180         if (locators != null) {
181             for (Map.Entry<UUID, DeviceData> entry : locators.entrySet()) {
182                 result.put(entry.getKey(), (PhysicalLocator) entry.getValue().getData());
183             }
184         }
185         return result;
186     }
187
188     public void putPhysicalSwitchForTunnel(UUID uuid, UUID psUUID) {
189         mapTunnelToPhysicalSwitch.put(uuid, psUUID);
190     }
191
192     public PhysicalSwitch getPhysicalSwitchForTunnel(UUID uuid) {
193         return physicalSwitches.get(mapTunnelToPhysicalSwitch.get(uuid));
194     }
195
196     public void removePhysicalSwitchForTunnel(UUID uuid) {
197         mapTunnelToPhysicalSwitch.remove(uuid);
198     }
199
200     public Map<UUID, UUID> getPhysicalSwitchesForTunnels() {
201         return mapTunnelToPhysicalSwitch;
202     }
203
204     public boolean isKeyInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
205         DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
206         return deviceData != null && DeviceDataStatus.IN_TRANSIT == deviceData.status;
207     }
208
209     public boolean isConfigDataAvailable(Class<? extends Identifiable> cls, InstanceIdentifier key) {
210         return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key) != null;
211     }
212
213     public void updateConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key, Object data) {
214         HwvtepSouthboundUtil.updateData(configKeyVsData, cls, key,
215                 new DeviceData(key, null, data, DeviceDataStatus.AVAILABLE));
216     }
217
218     public DeviceData getConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
219         return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key);
220     }
221
222     public Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> getConfigData() {
223         return Collections.unmodifiableMap(configKeyVsData);
224     }
225
226     public void clearConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
227         HwvtepSouthboundUtil.clearData(configKeyVsData, cls, key);
228     }
229
230     public void markKeyAsInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
231         LOG.debug("Marking device data as intransit {}", key);
232         DeviceData deviceData = getDeviceOperData(cls, key);
233         UUID uuid = null;
234         Object data = null;
235         if (deviceData != null) {
236             uuid = deviceData.getUuid();
237             data = deviceData.getData();
238         }
239         HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
240                 new DeviceData(key, uuid, data, DeviceDataStatus.IN_TRANSIT));
241     }
242
243     public void updateDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key,
244             UUID uuid, Object data) {
245         LOG.debug("Updating device data {}", key);
246         DeviceData deviceData = new DeviceData(key, uuid, data, DeviceDataStatus.AVAILABLE);
247         HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key, deviceData);
248         HwvtepSouthboundUtil.updateData(uuidVsData, cls, uuid, deviceData);
249     }
250
251     public void clearDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
252         DeviceData deviceData = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
253         if (deviceData != null && deviceData.uuid != null) {
254             HwvtepSouthboundUtil.clearData(uuidVsData, cls, deviceData.uuid);
255         }
256         HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
257     }
258
259     public void clearDeviceOperData(Class<? extends Identifiable> cls) {
260         Map<InstanceIdentifier, DeviceData> iids = opKeyVsData.get(cls);
261         if (iids != null && !iids.isEmpty()) {
262             Iterator<Map.Entry<InstanceIdentifier, DeviceData>> it = iids.entrySet().iterator();
263             while (it.hasNext()) {
264                 Map.Entry<InstanceIdentifier, DeviceData> entry = it.next();
265                 DeviceData deviceData = entry.getValue();
266                 if (deviceData != null && deviceData.getStatus() != DeviceDataStatus.IN_TRANSIT) {
267                     it.remove();
268                 }
269             }
270         }
271     }
272
273     public DeviceData getDeviceOperData(Class<? extends Identifiable> cls, UUID uuid) {
274         return HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
275     }
276
277     public DeviceData getDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
278         return HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
279     }
280
281     public Map<InstanceIdentifier, DeviceData> getDeviceOperData(Class<? extends Identifiable> cls) {
282         return opKeyVsData.get(cls);
283     }
284
285     public InstanceIdentifier getDeviceOperKey(final Class<? extends Identifiable> cls, final UUID uuid) {
286         DeviceData deviceData = HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
287         if (deviceData != null) {
288             return deviceData.getKey();
289         }
290         return null;
291     }
292
293     public UUID getUUID(Class<? extends Identifiable> cls, InstanceIdentifier key) {
294         DeviceData data = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
295         if (data != null) {
296             return data.uuid;
297         }
298         return null;
299     }
300
301     public <T extends Identifiable> void addJobToQueue(DependentJob<T> job) {
302         dependencyQueue.addToQueue(job);
303     }
304
305     public void onConfigDataAvailable() {
306         dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance);
307     }
308
309     public synchronized void onOperDataAvailable() {
310         dependencyQueue.processReadyJobsFromOpQueue(connectionInstance);
311     }
312
313     public void scheduleTransaction(final TransactCommand transactCommand) {
314         dependencyQueue.submit(() -> connectionInstance.transact(transactCommand));
315     }
316
317     public void clearInTransit(Class<? extends Identifiable> cls, InstanceIdentifier key) {
318         DeviceData deviceData = getDeviceOperData(cls, key);
319         if (deviceData != null && deviceData.isInTransitState()) {
320             if (deviceData.getData() != null) {
321                 HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
322                         new DeviceData(key, deviceData.getUuid(), deviceData.getData(), DeviceDataStatus.AVAILABLE));
323             } else {
324                 clearDeviceOperData(cls, key);
325             }
326         }
327     }
328
329     public void incRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
330         if (reference == null || tep == null) {
331             return;
332         }
333         tepIdReferences.computeIfAbsent(tep, (tepId) -> Sets.newConcurrentHashSet());
334         tepIdReferences.get(tep).add(reference);
335     }
336
337     public int getRefCount(InstanceIdentifier tep) {
338         return tepIdReferences.containsKey(tep) ? tepIdReferences.get(tep).size() : 0;
339     }
340
341     public Set<InstanceIdentifier> getRefCounts(InstanceIdentifier tep) {
342         return tepIdReferences.get(tep);
343     }
344
345     public void decRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
346         if (reference == null || tep == null || !tepIdReferences.containsKey(tep)) {
347             return;
348         }
349         //synchronize to make sure that no two parallel deletes puts the key in transit state twice
350         synchronized (this) {
351             boolean removed = tepIdReferences.get(tep).remove(reference);
352             if (removed && tepIdReferences.get(tep).isEmpty()) {
353                 LOG.debug("Marking the termination point as in transit ref count zero {} ", tep);
354                 markKeyAsInTransit(TerminationPoint.class, tep);
355             }
356         }
357     }
358
359     public void clearLogicalSwitchRefs(InstanceIdentifier<LogicalSwitches> logicalSwitchKey) {
360         Map<InstanceIdentifier<RemoteMcastMacs>, RemoteMcastMacs> mcasts = logicalSwitchVsMcasts.get(logicalSwitchKey);
361         if (mcasts != null) {
362             mcasts.entrySet().forEach((entry) -> removeRemoteMcast(logicalSwitchKey, entry.getKey()));
363         }
364         Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs> ucasts = logicalSwitchVsUcasts.get(logicalSwitchKey);
365         if (ucasts != null) {
366             ucasts.entrySet().forEach((entry) -> removeRemoteUcast(logicalSwitchKey, entry.getKey()));
367         }
368         markKeyAsInTransit(LogicalSwitches.class, logicalSwitchKey);
369     }
370
371     public  void updateRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid,
372                                    InstanceIdentifier<RemoteMcastMacs> mcastIid,
373                                    RemoteMcastMacs mac) {
374         logicalSwitchVsMcasts.computeIfAbsent(lsIid, (lsKey) -> new ConcurrentHashMap<>());
375         logicalSwitchVsMcasts.get(lsIid).put(mcastIid, mac);
376         if (mac.getLocatorSet() != null) {
377             mac.getLocatorSet().forEach((iid) -> incRefCount(mcastIid, iid.getLocatorRef().getValue()));
378         }
379     }
380
381     public  void updateRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
382                                    InstanceIdentifier<RemoteUcastMacs> ucastIid,
383                                    RemoteUcastMacs mac) {
384         logicalSwitchVsUcasts.computeIfAbsent(lsIid, (lsKey) -> new ConcurrentHashMap<>());
385         logicalSwitchVsUcasts.get(lsIid).put(ucastIid, mac);
386         incRefCount(ucastIid, mac.getLocatorRef().getValue());
387     }
388
389     public void removeRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid,
390             InstanceIdentifier<RemoteMcastMacs> mcastIid) {
391         if (!logicalSwitchVsMcasts.containsKey(lsIid)) {
392             return;
393         }
394         RemoteMcastMacs mac = logicalSwitchVsMcasts.get(lsIid).remove(mcastIid);
395         if (mac != null && mac.getLocatorSet() != null) {
396             mac.getLocatorSet().forEach((iid) -> decRefCount(mcastIid, iid.getLocatorRef().getValue()));
397         }
398         markKeyAsInTransit(RemoteMcastMacs.class, mcastIid);
399     }
400
401     public void removeRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
402                                    InstanceIdentifier<RemoteUcastMacs> ucastIid) {
403         if (!logicalSwitchVsUcasts.containsKey(lsIid)) {
404             return;
405         }
406         RemoteUcastMacs mac = logicalSwitchVsUcasts.get(lsIid).remove(ucastIid);
407         if (mac != null) {
408             decRefCount(ucastIid, mac.getLocatorRef().getValue());
409         }
410         markKeyAsInTransit(RemoteUcastMacs.class, ucastIid);
411     }
412
413     public HwvtepConnectionInstance getConnectionInstance() {
414         return connectionInstance;
415     }
416
417     public void setConfigKeyVsData(Map<Class<? extends Identifiable>, Map<InstanceIdentifier,
418             DeviceData>> configKeyVsData) {
419         this.configKeyVsData = configKeyVsData;
420     }
421
422     public void setControllerTxHistory(TransactionHistory controllerTxHistory) {
423         this.controllerTxHistory = controllerTxHistory;
424     }
425
426     public void setDeviceUpdateHistory(TransactionHistory deviceUpdateHistory) {
427         this.deviceUpdateHistory = deviceUpdateHistory;
428     }
429
430     public void addToControllerTx(TransactionType transactionType, Object object) {
431         controllerTxHistory.addToHistory(transactionType, object);
432     }
433
434     public void addToDeviceUpdate(TransactionType transactionType, Object object) {
435         deviceUpdateHistory.addToHistory(transactionType, object);
436     }
437
438     public Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> getOperData() {
439         return Collections.unmodifiableMap(opKeyVsData);
440     }
441
442     public Map<Class<? extends Identifiable>, Map<UUID, DeviceData>> getUuidData() {
443         return Collections.unmodifiableMap(uuidVsData);
444     }
445 }