ONOS-6626 OFAgent - handle StatsRequest, GetConfigRequest and SetConfigMessage

Change-Id: Ie6744c7846c41024173049d2094260ea571844b3
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
index 6413cba..6e2f5ad 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/api/OFSwitchOperationService.java
@@ -126,4 +126,28 @@
      * @param msg     echo request message
      */
     void processEchoRequest(Channel channel, OFMessage msg);
+
+    /**
+     * Processes GetConfig request from the controllers.
+     *
+     * @param channel received channel
+     * @param msg     GetConfig request message
+     */
+    void processGetConfigRequest(Channel channel, OFMessage msg);
+
+    /**
+     * Processes SetConfig message from the controllers.
+     *
+     * @param channel received channel
+     * @param msg     SetConfig message
+     */
+    void processSetConfigMessage(Channel channel, OFMessage msg);
+
+    /**
+     * Processes barrier request from the controllers.
+     *
+     * @param channel received channel
+     * @param msg     barrier request message
+     */
+    void processBarrierRequest(Channel channel, OFMessage msg);
 }
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 878fae0..116e1cf 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
@@ -22,16 +22,25 @@
 import org.onosproject.net.packet.InboundPacket;
 import org.onosproject.ofagent.api.OFSwitch;
 import org.onosproject.ofagent.api.OFSwitchCapabilities;
+import org.projectfloodlight.openflow.protocol.OFBarrierReply;
 import org.projectfloodlight.openflow.protocol.OFControllerRole;
 import org.projectfloodlight.openflow.protocol.OFEchoReply;
 import org.projectfloodlight.openflow.protocol.OFEchoRequest;
 import org.projectfloodlight.openflow.protocol.OFFactories;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
+import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
 import org.projectfloodlight.openflow.protocol.OFHello;
 import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
+import org.projectfloodlight.openflow.protocol.OFSetConfig;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsRequest;
+import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.projectfloodlight.openflow.types.DatapathId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Collections;
 import java.util.Set;
@@ -39,7 +48,7 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.projectfloodlight.openflow.protocol.OFControllerRole.*;
+import static org.projectfloodlight.openflow.protocol.OFControllerRole.ROLE_EQUAL;
 
 /**
  * Implementation of the default OpenFlow switch.
@@ -51,9 +60,15 @@
     private static final long NUM_BUFFERS = 1024;
     private static final short NUM_TABLES = 3;
 
+    private final Logger log;
+
     private final DatapathId dpId;
     private final OFSwitchCapabilities capabilities;
 
+    // miss_send_len field (in OFSetConfig and OFGetConfig messages) indicates the max
+    // bytes of a packet that the switch sends to the controller
+    private int missSendLen = 0xffff;
+
     private final ConcurrentHashMap<Channel, OFControllerRole> controllerRoleMap
             = new ConcurrentHashMap<>();
     private static final OFFactory FACTORY = OFFactories.getFactory(OFVersion.OF_13);
@@ -63,6 +78,7 @@
     private DefaultOFSwitch(DatapathId dpid, OFSwitchCapabilities capabilities) {
         this.dpId = dpid;
         this.capabilities = capabilities;
+        log = LoggerFactory.getLogger(getClass().getName() + " : " + dpid);
     }
 
     public static DefaultOFSwitch of(DatapathId dpid, OFSwitchCapabilities capabilities) {
@@ -125,41 +141,86 @@
     @Override
     public void processPortAdded(Port port) {
         // TODO generate FEATURES_REPLY message and send it to the controller
+        log.debug("Functionality not yet supported for {}", port);
     }
 
     @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);
     }
 
     @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);
     }
 
     @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);
     }
 
     @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);
     }
 
     @Override
     public void processControllerCommand(Channel channel, OFMessage msg) {
         // TODO process controller command
+        log.debug("Functionality not yet supported for {}", msg);
     }
 
     @Override
     public void processStatsRequest(Channel channel, OFMessage msg) {
-        // TODO process request and send reply
+        if (msg.getType() != OFType.STATS_REQUEST) {
+            log.warn("Ignoring message of type {}.", msg.getType());
+            return;
+        }
+
+        OFStatsRequest ofStatsRequest = (OFStatsRequest) msg;
+        OFStatsReply ofStatsReply = null;
+        switch (ofStatsRequest.getStatsType()) {
+            case PORT_DESC:
+                ofStatsReply = FACTORY.buildPortDescStatsReply()
+                        .setXid(msg.getXid())
+                        //TODO add details
+                        .build();
+                break;
+            case METER_FEATURES:
+                OFMeterFeatures ofMeterFeatures = FACTORY.buildMeterFeatures()
+                        .build();
+                ofStatsReply = FACTORY.buildMeterFeaturesStatsReply()
+                        .setXid(msg.getXid())
+                        .setFeatures(ofMeterFeatures)
+                        //TODO add details
+                        .build();
+                break;
+            case DESC:
+                ofStatsReply = FACTORY.buildDescStatsReply()
+                        .setXid(msg.getXid())
+                        .build();
+                break;
+            default:
+                log.debug("Functionality not yet supported for type {} statsType{} msg {}",
+                          msg.getType(), ofStatsRequest.getStatsType(), msg);
+                break;
+        }
+
+        if (ofStatsReply != null) {
+            log.trace("request {}; reply {}", msg, ofStatsReply);
+            channel.writeAndFlush(Collections.singletonList(ofStatsReply));
+        }
+
     }
 
     @Override
     public void processRoleRequest(Channel channel, OFMessage msg) {
         // TODO process role request and send reply
+        log.debug("Functionality not yet supported for {}", msg);
     }
 
     @Override
@@ -195,4 +256,36 @@
                 .build();
         channel.writeAndFlush(Collections.singletonList(ofEchoReply));
     }
+
+    @Override
+    public void processGetConfigRequest(Channel channel, OFMessage msg) {
+        OFGetConfigReply ofGetConfigReply = FACTORY.buildGetConfigReply()
+                .setXid(msg.getXid())
+                .setMissSendLen(missSendLen)
+                .build();
+        log.trace("request {}; reply {}", msg, ofGetConfigReply);
+        channel.writeAndFlush(Collections.singletonList(ofGetConfigReply));
+    }
+
+    @Override
+    public void processSetConfigMessage(Channel channel, OFMessage msg) {
+        OFSetConfig ofSetConfig = (OFSetConfig) msg;
+        if (missSendLen != ofSetConfig.getMissSendLen()) {
+            log.trace("Changing missSendLen from {} to {}.",
+                      missSendLen, ofSetConfig.getMissSendLen());
+            missSendLen = ofSetConfig.getMissSendLen();
+        }
+
+        // SetConfig message is not acknowledged
+    }
+
+    @Override
+    public void processBarrierRequest(Channel channel, OFMessage msg) {
+        // TODO check previous state requests have been handled before issuing BarrierReply
+        OFBarrierReply ofBarrierReply = FACTORY.buildBarrierReply()
+                .setXid(msg.getXid())
+                .build();
+        log.trace("request {}; reply {}", msg, ofBarrierReply);
+        channel.writeAndFlush(Collections.singletonList(ofBarrierReply));
+    }
 }
diff --git a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
index 6514b3c..9d49982 100644
--- a/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
+++ b/apps/ofagent/src/main/java/org/onosproject/ofagent/impl/OFChannelHandler.java
@@ -51,6 +51,7 @@
             @Override
             void processOFMessage(final OFChannelHandler handler,
                                   final OFMessage msg) {
+                logProcessOFMessageDetails(handler, msg, this);
                 // TODO implement
             }
         },
@@ -58,6 +59,7 @@
             @Override
             void processOFMessage(final OFChannelHandler handler,
                                   final OFMessage msg) {
+                logProcessOFMessageDetails(handler, msg, this);
                 switch (msg.getType()) {
                     case HELLO:
                         handler.setState(ChannelState.WAIT_FEATURE_REQUEST);
@@ -72,6 +74,7 @@
             @Override
             void processOFMessage(final OFChannelHandler handler,
                                   final OFMessage msg) {
+                logProcessOFMessageDetails(handler, msg, this);
                 switch (msg.getType()) {
                     case FEATURES_REQUEST:
                         handler.ofSwitch.processFeaturesRequest(handler.channel, msg);
@@ -94,21 +97,26 @@
             @Override
             void processOFMessage(final OFChannelHandler handler,
                                   final OFMessage msg) {
+                logProcessOFMessageDetails(handler, msg, this);
                 // TODO implement
                 // TODO add this channel to ofSwitch role service
                 switch (msg.getType()) {
                     case STATS_REQUEST:
                         //TODO implement
                         //TODO: use vNetService to build OFPortDesc.
+                        handler.ofSwitch.processStatsRequest(handler.channel, msg);
                         break;
                     case SET_CONFIG:
                         //TODO implement
+                        handler.ofSwitch.processSetConfigMessage(handler.channel, msg);
                         break;
                     case GET_CONFIG_REQUEST:
                         //TODO implement
+                        handler.ofSwitch.processGetConfigRequest(handler.channel, msg);
                         break;
                     case BARRIER_REQUEST:
                         //TODO implement
+                        handler.ofSwitch.processBarrierRequest(handler.channel, msg);
                         break;
                     case ECHO_REQUEST:
                         handler.ofSwitch.processEchoRequest(handler.channel, msg);
@@ -124,6 +132,12 @@
         };
 
         abstract void processOFMessage(final OFChannelHandler handler, final OFMessage msg);
+
+        private static void logProcessOFMessageDetails(final OFChannelHandler handler,
+                                            final OFMessage msg, ChannelState chnState) {
+            handler.log.trace("Channel state: {} dpid: {} processOFMessage type: {} nsg: {}",
+                              chnState, handler.ofSwitch.dpid(), msg.getType(), msg);
+        }
     }
 
     /**
@@ -199,12 +213,12 @@
     }
 
     private void illegalMessageReceived(OFMessage ofMessage) {
-        log.warn("Controller should never send this message {} in current state {}",
-                ofMessage.getType(), state);
+        log.warn("Controller should never send message {} to switch {} in current state {}",
+                ofMessage.getType(), ofSwitch.dpid(), state);
     }
 
     private void unhandledMessageReceived(OFMessage ofMessage) {
-        log.warn("Unexpected message {} received in state {}",
-                ofMessage.getType(), state);
+        log.warn("Unexpected message {} received for switch {} in state {}",
+                ofMessage.getType(), ofSwitch.dpid(), state);
     }
 }