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