ONOS-5475 OFAgent - handle PortStatsRequest

Change-Id: I6fe87bd2d390dffffde0ccb8c72892bdf23e5198
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
index 1fbd9c2..30f6d37 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchService.java
@@ -18,7 +18,9 @@
 import org.onosproject.incubator.net.virtual.NetworkId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
+import org.onosproject.net.device.PortStatistics;
 
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -42,6 +44,15 @@
     Set<OFSwitch> ofSwitches(NetworkId networkId);
 
     /**
+     * Returns openflow switch for the specified device in the specified network.
+     *
+     * @param networkId network id
+     * @param deviceId device id
+     * @return openflow switch; null if none exists
+     */
+    OFSwitch ofSwitch(NetworkId networkId, DeviceId deviceId);
+
+    /**
      * Returns all ports of the specified device in the specified network.
      *
      * @param networkId network id
@@ -49,4 +60,14 @@
      * @return set of ports; empty set if no ports exist for the specified device
      */
     Set<Port> ports(NetworkId networkId, DeviceId deviceId);
+
+    /**
+     * Returns all port statistics of the specified device in the specified network.
+     *
+     * @param networkId network id
+     * @param deviceId device id
+     * @return list of port statistics; empty list if none exists for the specified device
+     */
+    List<PortStatistics> getPortStatistics(NetworkId networkId, DeviceId deviceId);
+
 }
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
index 880d3bd..8efcf1c 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/DefaultOFSwitch.java
@@ -21,6 +21,7 @@
 import org.onosproject.incubator.net.virtual.NetworkId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
+import org.onosproject.net.device.PortStatistics;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.ofagent.api.OFSwitch;
@@ -39,6 +40,8 @@
 import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortReason;
+import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFPortStatsRequest;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFRoleReply;
 import org.projectfloodlight.openflow.protocol.OFRoleRequest;
@@ -49,6 +52,7 @@
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.types.DatapathId;
 import org.projectfloodlight.openflow.types.OFPort;
+import org.projectfloodlight.openflow.types.U64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -175,31 +179,31 @@
     @Override
     public void processPortDown(Port port) {
         // TODO generate PORT_STATUS message and send it to the controller
-        log.debug("Functionality not yet supported for {}", port);
+        log.debug("processPortDown: Functionality not yet supported for {}", port);
     }
 
     @Override
     public void processPortUp(Port port) {
         // TODO generate PORT_STATUS message and send it to the controller
-        log.debug("Functionality not yet supported for {}", port);
+        log.debug("processPortUp: Functionality not yet supported for {}", port);
     }
 
     @Override
     public void processFlowRemoved(FlowRule flowRule) {
         // TODO generate FLOW_REMOVED message and send it to the controller
-        log.debug("Functionality not yet supported for {}", flowRule);
+        log.debug("processFlowRemoved: Functionality not yet supported for {}", flowRule);
     }
 
     @Override
     public void processPacketIn(InboundPacket packet) {
         // TODO generate PACKET_IN message and send it to the controller
-        log.debug("Functionality not yet supported for {}", packet);
+        log.debug("processPacketIn: Functionality not yet supported for {}", packet);
     }
 
     @Override
     public void processControllerCommand(Channel channel, OFMessage msg) {
         // TODO process controller command
-        log.debug("Functionality not yet supported for {}", msg);
+        log.debug("processControllerCommand: Functionality not yet supported for {}", msg);
     }
 
     private void sendPortStatus(Port port, OFPortReason ofPortReason) {
@@ -228,6 +232,23 @@
         return ofPortDesc;
     }
 
+    private OFPortStatsEntry portStatsEntry(PortStatistics portStatistic) {
+        OFPortStatsEntry ofPortStatsEntry = FACTORY.buildPortStatsEntry()
+                .setPortNo(OFPort.of(portStatistic.port()))
+                .setTxBytes(U64.of(portStatistic.bytesSent()))
+                .setTxPackets(U64.of(portStatistic.packetsSent()))
+                .setTxDropped(U64.of(portStatistic.packetsTxDropped()))
+                .setTxErrors(U64.of(portStatistic.packetsTxErrors()))
+                .setRxBytes(U64.of(portStatistic.bytesReceived()))
+                .setRxPackets(U64.of(portStatistic.packetsReceived()))
+                .setRxDropped(U64.of(portStatistic.packetsRxDropped()))
+                .setRxErrors(U64.of(portStatistic.packetsRxErrors()))
+                .setDurationSec(portStatistic.durationSec())
+                .setDurationNsec(portStatistic.durationNano())
+                .build();
+        return ofPortStatsEntry;
+    }
+
     @Override
     public void processStatsRequest(Channel channel, OFMessage msg) {
         if (msg.getType() != OFType.STATS_REQUEST) {
@@ -251,6 +272,23 @@
                         //TODO add details
                         .build();
                 break;
+            case PORT:
+                OFPortStatsRequest portStatsRequest = (OFPortStatsRequest) msg;
+                OFPort ofPort = portStatsRequest.getPortNo();
+                List<OFPortStatsEntry> portStatsEntries = new ArrayList<>();
+                List<PortStatistics> portStatistics =
+                        ofSwitchService.getPortStatistics(networkId, deviceId);
+                if (ofPort.equals(OFPort.ANY)) {
+                    portStatistics.forEach(portStatistic -> {
+                        OFPortStatsEntry ofPortStatsEntry = portStatsEntry(portStatistic);
+                        portStatsEntries.add(ofPortStatsEntry);
+                    });
+                }
+                ofStatsReply = FACTORY.buildPortStatsReply()
+                        .setEntries(portStatsEntries)
+                        .setXid(msg.getXid())
+                        .build();
+                break;
             case METER_FEATURES:
                 OFMeterFeatures ofMeterFeatures = FACTORY.buildMeterFeatures()
                         .build();
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
index deac523..36be111 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFSwitchManager.java
@@ -40,6 +40,7 @@
 import org.onosproject.net.device.DeviceEvent;
 import org.onosproject.net.device.DeviceListener;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.device.PortStatistics;
 import org.onosproject.net.flow.FlowRuleEvent;
 import org.onosproject.net.flow.FlowRuleListener;
 import org.onosproject.net.flow.FlowRuleService;
@@ -60,6 +61,7 @@
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -160,6 +162,11 @@
     }
 
     @Override
+    public OFSwitch ofSwitch(NetworkId networkId, DeviceId deviceId) {
+        return ofSwitchMap.get(deviceId);
+    }
+
+    @Override
     public Set<Port> ports(NetworkId networkId, DeviceId deviceId) {
         Set<Port> ports = virtualNetService.getVirtualPorts(networkId, deviceId)
                 .stream()
@@ -167,6 +174,13 @@
         return ImmutableSet.copyOf(ports);
     }
 
+    @Override
+    public List<PortStatistics> getPortStatistics(NetworkId networkId, DeviceId deviceId) {
+        DeviceService deviceService = virtualNetService.get(networkId, DeviceService.class);
+        List<PortStatistics> portStatistics = deviceService.getPortStatistics(deviceId);
+        return portStatistics;
+    }
+
     private void addOFSwitch(NetworkId networkId, DeviceId deviceId) {
         OFSwitch ofSwitch = DefaultOFSwitch.of(
                 dpidWithDeviceId(deviceId),