Merge "Revert "Spec for Counter Framework bundle""
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / pmcounters / NodeConnectorStatsImpl.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.genius.interfacemanager.pmcounters;
9
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.Executors;
18 import java.util.concurrent.ScheduledExecutorService;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.ThreadFactory;
21 import java.util.concurrent.TimeUnit;
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.NotificationService;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
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.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 @Singleton
52 public class NodeConnectorStatsImpl extends AsyncDataTreeChangeListenerBase<Node, NodeConnectorStatsImpl> {
53     private static final Logger LOG = LoggerFactory.getLogger(NodeConnectorStatsImpl.class);
54     private static final String STATS_POLL_FLAG = "interfacemgr.pmcounters.poll";
55     private static final int THREAD_POOL_SIZE = 4;
56     private static final int NO_DELAY = 0;
57     public static final PMAgentForNodeConnectorCounters PMAGENT = new PMAgentForNodeConnectorCounters();
58     private final PortRpcStatisticsListener portStatsListener = new PortRpcStatisticsListener();
59     private final FlowRpcStatisticsListener flowTableStatsListener = new FlowRpcStatisticsListener();
60     private final List<BigInteger> nodes = new ArrayList<>();
61     Map<String, Map<String, String>> nodeAndNcIdOFPortDurationMap = new ConcurrentHashMap<>();
62     Map<String, Map<String, String>> nodeAndNcIdOFPortReceiveDropMap = new ConcurrentHashMap<>();
63     Map<String, Map<String, String>> nodeAndNcIdOFPortReceiveError = new ConcurrentHashMap<>();
64     Map<String, Map<String, String>> nodeAndNcIdPacketSentMap = new ConcurrentHashMap<>();
65     Map<String, Map<String, String>> nodeAndNcIdPacketReceiveMap = new ConcurrentHashMap<>();
66     Map<String, Map<String, String>> nodeAndNcIdBytesSentMap = new ConcurrentHashMap<>();
67     Map<String, Map<String, String>> nodeAndNcIdBytesReceiveMap = new ConcurrentHashMap<>();
68     Map<String, Map<String, String>> nodeAndEntriesPerOFTableMap = new ConcurrentHashMap<>();
69     private ScheduledFuture<?> scheduledResult;
70     private final OpendaylightPortStatisticsService statPortService;
71     private final ScheduledExecutorService portStatExecutorService;
72     private final OpendaylightFlowTableStatisticsService opendaylightFlowTableStatisticsService;
73
74     @Inject
75     public NodeConnectorStatsImpl(DataBroker dataBroker, NotificationService notificationService,
76                                   final OpendaylightPortStatisticsService opendaylightPortStatisticsService,
77                                   final OpendaylightFlowTableStatisticsService opendaylightFlowTableStatisticsService) {
78         super(Node.class, NodeConnectorStatsImpl.class);
79         this.statPortService = opendaylightPortStatisticsService;
80         this.opendaylightFlowTableStatisticsService = opendaylightFlowTableStatisticsService;
81         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
82         portStatExecutorService = Executors.newScheduledThreadPool(THREAD_POOL_SIZE,
83             getThreadFactory("Port Stats " + "Request Task"));
84         notificationService.registerNotificationListener(portStatsListener);
85         notificationService.registerNotificationListener(flowTableStatsListener);
86         PMAGENT.registerMbean();
87     }
88
89     @Override
90     public InstanceIdentifier<Node> getWildCardPath() {
91         return InstanceIdentifier.create(Nodes.class).child(Node.class);
92     }
93
94     @Override
95     protected NodeConnectorStatsImpl getDataTreeChangeListener() {
96         return NodeConnectorStatsImpl.this;
97     }
98
99     /*
100      * PortStat request task is started when first DPN gets connected
101      */
102     private void schedulePortStatRequestTask() {
103         if (!Boolean.getBoolean(STATS_POLL_FLAG)) {
104             LOG.info("Port statistics is turned off");
105             return;
106         }
107         LOG.info("Scheduling port statistics request");
108         PortStatRequestTask portStatRequestTask = new PortStatRequestTask();
109         scheduledResult = portStatExecutorService.scheduleAtFixedRate(portStatRequestTask, NO_DELAY, 10000,
110                 TimeUnit.MILLISECONDS);
111     }
112
113     /*
114      * PortStat request task is stopped when last DPN is removed.
115      */
116     private void stopPortStatRequestTask() {
117         if (scheduledResult != null) {
118             LOG.info("Stopping port statistics request");
119             scheduledResult.cancel(true);
120         }
121     }
122
123     /*
124      * This task queries for node connector statistics as well as flowtables
125      * statistics every 10 secs. Minimum period which can be configured for
126      * PMJob is 10 secs.
127      */
128     private class PortStatRequestTask implements Runnable {
129
130         @Override
131         public void run() {
132             if (LOG.isTraceEnabled()) {
133                 LOG.trace("Requesting port stats - {}");
134             }
135             for (BigInteger node : nodes) {
136                 LOG.trace("Requesting AllNodeConnectorStatistics for node - {}", node);
137                 statPortService.getAllNodeConnectorsStatistics(buildGetAllNodeConnectorStatistics(node));
138                 opendaylightFlowTableStatisticsService.getFlowTablesStatistics(buildGetFlowTablesStatistics(node));
139             }
140         }
141
142         private GetAllNodeConnectorsStatisticsInput buildGetAllNodeConnectorStatistics(BigInteger dpId) {
143             return new GetAllNodeConnectorsStatisticsInputBuilder()
144                     .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
145                             .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId.toString()))).build()))
146                     .build();
147         }
148
149         private GetFlowTablesStatisticsInput buildGetFlowTablesStatistics(BigInteger dpId) {
150             return new GetFlowTablesStatisticsInputBuilder()
151                     .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
152                             .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId.toString()))).build()))
153                     .build();
154         }
155     }
156
157     private ThreadFactory getThreadFactory(String threadNameFormat) {
158         ThreadFactoryBuilder builder = new ThreadFactoryBuilder();
159         builder.setNameFormat(threadNameFormat);
160         builder.setUncaughtExceptionHandler((thread, exception) -> LOG
161                 .error("Received Uncaught Exception event in Thread: {}", thread.getName(), exception));
162         return builder.build();
163     }
164
165     /*
166      * PortRpcStatisticsListener listens for the NodeConnectorStatisticsUpdate
167      * and then update the corresponding counter map
168      */
169     class PortRpcStatisticsListener implements OpendaylightPortStatisticsListener {
170
171         @Override
172         public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate ncStats) {
173             Map<String, String> ncIdOFPortDurationMap = new HashMap<>();
174             Map<String, String> ncIdOFPortReceiveDropMap = new HashMap<>();
175             Map<String, String> ncIdOFPortReceiveError = new HashMap<>();
176             Map<String, String> ncIdPacketSentMap = new HashMap<>();
177             Map<String, String> ncIdPacketReceiveMap = new HashMap<>();
178             Map<String, String> ncIdBytesSentMap = new HashMap<>();
179             Map<String, String> ncIdBytesReceiveMap = new HashMap<>();
180             List<NodeConnectorStatisticsAndPortNumberMap> ncStatsAndPortMapList = ncStats
181                     .getNodeConnectorStatisticsAndPortNumberMap();
182             NodeId nodeId = ncStats.getId();
183             String node = nodeId.getValue().split(":")[1];
184             for (NodeConnectorStatisticsAndPortNumberMap ncStatsAndPortMap : ncStatsAndPortMapList) {
185                 NodeConnectorId nodeConnector = ncStatsAndPortMap.getNodeConnectorId();
186                 String port = nodeConnector.getValue().split(":")[2];
187                 String nodePortStr = "dpnId_" + node + "_portNum_" + port;
188                 ncIdOFPortDurationMap.put("OFPortDuration:" + nodePortStr + "_OFPortDuration",
189                         ncStatsAndPortMap.getDuration().getSecond().getValue().toString());
190                 ncIdOFPortReceiveDropMap.put(
191                         "PacketsPerOFPortReceiveDrop:" + nodePortStr + "_PacketsPerOFPortReceiveDrop",
192                         ncStatsAndPortMap.getReceiveDrops().toString());
193                 ncIdOFPortReceiveError.put(
194                         "PacketsPerOFPortReceiveError:" + nodePortStr + "_PacketsPerOFPortReceiveError",
195                         ncStatsAndPortMap.getReceiveErrors().toString());
196                 ncIdPacketSentMap.put("PacketsPerOFPortSent:" + nodePortStr + "_PacketsPerOFPortSent",
197                         ncStatsAndPortMap.getPackets().getTransmitted().toString());
198                 ncIdPacketReceiveMap.put("PacketsPerOFPortReceive:" + nodePortStr + "_PacketsPerOFPortReceive",
199                         ncStatsAndPortMap.getPackets().getReceived().toString());
200                 ncIdBytesSentMap.put("BytesPerOFPortSent:" + nodePortStr + "_BytesPerOFPortSent",
201                         ncStatsAndPortMap.getBytes().getTransmitted().toString());
202                 ncIdBytesReceiveMap.put("BytesPerOFPortReceive:" + nodePortStr + "_BytesPerOFPortReceive",
203                         ncStatsAndPortMap.getBytes().getReceived().toString());
204             }
205             LOG.trace("Port Stats {}", ncStatsAndPortMapList);
206             // Storing allNodeConnectorStats(like ncIdOFPortDurationMap) in a
207             // map with key as node for easy removal and addition of
208             // allNodeConnectorStats.
209             nodeAndNcIdOFPortDurationMap.put(node, ncIdOFPortDurationMap);
210             nodeAndNcIdOFPortReceiveDropMap.put(node, ncIdOFPortReceiveDropMap);
211             nodeAndNcIdOFPortReceiveError.put(node, ncIdOFPortReceiveError);
212             nodeAndNcIdPacketSentMap.put(node, ncIdPacketSentMap);
213             nodeAndNcIdPacketReceiveMap.put(node, ncIdPacketReceiveMap);
214             nodeAndNcIdBytesSentMap.put(node, ncIdBytesSentMap);
215             nodeAndNcIdBytesReceiveMap.put(node, ncIdBytesReceiveMap);
216             // Combining the stats of all nodeconnectors in all nodes. This Map
217             // will be stored under MBean which will be queried as regular
218             // intervals.
219             ncIdOFPortDurationMap = combineAllNodesStats(nodeAndNcIdOFPortDurationMap);
220             ncIdOFPortReceiveDropMap = combineAllNodesStats(nodeAndNcIdOFPortReceiveDropMap);
221             ncIdOFPortReceiveError = combineAllNodesStats(nodeAndNcIdOFPortReceiveError);
222             ncIdPacketSentMap = combineAllNodesStats(nodeAndNcIdPacketSentMap);
223             ncIdPacketReceiveMap = combineAllNodesStats(nodeAndNcIdPacketReceiveMap);
224             ncIdBytesSentMap = combineAllNodesStats(nodeAndNcIdBytesSentMap);
225             ncIdBytesReceiveMap = combineAllNodesStats(nodeAndNcIdBytesReceiveMap);
226             PMAGENT.connectToPMAgent(ncIdOFPortDurationMap, ncIdOFPortReceiveDropMap, ncIdOFPortReceiveError,
227                     ncIdPacketSentMap, ncIdPacketReceiveMap, ncIdBytesSentMap, ncIdBytesReceiveMap);
228         }
229
230         /*
231          * Input allNodesStats contains statistics of all nodeConnectors of all
232          * nodes. Key is the node and values contains another map with key as
233          * node connector and value as statresult. Output will be a map with key
234          * as nodeconnector and value as the statresult. The key contains
235          * nodeconnectors of all the nodes.
236          */
237     }
238
239     private Map<String, String> combineAllNodesStats(Map<String, Map<String, String>> allNodesStats) {
240         Map<String, String> allNcsStatsMap = new HashMap<>();
241         for (Map.Entry<String, Map<String, String>> entry : allNodesStats.entrySet()) {
242             Map<String, String> ncStatsMap = entry.getValue();
243             for (Map.Entry<String, String> statResult : ncStatsMap.entrySet()) {
244                 allNcsStatsMap.put(statResult.getKey(), statResult.getValue());
245             }
246         }
247         return allNcsStatsMap;
248     }
249
250     /*
251      * FlowRpcStatisticsListener listens for the FlowTableStatisticsUpdate and
252      * then update the corresponding counter map
253      */
254     class FlowRpcStatisticsListener implements OpendaylightFlowTableStatisticsListener {
255
256         @Override
257         public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate flowTableStats) {
258             String node = flowTableStats.getId().getValue().split(":")[1];
259             Map<String, String> entriesPerOFTableMap = new HashMap<>();
260             List<FlowTableAndStatisticsMap> flowTableAndStatisticsMapList = flowTableStats
261                     .getFlowTableAndStatisticsMap();
262             for (FlowTableAndStatisticsMap flowTableAndStatisticsMap : flowTableAndStatisticsMapList) {
263                 String nodeTableStr = "dpnId_" + node + "_table_"
264                         + flowTableAndStatisticsMap.getTableId().getValue().toString();
265                 entriesPerOFTableMap.put("EntriesPerOFTable:" + nodeTableStr + "_EntriesPerOFTable",
266                         flowTableAndStatisticsMap.getActiveFlows().getValue().toString());
267             }
268             nodeAndEntriesPerOFTableMap.put(node, entriesPerOFTableMap);
269             entriesPerOFTableMap = combineAllNodesStats(nodeAndEntriesPerOFTableMap);
270             PMAGENT.connectToPMAgentAndInvokeEntriesPerOFTable(entriesPerOFTableMap);
271         }
272     }
273
274     @Override
275     protected void remove(InstanceIdentifier<Node> identifier, Node node) {
276         NodeId nodeId = node.getId();
277         String nodeVal = nodeId.getValue().split(":")[1];
278         BigInteger dpId = new BigInteger(nodeVal);
279         if (nodes.contains(dpId)) {
280             nodes.remove(dpId);
281             nodeAndNcIdOFPortDurationMap.remove(nodeVal);
282             nodeAndNcIdOFPortReceiveDropMap.remove(nodeVal);
283             nodeAndNcIdOFPortReceiveError.remove(nodeVal);
284             nodeAndNcIdPacketSentMap.remove(nodeVal);
285             nodeAndNcIdPacketReceiveMap.remove(nodeVal);
286             nodeAndNcIdBytesSentMap.remove(nodeVal);
287             nodeAndNcIdBytesReceiveMap.remove(nodeVal);
288             nodeAndEntriesPerOFTableMap.remove(nodeVal);
289         }
290         if (nodes.isEmpty()) {
291             stopPortStatRequestTask();
292         }
293     }
294
295     @Override
296     protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
297         // TODO Auto-generated method stub
298     }
299
300     @Override
301     protected void add(InstanceIdentifier<Node> identifier, Node node) {
302         NodeId nodeId = node.getId();
303         BigInteger dpId = new BigInteger(nodeId.getValue().split(":")[1]);
304         if (nodes.contains(dpId)) {
305             return;
306         }
307         nodes.add(dpId);
308         if (nodes.size() == 1) {
309             schedulePortStatRequestTask();
310         }
311     }
312 }