2 * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.ovsdb.hwvtepsouthbound;
10 import com.google.common.collect.Sets;
11 import java.util.Collections;
12 import java.util.HashMap;
13 import java.util.Iterator;
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;
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.
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.
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.
54 public class HwvtepDeviceInfo {
56 private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceInfo.class);
58 private Map<Class<? extends KeyAware>, Map<InstanceIdentifier, Boolean>> availableInOperDs =
59 new ConcurrentHashMap<>();
61 public void markAvailableInOperDs(Class<? extends KeyAware> cls, InstanceIdentifier key) {
62 availableInOperDs.putIfAbsent(cls, new ConcurrentHashMap<>());
63 availableInOperDs.get(cls).put(key, Boolean.TRUE);
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);
71 public Boolean clearOperDsAvailability(Class<? extends KeyAware> cls, InstanceIdentifier key) {
72 availableInOperDs.putIfAbsent(cls, new ConcurrentHashMap<>());
73 return availableInOperDs.get(cls).remove(key);
76 public enum DeviceDataStatus {
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;
89 DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
94 if (status == DeviceDataStatus.IN_TRANSIT) {
95 intransitTimeStamp = System.currentTimeMillis();
99 public Object getData() {
103 public DeviceDataStatus getStatus() {
107 public UUID getUuid() {
111 public InstanceIdentifier getKey() {
115 public boolean isIntransitTimeExpired() {
116 return System.currentTimeMillis()
117 > intransitTimeStamp + HwvtepSouthboundConstants.IN_TRANSIT_STATE_EXPIRY_TIME_MILLIS;
120 public boolean isInTransitState() {
121 return status == DeviceDataStatus.IN_TRANSIT;
124 public boolean isAvailableInOperDs() {
129 public String toString() {
130 return key + " uuid:" + uuid + " data:" + data + " status:" + status;
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;
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;
153 public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
154 this.connectionInstance = hwvtepConnectionInstance;
155 this.dependencyQueue = new DependencyQueue(this);
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();
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());
177 public void putPhysicalSwitch(UUID uuid, PhysicalSwitch physicalSwitch) {
178 physicalSwitches.put(uuid, physicalSwitch);
181 public PhysicalSwitch getPhysicalSwitch(UUID uuid) {
182 return physicalSwitches.get(uuid);
185 public PhysicalSwitch removePhysicalSwitch(UUID uuid) {
186 return physicalSwitches.remove(uuid);
189 public Map<UUID, PhysicalSwitch> getPhysicalSwitches() {
190 return physicalSwitches;
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();
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());
212 public void putPhysicalSwitchForTunnel(UUID uuid, UUID psUUID) {
213 mapTunnelToPhysicalSwitch.put(uuid, psUUID);
216 public PhysicalSwitch getPhysicalSwitchForTunnel(UUID uuid) {
217 return physicalSwitches.get(mapTunnelToPhysicalSwitch.get(uuid));
220 public void removePhysicalSwitchForTunnel(UUID uuid) {
221 mapTunnelToPhysicalSwitch.remove(uuid);
224 public Map<UUID, UUID> getPhysicalSwitchesForTunnels() {
225 return mapTunnelToPhysicalSwitch;
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;
233 public boolean isConfigDataAvailable(Class<? extends KeyAware> cls, InstanceIdentifier key) {
234 return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key) != null;
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));
242 public DeviceData getConfigData(Class<? extends KeyAware> cls, InstanceIdentifier key) {
243 return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key);
246 public Map<Class<? extends KeyAware>, Map<InstanceIdentifier, DeviceData>> getConfigData() {
247 return Collections.unmodifiableMap(configKeyVsData);
250 public void clearConfigData(Class<? extends KeyAware> cls, InstanceIdentifier key) {
251 HwvtepSouthboundUtil.clearData(configKeyVsData, cls, key);
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);
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);
264 HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
265 new DeviceData(key, uuid, data, DeviceDataStatus.IN_TRANSIT));
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);
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);
281 HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
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) {
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());
303 HwvtepSouthboundUtil.clearData(uuidVsData, cls, uuid);
304 HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
307 public DeviceData getDeviceOperData(Class<? extends KeyAware> cls, UUID uuid) {
308 return HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
311 public DeviceData getDeviceOperData(Class<? extends KeyAware> cls, InstanceIdentifier key) {
312 return HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
315 public Map<InstanceIdentifier, DeviceData> getDeviceOperData(Class<? extends KeyAware> cls) {
316 return opKeyVsData.get(cls);
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();
327 public UUID getUUID(Class<? extends KeyAware> cls, InstanceIdentifier key) {
328 DeviceData data = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
335 public <T extends KeyAware> void addJobToQueue(DependentJob<T> job) {
336 dependencyQueue.addToQueue(job);
339 public void onConfigDataAvailable() {
340 dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance);
343 public synchronized void onOperDataAvailable() {
344 dependencyQueue.processReadyJobsFromOpQueue(connectionInstance);
347 public void scheduleTransaction(final TransactCommand transactCommand) {
348 dependencyQueue.submit(() -> connectionInstance.transact(transactCommand));
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));
358 clearDeviceOperData(cls, key);
363 public void incRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
364 if (reference == null || tep == null) {
367 tepIdReferences.computeIfAbsent(tep, (tepId) -> Sets.newConcurrentHashSet());
368 tepIdReferences.get(tep).add(reference);
371 public int getRefCount(InstanceIdentifier tep) {
372 return tepIdReferences.containsKey(tep) ? tepIdReferences.get(tep).size() : 0;
375 public Set<InstanceIdentifier> getRefCounts(InstanceIdentifier tep) {
376 return tepIdReferences.get(tep);
379 public void decRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
380 if (reference == null || tep == null || !tepIdReferences.containsKey(tep)) {
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);
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()));
398 Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs> ucasts = logicalSwitchVsUcasts.get(logicalSwitchKey);
399 if (ucasts != null) {
400 ucasts.entrySet().forEach((entry) -> removeRemoteUcast(logicalSwitchKey, entry.getKey()));
402 markKeyAsInTransit(LogicalSwitches.class, logicalSwitchKey);
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()));
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());
423 public void removeRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid,
424 InstanceIdentifier<RemoteMcastMacs> mcastIid) {
425 if (!logicalSwitchVsMcasts.containsKey(lsIid)) {
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()));
432 markKeyAsInTransit(RemoteMcastMacs.class, mcastIid);
435 public void removeRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
436 InstanceIdentifier<RemoteUcastMacs> ucastIid) {
437 if (!logicalSwitchVsUcasts.containsKey(lsIid)) {
440 RemoteUcastMacs mac = logicalSwitchVsUcasts.get(lsIid).remove(ucastIid);
442 decRefCount(ucastIid, mac.getLocatorRef().getValue());
444 markKeyAsInTransit(RemoteUcastMacs.class, ucastIid);
447 public HwvtepConnectionInstance getConnectionInstance() {
448 return connectionInstance;
451 public void setConfigKeyVsData(Map<Class<? extends KeyAware>, Map<InstanceIdentifier,
452 DeviceData>> configKeyVsData) {
453 this.configKeyVsData = configKeyVsData;
456 public void setControllerTxHistory(TransactionHistory controllerTxHistory) {
457 this.controllerTxHistory = controllerTxHistory;
460 public void setDeviceUpdateHistory(TransactionHistory deviceUpdateHistory) {
461 this.deviceUpdateHistory = deviceUpdateHistory;
464 public void addToControllerTx(TransactionType transactionType, Object object) {
465 controllerTxHistory.addToHistory(transactionType, object);
468 public void addToDeviceUpdate(TransactionType transactionType, Object object) {
469 deviceUpdateHistory.addToHistory(transactionType, object);
472 public Map<Class<? extends KeyAware>, Map<InstanceIdentifier, DeviceData>> getOperData() {
473 return Collections.unmodifiableMap(opKeyVsData);
476 public Map<Class<? extends KeyAware>, Map<UUID, DeviceData>> getUuidData() {
477 return Collections.unmodifiableMap(uuidVsData);
480 public void putKeyInDependencyQueue(InstanceIdentifier iid) {
481 iidInQueueCount.putIfAbsent(iid, new AtomicInteger(0));
482 iidInQueueCount.get(iid).incrementAndGet();
485 public void clearKeyFromDependencyQueue(InstanceIdentifier iid) {
486 iidInQueueCount.remove(iid);
489 public boolean isKeyInDependencyQueue(InstanceIdentifier iid) {
490 return iidInQueueCount.containsKey(iid);