[ONOS-7242] Support MPLS by fabric.p4 pipeliner

Change-Id: I56a8f266e6d0afe5ad6737b8d0e399758fb75378
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
index a71cfa4..63badda 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricConstants.java
@@ -126,8 +126,8 @@
     public static final PiActionId ACT_PUSH_INTERNAL_VLAN_ID = PiActionId.of("filtering.push_internal_vlan");
     public static final PiActionId ACT_SET_VLAN_OUTPUT_ID = PiActionId.of("next.set_vlan_output");
     public static final PiActionId ACT_NOACTION_ID = PiActionId.of("NoAction");
-    public static final PiActionId ACT_PUSH_MPLS_AND_NEXT_V6_ID = PiActionId.of("forwarding.push_mpls_and_next_v6");
-    public static final PiActionId ACT_PUSH_MPLS_AND_NEXT_V4_ID = PiActionId.of("forwarding.push_mpls_and_next_v4");
+    public static final PiActionId ACT_MPLS_ROUTING_V4_ID = PiActionId.of("next.mpls_routing_v4");
+    public static final PiActionId ACT_MPLS_ROUTING_V6_ID = PiActionId.of("next.mpls_routing_v6");
     public static final PiActionId ACT_SET_FORWARDING_TYPE_ID = PiActionId.of("filtering.set_forwarding_type");
     public static final PiActionId ACT_POP_MPLS_AND_NEXT_ID = PiActionId.of("forwarding.pop_mpls_and_next");
     public static final PiActionId ACT_SET_NEXT_TYPE_ID = PiActionId.of("next.set_next_type");
@@ -150,11 +150,11 @@
     public static final PiActionParamId ACT_PRM_NEXT_ID_ID = PiActionParamId.of("next_id");
 
     // Action Profile IDs
-    public static final PiActionProfileId ACT_PRF_ECMP_SELECTOR_ID = PiActionProfileId.of("ecmp_selector");
+    public static final PiActionProfileId ACT_PRF_ECMP_SELECTOR_ID = PiActionProfileId.of("next.ecmp_selector");
 
     // Packet Metadata IDs
     public static final PiControlMetadataId CTRL_META_EGRESS_PORT_ID = PiControlMetadataId.of("egress_port");
     public static final PiControlMetadataId CTRL_META_INGRESS_PORT_ID = PiControlMetadataId.of("ingress_port");
 
     public static final int PORT_BITWIDTH = 9;
-}
\ No newline at end of file
+}
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
index a2e4974..234e541 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/FabricTreatmentInterpreter.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableList;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.net.PortNumber;
@@ -27,24 +28,26 @@
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
 import org.onosproject.net.pi.model.PiActionId;
 import org.onosproject.net.pi.model.PiPipelineInterpreter.PiInterpreterException;
 import org.onosproject.net.pi.runtime.PiAction;
 import org.onosproject.net.pi.runtime.PiActionParam;
+import org.slf4j.Logger;
 
 import java.util.List;
 
 import static java.lang.String.format;
 import static org.onosproject.net.flow.instructions.Instruction.Type.L2MODIFICATION;
 import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_DST;
-import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.ETH_SRC;
 import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_ID;
 import static org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType.VLAN_PUSH;
+import static org.slf4j.LoggerFactory.getLogger;
 
 
 final class FabricTreatmentInterpreter {
+    private static final Logger log = getLogger(FabricTreatmentInterpreter.class);
     private static final String INVALID_TREATMENT = "Invalid treatment for %s block: %s";
 
     // Hide default constructor
@@ -149,11 +152,15 @@
     /*
      * In Next block, we need to implement these actions:
      * output
-     * output_ecmp
      * set_vlan_output
+     * l3_routing
+     * mpls_routing_v4
      *
      * Unsupported, using PiAction directly:
-     * set_mcast_group
+     * set_next_type
+     *
+     * Unsupported, need to find a way to implement it
+     * mpls_routing_v6
      */
 
     public static PiAction mapNextTreatment(TrafficTreatment treatment)
@@ -163,29 +170,36 @@
         ModEtherInstruction modEthDstInst = null;
         ModEtherInstruction modEthSrcInst = null;
         ModVlanIdInstruction modVlanIdInst = null;
+        ModMplsLabelInstruction modMplsInst = null;
 
-        // TODO: use matrix to store the combination of instruction
+        // TODO: add NextFunctionType (like ForwardingFunctionType)
         for (Instruction inst : insts) {
             switch (inst.type()) {
                 case L2MODIFICATION:
                     L2ModificationInstruction l2Inst = (L2ModificationInstruction) inst;
-
-                    if (l2Inst.subtype() == ETH_SRC) {
-                        modEthSrcInst = (ModEtherInstruction) l2Inst;
-                    }
-
-                    if (l2Inst.subtype() == ETH_DST) {
-                        modEthDstInst = (ModEtherInstruction) l2Inst;
-                    }
-
-                    if (l2Inst.subtype() == VLAN_ID) {
-                        modVlanIdInst = (ModVlanIdInstruction) l2Inst;
+                    switch (l2Inst.subtype()) {
+                        case ETH_SRC:
+                            modEthSrcInst = (ModEtherInstruction) l2Inst;
+                            break;
+                        case ETH_DST:
+                            modEthDstInst = (ModEtherInstruction) l2Inst;
+                            break;
+                        case VLAN_ID:
+                            modVlanIdInst = (ModVlanIdInstruction) l2Inst;
+                            break;
+                        case MPLS_LABEL:
+                            modMplsInst = (ModMplsLabelInstruction) l2Inst;
+                            break;
+                        default:
+                            log.warn("Unsupported l2 instruction sub type: {}", l2Inst.subtype());
+                            break;
                     }
                     break;
                 case OUTPUT:
                     outInst = (OutputInstruction) inst;
                     break;
                 default:
+                    log.warn("Unsupported instruction sub type: {}", inst.type());
                     break;
             }
         }
@@ -217,13 +231,36 @@
         }
 
         if (modEthDstInst != null && modEthSrcInst != null) {
-            // output and rewrite src/dst mac
             MacAddress srcMac = modEthSrcInst.mac();
             MacAddress dstMac = modEthDstInst.mac();
             PiActionParam srcMacParam = new PiActionParam(FabricConstants.ACT_PRM_SMAC_ID,
                                                           ImmutableByteSequence.copyFrom(srcMac.toBytes()));
             PiActionParam dstMacParam = new PiActionParam(FabricConstants.ACT_PRM_DMAC_ID,
                                                           ImmutableByteSequence.copyFrom(dstMac.toBytes()));
+
+            if (modMplsInst != null) {
+                // MPLS routing
+                MplsLabel mplsLabel = modMplsInst.label();
+                try {
+                    ImmutableByteSequence mplsValue =
+                            ImmutableByteSequence.fit(ImmutableByteSequence.copyFrom(mplsLabel.toInt()), 20);
+                    PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsValue);
+                    return PiAction.builder()
+                            // FIXME: fins a way to determine v4 or v6
+                            .withId(FabricConstants.ACT_MPLS_ROUTING_V4_ID)
+                            .withParameters(ImmutableList.of(portNumParam,
+                                                             srcMacParam,
+                                                             dstMacParam,
+                                                             mplsParam))
+                            .build();
+                } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
+                    // Basically this won't happened because we already limited
+                    // size of mpls value to 20 bits (0xFFFFF)
+                    throw new PiInterpreterException(format(INVALID_TREATMENT, "next", treatment));
+                }
+            }
+
+            // L3 routing
             return PiAction.builder()
                     .withId(FabricConstants.ACT_L3_ROUTING_ID)
                     .withParameters(ImmutableList.of(portNumParam,
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
index dfd8d85..bceefdd 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipeliner.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.IPCriterion;
+import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.VlanIdCriterion;
 import org.onosproject.net.flowobjective.ForwardingObjective;
 import org.onosproject.net.flowobjective.ObjectiveError;
@@ -97,6 +98,7 @@
         VlanIdCriterion vlanIdCriterion = null;
         EthCriterion ethDstCriterion = null;
         IPCriterion ipDstCriterion = null;
+        MplsCriterion mplsCriterion = null;
 
         for (Criterion criterion : criteria) {
             switch (criterion.type()) {
@@ -109,6 +111,13 @@
                 case IPV4_DST:
                     ipDstCriterion = (IPCriterion) criterion;
                     break;
+                case MPLS_LABEL:
+                    mplsCriterion = (MplsCriterion) criterion;
+                    break;
+                case ETH_TYPE:
+                case MPLS_BOS:
+                    // do nothing
+                    break;
                 default:
                     log.warn("Unsupported criterion {}", criterion);
                     break;
@@ -127,10 +136,12 @@
             case IPV4_UNICAST:
                 processIpv4UnicastRule(ipDstCriterion, fwd, resultBuilder);
                 break;
+            case MPLS:
+                processMplsRule(mplsCriterion, fwd, resultBuilder);
+                break;
             case IPV4_MULTICAST:
             case IPV6_UNICAST:
             case IPV6_MULTICAST:
-            case MPLS:
             default:
                 log.warn("Unsupported forwarding function type {}", criteria);
                 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
@@ -228,6 +239,41 @@
         resultBuilder.addFlowRule(flowRule);
     }
 
+    private void processMplsRule(MplsCriterion mplsCriterion, ForwardingObjective fwd,
+                                 PipelinerTranslationResult.Builder resultBuilder) {
+        checkNotNull(mplsCriterion, "Mpls criterion should not be null");
+        if (fwd.nextId() == null) {
+            log.warn("Forwarding objective for MPLS should contains next id");
+            resultBuilder.setError(ObjectiveError.BADPARAMS);
+            return;
+        }
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .add(mplsCriterion)
+                .build();
+
+        PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
+                                                      ImmutableByteSequence.copyFrom(fwd.nextId().byteValue()));
+        PiAction nextIdAction = PiAction.builder()
+                .withId(FabricConstants.ACT_POP_MPLS_AND_NEXT_ID)
+                .withParameter(nextIdParam)
+                .build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .piTableAction(nextIdAction)
+                .build();
+
+        FlowRule flowRule = DefaultFlowRule.builder()
+                .withSelector(selector)
+                .withTreatment(treatment)
+                .fromApp(fwd.appId())
+                .withPriority(fwd.priority())
+                .makePermanent()
+                .forDevice(deviceId)
+                .forTable(FabricConstants.TBL_MPLS_ID)
+                .build();
+
+        resultBuilder.addFlowRule(flowRule);
+    }
+
     private static TrafficTreatment buildSetNextIdTreatment(Integer nextId) {
         PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
                                                       ImmutableByteSequence.copyFrom(nextId.byteValue()));
@@ -240,5 +286,4 @@
                 .piTableAction(nextIdAction)
                 .build();
     }
-
 }
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
index 7487fbe..324a4f5 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipeliner.java
@@ -17,12 +17,10 @@
 package org.onosproject.pipelines.fabric.pipeliner;
 
 import com.google.common.collect.ImmutableMap;
-import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.flow.criteria.PiCriterion;
@@ -30,14 +28,29 @@
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
 import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
 import org.onosproject.net.pi.runtime.PiActionParam;
-import org.onosproject.pipelines.fabric.FabricConstants;
+import org.onosproject.net.pi.runtime.PiGroupKey;
 import org.slf4j.Logger;
 
+import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
-import static org.onosproject.pipelines.fabric.pipeliner.FabricPipeliner.fail;
+import static org.onlab.util.ImmutableByteSequence.copyFrom;
+import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRF_ECMP_SELECTOR_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRM_NEXT_TYPE_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.ACT_SET_NEXT_TYPE_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.TBL_HASHED_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.TBL_NEXT_ID_MAPPING_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.TBL_SIMPLE_ID;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -47,15 +60,15 @@
     private static final Logger log = getLogger(FabricNextPipeliner.class);
 
     // Next types
-    private static final byte TBL_SIMPLE = 0;
-    private static final byte TBL_HASHED = 1;
-    private static final byte TBL_BROADCAST = 2;
-    private static final byte PUNT = 3;
+    private static final byte NXT_TYPE_SIMPLE = 0;
+    private static final byte NXT_TYPE_HASHED = 1;
+    private static final byte NXT_TYPE_BROADCAST = 2;
+    private static final byte NXT_TYPE_PUNT = 3;
     private static final Map<NextObjective.Type, Byte> NEXT_TYPE_MAP =
             ImmutableMap.<NextObjective.Type, Byte>builder()
-                    .put(NextObjective.Type.SIMPLE, TBL_SIMPLE)
-                    .put(NextObjective.Type.HASHED, TBL_HASHED)
-                    .put(NextObjective.Type.BROADCAST, TBL_BROADCAST)
+                    .put(NextObjective.Type.SIMPLE, NXT_TYPE_SIMPLE)
+                    .put(NextObjective.Type.HASHED, NXT_TYPE_HASHED)
+                    .put(NextObjective.Type.BROADCAST, NXT_TYPE_BROADCAST)
                     .build();
 
     protected DeviceId deviceId;
@@ -66,11 +79,14 @@
 
     public PipelinerTranslationResult next(NextObjective nextObjective) {
         PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
-        FlowRule nextIdMappingRule = processNextIdMapping(nextObjective);
-        FlowRule nextRule = null;
+        processNextIdMapping(nextObjective, resultBuilder);
+
         switch (nextObjective.type()) {
             case SIMPLE:
-                nextRule = processSimpleNext(nextObjective);
+                processSimpleNext(nextObjective, resultBuilder);
+                break;
+            case HASHED:
+                processHashedNext(nextObjective, resultBuilder);
                 break;
             default:
                 log.warn("Unsupported next type {}", nextObjective);
@@ -78,35 +94,33 @@
                 break;
         }
 
-        if (nextIdMappingRule != null && nextRule != null) {
-            resultBuilder.addFlowRule(nextIdMappingRule);
-            resultBuilder.addFlowRule(nextRule);
-        }
-
         return resultBuilder.build();
     }
 
-    private FlowRule processNextIdMapping(NextObjective next) {
+    private void processNextIdMapping(NextObjective next,
+                                      PipelinerTranslationResult.Builder resultBuilder) {
         // program the next id mapping table
         TrafficSelector nextIdSelector = buildNextIdSelector(next.id());
         TrafficTreatment setNextTypeTreatment = buildSetNextTypeTreatment(next.type());
 
-        return DefaultFlowRule.builder()
-                .withSelector(nextIdSelector)
-                .withTreatment(setNextTypeTreatment)
-                .forDevice(deviceId)
-                .forTable(FabricConstants.TBL_NEXT_ID_MAPPING_ID)
-                .makePermanent()
-                .withPriority(next.priority())
-                .fromApp(next.appId())
-                .build();
+        resultBuilder.addFlowRule(DefaultFlowRule.builder()
+                                          .withSelector(nextIdSelector)
+                                          .withTreatment(setNextTypeTreatment)
+                                          .forDevice(deviceId)
+                                          .forTable(TBL_NEXT_ID_MAPPING_ID)
+                                          .makePermanent()
+                                          .withPriority(next.priority())
+                                          .fromApp(next.appId())
+                                          .build());
     }
 
-    private FlowRule processSimpleNext(NextObjective next) {
+    private void processSimpleNext(NextObjective next,
+                                   PipelinerTranslationResult.Builder resultBuilder) {
+
         if (next.next().size() > 1) {
             log.warn("Only one treatment in simple next objective");
-            fail(next, ObjectiveError.BADPARAMS);
-            return null;
+            resultBuilder.setError(ObjectiveError.BADPARAMS);
+            return;
         }
 
         TrafficSelector selector = buildNextIdSelector(next.id());
@@ -120,36 +134,79 @@
 
         if (outputInst == null) {
             log.warn("At least one output instruction in simple next objective");
-            fail(next, ObjectiveError.BADPARAMS);
-            return null;
+            resultBuilder.setError(ObjectiveError.BADPARAMS);
+            return;
         }
-        return DefaultFlowRule.builder()
-                .withSelector(selector)
-                .withTreatment(treatment)
-                .forTable(FabricConstants.TBL_SIMPLE_ID)
-                .makePermanent()
-                .withPriority(next.priority())
-                .forDevice(deviceId)
-                .fromApp(next.appId())
+        resultBuilder.addFlowRule(DefaultFlowRule.builder()
+                                          .withSelector(selector)
+                                          .withTreatment(treatment)
+                                          .forTable(TBL_SIMPLE_ID)
+                                          .makePermanent()
+                                          .withPriority(next.priority())
+                                          .forDevice(deviceId)
+                                          .fromApp(next.appId())
+                                          .build());
+    }
+
+    private void processHashedNext(NextObjective nextObjective, PipelinerTranslationResult.Builder resultBuilder) {
+        // create hash groups
+        int groupId = nextObjective.id();
+        List<GroupBucket> bucketList = nextObjective.next().stream()
+                .map(DefaultGroupBucket::createSelectGroupBucket)
+                .collect(Collectors.toList());
+
+        if (bucketList.size() != nextObjective.next().size()) {
+            // some action not converted
+            // set error
+            log.warn("Expected bucket size {}, got {}", nextObjective.next().size(), bucketList.size());
+            resultBuilder.setError(ObjectiveError.BADPARAMS);
+            return;
+        }
+
+        GroupBuckets buckets = new GroupBuckets(bucketList);
+        PiGroupKey groupKey = new PiGroupKey(TBL_HASHED_ID,
+                                             ACT_PRF_ECMP_SELECTOR_ID,
+                                             groupId);
+
+        resultBuilder.addGroup(new DefaultGroupDescription(deviceId,
+                                                           GroupDescription.Type.SELECT,
+                                                           buckets,
+                                                           groupKey,
+                                                           groupId,
+                                                           nextObjective.appId()));
+
+        // flow
+        TrafficSelector selector = buildNextIdSelector(nextObjective.id());
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .piTableAction(PiActionGroupId.of(nextObjective.id()))
                 .build();
+
+        resultBuilder.addFlowRule(DefaultFlowRule.builder()
+                                          .withSelector(selector)
+                                          .withTreatment(treatment)
+                                          .forTable(TBL_HASHED_ID)
+                                          .makePermanent()
+                                          .withPriority(nextObjective.priority())
+                                          .forDevice(deviceId)
+                                          .fromApp(nextObjective.appId())
+                                          .build());
     }
 
     private TrafficSelector buildNextIdSelector(int nextId) {
-        byte[] nextIdVal = new byte[]{(byte) nextId};
-        PiCriterion nextIdCrriterion = PiCriterion.builder()
-                .matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, nextIdVal)
+        PiCriterion nextIdCriterion = PiCriterion.builder()
+                .matchExact(HF_FABRIC_METADATA_NEXT_ID_ID, nextId)
                 .build();
         return DefaultTrafficSelector.builder()
-                .matchPi(nextIdCrriterion)
+                .matchPi(nextIdCriterion)
                 .build();
     }
 
     private TrafficTreatment buildSetNextTypeTreatment(NextObjective.Type nextType) {
-        byte nextTypeVal = NEXT_TYPE_MAP.getOrDefault(nextType, PUNT);
-        PiActionParam nextTypeParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_TYPE_ID,
-                                                        ImmutableByteSequence.copyFrom(nextTypeVal));
+        byte nextTypeVal = NEXT_TYPE_MAP.getOrDefault(nextType, NXT_TYPE_PUNT);
+        PiActionParam nextTypeParam = new PiActionParam(ACT_PRM_NEXT_TYPE_ID,
+                                                        copyFrom(nextTypeVal));
         PiAction nextTypeAction = PiAction.builder()
-                .withId(FabricConstants.ACT_SET_NEXT_TYPE_ID)
+                .withId(ACT_SET_NEXT_TYPE_ID)
                 .withParameter(nextTypeParam)
                 .build();
         return DefaultTrafficTreatment.builder()
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
index e2d8048..3fceb5d 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipeliner.java
@@ -17,6 +17,7 @@
 package org.onosproject.pipelines.fabric.pipeliner;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.net.DeviceId;
@@ -37,6 +38,7 @@
 import org.onosproject.net.flowobjective.NextObjective;
 import org.onosproject.net.flowobjective.Objective;
 import org.onosproject.net.flowobjective.ObjectiveError;
+import org.onosproject.net.group.Group;
 import org.onosproject.net.group.GroupDescription;
 import org.onosproject.net.group.GroupEvent;
 import org.onosproject.net.group.GroupListener;
@@ -46,12 +48,14 @@
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -67,7 +71,14 @@
             .build("FabricPipeliner");
 
     // TODO: make this configurable
-    private static final long DEFAULT_INSTALLATION_TIME_OUT = 10;
+    private static final long DEFAULT_INSTALLATION_TIME_OUT = 40;
+    private static final Map<Objective.Operation, GroupEvent.Type> OBJ_OP_TO_GRP_EVENT_TYPE =
+            ImmutableMap.<Objective.Operation, GroupEvent.Type>builder()
+                    .put(Objective.Operation.ADD, GroupEvent.Type.GROUP_ADDED)
+                    .put(Objective.Operation.ADD_TO_EXISTING, GroupEvent.Type.GROUP_UPDATED)
+                    .put(Objective.Operation.REMOVE, GroupEvent.Type.GROUP_REMOVED)
+                    .put(Objective.Operation.REMOVE_FROM_EXISTING, GroupEvent.Type.GROUP_UPDATED)
+            .build();
 
     protected DeviceId deviceId;
     protected FlowRuleService flowRuleService;
@@ -132,6 +143,13 @@
             return;
         }
 
+        if (nextObjective.op() == Objective.Operation.VERIFY) {
+            // TODO: support VERIFY operation
+            log.debug("Currently we don't support VERIFY operation, return success directly to the context");
+            success(nextObjective);
+            return;
+        }
+
         applyTranslationResult(nextObjective, result, success -> {
             if (!success) {
                 fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
@@ -161,7 +179,13 @@
 
     @Override
     public List<String> getNextMappings(NextGroup nextGroup) {
-        return null;
+        FabricNextGroup fabricNextGroup = KRYO.deserialize(nextGroup.data());
+        NextObjective.Type type = fabricNextGroup.type();
+        Collection<PortNumber> outputPorts = fabricNextGroup.outputPorts();
+
+        return outputPorts.stream()
+                .map(port -> String.format("%s -> %s", type, port))
+                .collect(Collectors.toList());
     }
 
     private void applyTranslationResult(Objective objective,
@@ -204,7 +228,7 @@
         try {
             return flowInstallFuture.get(DEFAULT_INSTALLATION_TIME_OUT, TimeUnit.SECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
-            log.warn("Got exception while installing groups: {}", e);
+            log.warn("Got exception while installing flows:{}", e.getMessage());
             return false;
         }
     }
@@ -213,12 +237,18 @@
         if (groups.isEmpty()) {
             return true;
         }
+        Collection<Integer> groupIds = groups.stream()
+                .map(GroupDescription::givenGroupId)
+                .collect(Collectors.toSet());
+
         int numGroupsToBeInstalled = groups.size();
         CompletableFuture<Boolean> groupInstallFuture = new CompletableFuture<>();
         AtomicInteger numGroupsInstalled = new AtomicInteger(0);
+
         GroupListener listener = new GroupListener() {
             @Override
             public void event(GroupEvent event) {
+                log.debug("Receive group event for group {}", event.subject());
                 int currentNumGroupInstalled = numGroupsInstalled.incrementAndGet();
                 if (currentNumGroupInstalled == numGroupsToBeInstalled) {
                     // install completed
@@ -228,9 +258,11 @@
             }
             @Override
             public boolean isRelevant(GroupEvent event) {
-                return groups.contains(event.subject());
+                Group group = event.subject();
+                return groupIds.contains(group.givenGroupId());
             }
         };
+
         groupService.addListener(listener);
 
         switch (objective.op()) {
@@ -240,6 +272,22 @@
             case REMOVE:
                 groups.forEach(group -> groupService.removeGroup(deviceId, group.appCookie(), objective.appId()));
                 break;
+            case ADD_TO_EXISTING:
+                groups.forEach(group -> {
+                    groupService.addBucketsToGroup(deviceId, group.appCookie(),
+                                                   group.buckets(),
+                                                   group.appCookie(),
+                                                   group.appId());
+                });
+                break;
+            case REMOVE_FROM_EXISTING:
+                groups.forEach(group -> {
+                    groupService.removeBucketsFromGroup(deviceId, group.appCookie(),
+                                                        group.buckets(),
+                                                        group.appCookie(),
+                                                        group.appId());
+                });
+                break;
             default:
                 log.warn("Unsupported objective operation {}", objective.op());
                 groupService.removeListener(listener);
@@ -247,7 +295,8 @@
         try {
             return groupInstallFuture.get(DEFAULT_INSTALLATION_TIME_OUT, TimeUnit.SECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
-            log.warn("Got exception while installing groups: {}", e);
+            groupService.removeListener(listener);
+            log.warn("Got exception while installing groups: {}", e.getMessage());
             return false;
         }
     }
@@ -300,4 +349,5 @@
             return KRYO.serialize(this);
         }
     }
+
 }
diff --git a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
index 8d8de54..3cf015d 100644
--- a/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
+++ b/pipelines/fabric/src/main/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionType.java
@@ -65,11 +65,16 @@
     IPV6_MULTICAST,
 
     /**
-     * MPLS, with EtherType, MPLS label and MPLS BOS criterion.
+     * MPLS, with EtherType, MPLS label and MPLS BOS(true) criterion.
      */
     MPLS,
 
     /**
+     * Pseudo-wire, with EtherType, MPLS label and MPLS BOS(false) criterion.
+     */
+    PW,
+
+    /**
      * Unsupported type.
      */
     UNSUPPORTED;
diff --git a/pipelines/fabric/src/main/resources/include/control/forwarding.p4 b/pipelines/fabric/src/main/resources/include/control/forwarding.p4
index fb5f231..62aeac7 100644
--- a/pipelines/fabric/src/main/resources/include/control/forwarding.p4
+++ b/pipelines/fabric/src/main/resources/include/control/forwarding.p4
@@ -49,34 +49,11 @@
         fabric_metadata.next_id = next_id;
     }
 
-    action push_mpls (mpls_label_t label, bit<3> tc) {
-        //Suppose that the maximum number of label is one.
-        hdr.mpls.setValid();
-        hdr.ethernet.ether_type = ETHERTYPE_MPLS;
-        hdr.mpls.label = label;
-        hdr.mpls.tc = tc;
-        hdr.mpls.bos = 1;
-        hdr.mpls.ttl = 64;
-    }
-
-    action push_mpls_and_next_v4 (mpls_label_t label,
-                                  next_id_t next_id) {
-        set_next_id(next_id);
-        push_mpls(label, hdr.ipv4.diffserv[7:5]);
-    }
-
-    action push_mpls_and_next_v6 (mpls_label_t label, next_id_t next_id) {
-        set_next_id(next_id);
-        push_mpls(label, hdr.ipv6.traffic_class[7:5]);
-    }
-
     action duplicate_to_controller() {
         fabric_metadata.next_type = NEXT_TYPE_PUNT;
         standard_metadata.egress_spec = CPU_PORT;
     }
 
-
-
     table bridging {
         key = {
             hdr.vlan_tag.vlan_id: exact;
@@ -107,7 +84,6 @@
 
         actions = {
             set_next_id;
-            push_mpls_and_next_v4;
         }
         counters = unicast_v4_counter;
     }
@@ -131,7 +107,6 @@
 
         actions = {
             set_next_id;
-            push_mpls_and_next_v6;
         }
         counters = unicast_v6_counter;
     }
diff --git a/pipelines/fabric/src/main/resources/include/control/next.p4 b/pipelines/fabric/src/main/resources/include/control/next.p4
index 5ab18fa..2b3019c 100644
--- a/pipelines/fabric/src/main/resources/include/control/next.p4
+++ b/pipelines/fabric/src/main/resources/include/control/next.p4
@@ -73,6 +73,28 @@
         rewrite_smac(smac);
     }
 
+    action push_mpls (mpls_label_t label, bit<3> tc) {
+        //Suppose that the maximum number of label is one.
+        hdr.mpls.setValid();
+        hdr.ethernet.ether_type = ETHERTYPE_MPLS;
+        hdr.mpls.label = label;
+        hdr.mpls.tc = tc;
+        hdr.mpls.bos = 1; // BOS = TRUE
+        hdr.mpls.ttl = DEFAULT_MPLS_TTL;
+    }
+
+    action mpls_routing_v4 (port_num_t port_num, mac_addr_t smac, mac_addr_t dmac,
+                            mpls_label_t label) {
+        l3_routing(port_num, smac, dmac);
+        push_mpls(label, hdr.ipv4.diffserv[7:5]);
+    }
+
+    action mpls_routing_v6 (port_num_t port_num, mac_addr_t smac, mac_addr_t dmac,
+                            mpls_label_t label) {
+        l3_routing(port_num, smac, dmac);
+        push_mpls(label, hdr.ipv6.traffic_class[7:5]);
+    }
+
     table next_id_mapping {
         key = {
             fabric_metadata.next_id: exact;
@@ -112,6 +134,8 @@
 
         actions = {
             l3_routing;
+            mpls_routing_v4;
+            mpls_routing_v6;
         }
 
         implementation = ecmp_selector;
diff --git a/pipelines/fabric/src/main/resources/include/define.p4 b/pipelines/fabric/src/main/resources/include/define.p4
index 9ba84e9..1db958f 100644
--- a/pipelines/fabric/src/main/resources/include/define.p4
+++ b/pipelines/fabric/src/main/resources/include/define.p4
@@ -20,7 +20,7 @@
 #define MAX_PORTS 511
 
 typedef bit<3>  fwd_type_t;
-typedef bit<32>  next_id_t;
+typedef bit<32> next_id_t;
 typedef bit<3>  next_type_t;
 typedef bit<20> mpls_label_t;
 typedef bit<9>  port_num_t;
@@ -60,4 +60,6 @@
 const next_type_t NEXT_TYPE_BROADCAST = 2;
 const next_type_t NEXT_TYPE_PUNT = 3;
 
+const bit<8> DEFAULT_MPLS_TTL = 64;
+
 #endif
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
index 151fca7..a683e8b 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.json
@@ -2272,364 +2272,8 @@
       ]
     },
     {
-      "name" : "forwarding.push_mpls_and_next_v4",
-      "id" : 24,
-      "runtime_data" : [
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        },
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 39,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 54,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 34,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 56,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "expression",
-              "value" : {
-                "type" : "expression",
-                "value" : {
-                  "op" : "&",
-                  "left" : {
-                    "type" : "expression",
-                    "value" : {
-                      "op" : "&",
-                      "left" : {
-                        "type" : "expression",
-                        "value" : {
-                          "op" : ">>",
-                          "left" : {
-                            "type" : "field",
-                            "value" : ["ipv4", "diffserv"]
-                          },
-                          "right" : {
-                            "type" : "hexstr",
-                            "value" : "0x5"
-                          }
-                        }
-                      },
-                      "right" : {
-                        "type" : "hexstr",
-                        "value" : "0xff"
-                      }
-                    }
-                  },
-                  "right" : {
-                    "type" : "hexstr",
-                    "value" : "0x07"
-                  }
-                }
-              }
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 57,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 58,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 59,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.ttl = 64"
-          }
-        }
-      ]
-    },
-    {
-      "name" : "forwarding.push_mpls_and_next_v6",
-      "id" : 25,
-      "runtime_data" : [
-        {
-          "name" : "label",
-          "bitwidth" : 20
-        },
-        {
-          "name" : "next_id",
-          "bitwidth" : 32
-        }
-      ],
-      "primitives" : [
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["scalars", "fabric_metadata_t.next_id"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 1
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 39,
-            "column" : 8,
-            "source_fragment" : "fabric_metadata.next_id = next_id; ..."
-          }
-        },
-        {
-          "op" : "add_header",
-          "parameters" : [
-            {
-              "type" : "header",
-              "value" : "mpls"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 54,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.setValid()"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["ethernet", "ether_type"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x8847"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/../define.p4",
-            "line" : 34,
-            "column" : 31,
-            "source_fragment" : "0x8847; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "label"]
-            },
-            {
-              "type" : "runtime_data",
-              "value" : 0
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 56,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.label = label; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "tc"]
-            },
-            {
-              "type" : "expression",
-              "value" : {
-                "type" : "expression",
-                "value" : {
-                  "op" : "&",
-                  "left" : {
-                    "type" : "expression",
-                    "value" : {
-                      "op" : "&",
-                      "left" : {
-                        "type" : "expression",
-                        "value" : {
-                          "op" : ">>",
-                          "left" : {
-                            "type" : "field",
-                            "value" : ["ipv6", "traffic_class"]
-                          },
-                          "right" : {
-                            "type" : "hexstr",
-                            "value" : "0x5"
-                          }
-                        }
-                      },
-                      "right" : {
-                        "type" : "hexstr",
-                        "value" : "0xff"
-                      }
-                    }
-                  },
-                  "right" : {
-                    "type" : "hexstr",
-                    "value" : "0x07"
-                  }
-                }
-              }
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 57,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.tc = tc; ..."
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "bos"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x01"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 58,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.bos = 1"
-          }
-        },
-        {
-          "op" : "assign",
-          "parameters" : [
-            {
-              "type" : "field",
-              "value" : ["mpls", "ttl"]
-            },
-            {
-              "type" : "hexstr",
-              "value" : "0x40"
-            }
-          ],
-          "source_info" : {
-            "filename" : "./include/control/forwarding.p4",
-            "line" : 59,
-            "column" : 8,
-            "source_fragment" : "hdr.mpls.ttl = 64"
-          }
-        }
-      ]
-    },
-    {
       "name" : "forwarding.duplicate_to_controller",
-      "id" : 26,
+      "id" : 24,
       "runtime_data" : [],
       "primitives" : [
         {
@@ -2645,8 +2289,8 @@
             }
           ],
           "source_info" : {
-            "filename" : "./include/control/../header.p4",
-            "line" : 19,
+            "filename" : "./include/control/../define.p4",
+            "line" : 61,
             "column" : 35,
             "source_fragment" : "3; ..."
           }
@@ -2674,7 +2318,7 @@
     },
     {
       "name" : "next.set_next_type",
-      "id" : 27,
+      "id" : 25,
       "runtime_data" : [
         {
           "name" : "next_type",
@@ -2705,7 +2349,7 @@
     },
     {
       "name" : "next.output",
-      "id" : 28,
+      "id" : 26,
       "runtime_data" : [
         {
           "name" : "port_num",
@@ -2935,7 +2579,7 @@
     },
     {
       "name" : "next.set_vlan_output",
-      "id" : 29,
+      "id" : 27,
       "runtime_data" : [
         {
           "name" : "new_vlan_id",
@@ -3217,7 +2861,7 @@
     },
     {
       "name" : "next.l3_routing",
-      "id" : 30,
+      "id" : 28,
       "runtime_data" : [
         {
           "name" : "port_num",
@@ -3493,7 +3137,7 @@
     },
     {
       "name" : "next.l3_routing",
-      "id" : 31,
+      "id" : 29,
       "runtime_data" : [
         {
           "name" : "port_num",
@@ -3769,7 +3413,7 @@
     },
     {
       "name" : "next.set_mcast_group",
-      "id" : 32,
+      "id" : 30,
       "runtime_data" : [
         {
           "name" : "gid",
@@ -3822,6 +3466,852 @@
       ]
     },
     {
+      "name" : "next.mpls_routing_v4",
+      "id" : 31,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 58,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 38,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ipv4", "ttl"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "?",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "+",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv4", "ttl"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0xff"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "field",
+                    "value" : ["ipv4", "ttl"]
+                  },
+                  "cond" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "and",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "!=",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["mpls", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "==",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv4", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 41,
+            "column" : 16,
+            "source_fragment" : "hdr.ipv4.ttl ="
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ipv6", "hop_limit"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "?",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "+",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv6", "hop_limit"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0xff"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "field",
+                    "value" : ["ipv6", "hop_limit"]
+                  },
+                  "cond" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "and",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "and",
+                          "left" : {
+                            "type" : "expression",
+                            "value" : {
+                              "op" : "!=",
+                              "left" : {
+                                "type" : "field",
+                                "value" : ["mpls", "$valid$"]
+                              },
+                              "right" : {
+                                "type" : "hexstr",
+                                "value" : "0x01"
+                              }
+                            }
+                          },
+                          "right" : {
+                            "type" : "expression",
+                            "value" : {
+                              "op" : "not",
+                              "left" : null,
+                              "right" : {
+                                "type" : "expression",
+                                "value" : {
+                                  "op" : "==",
+                                  "left" : {
+                                    "type" : "field",
+                                    "value" : ["ipv4", "$valid$"]
+                                  },
+                                  "right" : {
+                                    "type" : "hexstr",
+                                    "value" : "0x01"
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "==",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv6", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 44,
+            "column" : 16,
+            "source_fragment" : "hdr.ipv6.hop_limit ="
+          }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 78,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/../define.p4",
+            "line" : 34,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 80,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : ">>",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv4", "diffserv"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x5"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0x07"
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 81,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 82,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/../header.p4",
+            "line" : 19,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
+        }
+      ]
+    },
+    {
+      "name" : "next.mpls_routing_v6",
+      "id" : 32,
+      "runtime_data" : [
+        {
+          "name" : "port_num",
+          "bitwidth" : 9
+        },
+        {
+          "name" : "smac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "dmac",
+          "bitwidth" : 48
+        },
+        {
+          "name" : "label",
+          "bitwidth" : 20
+        }
+      ],
+      "primitives" : [
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "src_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 1
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 58,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.src_addr = smac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "dst_addr"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 2
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 62,
+            "column" : 8,
+            "source_fragment" : "hdr.ethernet.dst_addr = dmac; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["standard_metadata", "egress_spec"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 0
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 38,
+            "column" : 8,
+            "source_fragment" : "standard_metadata.egress_spec = port_num; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ipv4", "ttl"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "?",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "+",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv4", "ttl"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0xff"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "field",
+                    "value" : ["ipv4", "ttl"]
+                  },
+                  "cond" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "and",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "!=",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["mpls", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "==",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv4", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 41,
+            "column" : 16,
+            "source_fragment" : "hdr.ipv4.ttl ="
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ipv6", "hop_limit"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "?",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "+",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv6", "hop_limit"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0xff"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "field",
+                    "value" : ["ipv6", "hop_limit"]
+                  },
+                  "cond" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "and",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "and",
+                          "left" : {
+                            "type" : "expression",
+                            "value" : {
+                              "op" : "!=",
+                              "left" : {
+                                "type" : "field",
+                                "value" : ["mpls", "$valid$"]
+                              },
+                              "right" : {
+                                "type" : "hexstr",
+                                "value" : "0x01"
+                              }
+                            }
+                          },
+                          "right" : {
+                            "type" : "expression",
+                            "value" : {
+                              "op" : "not",
+                              "left" : null,
+                              "right" : {
+                                "type" : "expression",
+                                "value" : {
+                                  "op" : "==",
+                                  "left" : {
+                                    "type" : "field",
+                                    "value" : ["ipv4", "$valid$"]
+                                  },
+                                  "right" : {
+                                    "type" : "hexstr",
+                                    "value" : "0x01"
+                                  }
+                                }
+                              }
+                            }
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : "==",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv6", "$valid$"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x01"
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 44,
+            "column" : 16,
+            "source_fragment" : "hdr.ipv6.hop_limit ="
+          }
+        },
+        {
+          "op" : "add_header",
+          "parameters" : [
+            {
+              "type" : "header",
+              "value" : "mpls"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 78,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.setValid()"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["ethernet", "ether_type"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x8847"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/../define.p4",
+            "line" : 34,
+            "column" : 31,
+            "source_fragment" : "0x8847; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "label"]
+            },
+            {
+              "type" : "runtime_data",
+              "value" : 3
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 80,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.label = label; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "tc"]
+            },
+            {
+              "type" : "expression",
+              "value" : {
+                "type" : "expression",
+                "value" : {
+                  "op" : "&",
+                  "left" : {
+                    "type" : "expression",
+                    "value" : {
+                      "op" : "&",
+                      "left" : {
+                        "type" : "expression",
+                        "value" : {
+                          "op" : ">>",
+                          "left" : {
+                            "type" : "field",
+                            "value" : ["ipv6", "traffic_class"]
+                          },
+                          "right" : {
+                            "type" : "hexstr",
+                            "value" : "0x5"
+                          }
+                        }
+                      },
+                      "right" : {
+                        "type" : "hexstr",
+                        "value" : "0xff"
+                      }
+                    }
+                  },
+                  "right" : {
+                    "type" : "hexstr",
+                    "value" : "0x07"
+                  }
+                }
+              }
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 81,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.tc = tc; ..."
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "bos"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x01"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/next.p4",
+            "line" : 82,
+            "column" : 8,
+            "source_fragment" : "hdr.mpls.bos = 1"
+          }
+        },
+        {
+          "op" : "assign",
+          "parameters" : [
+            {
+              "type" : "field",
+              "value" : ["mpls", "ttl"]
+            },
+            {
+              "type" : "hexstr",
+              "value" : "0x40"
+            }
+          ],
+          "source_info" : {
+            "filename" : "./include/control/../header.p4",
+            "line" : 19,
+            "column" : 32,
+            "source_fragment" : "64; ..."
+          }
+        }
+      ]
+    },
+    {
       "name" : "act",
       "id" : 33,
       "runtime_data" : [],
@@ -3966,7 +4456,7 @@
           ],
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 151,
+            "line" : 175,
             "column" : 12,
             "source_fragment" : "hdr.vlan_tag.setInvalid()"
           }
@@ -4168,7 +4658,7 @@
           "id" : 3,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 80,
+            "line" : 57,
             "column" : 10,
             "source_fragment" : "bridging"
           },
@@ -4208,7 +4698,7 @@
           "id" : 4,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 92,
+            "line" : 69,
             "column" : 10,
             "source_fragment" : "mpls"
           },
@@ -4243,7 +4733,7 @@
           "id" : 5,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 103,
+            "line" : 80,
             "column" : 10,
             "source_fragment" : "unicast_v4"
           },
@@ -4259,12 +4749,11 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [18, 24, 6],
-          "actions" : ["forwarding.set_next_id", "forwarding.push_mpls_and_next_v4", "NoAction"],
+          "action_ids" : [18, 6],
+          "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
             "forwarding.set_next_id" : "forwarding.acl",
-            "forwarding.push_mpls_and_next_v4" : "forwarding.acl",
             "NoAction" : "forwarding.acl"
           },
           "default_entry" : {
@@ -4279,7 +4768,7 @@
           "id" : 6,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 115,
+            "line" : 91,
             "column" : 10,
             "source_fragment" : "multicast_v4"
           },
@@ -4319,7 +4808,7 @@
           "id" : 7,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 127,
+            "line" : 103,
             "column" : 10,
             "source_fragment" : "unicast_v6"
           },
@@ -4335,12 +4824,11 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [20, 25, 8],
-          "actions" : ["forwarding.set_next_id", "forwarding.push_mpls_and_next_v6", "NoAction"],
+          "action_ids" : [20, 8],
+          "actions" : ["forwarding.set_next_id", "NoAction"],
           "base_default_next" : "forwarding.acl",
           "next_tables" : {
             "forwarding.set_next_id" : "forwarding.acl",
-            "forwarding.push_mpls_and_next_v6" : "forwarding.acl",
             "NoAction" : "forwarding.acl"
           },
           "default_entry" : {
@@ -4355,7 +4843,7 @@
           "id" : 8,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 139,
+            "line" : 114,
             "column" : 10,
             "source_fragment" : "multicast_v6"
           },
@@ -4395,7 +4883,7 @@
           "id" : 9,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 151,
+            "line" : 126,
             "column" : 10,
             "source_fragment" : "acl"
           },
@@ -4516,7 +5004,7 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [22, 26, 3, 1],
+          "action_ids" : [22, 24, 3, 1],
           "actions" : ["forwarding.set_next_id", "forwarding.duplicate_to_controller", "drop", "nop"],
           "base_default_next" : "next.next_id_mapping",
           "next_tables" : {
@@ -4537,7 +5025,7 @@
           "id" : 10,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 76,
+            "line" : 98,
             "column" : 10,
             "source_fragment" : "next_id_mapping"
           },
@@ -4553,7 +5041,7 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [27, 10],
+          "action_ids" : [25, 10],
           "actions" : ["next.set_next_type", "NoAction"],
           "base_default_next" : "node_20",
           "next_tables" : {
@@ -4572,7 +5060,7 @@
           "id" : 11,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 87,
+            "line" : 109,
             "column" : 10,
             "source_fragment" : "simple"
           },
@@ -4588,7 +5076,7 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [28, 29, 30, 11],
+          "action_ids" : [26, 27, 28, 11],
           "actions" : ["next.output", "next.set_vlan_output", "next.l3_routing", "NoAction"],
           "base_default_next" : "node_26",
           "next_tables" : {
@@ -4609,7 +5097,7 @@
           "id" : 12,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 100,
+            "line" : 122,
             "column" : 10,
             "source_fragment" : "hashed"
           },
@@ -4626,11 +5114,13 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [31, 12],
-          "actions" : ["next.l3_routing", "NoAction"],
+          "action_ids" : [29, 31, 32, 12],
+          "actions" : ["next.l3_routing", "next.mpls_routing_v4", "next.mpls_routing_v6", "NoAction"],
           "base_default_next" : "node_26",
           "next_tables" : {
             "next.l3_routing" : "node_26",
+            "next.mpls_routing_v4" : "node_26",
+            "next.mpls_routing_v6" : "node_26",
             "NoAction" : "node_26"
           }
         },
@@ -4639,7 +5129,7 @@
           "id" : 13,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 124,
+            "line" : 148,
             "column" : 10,
             "source_fragment" : "broadcast"
           },
@@ -4655,7 +5145,7 @@
           "max_size" : 1024,
           "support_timeout" : false,
           "direct_meters" : null,
-          "action_ids" : [32, 13],
+          "action_ids" : [30, 13],
           "actions" : ["next.set_mcast_group", "NoAction"],
           "base_default_next" : "node_26",
           "next_tables" : {
@@ -4792,7 +5282,7 @@
           "id" : 1,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 189,
+            "line" : 164,
             "column" : 11,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_BRIDGING"
           },
@@ -4818,7 +5308,7 @@
           "id" : 2,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 190,
+            "line" : 165,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_MPLS"
           },
@@ -4844,7 +5334,7 @@
           "id" : 3,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 191,
+            "line" : 166,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_UNICAST"
           },
@@ -4870,7 +5360,7 @@
           "id" : 4,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 192,
+            "line" : 167,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV4_MULTICAST"
           },
@@ -4896,7 +5386,7 @@
           "id" : 5,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 193,
+            "line" : 168,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV6_UNICAST"
           },
@@ -4922,7 +5412,7 @@
           "id" : 6,
           "source_info" : {
             "filename" : "./include/control/forwarding.p4",
-            "line" : 194,
+            "line" : 169,
             "column" : 17,
             "source_fragment" : "fabric_metadata.fwd_type == FWD_IPV6_MULTICAST"
           },
@@ -4948,7 +5438,7 @@
           "id" : 7,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 136,
+            "line" : 160,
             "column" : 12,
             "source_fragment" : "fabric_metadata.next_type == NEXT_TYPE_SIMPLE"
           },
@@ -4974,7 +5464,7 @@
           "id" : 8,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 137,
+            "line" : 161,
             "column" : 17,
             "source_fragment" : "fabric_metadata.next_type == NEXT_TYPE_HASHED"
           },
@@ -5000,7 +5490,7 @@
           "id" : 9,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 138,
+            "line" : 162,
             "column" : 17,
             "source_fragment" : "fabric_metadata.next_type == NEXT_TYPE_BROADCAST"
           },
@@ -5163,7 +5653,7 @@
           "id" : 12,
           "source_info" : {
             "filename" : "./include/control/next.p4",
-            "line" : 150,
+            "line" : 174,
             "column" : 12,
             "source_fragment" : "fabric_metadata.pop_vlan_at_egress"
           },
diff --git a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
index 377d2f9..2ba127c 100644
--- a/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
+++ b/pipelines/fabric/src/main/resources/p4c-out/bmv2/fabric.p4info
@@ -135,9 +135,6 @@
     id: 16829931
   }
   action_refs {
-    id: 16788751
-  }
-  action_refs {
     id: 16800567
     annotations: "@defaultonly()"
   }
@@ -188,9 +185,6 @@
     id: 16829931
   }
   action_refs {
-    id: 16827504
-  }
-  action_refs {
     id: 16800567
     annotations: "@defaultonly()"
   }
@@ -445,6 +439,12 @@
     id: 16804266
   }
   action_refs {
+    id: 16841192
+  }
+  action_refs {
+    id: 16788519
+  }
+  action_refs {
     id: 16800567
     annotations: "@defaultonly()"
   }
@@ -557,40 +557,6 @@
 }
 actions {
   preamble {
-    id: 16788751
-    name: "forwarding.push_mpls_and_next_v4"
-    alias: "push_mpls_and_next_v4"
-  }
-  params {
-    id: 1
-    name: "label"
-    bitwidth: 20
-  }
-  params {
-    id: 2
-    name: "next_id"
-    bitwidth: 32
-  }
-}
-actions {
-  preamble {
-    id: 16827504
-    name: "forwarding.push_mpls_and_next_v6"
-    alias: "push_mpls_and_next_v6"
-  }
-  params {
-    id: 1
-    name: "label"
-    bitwidth: 20
-  }
-  params {
-    id: 2
-    name: "next_id"
-    bitwidth: 32
-  }
-}
-actions {
-  preamble {
     id: 16805452
     name: "forwarding.duplicate_to_controller"
     alias: "duplicate_to_controller"
@@ -676,6 +642,60 @@
     bitwidth: 48
   }
 }
+actions {
+  preamble {
+    id: 16841192
+    name: "next.mpls_routing_v4"
+    alias: "mpls_routing_v4"
+  }
+  params {
+    id: 1
+    name: "port_num"
+    bitwidth: 9
+  }
+  params {
+    id: 2
+    name: "smac"
+    bitwidth: 48
+  }
+  params {
+    id: 3
+    name: "dmac"
+    bitwidth: 48
+  }
+  params {
+    id: 4
+    name: "label"
+    bitwidth: 20
+  }
+}
+actions {
+  preamble {
+    id: 16788519
+    name: "next.mpls_routing_v6"
+    alias: "mpls_routing_v6"
+  }
+  params {
+    id: 1
+    name: "port_num"
+    bitwidth: 9
+  }
+  params {
+    id: 2
+    name: "smac"
+    bitwidth: 48
+  }
+  params {
+    id: 3
+    name: "dmac"
+    bitwidth: 48
+  }
+  params {
+    id: 4
+    name: "label"
+    bitwidth: 20
+  }
+}
 action_profiles {
   preamble {
     id: 285225078
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
index 76bd030..fdda55f 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/FabricInterpreterTest.java
@@ -20,6 +20,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onlab.util.ImmutableByteSequence;
 import org.onosproject.net.PortNumber;
@@ -38,6 +39,7 @@
     private static final PortNumber PORT_1 = PortNumber.portNumber(1);
     private static final MacAddress SRC_MAC = MacAddress.valueOf("00:00:00:00:00:01");
     private static final MacAddress DST_MAC = MacAddress.valueOf("00:00:00:00:00:02");
+    private static final MplsLabel MPLS_10 = MplsLabel.mplsLabel(10);
 
     private FabricInterpreter interpreter;
 
@@ -198,4 +200,33 @@
 
         assertEquals(expectedAction, mappedAction);
     }
+
+    @Test
+    public void testMplsRoutingTreatment() throws Exception {
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setEthDst(DST_MAC)
+                .setEthSrc(SRC_MAC)
+                .pushMpls()
+                .copyTtlOut()
+                .setMpls(MPLS_10)
+                .setOutput(PORT_1)
+                .build();
+        PiAction mappedAction = interpreter.mapTreatment(treatment,
+                                                         FabricConstants.TBL_HASHED_ID);
+        short portNumVal = (short) PORT_1.toLong();
+        PiActionParam ethSrcParam = new PiActionParam(FabricConstants.ACT_PRM_SMAC_ID,
+                                                      ImmutableByteSequence.copyFrom(SRC_MAC.toBytes()));
+        PiActionParam ethDstParam = new PiActionParam(FabricConstants.ACT_PRM_DMAC_ID,
+                                                      ImmutableByteSequence.copyFrom(DST_MAC.toBytes()));
+        PiActionParam portParam = new PiActionParam(FabricConstants.ACT_PRM_PORT_NUM_ID,
+                                                    ImmutableByteSequence.copyFrom(portNumVal));
+        ImmutableByteSequence mplsVal =
+                ImmutableByteSequence.fit(ImmutableByteSequence.copyFrom(MPLS_10.toInt()), 20);
+        PiActionParam mplsParam = new PiActionParam(FabricConstants.ACT_PRM_LABEL_ID, mplsVal);
+        PiAction expectedAction = PiAction.builder()
+                .withId(FabricConstants.ACT_MPLS_ROUTING_V4_ID)
+                .withParameters(ImmutableList.of(ethSrcParam, ethDstParam, portParam, mplsParam))
+                .build();
+        assertEquals(expectedAction, mappedAction);
+    }
 }
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
index 0332e63..1602c58 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricForwardingPipelineTest.java
@@ -210,13 +210,46 @@
     }
 
     @Test
-    @Ignore
     public void testMpls() {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.MPLS_UNICAST)
+                .matchMplsLabel(MPLS_10)
+                .matchMplsBos(true)
+                .build();
+        TrafficSelector expectedSelector = DefaultTrafficSelector.builder()
+                .matchMplsLabel(MPLS_10)
+                .build();
 
+        PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
+                                                      ImmutableByteSequence.copyFrom(NEXT_ID_1.byteValue()));
+        PiAction setNextIdAction = PiAction.builder()
+                .withId(FabricConstants.ACT_POP_MPLS_AND_NEXT_ID)
+                .withParameter(nextIdParam)
+                .build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .piTableAction(setNextIdAction)
+                .build();
+        testSpecificForward(FabricConstants.TBL_MPLS_ID, expectedSelector, selector, NEXT_ID_1, treatment);
     }
 
     private void testSpecificForward(PiTableId expectedTableId, TrafficSelector expectedSelector,
                                      TrafficSelector selector, Integer nextId) {
+        PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
+                                                      ImmutableByteSequence.copyFrom(nextId.byteValue()));
+        PiAction setNextIdAction = PiAction.builder()
+                .withId(FabricConstants.ACT_SET_NEXT_ID_ID)
+                .withParameter(nextIdParam)
+                .build();
+        TrafficTreatment setNextIdTreatment = DefaultTrafficTreatment.builder()
+                .piTableAction(setNextIdAction)
+                .build();
+
+        testSpecificForward(expectedTableId, expectedSelector, selector, nextId, setNextIdTreatment);
+
+    }
+
+    private void testSpecificForward(PiTableId expectedTableId, TrafficSelector expectedSelector,
+                                     TrafficSelector selector, Integer nextId, TrafficTreatment treatment) {
         ForwardingObjective fwd = DefaultForwardingObjective.builder()
                 .withSelector(selector)
                 .withPriority(PRIORITY)
@@ -234,15 +267,6 @@
         assertTrue(groupsInstalled.isEmpty());
 
         FlowRule actualFlowRule = flowRulesInstalled.get(0);
-        PiActionParam nextIdParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_ID_ID,
-                                                      ImmutableByteSequence.copyFrom(nextId.byteValue()));
-        PiAction setNextIdAction = PiAction.builder()
-                .withId(FabricConstants.ACT_SET_NEXT_ID_ID)
-                .withParameter(nextIdParam)
-                .build();
-        TrafficTreatment setNextIdTreatment = DefaultTrafficTreatment.builder()
-                .piTableAction(setNextIdAction)
-                .build();
 
         FlowRule expectedFlowRule = DefaultFlowRule.builder()
                 .forDevice(DEVICE_ID)
@@ -250,7 +274,7 @@
                 .withPriority(PRIORITY)
                 .makePermanent()
                 .withSelector(expectedSelector)
-                .withTreatment(setNextIdTreatment)
+                .withTreatment(treatment)
                 .fromApp(APP_ID)
                 .build();
 
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
index 3fe196b..8493ca6 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricNextPipelinerTest.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.pipelines.fabric.pipeliner;
 
+import com.google.common.collect.ImmutableList;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.onlab.util.ImmutableByteSequence;
@@ -28,15 +29,24 @@
 import org.onosproject.net.flow.criteria.PiCriterion;
 import org.onosproject.net.flowobjective.DefaultNextObjective;
 import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
 import org.onosproject.net.group.GroupDescription;
 import org.onosproject.net.pi.runtime.PiAction;
+import org.onosproject.net.pi.runtime.PiActionGroupId;
 import org.onosproject.net.pi.runtime.PiActionParam;
+import org.onosproject.net.pi.runtime.PiGroupKey;
 import org.onosproject.pipelines.fabric.FabricConstants;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRF_ECMP_SELECTOR_ID;
+import static org.onosproject.pipelines.fabric.FabricConstants.TBL_HASHED_ID;
 
 /**
  * Test cases for fabric.p4 pipeline next control block.
@@ -96,20 +106,39 @@
         assertEquals(2, flowRulesInstalled.size());
         assertTrue(groupsInstalled.isEmpty());
 
-        FlowRule actualFlowRule;
-        FlowRule expectedFlowRule;
+        verifyNextIdMapping(flowRulesInstalled.get(0), NEXT_TYPE_SIMPLE);
 
-        // Next id mapping table
-        actualFlowRule = flowRulesInstalled.get(0);
-        byte[] nextIdVal = new byte[]{NEXT_ID_1.byteValue()};
+        // Simple table
         PiCriterion nextIdCriterion = PiCriterion.builder()
-                .matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, nextIdVal)
+                .matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, NEXT_ID_1)
+                .build();
+        TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
+                .matchPi(nextIdCriterion)
+                .build();
+        FlowRule actualFlowRule = flowRulesInstalled.get(1);
+        FlowRule expectedFlowRule = DefaultFlowRule.builder()
+                .forDevice(DEVICE_ID)
+                .fromApp(APP_ID)
+                .makePermanent()
+                // FIXME: currently next objective doesn't support priority, ignore this
+                .withPriority(0)
+                .forTable(FabricConstants.TBL_SIMPLE_ID)
+                .withSelector(nextIdSelector)
+                .withTreatment(treatment)
+                .build();
+        assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
+    }
+
+    private void verifyNextIdMapping(FlowRule flowRule, byte nextType) {
+        FlowRule expectedFlowRule;
+        PiCriterion nextIdCriterion = PiCriterion.builder()
+                .matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, NEXT_ID_1)
                 .build();
         TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
                 .matchPi(nextIdCriterion)
                 .build();
         PiActionParam setNextToSimpleParam = new PiActionParam(FabricConstants.ACT_PRM_NEXT_TYPE_ID,
-                                                               ImmutableByteSequence.copyFrom(NEXT_TYPE_SIMPLE));
+                                                               ImmutableByteSequence.copyFrom(nextType));
         PiAction setNextToSimpleAction = PiAction.builder()
                 .withId(FabricConstants.ACT_SET_NEXT_TYPE_ID)
                 .withParameter(setNextToSimpleParam)
@@ -127,29 +156,87 @@
                 .withSelector(nextIdSelector)
                 .withTreatment(setNextTypeTreatment)
                 .build();
-        assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
-
-        // Simple table
-        actualFlowRule = flowRulesInstalled.get(1);
-        expectedFlowRule = DefaultFlowRule.builder()
-                .forDevice(DEVICE_ID)
-                .fromApp(APP_ID)
-                .makePermanent()
-                // FIXME: currently next objective doesn't support priority, ignore this
-                .withPriority(0)
-                .forTable(FabricConstants.TBL_SIMPLE_ID)
-                .withSelector(nextIdSelector)
-                .withTreatment(treatment)
-                .build();
-        assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
+        assertTrue(expectedFlowRule.exactMatch(flowRule));
     }
 
     /**
      * Test program ecmp output group for Hashed table.
      */
     @Test
-    @Ignore
-    public void testHashedOutput() {
+    public void testHashedOutput() throws Exception {
+        TrafficTreatment treatment1 = DefaultTrafficTreatment.builder()
+                .setEthSrc(ROUTER_MAC)
+                .setEthDst(HOST_MAC)
+                .setOutput(PORT_1)
+                .build();
+        TrafficTreatment treatment2 = DefaultTrafficTreatment.builder()
+                .setEthSrc(ROUTER_MAC)
+                .setEthDst(HOST_MAC)
+                .setOutput(PORT_2)
+                .build();
+
+        NextObjective nextObjective = DefaultNextObjective.builder()
+                .withId(NEXT_ID_1)
+                .withPriority(PRIORITY)
+                .addTreatment(treatment1)
+                .addTreatment(treatment2)
+                .withType(NextObjective.Type.HASHED)
+                .makePermanent()
+                .fromApp(APP_ID)
+                .add();
+
+        PipelinerTranslationResult result = pipeliner.pipelinerNext.next(nextObjective);
+
+        // Should generates 2 flows and 1 group
+        List<FlowRule> flowRulesInstalled = (List<FlowRule>) result.flowRules();
+        List<GroupDescription> groupsInstalled = (List<GroupDescription>) result.groups();
+        assertEquals(2, flowRulesInstalled.size());
+        assertEquals(1, groupsInstalled.size());
+
+        verifyNextIdMapping(flowRulesInstalled.get(0), NEXT_TYPE_HASHED);
+
+        // Hashed table
+        PiCriterion nextIdCriterion = PiCriterion.builder()
+                .matchExact(FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID, NEXT_ID_1)
+                .build();
+        TrafficSelector nextIdSelector = DefaultTrafficSelector.builder()
+                .matchPi(nextIdCriterion)
+                .build();
+        PiActionGroupId actionGroupId = PiActionGroupId.of(NEXT_ID_1);
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .piTableAction(actionGroupId)
+                .build();
+        FlowRule actualFlowRule = flowRulesInstalled.get(1);
+        FlowRule expectedFlowRule = DefaultFlowRule.builder()
+                .forDevice(DEVICE_ID)
+                .fromApp(APP_ID)
+                .makePermanent()
+                // FIXME: currently next objective doesn't support priority, ignore this
+                .withPriority(0)
+                .forTable(TBL_HASHED_ID)
+                .withSelector(nextIdSelector)
+                .withTreatment(treatment)
+                .build();
+        assertTrue(expectedFlowRule.exactMatch(actualFlowRule));
+
+        // Group
+        GroupDescription actualGroup = groupsInstalled.get(0);
+        List<TrafficTreatment> treatments = ImmutableList.of(treatment1, treatment2);
+
+        List<GroupBucket> buckets = treatments.stream()
+                .map(DefaultGroupBucket::createSelectGroupBucket)
+                .collect(Collectors.toList());
+        GroupBuckets groupBuckets = new GroupBuckets(buckets);
+        PiGroupKey groupKey = new PiGroupKey(TBL_HASHED_ID, ACT_PRF_ECMP_SELECTOR_ID, NEXT_ID_1);
+        GroupDescription expectedGroup = new DefaultGroupDescription(
+                DEVICE_ID,
+                GroupDescription.Type.SELECT,
+                groupBuckets,
+                groupKey,
+                NEXT_ID_1,
+                APP_ID
+        );
+        assertEquals(expectedGroup, actualGroup);
 
     }
 
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
index 30610ed..fb92bf9 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/FabricPipelinerTest.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.behaviour.PipelinerContext;
 import org.onosproject.net.flow.criteria.PiCriterion;
 import org.onosproject.pipelines.fabric.FabricConstants;
+import org.onosproject.pipelines.fabric.FabricInterpreter;
 
 import static org.easymock.EasyMock.createNiceMock;
 import static org.easymock.EasyMock.expect;
@@ -39,6 +40,7 @@
     static final DeviceId DEVICE_ID = DeviceId.deviceId("device:bmv2:11");
     static final int PRIORITY = 100;
     static final PortNumber PORT_1 = PortNumber.portNumber(1);
+    static final PortNumber PORT_2 = PortNumber.portNumber(2);
     static final VlanId VLAN_100 = VlanId.vlanId("100");
     static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
     static final MacAddress ROUTER_MAC = MacAddress.valueOf("00:00:00:00:02:01");
@@ -71,6 +73,7 @@
             .build();
 
     FabricPipeliner pipeliner;
+    FabricInterpreter interpreter;
 
     @Before
     public void setup() {
@@ -82,5 +85,6 @@
         replay(serviceDirectory, pipelinerContext);
 
         pipeliner.init(DEVICE_ID, pipelinerContext);
+        interpreter = new FabricInterpreter();
     }
 }
diff --git a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
index 44ec9bc..5e77906 100644
--- a/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
+++ b/pipelines/fabric/src/test/java/org/onosproject/pipelines/fabric/pipeliner/ForwardingFunctionTypeTest.java
@@ -106,7 +106,6 @@
     }
 
     @Test
-    @Ignore
     public void testMplsUnicast() {
         selector = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.MPLS_UNICAST)