org.opendaylight.vpnservice.interfacemgr.pmcounters.NodeConnectorStatsImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.vpnservice.interfacemgr.pmcounters.NodeConnectorStatsImpl.java

Source

/*
 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.vpnservice.interfacemgr.pmcounters;

import java.lang.Thread.UncaughtExceptionHandler;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationService;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.FlowTableStatisticsUpdate;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.GetFlowTablesStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.OpendaylightFlowTableStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.table.statistics.rev131215.flow.table.and.statistics.map.FlowTableAndStatisticsMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.GetAllNodeConnectorsStatisticsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.NodeConnectorStatisticsUpdate;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.OpendaylightPortStatisticsService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.node.connector.statistics.and.port.number.map.NodeConnectorStatisticsAndPortNumberMap;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

public class NodeConnectorStatsImpl extends AbstractDataChangeListener<Node> {

    private static final Logger logger = LoggerFactory.getLogger(NodeConnectorStatsImpl.class);
    private static final int THREAD_POOL_SIZE = 4;
    private static final int NO_DELAY = 0;
    public static final PMAgentForNodeConnectorCounters pmagent = new PMAgentForNodeConnectorCounters();
    private PortRpcStatisticsListener portStatsListener = new PortRpcStatisticsListener();
    private FlowRpcStatisticsListener flowTableStatsListener = new FlowRpcStatisticsListener();
    private List<BigInteger> nodes = new ArrayList<>();
    Map<String, Map<String, String>> nodeAndNcIdOFPortDurationMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdOFPortReceiveDropMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdOFPortReceiveError = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdPacketSentMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdPacketReceiveMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdBytesSentMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndNcIdBytesReceiveMap = new ConcurrentHashMap<String, Map<String, String>>();
    Map<String, Map<String, String>> nodeAndEntriesPerOFTableMap = new ConcurrentHashMap<String, Map<String, String>>();
    private ScheduledFuture<?> scheduledResult;
    private OpendaylightPortStatisticsService statPortService;
    private ScheduledExecutorService portStatExecutorService;
    private OpendaylightFlowTableStatisticsService opendaylightFlowTableStatisticsService;

    public NodeConnectorStatsImpl(DataBroker db, NotificationService notificationService,
            OpendaylightPortStatisticsService statPortService,
            OpendaylightFlowTableStatisticsService opendaylightFlowTableStatisticsService) {
        super(Node.class);
        this.statPortService = statPortService;
        this.opendaylightFlowTableStatisticsService = opendaylightFlowTableStatisticsService;
        registerListener(db);
        portStatExecutorService = Executors.newScheduledThreadPool(THREAD_POOL_SIZE,
                getThreadFactory("Port Stats Request Task"));
        notificationService.registerNotificationListener(portStatsListener);
        notificationService.registerNotificationListener(flowTableStatsListener);
        pmagent.registerMbean();
    }

    private void registerListener(final DataBroker db) {
        try {
            db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, getWildCardPath(),
                    NodeConnectorStatsImpl.this, AsyncDataBroker.DataChangeScope.SUBTREE);
        } catch (final Exception e) {
            logger.error("NodeConnectorStatsImpl: DataChange listener registration fail!", e);
            throw new IllegalStateException("NodeConnectorStatsImpl: registration Listener failed.", e);
        }
    }

    private InstanceIdentifier<Node> getWildCardPath() {
        return InstanceIdentifier.create(Nodes.class).child(Node.class);
    }

    /*
     * PortStat request task is started when first DPN gets connected
     */
    private void schedulePortStatRequestTask() {
        logger.info("Scheduling port statistics request");
        PortStatRequestTask portStatRequestTask = new PortStatRequestTask();
        scheduledResult = portStatExecutorService.scheduleAtFixedRate(portStatRequestTask, NO_DELAY, 10000,
                TimeUnit.MILLISECONDS);
    }

    /*
     * PortStat request task is stopped when last DPN is removed.
     */
    private void stopPortStatRequestTask() {
        if (scheduledResult != null) {
            logger.info("Stopping port statistics request");
            scheduledResult.cancel(true);
        }
    }

    /*
     * This task queries for node connector statistics as well as flowtables statistics every 10 secs.
     * Minimum period which can be configured for PMJob is 10 secs.
     */
    private class PortStatRequestTask implements Runnable {

        @Override
        public void run() {
            if (logger.isTraceEnabled()) {
                logger.trace("Requesting port stats - {}");
            }
            for (BigInteger node : nodes) {
                logger.trace("Requesting AllNodeConnectorStatistics for node - {}", node);
                statPortService.getAllNodeConnectorsStatistics(buildGetAllNodeConnectorStatistics(node));
                opendaylightFlowTableStatisticsService.getFlowTablesStatistics(buildGetFlowTablesStatistics(node));
            }
        }

        private GetAllNodeConnectorsStatisticsInput buildGetAllNodeConnectorStatistics(BigInteger dpId) {
            return new GetAllNodeConnectorsStatisticsInputBuilder()
                    .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
                            .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId.toString()))).build()))
                    .build();
        }

        private GetFlowTablesStatisticsInput buildGetFlowTablesStatistics(BigInteger dpId) {
            return new GetFlowTablesStatisticsInputBuilder()
                    .setNode(new NodeRef(InstanceIdentifier.builder(Nodes.class)
                            .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId.toString()))).build()))
                    .build();
        }

    }

    private ThreadFactory getThreadFactory(String threadNameFormat) {
        ThreadFactoryBuilder builder = new ThreadFactoryBuilder();
        builder.setNameFormat(threadNameFormat);
        builder.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                logger.error("Received Uncaught Exception event in Thread: {}", t.getName(), e);
            }
        });
        return builder.build();
    }

    /*
     * PortRpcStatisticsListener listens for the NodeConnectorStatisticsUpdate and then update the corresponding counter map
     */
    class PortRpcStatisticsListener implements OpendaylightPortStatisticsListener {

        @Override
        public void onNodeConnectorStatisticsUpdate(NodeConnectorStatisticsUpdate ncStats) {
            Map<String, String> ncIdOFPortDurationMap = new HashMap<String, String>();
            Map<String, String> ncIdOFPortReceiveDropMap = new HashMap<String, String>();
            Map<String, String> ncIdOFPortReceiveError = new HashMap<String, String>();
            Map<String, String> ncIdPacketSentMap = new HashMap<String, String>();
            Map<String, String> ncIdPacketReceiveMap = new HashMap<String, String>();
            Map<String, String> ncIdBytesSentMap = new HashMap<String, String>();
            Map<String, String> ncIdBytesReceiveMap = new HashMap<String, String>();
            List<NodeConnectorStatisticsAndPortNumberMap> ncStatsAndPortMapList = ncStats
                    .getNodeConnectorStatisticsAndPortNumberMap();
            NodeId nodeId = ncStats.getId();
            String node = nodeId.getValue().split(":")[1];
            for (NodeConnectorStatisticsAndPortNumberMap ncStatsAndPortMap : ncStatsAndPortMapList) {
                NodeConnectorId nodeConnector = ncStatsAndPortMap.getNodeConnectorId();
                String port = nodeConnector.getValue().split(":")[2];
                String nodePortStr = "dpnId_" + node + "_portNum_" + port;
                ncIdOFPortDurationMap.put("OFPortDuration:" + nodePortStr + "_OFPortDuration",
                        ncStatsAndPortMap.getDuration().getSecond().getValue().toString());
                ncIdOFPortReceiveDropMap.put(
                        "PacketsPerOFPortReceiveDrop:" + nodePortStr + "_PacketsPerOFPortReceiveDrop",
                        ncStatsAndPortMap.getReceiveDrops().toString());
                ncIdOFPortReceiveError.put(
                        "PacketsPerOFPortReceiveError:" + nodePortStr + "_PacketsPerOFPortReceiveError",
                        ncStatsAndPortMap.getReceiveErrors().toString());
                ncIdPacketSentMap.put("PacketsPerOFPortSent:" + nodePortStr + "_PacketsPerOFPortSent",
                        ncStatsAndPortMap.getPackets().getTransmitted().toString());
                ncIdPacketReceiveMap.put("PacketsPerOFPortReceive:" + nodePortStr + "_PacketsPerOFPortReceive",
                        ncStatsAndPortMap.getPackets().getReceived().toString());
                ncIdBytesSentMap.put("BytesPerOFPortSent:" + nodePortStr + "_BytesPerOFPortSent",
                        ncStatsAndPortMap.getBytes().getTransmitted().toString());
                ncIdBytesReceiveMap.put("BytesPerOFPortReceive:" + nodePortStr + "_BytesPerOFPortReceive",
                        ncStatsAndPortMap.getBytes().getReceived().toString());
            }
            logger.trace("Port Stats {}", ncStatsAndPortMapList);
            //Storing allNodeConnectorStats(like ncIdOFPortDurationMap) in a map with key as node for easy removal and addition of allNodeConnectorStats.
            nodeAndNcIdOFPortDurationMap.put(node, ncIdOFPortDurationMap);
            nodeAndNcIdOFPortReceiveDropMap.put(node, ncIdOFPortReceiveDropMap);
            nodeAndNcIdOFPortReceiveError.put(node, ncIdOFPortReceiveError);
            nodeAndNcIdPacketSentMap.put(node, ncIdPacketSentMap);
            nodeAndNcIdPacketReceiveMap.put(node, ncIdPacketReceiveMap);
            nodeAndNcIdBytesSentMap.put(node, ncIdBytesSentMap);
            nodeAndNcIdBytesReceiveMap.put(node, ncIdBytesReceiveMap);
            //Combining the stats of all nodeconnectors in all nodes. This Map will be stored under MBean which will be queried as regular intervals.
            ncIdOFPortDurationMap = combineAllNodesStats(nodeAndNcIdOFPortDurationMap);
            ncIdOFPortReceiveDropMap = combineAllNodesStats(nodeAndNcIdOFPortReceiveDropMap);
            ncIdOFPortReceiveError = combineAllNodesStats(nodeAndNcIdOFPortReceiveError);
            ncIdPacketSentMap = combineAllNodesStats(nodeAndNcIdPacketSentMap);
            ncIdPacketReceiveMap = combineAllNodesStats(nodeAndNcIdPacketReceiveMap);
            ncIdBytesSentMap = combineAllNodesStats(nodeAndNcIdBytesSentMap);
            ncIdBytesReceiveMap = combineAllNodesStats(nodeAndNcIdBytesReceiveMap);
            pmagent.connectToPMAgent(ncIdOFPortDurationMap, ncIdOFPortReceiveDropMap, ncIdOFPortReceiveError,
                    ncIdPacketSentMap, ncIdPacketReceiveMap, ncIdBytesSentMap, ncIdBytesReceiveMap);
        }

        /*
         * Input allNodesStats contains statistics of all nodeConnectors of all nodes. Key is the node and values contains another map with key as node connector and value as statresult.
         * Output will be a map with key as nodeconnector and value as the statresult. The key contains nodeconnectors of all the nodes.
         */
    }

    private Map<String, String> combineAllNodesStats(Map<String, Map<String, String>> allNodesStats) {
        Map<String, String> allNcsStatsMap = new HashMap<String, String>();
        for (Map.Entry<String, Map<String, String>> entry : allNodesStats.entrySet()) {
            Map<String, String> ncStatsMap = entry.getValue();
            for (Map.Entry<String, String> statResult : ncStatsMap.entrySet()) {
                allNcsStatsMap.put(statResult.getKey(), statResult.getValue());
            }
        }
        return allNcsStatsMap;
    }

    /*
     * FlowRpcStatisticsListener listens for the FlowTableStatisticsUpdate and then update the corresponding counter map
     */
    class FlowRpcStatisticsListener implements OpendaylightFlowTableStatisticsListener {

        @Override
        public void onFlowTableStatisticsUpdate(FlowTableStatisticsUpdate flowTableStats) {
            String node = flowTableStats.getId().getValue().split(":")[1];
            Map<String, String> entriesPerOFTableMap = new HashMap<String, String>();
            List<FlowTableAndStatisticsMap> flowTableAndStatisticsMapList = flowTableStats
                    .getFlowTableAndStatisticsMap();
            for (FlowTableAndStatisticsMap flowTableAndStatisticsMap : flowTableAndStatisticsMapList) {
                String nodeTableStr = "dpnId_" + node + "_table_"
                        + flowTableAndStatisticsMap.getTableId().getValue().toString();
                entriesPerOFTableMap.put("EntriesPerOFTable:" + nodeTableStr + "_EntriesPerOFTable",
                        flowTableAndStatisticsMap.getActiveFlows().getValue().toString());
            }
            nodeAndEntriesPerOFTableMap.put(node, entriesPerOFTableMap);
            entriesPerOFTableMap = combineAllNodesStats(nodeAndEntriesPerOFTableMap);
            pmagent.connectToPMAgentAndInvokeEntriesPerOFTable(entriesPerOFTableMap);
        }

    }

    @Override
    protected void remove(InstanceIdentifier<Node> identifier, Node node) {
        NodeId nodeId = node.getId();
        String nodeVal = nodeId.getValue().split(":")[1];
        BigInteger dpId = new BigInteger(nodeVal);
        if (nodes.contains(dpId)) {
            nodes.remove(dpId);
            nodeAndNcIdOFPortDurationMap.remove(nodeVal);
            nodeAndNcIdOFPortReceiveDropMap.remove(nodeVal);
            nodeAndNcIdOFPortReceiveError.remove(nodeVal);
            nodeAndNcIdPacketSentMap.remove(nodeVal);
            nodeAndNcIdPacketReceiveMap.remove(nodeVal);
            nodeAndNcIdBytesSentMap.remove(nodeVal);
            nodeAndNcIdBytesReceiveMap.remove(nodeVal);
            nodeAndEntriesPerOFTableMap.remove(nodeVal);
        }
        if (nodes.isEmpty()) {
            stopPortStatRequestTask();
        }
    }

    @Override
    protected void update(InstanceIdentifier<Node> identifier, Node original, Node update) {
        // TODO Auto-generated method stub
    }

    @Override
    protected void add(InstanceIdentifier<Node> identifier, Node node) {
        NodeId nodeId = node.getId();
        BigInteger dpId = new BigInteger(nodeId.getValue().split(":")[1]);
        if (nodes.contains(dpId)) {
            return;
        }
        nodes.add(dpId);
        if (nodes.size() == 1) {
            schedulePortStatRequestTask();
        }
    }
}