Add truncate instruction and support it with PI framework

To support truncate by P4Runtime clone/mirror session, we need to pass the
truncate size/length from ONOS northbound to the southbound.
As discussed in the SDFabric syncup, we decide to pass this information via
the instruction in group bucket so applications or pipeliners can simply
reuse current APIs.

Change-Id: I15cc822b7c8008b6b9f8b02f3f399769ae396ef0
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 ffad4f7..467cc6d 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
@@ -273,6 +273,7 @@
                 case L4MODIFICATION:
                 case PROTOCOL_INDEPENDENT:
                 case EXTENSION:
+                case TRUNCATE:
                     current.add(instruction);
                     break;
                 case TABLE:
@@ -559,6 +560,11 @@
         }
 
         @Override
+        public TrafficTreatment.Builder truncate(int maxLen) {
+            return add(Instructions.truncate(maxLen));
+        }
+
+        @Override
         public TrafficTreatment build() {
             if (deferred.isEmpty() && immediate.isEmpty()
                     && table == null && !clear) {
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 9fde774..538a78f 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
@@ -480,6 +480,14 @@
                             StatTriggerFlag statTriggerFlag);
 
         /**
+         * Adds a truncate instruction.
+         *
+         * @param maxLen the maximum frame length in bytes, must be a positive integer
+         * @return a treatment builder
+         */
+        Builder truncate(int maxLen);
+
+        /**
          * Add all instructions from another treatment.
          *
          * @param treatment another treatment
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 66fbb18..a87f3a3 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
@@ -101,7 +101,12 @@
         /**
          * Signifies that statistics will be triggered.
          */
-        STAT_TRIGGER
+        STAT_TRIGGER,
+
+        /**
+         * Signifies that the packet should be truncated.
+         */
+        TRUNCATE
     }
 
     /**
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 621c007..d330dcd 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
@@ -49,6 +49,7 @@
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -545,6 +546,17 @@
     }
 
     /**
+     * Creates a truncate instruction.
+     *
+     * @param maxLen the maximum frame length in bytes, must be a positive integer
+     * @return truncate instruction
+     */
+    public static TruncateInstruction truncate(int maxLen) {
+        checkArgument(maxLen > 0, "Truncate max length must be a positive integer.");
+        return new TruncateInstruction(maxLen);
+    }
+
+    /**
      *  No Action instruction.
      */
     public static final class NoActionInstruction implements Instruction {
@@ -974,6 +986,44 @@
         }
     }
 
+    public static final class TruncateInstruction implements Instruction {
+        private int maxLen;
+
+        public TruncateInstruction(int maxLen) {
+            this.maxLen = maxLen;
+        }
+
+        public int maxLen() {
+            return maxLen;
+        }
+
+        @Override
+        public Type type() {
+            return Type.TRUNCATE;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            TruncateInstruction that = (TruncateInstruction) o;
+            return maxLen == that.maxLen;
+        }
+
+        @Override
+        public int hashCode() {
+            return com.google.common.base.Objects.hashCode(maxLen);
+        }
+
+        @Override
+        public String toString() {
+            return type() + SEPARATOR + maxLen;
+        }
+    }
 }