CORD-413 Implement MPLS Termination in OFDPA3 pipeliner

Additionally, this patch includes
- Minor refactoring
- Skip method length checkstyle for FlowEntryBuilder::hasSetField

Change-Id: I7887f454f552a9e346c323524f359929deadf427
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java
index f036638..ec7cb15 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/ExtensionTreatmentType.java
@@ -49,6 +49,7 @@
         NICIRA_PUSH_NSH(38),
         NICIRA_POP_NSH(39),
         OFDPA_SET_VLAN_ID(64),
+        OFDPA_SET_MPLS_TYPE(65),
         NICIRA_TUN_GPE_NP(111),
         NICIRA_SET_NSH_SPI(113),
         NICIRA_SET_NSH_SI(114),
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3ExtensionTreatmentInterpreter.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3ExtensionTreatmentInterpreter.java
new file mode 100644
index 0000000..a07862e
--- /dev/null
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3ExtensionTreatmentInterpreter.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016-present 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.onosproject.net.behaviour.ExtensionTreatmentResolver;
+import org.onosproject.net.driver.AbstractHandlerBehaviour;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
+import org.onosproject.openflow.controller.ExtensionTreatmentInterpreter;
+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.OFOxmOfdpaMplsType;
+import org.projectfloodlight.openflow.types.U16;
+
+/**
+ * Interpreter for OFDPA3 OpenFlow treatment extensions.
+ */
+public class Ofdpa3ExtensionTreatmentInterpreter extends AbstractHandlerBehaviour
+        implements ExtensionTreatmentInterpreter, ExtensionTreatmentResolver {
+    @Override
+    public boolean supported(ExtensionTreatmentType extensionTreatmentType) {
+        if (extensionTreatmentType.equals(
+                ExtensionTreatmentType.ExtensionTreatmentTypes.OFDPA_SET_MPLS_TYPE.type())) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public OFAction mapInstruction(OFFactory factory, ExtensionTreatment extensionTreatment) {
+        ExtensionTreatmentType type = extensionTreatment.type();
+        if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.OFDPA_SET_MPLS_TYPE.type())) {
+            short mplsType = ((Ofdpa3SetMplsType) extensionTreatment).mplsType();
+            return factory.actions().setField(factory.oxms().ofdpaMplsType(
+                    U16.ofRaw(mplsType)));
+        }
+        throw new UnsupportedOperationException(
+                "Unexpected ExtensionTreatment: " + extensionTreatment.toString());
+    }
+
+    @Override
+    public ExtensionTreatment mapAction(OFAction action) throws UnsupportedOperationException {
+        if (action.getType().equals(OFActionType.SET_FIELD)) {
+            OFActionSetField setFieldAction = (OFActionSetField) action;
+            OFOxm<?> oxm = setFieldAction.getField();
+            switch (oxm.getMatchField().id) {
+                case OFDPA_MPLS_TYPE:
+                    OFOxmOfdpaMplsType mplsType = (OFOxmOfdpaMplsType) oxm;
+                    return new Ofdpa3SetMplsType(mplsType.getValue().getRaw());
+                default:
+                    throw new UnsupportedOperationException(
+                            "Driver does not support extension type " + oxm.getMatchField().id);
+            }
+        }
+        throw new UnsupportedOperationException(
+                "Unexpected OFAction: " + action.toString());
+    }
+
+    @Override
+    public ExtensionTreatment getExtensionInstruction(ExtensionTreatmentType type) {
+        if (type.equals(ExtensionTreatmentType.ExtensionTreatmentTypes.OFDPA_SET_MPLS_TYPE.type())) {
+            return new Ofdpa3SetMplsType();
+        }
+        throw new UnsupportedOperationException(
+                "Driver does not support extension type " + type.toString());
+    }
+}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3MplsType.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3MplsType.java
new file mode 100644
index 0000000..b4a9c56
--- /dev/null
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3MplsType.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present 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;
+
+/**
+ * OFDPA MPLS Type experimenter match fields.
+ */
+public enum Ofdpa3MplsType {
+    /**
+     * None.
+     */
+    NONE((short) 0),
+    /**
+     * Virtual Private Wire Service.
+     */
+    VPWS((short) 1),
+    /**
+     * Virtual Private LAN Service.
+     */
+    VPLS((short) 2),
+    /**
+     * MPLS-TP OAM (Operation, Administration and Maintenance).
+     */
+    OAM((short) 4),
+    /**
+     * L3 unicast.
+     */
+    L3_UNICAST ((short) 8),
+    /**
+     * L3 multicast.
+     */
+    L3_MULTICAST((short) 16),
+    /**
+     * L3 PHP (Penultimate Hop Popping).
+     */
+    L3_PHP((short) 32);
+
+    private short value;
+
+    Ofdpa3MplsType(short value) {
+        this.value = value;
+    }
+
+    /**
+     * Gets the value as an short.
+     *
+     * @return the value as an short
+     */
+    public short getValue() {
+        return this.value;
+    }
+}
\ No newline at end of file
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3SetMplsType.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3SetMplsType.java
new file mode 100644
index 0000000..a9b6e87
--- /dev/null
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/Ofdpa3SetMplsType.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016-present 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.util.KryoNamespace;
+import org.onosproject.net.flow.AbstractExtension;
+import org.onosproject.net.flow.instructions.ExtensionTreatment;
+import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * OFDPA set MPLS Type extension instruction.
+ */
+public class Ofdpa3SetMplsType extends AbstractExtension implements ExtensionTreatment {
+    private short mplsType;
+
+    private static final KryoNamespace APPKRYO = new KryoNamespace.Builder()
+            .register(Ofdpa3MplsType.class)
+            .build();
+
+    /**
+     * Constructs a new set MPLS type instruction.
+     */
+    protected Ofdpa3SetMplsType() {
+        mplsType = Ofdpa3MplsType.NONE.getValue();
+    }
+
+    /**
+     * Constructs a new set MPLS type instruction with given type.
+     *
+     * @param mplsType MPLS type in short
+     */
+    public Ofdpa3SetMplsType(short mplsType) {
+        checkNotNull(mplsType);
+        this.mplsType = mplsType;
+    }
+
+    /**
+     * Constructs a new set MPLS type instruction with given type.
+     *
+     * @param mplsType Ofdpa3MplsType
+     */
+    public Ofdpa3SetMplsType(Ofdpa3MplsType mplsType) {
+        checkNotNull(mplsType);
+        this.mplsType = mplsType.getValue();
+    }
+
+    /**
+     * Gets the MPLS type.
+     *
+     * @return MPLS type
+     */
+    public short mplsType() {
+        return mplsType;
+    }
+
+    @Override
+    public ExtensionTreatmentType type() {
+        return ExtensionTreatmentType.ExtensionTreatmentTypes.OFDPA_SET_MPLS_TYPE.type();
+    }
+
+    @Override
+    public void deserialize(byte[] data) {
+        mplsType = APPKRYO.deserialize(data);
+    }
+
+    @Override
+    public byte[] serialize() {
+        return APPKRYO.serialize(mplsType);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mplsType);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Ofdpa3SetMplsType) {
+            Ofdpa3SetMplsType that = (Ofdpa3SetMplsType) obj;
+            return Objects.equals(mplsType, that.mplsType);
+
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("mplsType", mplsType)
+                .toString();
+    }
+}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/Ofdpa3SetMplsTypeCodec.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/Ofdpa3SetMplsTypeCodec.java
new file mode 100644
index 0000000..9f3816a
--- /dev/null
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/Ofdpa3SetMplsTypeCodec.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016-present 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.codec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * JSON Codec for Ofdpa set mpls type class.
+ */
+public class Ofdpa3SetMplsTypeCodec extends JsonCodec<Ofdpa3SetMplsType>  {
+
+    private static final String MPLS_TYPE = "mplsType";
+
+    private static final String MISSING_MEMBER_MESSAGE = " member is required in Ofdpa3SetMplsType";
+    private static final String MISSING_MPLS_TYPE_MESSAGE = "mplsType cannot be null";
+
+    @Override
+    public ObjectNode encode(Ofdpa3SetMplsType mplsType, CodecContext context) {
+        checkNotNull(mplsType, MISSING_MPLS_TYPE_MESSAGE);
+        return context.mapper().createObjectNode()
+                .put(MPLS_TYPE, mplsType.mplsType());
+    }
+
+    @Override
+    public Ofdpa3SetMplsType decode(ObjectNode json, CodecContext context) {
+        if (json == null || !json.isObject()) {
+            return null;
+        }
+
+        // parse ofdpa mpls type
+        short mplsType = (short) nullIsIllegal(json.get(MPLS_TYPE),
+                MPLS_TYPE + MISSING_MEMBER_MESSAGE).asInt();
+        return new Ofdpa3SetMplsType(mplsType);
+    }
+}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaMatchVlanVidCodec.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaMatchVlanVidCodec.java
index bc0e876..65ed92b 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaMatchVlanVidCodec.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaMatchVlanVidCodec.java
@@ -30,15 +30,14 @@
 public class OfdpaMatchVlanVidCodec extends JsonCodec<OfdpaMatchVlanVid> {
 
     private static final String VLAN_ID = "vlanId";
-
     private static final String MISSING_MEMBER_MESSAGE = " member is required in OfdpaMatchVlanVid";
+    private static final String MISSING_VLAN_ID_MESSAGE = "Vlan ID cannot be null";
 
     @Override
     public ObjectNode encode(OfdpaMatchVlanVid vlanId, CodecContext context) {
-        checkNotNull(vlanId, "Vlan ID cannot be null");
-        ObjectNode root = context.mapper().createObjectNode()
+        checkNotNull(vlanId, MISSING_VLAN_ID_MESSAGE);
+        return context.mapper().createObjectNode()
                 .put(VLAN_ID, vlanId.vlanId().id());
-        return root;
     }
 
     @Override
diff --git a/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaSetVlanVidCodec.java b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaSetVlanVidCodec.java
index db5ee76..2009809 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaSetVlanVidCodec.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/extensions/codec/OfdpaSetVlanVidCodec.java
@@ -30,15 +30,14 @@
 public class OfdpaSetVlanVidCodec extends JsonCodec<OfdpaSetVlanVid> {
 
     private static final String VLAN_ID = "vlanId";
-
     private static final String MISSING_MEMBER_MESSAGE = " member is required in OfdpaSetVlanVid";
+    private static final String MISSING_VLAN_ID_MESSAGE = "Vlan ID cannot be null";
 
     @Override
     public ObjectNode encode(OfdpaSetVlanVid vlanId, CodecContext context) {
-        checkNotNull(vlanId, "Vlan ID cannot be null");
-        ObjectNode root = context.mapper().createObjectNode()
+        checkNotNull(vlanId, MISSING_VLAN_ID_MESSAGE);
+        return context.mapper().createObjectNode()
                 .put(VLAN_ID, vlanId.vlanId().id());
-        return root;
     }
 
     @Override
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOfdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOfdpa3Pipeline.java
index dbc3e39..9cf05d2 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOfdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CpqdOfdpa3Pipeline.java
@@ -59,6 +59,6 @@
 
     @Override
     protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
-        return processEthTypeSpecificInternal(fwd, true);
+        return processEthTypeSpecificInternal(fwd, true, ACL_TABLE);
     }
 }
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
index b9d8d89..a72eea1 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
@@ -37,6 +37,8 @@
 import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.driver.extensions.Ofdpa3MplsType;
+import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
 import org.onosproject.driver.extensions.OfdpaMatchVlanVid;
 import org.onosproject.driver.extensions.OfdpaSetVlanVid;
 import org.onosproject.net.DeviceId;
@@ -98,6 +100,7 @@
     protected static final int MULTICAST_ROUTING_TABLE = 40;
     protected static final int MPLS_TABLE_0 = 23;
     protected static final int MPLS_TABLE_1 = 24;
+    protected static final int MPLS_L3_TYPE = 27;
     protected static final int BRIDGING_TABLE = 50;
     protected static final int ACL_TABLE = 60;
     protected static final int MAC_LEARNING_TABLE = 254;
@@ -824,7 +827,7 @@
      * @return A collection of flow rules, or an empty set
      */
     protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
-        return processEthTypeSpecificInternal(fwd, false);
+        return processEthTypeSpecificInternal(fwd, false, ACL_TABLE);
     }
 
     /**
@@ -840,7 +843,8 @@
      * @return A collection of flow rules, or an empty set
      */
     protected Collection<FlowRule> processEthTypeSpecificInternal(ForwardingObjective fwd,
-                                                                  boolean allowDefaultRoute) {
+                                                                  boolean allowDefaultRoute,
+                                                                  int mplsNextTable) {
         TrafficSelector selector = fwd.selector();
         EthTypeCriterion ethType =
                 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
@@ -970,7 +974,17 @@
                 return Collections.emptySet();
             }
         }
-        tb.transition(ACL_TABLE);
+
+        if (forTableId == MPLS_TABLE_1) {
+            if (mplsNextTable == MPLS_L3_TYPE) {
+                Ofdpa3SetMplsType setMplsType = new Ofdpa3SetMplsType(Ofdpa3MplsType.L3_PHP);
+                tb.extension(setMplsType, deviceId);
+            }
+            tb.transition(mplsNextTable);
+        } else {
+            tb.transition(ACL_TABLE);
+        }
+
         FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
                 .fromApp(fwd.appId())
                 .withPriority(fwd.priority())
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
index 68c42e0..4f9740c 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
@@ -68,6 +68,6 @@
 
     @Override
     protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
-        return processEthTypeSpecificInternal(fwd, true);
+        return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE);
     }
 }
diff --git a/drivers/default/src/main/resources/onos-drivers.xml b/drivers/default/src/main/resources/onos-drivers.xml
index 6a69dda..b51f087 100644
--- a/drivers/default/src/main/resources/onos-drivers.xml
+++ b/drivers/default/src/main/resources/onos-drivers.xml
@@ -87,6 +87,10 @@
             manufacturer="Broadcom Corp." hwVersion="OF-DPA 3.0" swVersion="OF-DPA 3.0">
         <behaviour api="org.onosproject.net.behaviour.Pipeliner"
                    impl="org.onosproject.driver.pipeline.Ofdpa3Pipeline"/>
+        <behaviour api="org.onosproject.openflow.controller.ExtensionTreatmentInterpreter"
+                   impl="org.onosproject.driver.extensions.Ofdpa3ExtensionTreatmentInterpreter" />
+        <behaviour api="org.onosproject.net.behaviour.ExtensionTreatmentResolver"
+                   impl="org.onosproject.driver.extensions.Ofdpa3ExtensionTreatmentInterpreter" />
         <behaviour api="org.onosproject.openflow.controller.ExtensionSelectorInterpreter"
                    impl="org.onosproject.driver.extensions.OfdpaExtensionSelectorInterpreter" />
         <behaviour api="org.onosproject.net.behaviour.ExtensionSelectorResolver"
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
index e40990e..d2ed633 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/util/FlowEntryBuilder.java
@@ -427,7 +427,7 @@
         return configureTreatmentBuilder(actions, builder, driverHandler, deviceId);
     }
 
-
+    // CHECKSTYLE IGNORE MethodLength FOR NEXT 1 LINES
     private static void handleSetField(TrafficTreatment.Builder builder,
                                        OFActionSetField action,
                                        DriverHandler driverHandler,
@@ -577,6 +577,16 @@
             OFOxm<IPv4Address> arpspa = (OFOxm<IPv4Address>) oxm;
             builder.setArpSpa(Ip4Address.valueOf(arpspa.getValue().getInt()));
             break;
+        case OFDPA_MPLS_TYPE:
+            if (treatmentInterpreter != null) {
+                try {
+                    builder.extension(treatmentInterpreter.mapAction(action), deviceId);
+                    break;
+                } catch (UnsupportedOperationException e) {
+                    log.warn("Unsupported action extension");
+                }
+            }
+            break;
         case ARP_THA:
         case ARP_TPA:
         case BSN_EGR_PORT_GROUP_ID: