Generic extensions to the treatment API to support protocol extensions like
OF experimenter actions.

Change-Id: I88cc5896d17fdbf89807f911f9c23e4f19f6a5ad
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java b/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java
new file mode 100644
index 0000000..54cbc7a
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/ExtensionResolver.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.behaviour;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+
+/**
+ * Provides access to the extension implemented by this driver.
+ */
+@Beta
+public interface ExtensionResolver extends HandlerBehaviour {
+
+    /**
+     * Gets an extension instruction instance of the specified type, if supported
+     * by the driver.
+     *
+     * @param type type of extension to get
+     * @return extension instruction
+     * @throws UnsupportedOperationException if the extension type is not
+     * supported by this driver
+     */
+    ExtensionInstruction getExtensionInstruction(ExtensionType type);
+}
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 ac37d1f..6beeecc 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
@@ -27,8 +27,10 @@
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.meter.MeterId;
@@ -244,6 +246,7 @@
                 case L2MODIFICATION:
                 case L3MODIFICATION:
                 case L4MODIFICATION:
+                case EXTENSION:
                     current.add(instruction);
                     break;
                 case TABLE:
@@ -481,6 +484,12 @@
         }
 
         @Override
+        public TrafficTreatment.Builder extension(ExtensionInstruction extension,
+                                                  DeviceId deviceId) {
+            return add(Instructions.extension(extension, deviceId));
+        }
+
+        @Override
         public TrafficTreatment build() {
             if (deferred.size() == 0 && immediate.size() == 0
                     && 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 91c19b7..b14ab99 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
@@ -24,7 +24,9 @@
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.meter.MeterId;
@@ -413,6 +415,15 @@
         Builder setUdpDst(TpPort port);
 
         /**
+         * Uses an extension treatment.
+         *
+         * @param extension extension treatment
+         * @param deviceId device ID
+         * @return a treatment builder
+         */
+        Builder extension(ExtensionInstruction extension, DeviceId deviceId);
+
+        /**
          * Builds an immutable traffic treatment descriptor.
          * <p>
          * If the treatment is empty when build() is called, it will add a default
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java
new file mode 100644
index 0000000..9f22f88
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/AbstractExtensionInstruction.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.instructions;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract implementation of the set/get property methods of ExtensionInstruction.
+ */
+public abstract class AbstractExtensionInstruction implements ExtensionInstruction {
+
+    private static final String INVALID_KEY = "Invalid property key: ";
+    private static final String INVALID_TYPE = "Given type does not match field type: ";
+
+    @Override
+    public <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException {
+        Class<?> clazz = this.getClass();
+        try {
+            Field field = clazz.getDeclaredField(key);
+            field.setAccessible(true);
+            field.set(this, value);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExtensionPropertyException(INVALID_KEY + key);
+        }
+    }
+
+    @Override
+    public <T> T getPropertyValue(String key) throws ExtensionPropertyException {
+        Class<?> clazz = this.getClass();
+        try {
+            Field field = clazz.getDeclaredField(key);
+            field.setAccessible(true);
+            @SuppressWarnings("unchecked")
+            T result = (T) field.get(this);
+            return result;
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExtensionPropertyException(INVALID_KEY + key);
+        } catch (ClassCastException e) {
+            throw new ExtensionPropertyException(INVALID_TYPE + key);
+        }
+    }
+
+    @Override
+    public List<String> getProperties() {
+        Class<?> clazz = this.getClass();
+
+        List<String> fields = new ArrayList<>();
+
+        for (Field field : clazz.getDeclaredFields()) {
+            fields.add(field.getName());
+        }
+
+        return fields;
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java
new file mode 100644
index 0000000..89e0cc5
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionInstruction.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.instructions;
+
+import java.util.List;
+
+/**
+ * An extensible instruction type.
+ */
+public interface ExtensionInstruction {
+
+    /**
+     * Gets the type of the extension instruction.
+     *
+     * @return type
+     */
+    ExtensionType type();
+
+    /**
+     * Sets a property on the extension instruction.
+     *
+     * @param key property key
+     * @param value value to set for the given key
+     * @param <T> class of the value
+     * @throws ExtensionPropertyException if the given key is not a valid
+     * property on this extension instruction
+     */
+    <T> void setPropertyValue(String key, T value) throws ExtensionPropertyException;
+
+    /**
+     * Gets a property value of an extension instruction.
+     *
+     * @param key property key
+     * @param <T> class of the value
+     * @return value of the property
+     * @throws ExtensionPropertyException if the given key is not a valid
+     * property on this extension instruction
+     */
+    <T> T getPropertyValue(String key) throws ExtensionPropertyException;
+
+    /**
+     * Gets a list of all properties on the extension instruction.
+     *
+     * @return list of properties
+     */
+    List<String> getProperties();
+
+    /**
+     * Serialize the extension instruction to a byte array.
+     *
+     * @return byte array
+     */
+    byte[] serialize();
+
+    /**
+     * Deserialize the extension instruction from a byte array. The properties
+     * of this object will be overwritten with the data in the byte array.
+     *
+     * @param data input byte array
+     */
+    void deserialize(byte[] data);
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java
new file mode 100644
index 0000000..5750d09
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionPropertyException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.instructions;
+
+/**
+ * Exception indicating there was an error while setting/getting an extension
+ * instruction property.
+ */
+public class ExtensionPropertyException extends Exception {
+
+    public ExtensionPropertyException(String message) {
+        super(message);
+    }
+
+    public ExtensionPropertyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java
new file mode 100644
index 0000000..747a85b
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionType.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.instructions;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Type of extension instructions.
+ */
+@Beta
+public final class ExtensionType {
+
+    /**
+     * A list of well-known named extension instruction type codes.
+     */
+    public enum ExtensionTypes {
+        // TODO fix type numbers to include experimenter id
+        NICIRA_SET_TUNNEL_DST(31);
+
+        private ExtensionType type;
+
+        /**
+         * Creates a new named extension instruction type.
+         *
+         * @param type type code
+         */
+        ExtensionTypes(int type) {
+            this.type = new ExtensionType(type);
+        }
+
+        /**
+         * Gets the extension type object for this named type code.
+         *
+         * @return extension type object
+         */
+        public ExtensionType type() {
+            return type;
+        }
+    }
+
+    private final int type;
+
+    /**
+     * Creates an extension type with the given int type code.
+     *
+     * @param type type code
+     */
+    public ExtensionType(int type) {
+        this.type = type;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ExtensionType) {
+            final ExtensionType that = (ExtensionType) obj;
+            return this.type == that.type;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(ExtensionType.class)
+                .add("type", type)
+                .toString();
+    }
+}
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 2f6a1cc..31ad80c 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
@@ -92,7 +92,12 @@
         /**
          * Signifies that the traffic should be modified in L4 way.
          */
-        L4MODIFICATION
+        L4MODIFICATION,
+
+        /**
+         * Signifies that an extension instruction will be used.
+         */
+        EXTENSION
     }
 
     /**
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 8868bf7..aad407c 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
@@ -22,6 +22,7 @@
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.IndexedLambda;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
@@ -480,6 +481,20 @@
     }
 
     /**
+     * Creates an extension instruction.
+     *
+     * @param extension extension instruction
+     * @param deviceId device ID
+     * @return extension instruction
+     */
+    public static ExtensionInstructionWrapper extension(ExtensionInstruction extension,
+                                                        DeviceId deviceId) {
+        checkNotNull(extension, "Extension instruction cannot be null");
+        checkNotNull(deviceId, "Device ID cannot be null");
+        return new ExtensionInstructionWrapper(extension, deviceId);
+    }
+
+    /**
      *  Drop instruction.
      */
     @Deprecated
@@ -820,6 +835,59 @@
         }
     }
 
+    /**
+     *  Extension instruction.
+     */
+    public static class ExtensionInstructionWrapper implements Instruction {
+        private final ExtensionInstruction extensionInstruction;
+        private final DeviceId deviceId;
+
+        ExtensionInstructionWrapper(ExtensionInstruction extension, DeviceId deviceId) {
+            extensionInstruction = extension;
+            this.deviceId = deviceId;
+        }
+
+        public ExtensionInstruction extensionInstruction() {
+            return extensionInstruction;
+        }
+
+        public DeviceId deviceId() {
+            return deviceId;
+        }
+
+        @Override
+        public Type type() {
+            return Type.EXTENSION;
+        }
+
+        @Override
+        public String toString() {
+            return toStringHelper(type().toString())
+                    .add("extension", extensionInstruction)
+                    .add("deviceId", deviceId)
+                    .toString();
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(type().ordinal(), extensionInstruction, deviceId);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof ExtensionInstructionWrapper) {
+                ExtensionInstructionWrapper that = (ExtensionInstructionWrapper) obj;
+                return Objects.equals(extensionInstruction, that.extensionInstruction)
+                        && Objects.equals(deviceId, that.deviceId);
+
+            }
+            return false;
+        }
+    }
+
 }
 
 
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java
new file mode 100644
index 0000000..6b12df9
--- /dev/null
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/ExtensionInstructionSerializer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.store.serializers;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.Serializer;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+import org.onlab.osgi.DefaultServiceDirectory;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.behaviour.ExtensionResolver;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.net.flow.instructions.Instructions;
+
+/**
+ * Created by jono on 10/29/15.
+ */
+public class ExtensionInstructionSerializer extends
+        Serializer<Instructions.ExtensionInstructionWrapper> {
+
+    public ExtensionInstructionSerializer() {
+        super(false, true);
+    }
+
+    @Override
+    public void write(Kryo kryo, Output output, Instructions.ExtensionInstructionWrapper object) {
+        kryo.writeClassAndObject(output, object.extensionInstruction().type());
+        kryo.writeClassAndObject(output, object.deviceId());
+
+        kryo.writeClassAndObject(output, object.extensionInstruction().serialize());
+
+    }
+
+    @Override
+    public Instructions.ExtensionInstructionWrapper read(Kryo kryo, Input input,
+                                                         Class<Instructions.ExtensionInstructionWrapper> type) {
+        ExtensionType exType = (ExtensionType) kryo.readClassAndObject(input);
+        DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
+
+        DriverService driverService = DefaultServiceDirectory.getService(DriverService.class);
+        DriverHandler handler = new DefaultDriverHandler(
+                new DefaultDriverData(driverService.getDriver(deviceId), deviceId));
+
+        ExtensionResolver resolver = handler.behaviour(ExtensionResolver.class);
+
+        ExtensionInstruction instruction = resolver.getExtensionInstruction(exType);
+
+        byte[] bytes = (byte[]) kryo.readClassAndObject(input);
+
+        instruction.deserialize(bytes);
+
+        return Instructions.extension(instruction, deviceId);
+    }
+}
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 225b95d..0312baf 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
@@ -128,6 +128,7 @@
 import org.onosproject.net.flow.criteria.UdpPortCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flow.criteria.VlanPcpCriterion;
+import org.onosproject.net.flow.instructions.ExtensionType;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
 import org.onosproject.net.flow.instructions.L1ModificationInstruction;
@@ -450,6 +451,8 @@
             .register(new HostLocationSerializer(), HostLocation.class)
             .register(new DefaultOutboundPacketSerializer(), DefaultOutboundPacket.class)
             .register(new AnnotationsSerializer(), DefaultAnnotations.class)
+            .register(new ExtensionInstructionSerializer(), Instructions.ExtensionInstructionWrapper.class)
+            .register(ExtensionType.class)
             .register(Versioned.class)
             .register(MapEvent.class)
             .register(MapEvent.Type.class)
diff --git a/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java b/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java
new file mode 100644
index 0000000..082c5a6
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/extensions/NiciraExtensionInterpreter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.driver.extensions;
+
+import org.onlab.packet.Ip4Address;
+import org.onosproject.net.behaviour.ExtensionResolver;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
+import org.projectfloodlight.openflow.protocol.OFActionType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+import org.projectfloodlight.openflow.protocol.action.OFActionSetField;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxm;
+import org.projectfloodlight.openflow.protocol.oxm.OFOxmTunnelIpv4Dst;
+import org.projectfloodlight.openflow.types.IPv4Address;
+
+/**
+ * Interpreter for Nicira OpenFlow extensions.
+ */
+public class NiciraExtensionInterpreter extends AbstractHandlerBehaviour
+        implements ExtensionInterpreter, ExtensionResolver {
+
+    @Override
+    public boolean supported(ExtensionType extensionType) {
+        if (extensionType.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction) {
+        ExtensionType type = extensionInstruction.type();
+        if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
+            NiciraSetTunnelDst tunnelDst = (NiciraSetTunnelDst) extensionInstruction;
+            return factory.actions().setField(factory.oxms().tunnelIpv4Dst(
+                    IPv4Address.of(tunnelDst.tunnelDst().toInt())));
+        }
+        return null;
+    }
+
+    @Override
+    public ExtensionInstruction mapAction(OFAction action) {
+        if (action.getType().equals(OFActionType.SET_FIELD)) {
+            OFActionSetField setFieldAction = (OFActionSetField) action;
+            OFOxm<?> oxm = setFieldAction.getField();
+            switch (oxm.getMatchField().id) {
+            case TUNNEL_IPV4_DST:
+                OFOxmTunnelIpv4Dst tunnelIpv4Dst = (OFOxmTunnelIpv4Dst) oxm;
+                return new NiciraSetTunnelDst(Ip4Address.valueOf(tunnelIpv4Dst.getValue().getInt()));
+            default:
+                throw new UnsupportedOperationException(
+                        "Driver does not support extension type " + oxm.getMatchField().id);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ExtensionInstruction getExtensionInstruction(ExtensionType type) {
+        if (type.equals(ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type())) {
+            return new NiciraSetTunnelDst();
+        }
+        throw new UnsupportedOperationException(
+                "Driver does not support extension type " + type.toString());
+    }
+}
diff --git a/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java b/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java
new file mode 100644
index 0000000..16aa1b0
--- /dev/null
+++ b/drivers/src/main/java/org/onosproject/driver/extensions/NiciraSetTunnelDst.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.driver.extensions;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.Ip4Address;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.net.flow.instructions.AbstractExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.onosproject.store.serializers.Ip4AddressSerializer;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Nicira set tunnel destination extension instruction.
+ */
+public class NiciraSetTunnelDst extends AbstractExtensionInstruction {
+
+    private Ip4Address tunnelDst;
+
+    private final KryoNamespace appKryo = new KryoNamespace.Builder()
+            .register(new Ip4AddressSerializer(), Ip4Address.class)
+            .register(byte[].class)
+            .build();
+
+    /**
+     * Creates a new set tunnel destination instruction.
+     */
+    NiciraSetTunnelDst() {
+        tunnelDst = null;
+    }
+
+    /**
+     * Creates a new set tunnel destination instruction with a particular IPv4
+     * address.
+     */
+    NiciraSetTunnelDst(Ip4Address tunnelDst) {
+        checkNotNull(tunnelDst);
+        this.tunnelDst = tunnelDst;
+    }
+
+    /**
+     * Gets the tunnel destination IPv4 address.
+     *
+     * @return tunnel destination IPv4 address
+     */
+    public Ip4Address tunnelDst() {
+        return tunnelDst;
+    }
+
+    @Override
+    public ExtensionType type() {
+        return ExtensionType.ExtensionTypes.NICIRA_SET_TUNNEL_DST.type();
+    }
+
+    @Override
+    public void deserialize(byte[] data) {
+        tunnelDst = appKryo.deserialize(data);
+    }
+
+    @Override
+    public byte[] serialize() {
+        return appKryo.serialize(tunnelDst);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(tunnelDst);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof NiciraSetTunnelDst) {
+            NiciraSetTunnelDst that = (NiciraSetTunnelDst) obj;
+            return Objects.equals(tunnelDst, that.tunnelDst);
+
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("tunnelDst", tunnelDst)
+                .toString();
+    }
+}
diff --git a/drivers/src/main/resources/onos-drivers.xml b/drivers/src/main/resources/onos-drivers.xml
index 74281bf..af49883 100644
--- a/drivers/src/main/resources/onos-drivers.xml
+++ b/drivers/src/main/resources/onos-drivers.xml
@@ -32,6 +32,10 @@
                    impl="org.onosproject.driver.handshaker.NiciraSwitchHandshaker"/>
         <behaviour api="org.onosproject.net.behaviour.ControllerConfig"
                    impl="org.onosproject.driver.ovsdb.OvsdbControllerConfig"/>
+        <behaviour api="org.onosproject.openflow.controller.ExtensionInterpreter"
+                   impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
+        <behaviour api="org.onosproject.net.behaviour.ExtensionResolver"
+                   impl="org.onosproject.driver.extensions.NiciraExtensionInterpreter" />
     </driver>
     <driver name="ovs-corsa" extends="ovs"
             manufacturer="Corsa" hwVersion="emulation" swVersion="0.0.0">
diff --git a/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java b/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java
new file mode 100644
index 0000000..44b121a
--- /dev/null
+++ b/openflow/api/src/main/java/org/onosproject/openflow/controller/ExtensionInterpreter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * 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.openflow.controller;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.driver.HandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
+import org.onosproject.net.flow.instructions.ExtensionType;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.action.OFAction;
+
+/**
+ * Interprets extension instructions and converts them to/from OpenFlow objects.
+ */
+@Beta
+public interface ExtensionInterpreter extends HandlerBehaviour {
+
+    /**
+     * Returns true if the given extension instruction is supported by this
+     * driver.
+     *
+     * @param extensionType extension instruction type
+     * @return true if the instruction is supported, otherwise false
+     */
+    boolean supported(ExtensionType extensionType);
+
+    /**
+     * Maps an extension instruction to an OpenFlow action.
+     *
+     * @param factory OpenFlow factory
+     * @param extensionInstruction extension instruction
+     * @return OpenFlow action
+     */
+    OFAction mapInstruction(OFFactory factory, ExtensionInstruction extensionInstruction);
+
+    /**
+     * Maps an OpenFlow action to an extension instruction.
+     *
+     * @param action OpenFlow action
+     * @return extension instruction
+     */
+    ExtensionInstruction mapAction(OFAction action);
+
+}
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
index 2c01e96..4d5b6b2 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -28,6 +28,11 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverHandler;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.DefaultFlowEntry;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -39,6 +44,7 @@
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
@@ -106,7 +112,9 @@
 
     private final FlowType type;
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry) {
+    private final DriverService driverService;
+
+    public FlowEntryBuilder(Dpid dpid, OFFlowStatsEntry entry, DriverService driverService) {
         this.stat = entry;
         this.match = entry.getMatch();
         this.instructions = getInstructions(entry);
@@ -114,9 +122,10 @@
         this.removed = null;
         this.flowMod = null;
         this.type = FlowType.STAT;
+        this.driverService = driverService;
     }
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed) {
+    public FlowEntryBuilder(Dpid dpid, OFFlowRemoved removed, DriverService driverService) {
         this.match = removed.getMatch();
         this.removed = removed;
 
@@ -125,10 +134,10 @@
         this.stat = null;
         this.flowMod = null;
         this.type = FlowType.REMOVED;
-
+        this.driverService = driverService;
     }
 
-    public FlowEntryBuilder(Dpid dpid, OFFlowMod fm) {
+    public FlowEntryBuilder(Dpid dpid, OFFlowMod fm, DriverService driverService) {
         this.match = fm.getMatch();
         this.dpid = dpid;
         this.instructions = getInstructions(fm);
@@ -136,6 +145,7 @@
         this.flowMod = fm;
         this.stat = null;
         this.removed = null;
+        this.driverService = driverService;
     }
 
     public FlowEntry build(FlowEntryState... state) {
@@ -307,7 +317,7 @@
                     break;
                 case SET_FIELD:
                     OFActionSetField setField = (OFActionSetField) act;
-                    handleSetField(builder, setField.getField());
+                    handleSetField(builder, setField);
                     break;
                 case POP_MPLS:
                     OFActionPopMpls popMpls = (OFActionPopMpls) act;
@@ -363,7 +373,8 @@
     }
 
 
-    private void handleSetField(TrafficTreatment.Builder builder, OFOxm<?> oxm) {
+    private void handleSetField(TrafficTreatment.Builder builder, OFActionSetField action) {
+        OFOxm<?> oxm = action.getField();
         switch (oxm.getMatchField().id) {
         case VLAN_PCP:
             @SuppressWarnings("unchecked")
@@ -432,6 +443,13 @@
             OFOxm<TransportPort> udpsrc = (OFOxm<TransportPort>) oxm;
             builder.setUdpSrc(TpPort.tpPort(udpsrc.getValue().getPort()));
             break;
+        case TUNNEL_IPV4_DST:
+            DriverHandler driver = getDriver(dpid);
+            ExtensionInterpreter interpreter = driver.behaviour(ExtensionInterpreter.class);
+            if (interpreter != null) {
+                builder.extension(interpreter.mapAction(action), DeviceId.deviceId(Dpid.uri(dpid)));
+            }
+            break;
         case ARP_OP:
         case ARP_SHA:
         case ARP_SPA:
@@ -697,4 +715,11 @@
         }
         return builder.build();
     }
+
+    private DriverHandler getDriver(Dpid dpid) {
+        DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
+        Driver driver = driverService.getDriver(deviceId);
+        DriverHandler handler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
+        return handler;
+    }
 }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
index e050524..7eca492 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -15,16 +15,13 @@
  */
 package org.onosproject.provider.of.flow.impl;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Optional;
-
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.VlanId;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -85,6 +82,10 @@
 import org.projectfloodlight.openflow.types.VlanVid;
 import org.slf4j.Logger;
 
+import java.util.Optional;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Builder for OpenFlow flow mods based on FlowRules.
  */
@@ -96,6 +97,7 @@
     private final FlowRule flowRule;
     private final TrafficSelector selector;
     protected final Long xid;
+    protected final Optional<DriverService> driverService;
 
     /**
      * Creates a new flow mod builder.
@@ -107,12 +109,13 @@
      */
     public static FlowModBuilder builder(FlowRule flowRule,
                                          OFFactory factory,
-                                         Optional<Long> xid) {
+                                         Optional<Long> xid,
+                                         Optional<DriverService> driverService) {
         switch (factory.getVersion()) {
         case OF_10:
-            return new FlowModBuilderVer10(flowRule, factory, xid);
+            return new FlowModBuilderVer10(flowRule, factory, xid, driverService);
         case OF_13:
-            return new FlowModBuilderVer13(flowRule, factory, xid);
+            return new FlowModBuilderVer13(flowRule, factory, xid, driverService);
         default:
             throw new UnsupportedOperationException(
                     "No flow mod builder for protocol version " + factory.getVersion());
@@ -126,12 +129,13 @@
      * @param factory the OpenFlow factory to use to build the flow mod
      * @param xid the transaction ID
      */
-    protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
+    protected FlowModBuilder(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
+                             Optional<DriverService> driverService) {
         this.factory = factory;
         this.flowRule = flowRule;
         this.selector = flowRule.selector();
         this.xid = xid.orElse(0L);
-
+        this.driverService = driverService;
     }
 
     /**
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
index f77819d..c789841 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -17,6 +17,7 @@
 
 import org.onlab.packet.Ip4Address;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.instructions.Instruction;
@@ -68,8 +69,9 @@
      * @param xid the transaction ID
      */
     protected FlowModBuilderVer10(FlowRule flowRule,
-                                  OFFactory factory, Optional<Long> xid) {
-        super(flowRule, factory, xid);
+                                  OFFactory factory, Optional<Long> xid,
+                                  Optional<DriverService> driverService) {
+        super(flowRule, factory, xid, driverService);
 
         this.treatment = flowRule.treatment();
     }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index 64b4360..a99aa81 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -18,10 +18,16 @@
 import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip6Address;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.OchSignal;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.driver.DefaultDriverData;
+import org.onosproject.net.driver.DefaultDriverHandler;
+import org.onosproject.net.driver.Driver;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.instructions.ExtensionInstruction;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
@@ -34,15 +40,16 @@
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.PushHeaderInstructions;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
+import org.onosproject.openflow.controller.ExtensionInterpreter;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFFlowAdd;
 import org.projectfloodlight.openflow.protocol.OFFlowDelete;
@@ -88,6 +95,7 @@
     private static final int OFPCML_NO_BUFFER = 0xffff;
 
     private final TrafficTreatment treatment;
+    private final DeviceId deviceId;
 
     /**
      * Constructor for a flow mod builder for OpenFlow 1.3.
@@ -96,10 +104,12 @@
      * @param factory the OpenFlow factory to use to build the flow mod
      * @param xid the transaction ID
      */
-    protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid) {
-        super(flowRule, factory, xid);
+    protected FlowModBuilderVer13(FlowRule flowRule, OFFactory factory, Optional<Long> xid,
+                                  Optional<DriverService> driverService) {
+        super(flowRule, factory, xid, driverService);
 
         this.treatment = flowRule.treatment();
+        this.deviceId = flowRule.deviceId();
     }
 
     @Override
@@ -256,6 +266,10 @@
                     //FIXME: should not occur here.
                     tableFound = true;
                     break;
+                case EXTENSION:
+                    actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i)
+                            .extensionInstruction()));
+                    break;
                 default:
                     log.warn("Instruction type {} not yet implemented.", i.type());
             }
@@ -467,4 +481,20 @@
         return null;
     }
 
+    private OFAction buildExtensionAction(ExtensionInstruction i) {
+        if (!driverService.isPresent()) {
+            log.error("No driver service present");
+            return null;
+        }
+        Driver driver = driverService.get().getDriver(deviceId);
+        if (driver.hasBehaviour(ExtensionInterpreter.class)) {
+            DefaultDriverHandler handler =
+                    new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
+            ExtensionInterpreter interpreter = handler.behaviour(ExtensionInterpreter.class);
+            return interpreter.mapInstruction(factory(), i);
+        }
+
+        return null;
+    }
+
 }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
index 487cae9..d5186fa 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/NewAdaptiveFlowStatsCollector.java
@@ -16,21 +16,10 @@
 

 package org.onosproject.provider.of.flow.impl;

 

-import java.util.HashSet;

-import java.util.List;

-import java.util.Map;

-import java.util.Optional;

-import java.util.Set;

-import java.util.concurrent.TimeUnit;

-import java.util.concurrent.ScheduledFuture;

-import java.util.concurrent.Executors;

-import java.util.concurrent.ScheduledExecutorService;

-

 import com.google.common.base.Objects;

 import com.google.common.collect.ImmutableSet;

 import com.google.common.collect.Maps;

 import com.google.common.collect.Sets;

-

 import org.onosproject.net.flow.DefaultTypedFlowEntry;

 import org.onosproject.net.flow.FlowEntry;

 import org.onosproject.net.flow.FlowId;

@@ -47,9 +36,19 @@
 import org.projectfloodlight.openflow.types.TableId;

 import org.slf4j.Logger;

 

+import java.util.HashSet;

+import java.util.List;

+import java.util.Map;

+import java.util.Optional;

+import java.util.Set;

+import java.util.concurrent.Executors;

+import java.util.concurrent.ScheduledExecutorService;

+import java.util.concurrent.ScheduledFuture;

+import java.util.concurrent.TimeUnit;

+

 import static com.google.common.base.Preconditions.checkNotNull;

 import static org.onlab.util.Tools.groupedThreads;

-import static org.onosproject.net.flow.TypedStoredFlowEntry.*;

+import static org.onosproject.net.flow.TypedStoredFlowEntry.FlowLiveType;

 import static org.slf4j.LoggerFactory.getLogger;

 

 /**

@@ -232,7 +231,8 @@
     // send openflow flow stats request message with getting the specific flow entry(fe) to a given switch sw

     private void ofFlowStatsRequestFlowSend(FlowEntry fe) {

         // set find match

-        Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty()).buildMatch();

+        Match match = FlowModBuilder.builder(fe, sw.factory(), Optional.empty(),

+                Optional.empty()).buildMatch();

         // set find tableId

         TableId tableId = TableId.of(fe.tableId());

         // set output port

diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
index 6374ca5..b37cb42 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -21,7 +21,6 @@
 import com.google.common.cache.RemovalNotification;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -32,6 +31,7 @@
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultTableStatisticsEntry;
 import org.onosproject.net.flow.FlowEntry;
@@ -61,12 +61,12 @@
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
 import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
 import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
-import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
-import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFStatsReply;
 import org.projectfloodlight.openflow.protocol.OFStatsType;
+import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
+import org.projectfloodlight.openflow.protocol.OFTableStatsReply;
 import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
 import org.projectfloodlight.openflow.protocol.errormsg.OFFlowModFailedErrorMsg;
 import org.slf4j.Logger;
@@ -106,6 +106,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService cfgService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DriverService driverService;
+
     private static final int DEFAULT_POLL_FREQUENCY = 5;
     @Property(name = "flowPollFrequency", intValue = DEFAULT_POLL_FREQUENCY,
             label = "Frequency (in seconds) for polling flow statistics")
@@ -269,7 +272,7 @@
             return;
         }
         sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
-                                          Optional.empty()).buildFlowAdd());
+                Optional.empty(), Optional.of(driverService)).buildFlowAdd());
 
         if (adaptiveFlowSampling) {
             // Add TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
@@ -298,7 +301,7 @@
             return;
         }
         sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(),
-                                          Optional.empty()).buildFlowDel());
+                                          Optional.empty(), Optional.of(driverService)).buildFlowDel());
 
         if (adaptiveFlowSampling) {
             // Remove TypedFlowEntry to deviceFlowEntries in NewAdaptiveFlowStatsCollector
@@ -334,7 +337,8 @@
                 continue;
             }
             FlowModBuilder builder =
-                    FlowModBuilder.builder(fbe.target(), sw.factory(), Optional.of(batch.id()));
+                    FlowModBuilder.builder(fbe.target(), sw.factory(),
+                            Optional.of(batch.id()), Optional.of(driverService));
             NewAdaptiveFlowStatsCollector collector = afsCollectors.get(dpid);
             switch (fbe.operator()) {
                 case ADD:
@@ -423,7 +427,7 @@
                 case FLOW_REMOVED:
                     OFFlowRemoved removed = (OFFlowRemoved) msg;
 
-                    FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
+                    FlowEntry fr = new FlowEntryBuilder(dpid, removed, driverService).build();
                     providerService.flowRemoved(fr);
 
                     if (adaptiveFlowSampling) {
@@ -474,7 +478,7 @@
                             InternalCacheEntry entry =
                                     pendingBatches.getIfPresent(msg.getXid());
                             if (entry != null) {
-                                entry.appendFailure(new FlowEntryBuilder(dpid, fm).build());
+                                entry.appendFailure(new FlowEntryBuilder(dpid, fm, driverService).build());
                             } else {
                                 log.error("No matching batch for this error: {}", error);
                             }
@@ -501,7 +505,7 @@
             DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
 
             List<FlowEntry> flowEntries = replies.getEntries().stream()
-                    .map(entry -> new FlowEntryBuilder(dpid, entry).build())
+                    .map(entry -> new FlowEntryBuilder(dpid, entry, driverService).build())
                     .collect(Collectors.toList());
 
             if (adaptiveFlowSampling)  {