2 * Copyright (c) 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.netvirt.qosservice;
12 import com.google.common.base.Optional;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import java.math.BigInteger;
16 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import javax.annotation.PostConstruct;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.GetNodeConnectorStatisticsOutput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.direct.statistics.rev160511.OpendaylightDirectStatisticsService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.qosalert.config.rev170301.QosalertConfig;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.qosalert.config.rev170301.QosalertConfigBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
46 import org.opendaylight.yangtools.yang.binding.DataObject;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.common.RpcResult;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
54 public final class QosAlertManager implements Runnable {
56 private short threshold;
57 private boolean alertEnabled;
58 private int pollInterval;
59 private final QosalertConfig defaultConfig;
60 private boolean statsPollThreadStart;
61 private static DataBroker dataBroker;
62 private static OpendaylightDirectStatisticsService odlDirectStatisticsService;
63 private static INeutronVpnManager neutronVpnManager;
64 private Thread thread;
65 private static OdlInterfaceRpcService odlInterfaceRpcService;
66 private static ConcurrentHashMap<BigInteger, ConcurrentHashMap<String, QosAlertPortData>>
67 qosAlertDpnPortNumberMap = new ConcurrentHashMap<>();
68 private static final Logger LOG = LoggerFactory.getLogger(QosAlertManager.class);
70 private static final FutureCallback<Void> DEFAULT_FUTURE_CALLBACK;
73 DEFAULT_FUTURE_CALLBACK = new FutureCallback<Void>() {
76 public void onSuccess(Void result) {
77 LOG.info("Datastore operation completed successfully");
81 public void onFailure(Throwable error) {
82 LOG.error("Error in datastore operation {}", error);
89 public QosAlertManager(final DataBroker dataBroker,
90 final OpendaylightDirectStatisticsService odlDirectStatisticsService,
91 final QosalertConfig defaultConfig,
92 final OdlInterfaceRpcService odlInterfaceRpcService,
93 final INeutronVpnManager neutronVpnManager) {
95 LOG.info("{} created", getClass().getSimpleName());
96 this.dataBroker = dataBroker;
97 this.odlDirectStatisticsService = odlDirectStatisticsService;
98 this.odlInterfaceRpcService = odlInterfaceRpcService;
99 this.neutronVpnManager = neutronVpnManager;
100 this.defaultConfig = defaultConfig;
102 LOG.info("QosAlert default config poll alertEnabled:{} threshold:{} pollInterval:{}",
103 defaultConfig.isQosAlertEnabled(), defaultConfig.getQosDropPacketThreshold(),
104 defaultConfig.getQosAlertPollInterval());
110 qosAlertDpnPortNumberMap.clear();
111 QosAlertPortData.setAlertThreshold(threshold);
112 statsPollThreadStart = true;
113 startStatsPollThread();
114 LOG.info("{} init done", getClass().getSimpleName());
118 public void close() {
119 statsPollThreadStart = false;
120 if (thread != null) {
123 LOG.info("{} close done", getClass().getSimpleName());
126 public void setQosAlertOwner(boolean isOwner) {
127 LOG.trace("qos alert set owner : {}", isOwner);
128 statsPollThreadStart = isOwner;
129 if (thread != null) {
132 startStatsPollThread();
138 LOG.info("Qos alert poll thread started");
140 while (statsPollThreadStart && alertEnabled) {
141 LOG.debug("Thread loop polling :{} threshold:{} pollInterval:{}", alertEnabled, threshold,
145 pollDirectStatisticsForAllNodes();
146 Thread.sleep(pollInterval * 60 * 1000); // pollInterval in minutes
147 } catch (final InterruptedException e) {
148 LOG.debug("Qos polling thread interrupted");
152 LOG.info("Qos alert poll thread stopped");
155 private void startStatsPollThread() {
156 if (statsPollThreadStart && alertEnabled && (thread == null)) {
157 thread = new Thread(this);
158 thread.setDaemon(true);
163 private void getDefaultConfig() {
164 alertEnabled = defaultConfig.isQosAlertEnabled();
165 threshold = defaultConfig.getQosDropPacketThreshold();
166 pollInterval = defaultConfig.getQosAlertPollInterval();
169 public void setQosalertConfig(QosalertConfig config) {
171 LOG.info("New QoS alert config threshold:{} polling alertEnabled:{} interval:{}",
172 config.getQosDropPacketThreshold(), config.isQosAlertEnabled(),
173 config.getQosAlertPollInterval());
175 threshold = config.getQosDropPacketThreshold().shortValue();
176 alertEnabled = config.isQosAlertEnabled().booleanValue();
177 pollInterval = config.getQosAlertPollInterval();
179 QosAlertPortData.setAlertThreshold(threshold);
181 if (thread != null) {
184 startStatsPollThread();
189 public void restoreDefaultConfig() {
190 LOG.info("Restoring default configuration");
192 QosAlertPortData.setAlertThreshold(threshold);
193 if (thread != null) {
196 startStatsPollThread();
200 public void setThreshold(short threshold) {
201 LOG.info("setting threshold {} in config data store", threshold);
202 this.threshold = threshold;
203 writeConfigDataStore();
206 public void setPollInterval(int pollInterval) {
207 LOG.info("setting interval {} in config data store", pollInterval);
208 this.pollInterval = pollInterval;
209 writeConfigDataStore();
212 public void setEnable(boolean alertEnabled) {
213 LOG.info("setting QoS poll to {} in config data store", alertEnabled);
214 this.alertEnabled = alertEnabled;
215 writeConfigDataStore();
218 public static void addToQosAlertCache(Port port) {
219 LOG.trace("Adding port {} in cache", port.getUuid());
221 BigInteger dpnId = QosNeutronUtils.getDpnForInterface(odlInterfaceRpcService, port.getUuid().getValue());
223 if (dpnId.equals(BigInteger.ZERO)) {
224 LOG.debug("DPN ID for port {} not found", port.getUuid());
228 String portNumber = QosNeutronUtils.getPortNumberForInterface(odlInterfaceRpcService,
229 port.getUuid().getValue());
231 if (qosAlertDpnPortNumberMap.containsKey(dpnId)) {
232 LOG.trace("Adding port {} port number {} in DPN {}", port.getUuid(), portNumber, dpnId);
233 qosAlertDpnPortNumberMap.get(dpnId).put(portNumber, new QosAlertPortData(port, neutronVpnManager));
235 LOG.trace("Adding DPN ID {} with port {} port number {}", dpnId, port.getUuid(), portNumber);
236 ConcurrentHashMap<String, QosAlertPortData> portDataMap = new ConcurrentHashMap<>();
237 portDataMap.put(portNumber, new QosAlertPortData(port, neutronVpnManager));
238 qosAlertDpnPortNumberMap.put(dpnId, portDataMap);
242 public static void addToQosAlertCache(Network network) {
243 LOG.trace("Adding network {} in cache", network.getUuid());
245 List<Uuid> subnetIds = QosNeutronUtils.getSubnetIdsFromNetworkId(dataBroker, network.getUuid());
247 if (subnetIds != null) {
248 for (Uuid subnetId : subnetIds) {
249 List<Uuid> portIds = QosNeutronUtils.getPortIdsFromSubnetId(dataBroker, subnetId);
250 if (portIds != null) {
251 for (Uuid portId : portIds) {
252 Port port = neutronVpnManager.getNeutronPort(portId);
254 if (!QosNeutronUtils.portHasQosPolicy(neutronVpnManager, port)) {
255 LOG.trace("Adding network {} port {} in cache", network.getUuid(), port.getUuid());
256 addToQosAlertCache(port);
265 public static void removeFromQosAlertCache(Port port) {
266 LOG.trace("Removing port {} from cache", port.getUuid());
268 BigInteger dpnId = QosNeutronUtils.getDpnForInterface(odlInterfaceRpcService, port.getUuid().getValue());
270 if (dpnId.equals(BigInteger.ZERO)) {
271 LOG.debug("DPN ID for port {} not found", port.getUuid());
275 String portNumber = QosNeutronUtils.getPortNumberForInterface(odlInterfaceRpcService,
276 port.getUuid().getValue());
278 if (qosAlertDpnPortNumberMap.containsKey(dpnId)
279 && qosAlertDpnPortNumberMap.get(dpnId).containsKey(portNumber)) {
280 qosAlertDpnPortNumberMap.get(dpnId).remove(portNumber);
281 LOG.trace("Removed DPN {} port {} port number {} from cache", dpnId, port.getUuid(), portNumber);
282 if (qosAlertDpnPortNumberMap.get(dpnId).isEmpty()) {
283 LOG.trace("DPN {} empty. Removing from cache", dpnId);
284 qosAlertDpnPortNumberMap.remove(dpnId);
287 LOG.trace("DPN {} port {} port number {} not found in cache", dpnId, port.getUuid(), portNumber);
292 public static void removeFromQosAlertCache(NodeConnectorId nodeConnectorId) {
293 LOG.trace("Removing node connector {} from cache", nodeConnectorId.getValue());
295 long nodeId = MDSALUtil.getDpnIdFromPortName(nodeConnectorId);
298 LOG.debug("Node ID for node connector {} not found", nodeConnectorId.getValue());
302 BigInteger dpnId = new BigInteger(String.valueOf(nodeId));
304 long portId = MDSALUtil.getOfPortNumberFromPortName(nodeConnectorId);
306 String portNumber = String.valueOf(portId);
308 if (qosAlertDpnPortNumberMap.containsKey(dpnId)
309 && qosAlertDpnPortNumberMap.get(dpnId).containsKey(portNumber)) {
310 qosAlertDpnPortNumberMap.get(dpnId).remove(portNumber);
311 LOG.trace("Removed DPN {} port number {} from cache", dpnId, portNumber);
313 LOG.trace("DPN {} port number {} not found in cache", dpnId, portNumber);
318 public static void removeFromQosAlertCache(Network network) {
319 LOG.trace("Removing network {} from cache", network.getUuid());
321 List<Uuid> subnetIds = QosNeutronUtils.getSubnetIdsFromNetworkId(dataBroker, network.getUuid());
323 if (subnetIds != null) {
324 for (Uuid subnetId : subnetIds) {
325 List<Uuid> portIds = QosNeutronUtils.getPortIdsFromSubnetId(dataBroker, subnetId);
326 if (portIds != null) {
327 for (Uuid portId : portIds) {
328 Port port = neutronVpnManager.getNeutronPort(portId);
330 if (!QosNeutronUtils.portHasQosPolicy(neutronVpnManager, port)) {
331 LOG.trace("Removing network {} port {} from cache", network.getUuid(), port.getUuid());
332 removeFromQosAlertCache(port);
341 private static <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
342 InstanceIdentifier<T> path, T data, DataBroker broker,
343 FutureCallback<Void> callback) {
344 WriteTransaction tx = broker.newWriteOnlyTransaction();
345 tx.put(datastoreType, path, data, true);
346 Futures.addCallback(tx.submit(), callback);
349 private void writeConfigDataStore() {
351 InstanceIdentifier<QosalertConfig> path = InstanceIdentifier.builder(QosalertConfig.class).build();
353 QosalertConfig qosAlertConfig = new QosalertConfigBuilder()
354 .setQosDropPacketThreshold(threshold)
355 .setQosAlertEnabled(alertEnabled)
356 .setQosAlertPollInterval(pollInterval)
359 asyncWrite(LogicalDatastoreType.CONFIGURATION, path, qosAlertConfig, dataBroker, DEFAULT_FUTURE_CALLBACK);
362 private void pollDirectStatisticsForAllNodes() {
363 LOG.trace("Polling direct statistics from nodes");
365 for (BigInteger dpn : qosAlertDpnPortNumberMap.keySet()) {
366 LOG.trace("Polling DPN ID {}", dpn);
367 GetNodeConnectorStatisticsInputBuilder input = new GetNodeConnectorStatisticsInputBuilder()
368 .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
369 .child(Node.class, new NodeKey(new NodeId(IfmConstants.OF_URI_PREFIX + dpn))).build()))
370 .setStoreStats(false);
371 Future<RpcResult<GetNodeConnectorStatisticsOutput>> rpcResultFuture =
372 odlDirectStatisticsService.getNodeConnectorStatistics(input.build());
374 RpcResult<GetNodeConnectorStatisticsOutput> rpcResult = null;
376 rpcResult = rpcResultFuture.get();
377 } catch (InterruptedException | ExecutionException e) {
378 LOG.error("Exception {} occurred with node {} Direct-Statistics get", e, dpn);
380 if (Optional.fromNullable(rpcResult).isPresent() && rpcResult.isSuccessful()
381 && Optional.fromNullable(rpcResult.getResult()).isPresent()) {
383 GetNodeConnectorStatisticsOutput nodeConnectorStatisticsOutput = rpcResult.getResult();
385 List<NodeConnectorStatisticsAndPortNumberMap> nodeConnectorStatisticsAndPortNumberMapList =
386 nodeConnectorStatisticsOutput.getNodeConnectorStatisticsAndPortNumberMap();
388 ConcurrentHashMap<String, QosAlertPortData> portDataMap = qosAlertDpnPortNumberMap.get(dpn);
389 for (NodeConnectorStatisticsAndPortNumberMap stats : nodeConnectorStatisticsAndPortNumberMapList) {
390 QosAlertPortData portData = portDataMap.get(stats.getNodeConnectorId().getValue());
391 if (portData != null) {
392 portData.updatePortStatistics(stats);
396 LOG.error("Direct-Statistics not available for node {}", dpn);