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