Implement OFActionSetQueue (OpenFlow 1.3 only)

Action "Set-Queue" (OFPAT_SET_QUEUE) is not yet implemented.

This patch adds such a QUEUE Treatment and implements it using the Set-Queue
action of OpenFlow 1.3.

The --setQueue parameter can be used when defining intents so that flows with
the respective Set-Queue action are installed.

This includes contributions by Michael Jarschel and Arne Schwabe and is the
result of our ONOS Hackaton project at EWSDN 2015.

Change-Id: Ie7bf01e8fd90fe68977477327ac4f53d7930e186
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index a628725..6174cef 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -237,6 +237,7 @@
                 case NOACTION:
                 case OUTPUT:
                 case GROUP:
+                case QUEUE:
                 case L0MODIFICATION:
                 case L2MODIFICATION:
                 case L3MODIFICATION:
@@ -381,6 +382,11 @@
         }
 
         @Override
+        public Builder setQueue(long queueId) {
+            return add(Instructions.setQueue(queueId));
+        }
+
+        @Override
         public TrafficTreatment.Builder meter(MeterId meterId) {
             return add(Instructions.meterTraffic(meterId));
         }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 33753af..e0fab95 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -261,6 +261,14 @@
         Builder group(GroupId groupId);
 
         /**
+         * Sets the Queue ID.
+         *
+         * @param queueId a queue ID
+         * @return a treatment builder
+         */
+        Builder setQueue(long queueId);
+
+        /**
          * Sets a meter to be used by this flow.
          *
          * @param meterId a meter id
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
index eddbbb7..2f6a1cc 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instruction.java
@@ -49,6 +49,12 @@
         GROUP,
 
         /**
+         * Signifies that the traffic should be enqueued to an already-configured
+         queue on a port.
+         */
+        QUEUE,
+
+        /**
          * Signifies that traffic should be metered according to a meter.
          */
         METER,
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index 26981e5..8868bf7 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -94,6 +94,17 @@
         return new GroupInstruction(groupId);
     }
 
+    /**
+     * Creates a set-queue instruction.
+     *
+     * @param queueId Queue Id
+     * @return set-queue instruction
+     */
+    public static SetQueueInstruction setQueue(final long queueId) {
+        checkNotNull(queueId, "queue ID cannot be null");
+        return new SetQueueInstruction(queueId);
+    }
+
     public static MeterInstruction meterTraffic(final MeterId meterId) {
         checkNotNull(meterId, "meter id cannot be null");
         return new MeterInstruction(meterId);
@@ -625,6 +636,50 @@
     }
 
     /**
+     *  Set-Queue Instruction.
+     */
+    public static final class SetQueueInstruction implements Instruction {
+        private final long queueId;
+
+        private SetQueueInstruction(long queueId) {
+            this.queueId = queueId;
+        }
+
+        public long queueId() {
+            return queueId;
+        }
+
+        @Override
+        public Type type() {
+            return Type.QUEUE;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("queueId", queueId).toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type().ordinal(), queueId);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof SetQueueInstruction) {
+                SetQueueInstruction that = (SetQueueInstruction) obj;
+                return Objects.equals(queueId, that.queueId);
+
+            }
+            return false;
+        }
+    }
+
+    /**
      * A meter instruction.
      */
     public static final class MeterInstruction implements Instruction {