ONOS-7077 Openflow 1.5 OXS and stat trigger support

Change-Id: I006bcd3d8eac451a780c7e5c69a12298ead14281
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 6c720c8..8bde2f6 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
@@ -17,6 +17,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 import org.onlab.packet.EthType;
@@ -49,6 +50,7 @@
     private final List<Instruction> all;
     private final Instructions.TableTypeTransition table;
     private final Instructions.MetadataInstruction meta;
+    private final Instructions.StatTriggerInstruction statTrigger;
 
     private final boolean hasClear;
 
@@ -69,6 +71,7 @@
         this.table = null;
         this.meta = null;
         this.meter = null;
+        this.statTrigger = null;
     }
 
     /**
@@ -80,11 +83,13 @@
      * @param clear instruction to clear the deferred actions list
      */
     private DefaultTrafficTreatment(List<Instruction> deferred,
-                                   List<Instruction> immediate,
-                                   Instructions.TableTypeTransition table,
-                                   boolean clear,
-                                   Instructions.MetadataInstruction meta,
-                                   Instructions.MeterInstruction meter) {
+                                    List<Instruction> immediate,
+                                    Instructions.TableTypeTransition table,
+                                    boolean clear,
+                                    Instructions.MetadataInstruction meta,
+                                    Instructions.MeterInstruction meter,
+                                    Instructions.StatTriggerInstruction statTrigger
+                                    ) {
         this.immediate = ImmutableList.copyOf(checkNotNull(immediate));
         this.deferred = ImmutableList.copyOf(checkNotNull(deferred));
         this.all = new ImmutableList.Builder<Instruction>()
@@ -95,6 +100,7 @@
         this.meta = meta;
         this.hasClear = clear;
         this.meter = meter;
+        this.statTrigger = statTrigger;
     }
 
     @Override
@@ -128,6 +134,11 @@
     }
 
     @Override
+    public Instructions.StatTriggerInstruction statTrigger() {
+        return statTrigger;
+    }
+
+    @Override
     public Instructions.MeterInstruction metered() {
         return meter;
     }
@@ -191,6 +202,7 @@
                 .add("transition", table == null ? "None" : table.toString())
                 .add("meter", meter == null ? "None" : meter.toString())
                 .add("cleared", hasClear)
+                .add("StatTrigger", statTrigger)
                 .add("metadata", meta)
                 .toString();
     }
@@ -209,6 +221,8 @@
 
         Instructions.MeterInstruction meter;
 
+        Instructions.StatTriggerInstruction statTrigger;
+
         List<Instruction> deferred = new ArrayList<>();
 
         List<Instruction> immediate = new ArrayList<>();
@@ -259,6 +273,9 @@
                 case METER:
                     meter = (Instructions.MeterInstruction) instruction;
                     break;
+                case STAT_TRIGGER:
+                    statTrigger = (Instructions.StatTriggerInstruction) instruction;
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown instruction type: " +
                                                                instruction.type());
@@ -493,6 +510,12 @@
         }
 
         @Override
+        public TrafficTreatment.Builder statTrigger(Map<StatTriggerField, Long> statTriggerFieldMap,
+                                                    StatTriggerFlag statTriggerFlag) {
+            return add(Instructions.statTrigger(statTriggerFieldMap, statTriggerFlag));
+        }
+
+        @Override
         public TrafficTreatment.Builder addTreatment(TrafficTreatment treatment) {
             List<Instruction> previous = current;
             deferred();
@@ -516,7 +539,7 @@
                 immediate();
                 noAction();
             }
-            return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter);
+            return new DefaultTrafficTreatment(deferred, immediate, table, clear, meta, meter, statTrigger);
         }
 
     }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java
new file mode 100644
index 0000000..f946542
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerField.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.flow;
+
+/**
+ * Stat fields are supported default by OXS.
+ */
+public enum StatTriggerField {
+    /** Time flow entry has been alive. Unit indicates nanoseconds. */
+    DURATION,
+    /** Time flow entry has been idle. Unit indicates nanoseconds. */
+    IDLE_TIME,
+    /** Number of aggregated flow entries. */
+    FLOW_COUNT,
+    /** Number of packets in flow entry. */
+    PACKET_COUNT,
+    /** Number of bytes in flow entry. */
+    BYTE_COUNT
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java
new file mode 100644
index 0000000..7ed650c
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/StatTriggerFlag.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.flow;
+
+/**
+ * Stat Trigger Flags.
+ */
+public enum StatTriggerFlag {
+    /** Trigger for all multiples of thresholds. */
+    PERIODIC,
+    /** Trigger on only first reach threshold. */
+    ONLY_FIRST
+}
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 9ddabe1..057f0f8 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
@@ -16,6 +16,7 @@
 package org.onosproject.net.flow;
 
 import java.util.List;
+import java.util.Map;
 
 import com.google.common.annotations.Beta;
 import org.onlab.packet.EthType;
@@ -81,6 +82,12 @@
     Instructions.MetadataInstruction writeMetadata();
 
     /**
+     * Returns the stat trigger instruction if there is one.
+     * @return a stat trigger instruction; may be null.
+     */
+    Instructions.StatTriggerInstruction statTrigger();
+
+    /**
      * Returns the meter instruction if there is one.
      *
      * @return a meter instruction that may be null
@@ -422,6 +429,16 @@
         Builder extension(ExtensionTreatment extension, DeviceId deviceId);
 
         /**
+         * Add stat trigger instruction.
+         *
+         * @param statTriggerFieldMap defines stat trigger constraints
+         * @param statTriggerFlag describes which circumstances that start will be triggered
+         * @return a treatment builder
+         */
+        Builder statTrigger(Map<StatTriggerField, Long> statTriggerFieldMap,
+                            StatTriggerFlag statTriggerFlag);
+
+        /**
          * 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 c3c9b60..66fbb18 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
@@ -96,7 +96,12 @@
         /**
          * Signifies that an extension instruction will be used.
          */
-        EXTENSION
+        EXTENSION,
+
+        /**
+         * Signifies that statistics will be triggered.
+         */
+        STAT_TRIGGER
     }
 
     /**
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 460976a..9bd7df5 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
@@ -16,6 +16,7 @@
 package org.onosproject.net.flow.instructions;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableMap;
 import org.onlab.packet.EthType;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
@@ -28,6 +29,8 @@
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModOchSignalInstruction;
 import org.onosproject.net.flow.instructions.L1ModificationInstruction.ModOduSignalIdInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.L3SubType;
@@ -42,6 +45,7 @@
 import org.onosproject.net.meter.MeterId;
 import org.onosproject.net.pi.runtime.PiTableAction;
 
+import java.util.Map;
 import java.util.Objects;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
@@ -498,6 +502,20 @@
     }
 
     /**
+     * Creates a stat trigger instruction.
+     *
+     * @param statTriggerMap map keeps stat trigger threshold
+     * @param flag stat trigger flag
+     * @return stat trigger instruction
+     */
+    public static StatTriggerInstruction statTrigger(Map<StatTriggerField, Long> statTriggerMap,
+                                                     StatTriggerFlag flag) {
+        checkNotNull(statTriggerMap, "Stat trigger map cannot be null");
+        checkNotNull(flag, "Stat trigger flag  cannot be null");
+        return new StatTriggerInstruction(statTriggerMap, flag);
+    }
+
+    /**
      *  No Action instruction.
      */
     public static final class NoActionInstruction implements Instruction {
@@ -865,6 +883,68 @@
         }
     }
 
+    public static class StatTriggerInstruction implements Instruction {
+        private Map<StatTriggerField, Long> statTriggerFieldMap;
+        private StatTriggerFlag statTriggerFlag;
+
+
+        StatTriggerInstruction(Map<StatTriggerField, Long> statTriggerMap,
+                                      StatTriggerFlag flag) {
+            this.statTriggerFieldMap = ImmutableMap.copyOf(statTriggerMap);
+            this.statTriggerFlag = flag;
+        }
+
+        public Map<StatTriggerField, Long> getStatTriggerFieldMap() {
+            return statTriggerFieldMap;
+        }
+
+        public StatTriggerFlag getStatTriggerFlag() {
+            return statTriggerFlag;
+        }
+
+        public Long getStatValue(StatTriggerField field) {
+            return statTriggerFieldMap.get(field);
+        }
+
+        @Override
+        public Type type() {
+            return Type.STAT_TRIGGER;
+        }
+
+        @Override
+        public String toString() {
+            return "StatTriggerInstruction{" +
+                    "statTriggerFieldMap=" + statTriggerFieldMap +
+                    ", statTriggerFlag=" + statTriggerFlag +
+                    '}';
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            StatTriggerInstruction that = (StatTriggerInstruction) o;
+
+            if (!Objects.equals(statTriggerFieldMap, that.statTriggerFieldMap)) {
+                return false;
+            }
+
+            return statTriggerFlag == that.statTriggerFlag;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = statTriggerFieldMap != null ? statTriggerFieldMap.hashCode() : 0;
+            result = 31 * result + (statTriggerFlag != null ? statTriggerFlag.hashCode() : 0);
+            return result;
+        }
+    }
+
 }
 
 
diff --git a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
index 9eada31..ddf6500 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
@@ -31,6 +31,8 @@
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
 import org.onosproject.net.meter.MeterId;
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionId;
@@ -38,7 +40,9 @@
 import org.onosproject.net.pi.runtime.PiActionParamId;
 import org.onosproject.net.pi.runtime.PiTableAction;
 
+import java.util.EnumMap;
 import java.util.List;
+import java.util.Map;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
@@ -829,6 +833,49 @@
                                meterInstruction2);
     }
 
+    private long packetCountValue1 = 5L;
+    private long byteCountValue1 = 10L;
+    private long packetCountValue2 = 10L;
+    private long byteCountValue2 = 5L;
+    private StatTriggerFlag flag1 = StatTriggerFlag.ONLY_FIRST;
+    private StatTriggerFlag flag2 = StatTriggerFlag.PERIODIC;
+    Map<StatTriggerField, Long> statTriggerFieldMap1 = new EnumMap<StatTriggerField, Long>(StatTriggerField.class) {
+        {
+            put(StatTriggerField.BYTE_COUNT, packetCountValue1);
+            put(StatTriggerField.PACKET_COUNT, byteCountValue1);
+        }
+    };
+    Map<StatTriggerField, Long> statTriggerFieldMap2 = new EnumMap<StatTriggerField, Long>(StatTriggerField.class) {
+        {
+            put(StatTriggerField.BYTE_COUNT, packetCountValue2);
+            put(StatTriggerField.PACKET_COUNT, byteCountValue2);
+        }
+    };
+
+    final Instruction statInstruction1 = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+    final Instruction statInstruction1Same = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+    final Instruction statInstruction2 = Instructions.statTrigger(statTriggerFieldMap2, flag2);
+
+    @Test
+    public void testStatTriggerTrafficMethod() {
+        final Instruction instruction = Instructions.statTrigger(statTriggerFieldMap1, flag1);
+        final Instructions.StatTriggerInstruction statTriggerInstruction =
+                checkAndConvert(instruction,
+                        Instruction.Type.STAT_TRIGGER,
+                        Instructions.StatTriggerInstruction.class);
+        assertThat(statTriggerInstruction.getStatTriggerFieldMap(), is(equalTo(statTriggerFieldMap1)));
+        assertThat(statTriggerInstruction.getStatTriggerFlag(), is(equalTo(flag1)));
+        assertThat(statTriggerInstruction.getStatTriggerFieldMap(), is(not(equalTo(statTriggerFieldMap2))));
+        assertThat(statTriggerInstruction.getStatTriggerFlag(), is(not(equalTo(flag2))));
+    }
+
+    @Test
+    public void testStatTriggerTrafficInstructionEquals() {
+        checkEqualsAndToString(statInstruction1,
+                statInstruction1Same,
+                statInstruction2);
+    }
+
     //  TableTypeTransition
 
     private final Instruction transitionInstruction1 = Instructions.transition(1);
diff --git a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
index 352e2f5..a05745c 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/IntentTestsMocks.java
@@ -113,6 +113,11 @@
         }
 
         @Override
+        public Instructions.StatTriggerInstruction statTrigger() {
+            return null;
+        }
+
+        @Override
         public Instructions.MeterInstruction metered() {
             return null;
         }
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index a9571f9..ff55e49 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -17,6 +17,7 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
 import org.onlab.osgi.DefaultServiceDirectory;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.packet.EthType;
@@ -37,6 +38,8 @@
 import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
 import org.onosproject.net.flow.instructions.ExtensionTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
@@ -48,10 +51,12 @@
 import org.onosproject.net.meter.MeterId;
 import org.slf4j.Logger;
 
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import static org.onlab.util.Tools.nullIsIllegal;
+import static org.onosproject.codec.impl.InstructionCodec.STAT_PACKET_COUNT;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -262,6 +267,58 @@
                 + subType + " is not supported");
     }
 
+    private Instruction decodeStatTrigger() {
+        String statTriggerFlag = nullIsIllegal(json.get(InstructionCodec.STAT_TRIGGER_FLAG),
+                InstructionCodec.STAT_TRIGGER_FLAG + InstructionCodec.ERROR_MESSAGE).asText();
+
+        StatTriggerFlag flag = null;
+
+        if (statTriggerFlag.equals(StatTriggerFlag.ONLY_FIRST.name())) {
+            flag = StatTriggerFlag.ONLY_FIRST;
+        } else if (statTriggerFlag.equals(StatTriggerFlag.PERIODIC.name())) {
+            flag = StatTriggerFlag.PERIODIC;
+        } else {
+            throw new IllegalArgumentException("statTriggerFlag "
+                    + statTriggerFlag + " is not supported");
+        }
+        if (!json.has(InstructionCodec.STAT_THRESHOLDS)) {
+            throw new IllegalArgumentException("statThreshold is not added");
+        }
+        JsonNode statThresholdsNode = nullIsIllegal(json.get(InstructionCodec.STAT_THRESHOLDS),
+                InstructionCodec.STAT_THRESHOLDS + InstructionCodec.ERROR_MESSAGE);
+        Map<StatTriggerField, Long> statThresholdMap = getStatThreshold(statThresholdsNode);
+        if (statThresholdMap.isEmpty()) {
+            throw new IllegalArgumentException("statThreshold must have at least one property");
+        }
+        return Instructions.statTrigger(statThresholdMap, flag);
+    }
+
+    private Map<StatTriggerField, Long> getStatThreshold(JsonNode statThresholdNode) {
+        Map<StatTriggerField, Long> statThresholdMap = Maps.newEnumMap(StatTriggerField.class);
+        for (JsonNode jsonNode : statThresholdNode) {
+            if (jsonNode.hasNonNull(InstructionCodec.STAT_BYTE_COUNT)) {
+                JsonNode byteCountNode = jsonNode.get(InstructionCodec.STAT_BYTE_COUNT);
+                if (!byteCountNode.isNull() && byteCountNode.isNumber()) {
+                    statThresholdMap.put(StatTriggerField.BYTE_COUNT, byteCountNode.asLong());
+                }
+            } else if (jsonNode.hasNonNull(STAT_PACKET_COUNT)) {
+                JsonNode packetCount = jsonNode.get(STAT_PACKET_COUNT);
+                if (!packetCount.isNull() && packetCount.isNumber()) {
+                    statThresholdMap.put(StatTriggerField.PACKET_COUNT, packetCount.asLong());
+                }
+            } else if (jsonNode.hasNonNull(InstructionCodec.STAT_DURATION)) {
+                JsonNode duration = jsonNode.get(InstructionCodec.STAT_DURATION);
+                if (!duration.isNull() && duration.isNumber()) {
+                    statThresholdMap.put(StatTriggerField.DURATION, duration.asLong());
+                }
+            } else {
+                log.error("Unsupported stat {}", jsonNode.toString());
+            }
+        }
+
+        return statThresholdMap;
+    }
+
     /**
      * Decodes a extension instruction.
      *
@@ -391,6 +448,8 @@
             return decodeL4();
         } else if (type.equals(Instruction.Type.EXTENSION.name())) {
             return decodeExtension();
+        } else if (type.equals(Instruction.Type.STAT_TRIGGER.name())) {
+            return decodeStatTrigger();
         }
         throw new IllegalArgumentException("Instruction type "
                 + type + " is not supported");
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
index 1f741b5..9762643 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
@@ -59,6 +59,11 @@
     protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap";
     protected static final String EXTENSION = "extension";
     protected static final String DEVICE_ID = "deviceId";
+    protected static final String STAT_TRIGGER_FLAG = "statTriggerFlag";
+    protected static final String STAT_THRESHOLDS = "statThreshold";
+    protected static final String STAT_BYTE_COUNT = "byteCount";
+    protected static final String STAT_PACKET_COUNT = "packetCount";
+    protected static final String STAT_DURATION = "duration";
 
     protected static final String MISSING_MEMBER_MESSAGE =
             " member is required in Instruction";
diff --git a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
index 825ef1a..7785a38 100644
--- a/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/flow/impl/FlowRuleManagerTest.java
@@ -664,6 +664,11 @@
         }
 
         @Override
+        public Instructions.StatTriggerInstruction statTrigger() {
+            return null;
+        }
+
+        @Override
         public Instructions.MeterInstruction metered() {
             return null;
         }
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index d5deae1..6c4ad07 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -100,16 +100,18 @@
 import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowId;
 import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleEvent;
+import org.onosproject.net.flow.FlowRuleExtPayLoad;
+import org.onosproject.net.flow.IndexTableId;
+import org.onosproject.net.flow.StatTriggerField;
+import org.onosproject.net.flow.StatTriggerFlag;
+import org.onosproject.net.flow.StoredFlowEntry;
+import org.onosproject.net.flow.TableId;
+import org.onosproject.net.flow.TableStatisticsEntry;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchEntry;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchEvent;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
 import org.onosproject.net.flow.oldbatch.FlowRuleBatchRequest;
-import org.onosproject.net.flow.FlowRuleEvent;
-import org.onosproject.net.flow.FlowRuleExtPayLoad;
-import org.onosproject.net.flow.IndexTableId;
-import org.onosproject.net.flow.StoredFlowEntry;
-import org.onosproject.net.flow.TableId;
-import org.onosproject.net.flow.TableStatisticsEntry;
 import org.onosproject.net.flow.criteria.ArpHaCriterion;
 import org.onosproject.net.flow.criteria.ArpOpCriterion;
 import org.onosproject.net.flow.criteria.ArpPaCriterion;
@@ -355,6 +357,9 @@
             .nextId(KryoNamespace.INITIAL_ID + BASIC_MAX_SIZE + MISC_MAX_SIZE)
             .register(
                     Instructions.MeterInstruction.class,
+                    Instructions.StatTriggerInstruction.class,
+                    StatTriggerFlag.class,
+                    StatTriggerField.class,
                     MeterId.class,
                     Version.class,
                     ControllerNode.State.class,