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
9 package org.opendaylight.ovsdb.hwvtepsouthbound;
11 import com.google.common.collect.Sets;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.Iterator;
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;
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.
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.
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.
56 public class HwvtepDeviceInfo {
58 private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceInfo.class);
60 public enum DeviceDataStatus {
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;
73 DeviceData(InstanceIdentifier key, UUID uuid, Object data, DeviceDataStatus status) {
78 if (status == DeviceDataStatus.IN_TRANSIT) {
79 intransitTimeStamp = System.currentTimeMillis();
83 public Object getData() {
87 public DeviceDataStatus getStatus() {
91 public UUID getUuid() {
95 public InstanceIdentifier getKey() {
99 public boolean isIntransitTimeExpired() {
100 return System.currentTimeMillis()
101 > intransitTimeStamp + HwvtepSouthboundConstants.IN_TRANSIT_STATE_EXPIRY_TIME_MILLIS;
104 public boolean isInTransitState() {
105 return status == DeviceDataStatus.IN_TRANSIT;
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<>();
117 private final HwvtepConnectionInstance connectionInstance;
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;
129 public HwvtepDeviceInfo(HwvtepConnectionInstance hwvtepConnectionInstance) {
130 this.connectionInstance = hwvtepConnectionInstance;
131 this.dependencyQueue = new DependencyQueue(this);
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();
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());
153 public void putPhysicalSwitch(UUID uuid, PhysicalSwitch physicalSwitch) {
154 physicalSwitches.put(uuid, physicalSwitch);
157 public PhysicalSwitch getPhysicalSwitch(UUID uuid) {
158 return physicalSwitches.get(uuid);
161 public PhysicalSwitch removePhysicalSwitch(UUID uuid) {
162 return physicalSwitches.remove(uuid);
165 public Map<UUID, PhysicalSwitch> getPhysicalSwitches() {
166 return physicalSwitches;
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();
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());
188 public void putPhysicalSwitchForTunnel(UUID uuid, UUID psUUID) {
189 mapTunnelToPhysicalSwitch.put(uuid, psUUID);
192 public PhysicalSwitch getPhysicalSwitchForTunnel(UUID uuid) {
193 return physicalSwitches.get(mapTunnelToPhysicalSwitch.get(uuid));
196 public void removePhysicalSwitchForTunnel(UUID uuid) {
197 mapTunnelToPhysicalSwitch.remove(uuid);
200 public Map<UUID, UUID> getPhysicalSwitchesForTunnels() {
201 return mapTunnelToPhysicalSwitch;
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;
209 public boolean isConfigDataAvailable(Class<? extends Identifiable> cls, InstanceIdentifier key) {
210 return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key) != null;
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));
218 public DeviceData getConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
219 return HwvtepSouthboundUtil.getData(configKeyVsData, cls, key);
222 public Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> getConfigData() {
223 return Collections.unmodifiableMap(configKeyVsData);
226 public void clearConfigData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
227 HwvtepSouthboundUtil.clearData(configKeyVsData, cls, key);
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);
235 if (deviceData != null) {
236 uuid = deviceData.getUuid();
237 data = deviceData.getData();
239 HwvtepSouthboundUtil.updateData(opKeyVsData, cls, key,
240 new DeviceData(key, uuid, data, DeviceDataStatus.IN_TRANSIT));
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);
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);
256 HwvtepSouthboundUtil.clearData(opKeyVsData, cls, key);
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) {
273 public DeviceData getDeviceOperData(Class<? extends Identifiable> cls, UUID uuid) {
274 return HwvtepSouthboundUtil.getData(uuidVsData, cls, uuid);
277 public DeviceData getDeviceOperData(Class<? extends Identifiable> cls, InstanceIdentifier key) {
278 return HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
281 public Map<InstanceIdentifier, DeviceData> getDeviceOperData(Class<? extends Identifiable> cls) {
282 return opKeyVsData.get(cls);
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();
293 public UUID getUUID(Class<? extends Identifiable> cls, InstanceIdentifier key) {
294 DeviceData data = HwvtepSouthboundUtil.getData(opKeyVsData, cls, key);
301 public <T extends Identifiable> void addJobToQueue(DependentJob<T> job) {
302 dependencyQueue.addToQueue(job);
305 public void onConfigDataAvailable() {
306 dependencyQueue.processReadyJobsFromConfigQueue(connectionInstance);
309 public synchronized void onOperDataAvailable() {
310 dependencyQueue.processReadyJobsFromOpQueue(connectionInstance);
313 public void scheduleTransaction(final TransactCommand transactCommand) {
314 dependencyQueue.submit(() -> connectionInstance.transact(transactCommand));
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));
324 clearDeviceOperData(cls, key);
329 public void incRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
330 if (reference == null || tep == null) {
333 tepIdReferences.computeIfAbsent(tep, (tepId) -> Sets.newConcurrentHashSet());
334 tepIdReferences.get(tep).add(reference);
337 public int getRefCount(InstanceIdentifier tep) {
338 return tepIdReferences.containsKey(tep) ? tepIdReferences.get(tep).size() : 0;
341 public Set<InstanceIdentifier> getRefCounts(InstanceIdentifier tep) {
342 return tepIdReferences.get(tep);
345 public void decRefCount(InstanceIdentifier reference, InstanceIdentifier tep) {
346 if (reference == null || tep == null || !tepIdReferences.containsKey(tep)) {
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);
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()));
364 Map<InstanceIdentifier<RemoteUcastMacs>, RemoteUcastMacs> ucasts = logicalSwitchVsUcasts.get(logicalSwitchKey);
365 if (ucasts != null) {
366 ucasts.entrySet().forEach((entry) -> removeRemoteUcast(logicalSwitchKey, entry.getKey()));
368 markKeyAsInTransit(LogicalSwitches.class, logicalSwitchKey);
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()));
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());
389 public void removeRemoteMcast(InstanceIdentifier<LogicalSwitches> lsIid,
390 InstanceIdentifier<RemoteMcastMacs> mcastIid) {
391 if (!logicalSwitchVsMcasts.containsKey(lsIid)) {
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()));
398 markKeyAsInTransit(RemoteMcastMacs.class, mcastIid);
401 public void removeRemoteUcast(InstanceIdentifier<LogicalSwitches> lsIid,
402 InstanceIdentifier<RemoteUcastMacs> ucastIid) {
403 if (!logicalSwitchVsUcasts.containsKey(lsIid)) {
406 RemoteUcastMacs mac = logicalSwitchVsUcasts.get(lsIid).remove(ucastIid);
408 decRefCount(ucastIid, mac.getLocatorRef().getValue());
410 markKeyAsInTransit(RemoteUcastMacs.class, ucastIid);
413 public HwvtepConnectionInstance getConnectionInstance() {
414 return connectionInstance;
417 public void setConfigKeyVsData(Map<Class<? extends Identifiable>, Map<InstanceIdentifier,
418 DeviceData>> configKeyVsData) {
419 this.configKeyVsData = configKeyVsData;
422 public void setControllerTxHistory(TransactionHistory controllerTxHistory) {
423 this.controllerTxHistory = controllerTxHistory;
426 public void setDeviceUpdateHistory(TransactionHistory deviceUpdateHistory) {
427 this.deviceUpdateHistory = deviceUpdateHistory;
430 public void addToControllerTx(TransactionType transactionType, Object object) {
431 controllerTxHistory.addToHistory(transactionType, object);
434 public void addToDeviceUpdate(TransactionType transactionType, Object object) {
435 deviceUpdateHistory.addToHistory(transactionType, object);
438 public Map<Class<? extends Identifiable>, Map<InstanceIdentifier, DeviceData>> getOperData() {
439 return Collections.unmodifiableMap(opKeyVsData);
442 public Map<Class<? extends Identifiable>, Map<UUID, DeviceData>> getUuidData() {
443 return Collections.unmodifiableMap(uuidVsData);