ONOS-631 #Initial MPLS intent implementation

Change-Id: I6f906b953f06f395cc67e612648802e333c0e581
diff --git a/apps/optical/src/main/java/org/onosproject/optical/testapp/MPLSForwarding.java b/apps/optical/src/main/java/org/onosproject/optical/testapp/MPLSForwarding.java
index bea39da..2601133 100644
--- a/apps/optical/src/main/java/org/onosproject/optical/testapp/MPLSForwarding.java
+++ b/apps/optical/src/main/java/org/onosproject/optical/testapp/MPLSForwarding.java
@@ -40,6 +40,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.MplsLabel;
 import org.slf4j.Logger;
 
 /**
@@ -98,7 +99,7 @@
         TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
         int inport = 1;
         int outport = 2;
-        Integer mplsLabel = 101;
+        MplsLabel mplsLabel = MplsLabel.mplsLabel(101);
         Integer switchNumber = uglyMap.get(device.id());
         if (switchNumber == null) {
             return;
diff --git a/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java b/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java
new file mode 100644
index 0000000..577743a
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/AddMplsIntent.java
@@ -0,0 +1,120 @@
+package org.onosproject.cli.net;
+
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.PortNumber.portNumber;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.apache.karaf.shell.commands.Option;
+
+import org.onlab.packet.MplsLabel;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.IntentService;
+import org.onosproject.net.intent.MplsIntent;
+
+@Command(scope = "onos", name = "add-mpls-intent", description = "Installs mpls connectivity intent")
+public class AddMplsIntent extends ConnectivityIntentCommand {
+
+    @Argument(index = 0, name = "ingressDevice",
+            description = "Ingress Device/Port Description",
+            required = true,
+            multiValued = false)
+    private String ingressDeviceString = null;
+
+    @Option(name = "--ingressLabel",
+            description = "Ingress Mpls label",
+            required = false,
+            multiValued = false)
+    private String ingressLabelString = "";
+
+    @Argument(index = 1, name = "egressDevice",
+            description = "Egress Device/Port Description",
+            required = true,
+            multiValued = false)
+    private String egressDeviceString = null;
+
+    @Option(name = "--egressLabel",
+            description = "Egress Mpls label",
+            required = false,
+            multiValued = false)
+    private String egressLabelString = "";
+
+    @Override
+    protected void execute() {
+        IntentService service = get(IntentService.class);
+
+        DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
+        PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
+        ConnectPoint ingress = new ConnectPoint(ingressDeviceId,
+                                                ingressPortNumber);
+        Optional<MplsLabel> ingressLabel = Optional.empty();
+        if (!ingressLabelString.isEmpty()) {
+            ingressLabel = Optional
+                    .ofNullable(MplsLabel.mplsLabel(parseInt(ingressLabelString)));
+        }
+
+        DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
+        PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
+        ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
+
+        Optional<MplsLabel> egressLabel = Optional.empty();
+        if (!ingressLabelString.isEmpty()) {
+            egressLabel = Optional
+                    .ofNullable(MplsLabel.mplsLabel(parseInt(egressLabelString)));
+        }
+
+        TrafficSelector selector = buildTrafficSelector();
+        TrafficTreatment treatment = buildTrafficTreatment();
+
+        List<Constraint> constraints = buildConstraints();
+
+        MplsIntent intent = new MplsIntent(appId(), selector, treatment,
+                                           ingress, ingressLabel, egress,
+                                           egressLabel, constraints);
+        service.submit(intent);
+    }
+
+    /**
+     * Extracts the port number portion of the ConnectPoint.
+     *
+     * @param deviceString string representing the device/port
+     * @return port number as a string, empty string if the port is not found
+     */
+    public static String getPortNumber(String deviceString) {
+        int slash = deviceString.indexOf('/');
+        if (slash <= 0) {
+            return "";
+        }
+        return deviceString.substring(slash + 1, deviceString.length());
+    }
+
+    /**
+     * Extracts the device ID portion of the ConnectPoint.
+     *
+     * @param deviceString string representing the device/port
+     * @return device ID string
+     */
+    public static String getDeviceId(String deviceString) {
+        int slash = deviceString.indexOf('/');
+        if (slash <= 0) {
+            return "";
+        }
+        return deviceString.substring(0, slash);
+    }
+
+    protected Integer parseInt(String value) {
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException nfe) {
+            return null;
+        }
+    }
+}
diff --git a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 478eaa9..314fa5e 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -297,6 +297,12 @@
         <command>
             <action class="org.onosproject.cli.net.WipeOutCommand"/>
         </command>
+        <command>
+			<action class="org.onosproject.cli.net.AddMplsIntent" />
+			<completers>
+			<ref component-id="connectPointCompleter" />
+		</completers>
+		</command>
     </command-bundle>
 
     <bean id="appNameCompleter" class="org.onosproject.cli.app.ApplicationNameCompleter"/>
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
index f3f3bf8..9ce3186 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficSelector.java
@@ -26,6 +26,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 import com.google.common.base.MoreObjects;
@@ -275,7 +276,7 @@
         }
 
         @Override
-        public Builder matchMplsLabel(Integer mplsLabel) {
+        public Builder matchMplsLabel(MplsLabel mplsLabel) {
             return add(Criteria.matchMplsLabel(mplsLabel));
         }
 
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index 6b5af75..37dcd06 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -17,8 +17,10 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
+
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.GroupId;
 import org.onosproject.net.PortNumber;
@@ -222,12 +224,12 @@
         }
 
         @Override
-        public Builder popMpls(short etherType) {
+        public Builder popMpls(Short etherType) {
             return add(Instructions.popMpls(etherType));
         }
 
         @Override
-        public Builder setMpls(Integer mplsLabel) {
+        public Builder setMpls(MplsLabel mplsLabel) {
             return add(Instructions.modMplsLabel(mplsLabel));
         }
 
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
index 7d31b08..533e2f5 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficSelector.java
@@ -22,6 +22,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 /**
@@ -297,7 +298,7 @@
          * @param mplsLabel a MPLS label.
          * @return a selection builder
          */
-        public Builder matchMplsLabel(Integer mplsLabel);
+        public Builder matchMplsLabel(MplsLabel mplsLabel);
 
         /**
          * Matches on IPv6 Extension Header pseudo-field fiags.
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 98cb3b2..bfb8f2e 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -19,9 +19,11 @@
 
 import org.onosproject.core.GroupId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment.Builder;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 /**
@@ -155,12 +157,12 @@
         public Builder popMpls();
 
         /**
-         * Pops MPLS ether type.
+         * Pops MPLS ether type and set the new ethertype.
          *
-         * @param ethType Ethernet type to set
+         * @param etherType an ether type
          * @return a treatment builder.
          */
-        public Builder popMpls(short ethType);
+        public Builder popMpls(Short etherType);
 
         /**
          * Sets the mpls label.
@@ -168,7 +170,7 @@
          * @param mplsLabel MPLS label.
          * @return a treatment builder.
          */
-        public Builder setMpls(Integer mplsLabel);
+        public Builder setMpls(MplsLabel mplsLabel);
 
         /**
          * Decrement MPLS TTL.
@@ -199,6 +201,8 @@
          * @return traffic treatment
          */
         TrafficTreatment build();
+
+
     }
 
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
index 34893a4..1eff64b 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/criteria/Criteria.java
@@ -18,11 +18,13 @@
 import static com.google.common.base.MoreObjects.toStringHelper;
 
 import java.util.Objects;
+
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.criteria.Criterion.Type;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 /**
@@ -338,7 +340,7 @@
      * @param mplsLabel MPLS label (20 bits)
      * @return match criterion
      */
-    public static Criterion matchMplsLabel(int mplsLabel) {
+    public static Criterion matchMplsLabel(MplsLabel mplsLabel) {
         return new MplsCriterion(mplsLabel);
     }
 
@@ -1510,15 +1512,10 @@
      */
     public static final class MplsCriterion implements Criterion {
         private static final int MASK = 0xfffff;
-        private final int mplsLabel;            // MPLS label: 20 bits
+        private final MplsLabel mplsLabel;
 
-        /**
-         * Constructor.
-         *
-         * @param mplsLabel the MPLS label to match (20 bits)
-         */
-        public MplsCriterion(int mplsLabel) {
-            this.mplsLabel = mplsLabel & MASK;
+        public MplsCriterion(MplsLabel mplsLabel) {
+            this.mplsLabel = mplsLabel;
         }
 
         @Override
@@ -1526,19 +1523,14 @@
             return Type.MPLS_LABEL;
         }
 
-        /**
-         * Gets the MPLS label to match.
-         *
-         * @return the MPLS label to match (20 bits)
-         */
-        public int label() {
+        public MplsLabel label() {
             return mplsLabel;
         }
 
         @Override
         public String toString() {
             return toStringHelper(type().toString())
-                .add("label", Long.toHexString(mplsLabel)).toString();
+                    .add("mpls", mplsLabel).toString();
         }
 
         @Override
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index 3838cdf..09ec536 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -35,6 +35,7 @@
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 /**
@@ -132,7 +133,7 @@
      * @param mplsLabel to set.
      * @return a L2 Modification
      */
-    public static L2ModificationInstruction modMplsLabel(Integer mplsLabel) {
+    public static L2ModificationInstruction modMplsLabel(MplsLabel mplsLabel) {
         checkNotNull(mplsLabel, "MPLS label cannot be null");
         return new ModMplsLabelInstruction(mplsLabel);
     }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
index 723bbe6..6147551 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/L2ModificationInstruction.java
@@ -20,6 +20,7 @@
 import java.util.Objects;
 
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 /**
@@ -287,14 +288,14 @@
     public static final class ModMplsLabelInstruction extends
     L2ModificationInstruction {
 
-        private final Integer mplsLabel;
+        private final MplsLabel mplsLabel;
 
-        public ModMplsLabelInstruction(Integer mplsLabel) {
+        public ModMplsLabelInstruction(MplsLabel mplsLabel) {
             this.mplsLabel = mplsLabel;
         }
 
         public Integer label() {
-            return mplsLabel;
+            return mplsLabel.toInt();
         }
 
         @Override
@@ -304,8 +305,8 @@
 
         @Override
         public String toString() {
-            return toStringHelper(subtype().toString())
-                    .add("mpls", mplsLabel.intValue()).toString();
+            return toStringHelper(type().toString())
+                    .add("mpls", mplsLabel).toString();
         }
 
         @Override
diff --git a/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java b/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java
new file mode 100644
index 0000000..22793ae
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/intent/MplsIntent.java
@@ -0,0 +1,159 @@
+package org.onosproject.net.intent;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.onlab.packet.MplsLabel;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Link;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.constraint.LinkTypeConstraint;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableList;
+
+
+/**
+ * Abstraction of MPLS label-switched connectivity.
+ */
+public class MplsIntent extends ConnectivityIntent {
+
+    private final ConnectPoint ingressPoint;
+    private final Optional<MplsLabel> ingressLabel;
+    private final ConnectPoint egressPoint;
+    private final Optional<MplsLabel> egressLabel;
+
+    /**
+     * Creates a new MPLS intent with the supplied ingress/egress
+     * ports and labels and with built-in link type constraint to avoid optical links.
+     *
+     * @param appId        application identifier
+     * @param selector     traffic selector
+     * @param treatment    treatment
+     * @param ingressPoint ingress port
+     * @param ingressLabel ingress MPLS label
+     * @param egressPoint  egress port
+     * @param egressLabel  egress MPLS label
+     * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
+     */
+    public MplsIntent(ApplicationId appId, TrafficSelector selector,
+                              TrafficTreatment treatment,
+                              ConnectPoint ingressPoint,
+                              Optional<MplsLabel> ingressLabel,
+                              ConnectPoint egressPoint,
+                              Optional<MplsLabel> egressLabel) {
+        this(appId, selector, treatment, ingressPoint, ingressLabel, egressPoint, egressLabel,
+             ImmutableList.of(new LinkTypeConstraint(false, Link.Type.OPTICAL)));
+    }
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports, labels and constraints.
+     *
+     * @param appId        application identifier
+     * @param selector     traffic selector
+     * @param treatment    treatment
+     * @param ingressPoint ingress port
+     * @param ingressLabel ingress MPLS label
+     * @param egressPoint  egress port
+     * @param egressLabel  egress MPLS label
+     * @param constraints  optional list of constraints
+     * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
+     */
+    public MplsIntent(ApplicationId appId, TrafficSelector selector,
+                              TrafficTreatment treatment,
+                              ConnectPoint ingressPoint,
+                              Optional<MplsLabel> ingressLabel,
+                              ConnectPoint egressPoint,
+                              Optional<MplsLabel> egressLabel,
+                              List<Constraint> constraints) {
+
+        super(appId, Collections.emptyList(), selector, treatment, constraints);
+
+        checkNotNull(ingressPoint);
+        checkNotNull(egressPoint);
+        checkArgument(!ingressPoint.equals(egressPoint),
+                "ingress and egress should be different (ingress: %s, egress: %s)", ingressPoint, egressPoint);
+        checkNotNull(ingressLabel);
+        checkNotNull(egressLabel);
+        this.ingressPoint = ingressPoint;
+        this.ingressLabel = ingressLabel;
+        this.egressPoint = egressPoint;
+        this.egressLabel = egressLabel;
+
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected MplsIntent() {
+        super();
+        this.ingressPoint = null;
+        this.ingressLabel = null;
+        this.egressPoint = null;
+        this.egressLabel = null;
+
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to
+     * the egress.
+     *
+     * @return ingress switch port
+     */
+    public ConnectPoint ingressPoint() {
+        return ingressPoint;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress switch port
+     */
+    public ConnectPoint egressPoint() {
+        return egressPoint;
+    }
+
+
+    /**
+     * Returns the MPLS label which the ingress traffic should tagged.
+     *
+     * @return ingress MPLS label
+     */
+    public Optional<MplsLabel> ingressLabel() {
+        return ingressLabel;
+    }
+
+    /**
+     * Returns the MPLS label which the egress traffic should tagged.
+     *
+     * @return egress MPLS label
+     */
+    public Optional<MplsLabel> egressLabel() {
+        return egressLabel;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", id())
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingressPoint", ingressPoint)
+                .add("ingressLabel", ingressLabel)
+                .add("egressPoint", egressPoint)
+                .add("egressLabel", egressLabel)
+                .add("constraints", constraints())
+                .toString();
+    }
+
+
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java b/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java
new file mode 100644
index 0000000..6c7ffd2
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/intent/MplsPathIntent.java
@@ -0,0 +1,88 @@
+package org.onosproject.net.intent;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+
+import org.onlab.packet.MplsLabel;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.Path;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+
+
+/**
+ * Abstraction of explicit MPLS label-switched path.
+ */
+
+public class MplsPathIntent extends PathIntent {
+
+    private Optional<MplsLabel> ingressLabel;
+    private Optional<MplsLabel> egressLabel;
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports and using the specified explicit path.
+     *
+     * @param appId application identifier
+     * @param selector traffic selector
+     * @param treatment treatment
+     * @param path traversed links
+     * @param ingressLabel MPLS egress label
+     * @param egressLabel MPLS ingress label
+     * @throws NullPointerException {@code path} is null
+     */
+    public MplsPathIntent(ApplicationId appId, TrafficSelector selector,
+            TrafficTreatment treatment, Path path, Optional<MplsLabel> ingressLabel,
+            Optional<MplsLabel> egressLabel) {
+        this(appId, selector, treatment, path, ingressLabel, egressLabel,
+             Collections.emptyList());
+
+    }
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports and using the specified explicit path.
+     *
+     * @param appId application identifier
+     * @param selector traffic selector
+     * @param treatment treatment
+     * @param path traversed links
+     * @param ingressLabel MPLS egress label
+     * @param egressLabel MPLS ingress label
+     * @param constraints optional list of constraints
+     * @throws NullPointerException {@code path} is null
+     */
+    public MplsPathIntent(ApplicationId appId, TrafficSelector selector,
+            TrafficTreatment treatment, Path path, Optional<MplsLabel> ingressLabel,
+            Optional<MplsLabel> egressLabel, List<Constraint> constraints) {
+        super(appId, selector, treatment, path, constraints);
+
+        checkNotNull(ingressLabel);
+        checkNotNull(egressLabel);
+        this.ingressLabel = ingressLabel;
+        this.egressLabel = egressLabel;
+    }
+
+    /**
+     * Returns the MPLS label which the ingress traffic should tagged.
+     *
+     * @return ingress MPLS label
+     */
+    public Optional<MplsLabel> ingressLabel() {
+        return ingressLabel;
+    }
+
+    /**
+     * Returns the MPLS label which the egress traffic should tagged.
+     *
+     * @return egress MPLS label
+     */
+    public Optional<MplsLabel> egressLabel() {
+        return egressLabel;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/DefaultLinkResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/DefaultLinkResourceRequest.java
index f4169de..bab3135 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/DefaultLinkResourceRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/DefaultLinkResourceRequest.java
@@ -117,6 +117,17 @@
         }
 
         /**
+         * Adds Mpls request.
+         *
+         * @return self
+         */
+        @Override
+        public Builder addMplsRequest() {
+            resources.add(new MplsLabelResourceRequest());
+            return this;
+        }
+
+        /**
          * Adds bandwidth request with bandwidth value.
          *
          * @param bandwidth bandwidth value to be requested
diff --git a/core/api/src/main/java/org/onosproject/net/resource/LinkResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/LinkResourceRequest.java
index 1172401..7313266 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/LinkResourceRequest.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/LinkResourceRequest.java
@@ -60,6 +60,13 @@
         public Builder addLambdaRequest();
 
         /**
+        * Adds MPLS request.
+        *
+        * @return self
+        */
+       public Builder addMplsRequest();
+
+        /**
          * Adds bandwidth request with bandwidth value.
          *
          * @param bandwidth bandwidth value to be requested
diff --git a/core/api/src/main/java/org/onosproject/net/resource/MplsLabel.java b/core/api/src/main/java/org/onosproject/net/resource/MplsLabel.java
new file mode 100644
index 0000000..7ef4096
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/MplsLabel.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.resource;
+
+import java.util.Objects;
+
+/**
+ * Representation of MPLS label resource.
+ */
+public final class MplsLabel extends LinkResource {
+
+    private final org.onlab.packet.MplsLabel mplsLabel;
+
+
+    /**
+     * Creates a new instance with given MPLS label.
+     *
+     * @param mplsLabel MPLS Label value to be assigned
+     */
+    public MplsLabel(int mplsLabel) {
+        this.mplsLabel =  org.onlab.packet.MplsLabel.mplsLabel(mplsLabel);
+    }
+
+    /**
+     * Creates a new instance with given MPLS label.
+     *
+     * @param mplsLabel mplsLabel value to be assigned
+     * @return {@link MplsLabel} instance with given bandwidth
+     */
+    public static MplsLabel valueOf(int mplsLabel) {
+        return new MplsLabel(mplsLabel);
+    }
+
+    /**
+     * Returns MPLS Label as an MPLS Label Object.
+     *
+     * @return MPLS label as an MPLS Label Object.
+     */
+    public org.onlab.packet.MplsLabel label() {
+        return mplsLabel;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof MplsLabel) {
+            MplsLabel that = (MplsLabel) obj;
+            return Objects.equals(this.mplsLabel, that.mplsLabel);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.mplsLabel);
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(this.mplsLabel);
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceAllocation.java b/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceAllocation.java
new file mode 100644
index 0000000..6fa0a04
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceAllocation.java
@@ -0,0 +1,77 @@
+ /*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.resource;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+/**
+ * Representation of allocated MPLS label resource.
+ */
+public class MplsLabelResourceAllocation extends MplsLabelResourceRequest
+        implements ResourceAllocation {
+    private final MplsLabel mplsLabel;
+
+    @Override
+    public ResourceType type() {
+        return ResourceType.MPLS_LABEL;
+    }
+
+    /**
+     * Creates a new {@link MplsLabelResourceAllocation} with {@link MplsLabel}
+     * object.
+     *
+     * @param mplsLabel allocated MPLS Label
+     */
+    public MplsLabelResourceAllocation(MplsLabel mplsLabel) {
+        this.mplsLabel = mplsLabel;
+    }
+
+    /**
+     * Returns the MPLS label resource.
+     *
+     * @return the MPLS label resource
+     */
+    public MplsLabel mplsLabel() {
+        return mplsLabel;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mplsLabel);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final MplsLabelResourceAllocation other = (MplsLabelResourceAllocation) obj;
+        return Objects.equals(this.mplsLabel, other.mplsLabel);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("mplsLabel", mplsLabel)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceRequest.java b/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceRequest.java
new file mode 100644
index 0000000..e0a69a0
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/resource/MplsLabelResourceRequest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.resource;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Representation of a request for lambda resource.
+ */
+public class MplsLabelResourceRequest implements ResourceRequest {
+
+    @Override
+    public ResourceType type() {
+        return ResourceType.MPLS_LABEL;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .toString();
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java b/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java
index 1ad0dde..1b75da5 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/ResourceType.java
@@ -28,4 +28,9 @@
      * Bandwidth resource type.
      */
     BANDWIDTH,
+
+    /**
+     * MPLS label resource type.
+     */
+    MPLS_LABEL,
 }
diff --git a/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java b/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
index 68c15ff..81e0d51 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/DefaultTrafficSelectorTest.java
@@ -28,6 +28,7 @@
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 import com.google.common.testing.EqualsTester;
@@ -251,7 +252,7 @@
         assertThat(selector, hasCriterionWithType(Type.IPV6_ND_TLL));
 
         selector = DefaultTrafficSelector.builder()
-                .matchMplsLabel(3).build();
+                .matchMplsLabel(MplsLabel.mplsLabel(3)).build();
         assertThat(selector, hasCriterionWithType(Type.MPLS_LABEL));
 
         selector = DefaultTrafficSelector.builder()
diff --git a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
index 42a7281..eb8d3b2 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/criteria/CriteriaTest.java
@@ -20,6 +20,7 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 import com.google.common.testing.EqualsTester;
@@ -186,8 +187,8 @@
     Criterion matchTargetLlAddr2 =
         Criteria.matchIPv6NDTargetLinkLayerAddress(llMac2);
 
-    int mpls1 = 1;
-    int mpls2 = 2;
+    MplsLabel mpls1 = MplsLabel.mplsLabel(1);
+    MplsLabel mpls2 = MplsLabel.mplsLabel(2);
     Criterion matchMpls1 = Criteria.matchMplsLabel(mpls1);
     Criterion sameAsMatchMpls1 = Criteria.matchMplsLabel(mpls1);
     Criterion matchMpls2 = Criteria.matchMplsLabel(mpls2);
diff --git a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
index bfb8409..070cd50 100644
--- a/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
+++ b/core/api/src/test/java/org/onosproject/net/flow/instructions/InstructionsTest.java
@@ -19,6 +19,7 @@
 import org.onosproject.net.PortNumber;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 
 import com.google.common.testing.EqualsTester;
@@ -527,16 +528,16 @@
                    is(not(equalTo(modIPv6FlowLabelInstruction2.hashCode()))));
     }
 
-    private Instruction modMplsLabelInstruction1 = Instructions.modMplsLabel(1);
-    private Instruction sameAsModMplsLabelInstruction1 = Instructions.modMplsLabel(1);
-    private Instruction modMplsLabelInstruction2 = Instructions.modMplsLabel(2);
+    private Instruction modMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1));
+    private Instruction sameAsModMplsLabelInstruction1 = Instructions.modMplsLabel(MplsLabel.mplsLabel(1));
+    private Instruction modMplsLabelInstruction2 = Instructions.modMplsLabel(MplsLabel.mplsLabel(2));
 
     /**
      * Test the modMplsLabel method.
      */
     @Test
     public void testModMplsMethod() {
-        final Instruction instruction = Instructions.modMplsLabel(33);
+        final Instruction instruction = Instructions.modMplsLabel(MplsLabel.mplsLabel(33));
         final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction =
                 checkAndConvert(instruction,
                         Instruction.Type.L2MODIFICATION,
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/MplsIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/MplsIntentCompiler.java
new file mode 100644
index 0000000..b8796d97
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/MplsIntentCompiler.java
@@ -0,0 +1,85 @@
+package org.onosproject.net.intent.impl;
+
+import static java.util.Arrays.asList;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultPath;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.MplsIntent;
+import org.onosproject.net.intent.MplsPathIntent;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.net.resource.LinkResourceAllocations;
+
+
+@Component(immediate = true)
+public class MplsIntentCompiler  extends ConnectivityIntentCompiler<MplsIntent> {
+
+    // TODO: use off-the-shell core provider ID
+    private static final ProviderId PID =
+            new ProviderId("core", "org.onosproject.core", true);
+    // TODO: consider whether the default cost is appropriate or not
+    public static final int DEFAULT_COST = 1;
+
+
+    @Activate
+    public void activate() {
+        intentManager.registerCompiler(MplsIntent.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterCompiler(MplsIntent.class);
+    }
+
+    @Override
+    public List<Intent> compile(MplsIntent intent, List<Intent> installable,
+                                Set<LinkResourceAllocations> resources) {
+        ConnectPoint ingressPoint = intent.ingressPoint();
+        ConnectPoint egressPoint = intent.egressPoint();
+
+        if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
+            List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false));
+            return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST), intent));
+        }
+
+        List<Link> links = new ArrayList<>();
+        Path path = getPath(intent, ingressPoint.deviceId(),
+                egressPoint.deviceId());
+
+        links.add(createEdgeLink(ingressPoint, true));
+        links.addAll(path.links());
+
+        links.add(createEdgeLink(egressPoint, false));
+
+        return asList(createPathIntent(new DefaultPath(PID, links, path.cost(),
+                                                       path.annotations()), intent));
+    }
+
+    /**
+     * Creates a path intent from the specified path and original
+     * connectivity intent.
+     *
+     * @param path   path to create an intent for
+     * @param intent original intent
+     */
+    private Intent createPathIntent(Path path,
+                                    MplsIntent intent) {
+        return new MplsPathIntent(intent.appId(),
+                              intent.selector(), intent.treatment(), path,
+                              intent.ingressLabel(), intent.egressLabel(),
+                              intent.constraints());
+    }
+
+
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/MplsPathIntentInstaller.java b/core/net/src/main/java/org/onosproject/net/intent/impl/MplsPathIntentInstaller.java
new file mode 100644
index 0000000..09c6551
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/MplsPathIntentInstaller.java
@@ -0,0 +1,296 @@
+package org.onosproject.net.intent.impl;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.Ethernet;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+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.FlowRuleBatchEntry;
+import org.onosproject.net.flow.FlowRuleBatchOperation;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
+import org.onosproject.net.flow.criteria.Criteria.EthTypeCriterion;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.Criterion.Type;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.IntentInstaller;
+import org.onosproject.net.intent.MplsPathIntent;
+import org.onosproject.net.link.LinkStore;
+import org.onosproject.net.resource.DefaultLinkResourceRequest;
+import org.onosproject.net.resource.LinkResourceAllocations;
+import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.LinkResourceService;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceType;
+import org.slf4j.Logger;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+/**
+ * Installer for {@link MplsPathIntent packet path connectivity intents}.
+ */
+@Component(immediate = true)
+public class MplsPathIntentInstaller implements IntentInstaller<MplsPathIntent> {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentExtensionService intentManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkResourceService resourceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkStore linkStore;
+
+    protected ApplicationId appId;
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication("org.onosproject.net.intent");
+        intentManager.registerInstaller(MplsPathIntent.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterInstaller(MplsPathIntent.class);
+    }
+
+    @Override
+    public List<FlowRuleBatchOperation> install(MplsPathIntent intent) {
+        LinkResourceAllocations allocations = assignMplsLabel(intent);
+        return generateRules(intent, allocations, FlowRuleOperation.ADD);
+
+    }
+
+    @Override
+    public List<FlowRuleBatchOperation> uninstall(MplsPathIntent intent) {
+        LinkResourceAllocations allocations = resourceService
+                .getAllocations(intent.id());
+        resourceService.releaseResources(allocations);
+
+        List<FlowRuleBatchOperation> rules = generateRules(intent,
+                                                           allocations,
+                                                           FlowRuleOperation.REMOVE);
+        return rules;
+    }
+
+    @Override
+    public List<FlowRuleBatchOperation> replace(MplsPathIntent oldIntent,
+                                                MplsPathIntent newIntent) {
+
+        List<FlowRuleBatchOperation> batches = Lists.newArrayList();
+        batches.addAll(uninstall(oldIntent));
+        batches.addAll(install(newIntent));
+        return batches;
+    }
+
+    private LinkResourceAllocations assignMplsLabel(MplsPathIntent intent) {
+
+        // TODO: do it better... Suggestions?
+        Set<Link> linkRequest = Sets.newHashSetWithExpectedSize(intent.path()
+                .links().size() - 2);
+        for (int i = 1; i <= intent.path().links().size() - 2; i++) {
+            Link link = intent.path().links().get(i);
+            linkRequest.add(link);
+            // add the inverse link. I want that the label is reserved both for
+            // the direct and inverse link
+            linkRequest.add(linkStore.getLink(link.dst(), link.src()));
+        }
+
+        LinkResourceRequest.Builder request = DefaultLinkResourceRequest
+                .builder(intent.id(), linkRequest).addMplsRequest();
+        LinkResourceAllocations reqMpls = resourceService
+                .requestResources(request.build());
+        return reqMpls;
+    }
+
+    private MplsLabel getMplsLabel(LinkResourceAllocations allocations,
+                                   Link link) {
+
+        for (ResourceAllocation allocation : allocations
+                .getResourceAllocation(link)) {
+            if (allocation.type() == ResourceType.MPLS_LABEL) {
+                return ((MplsLabelResourceAllocation) allocation).mplsLabel();
+
+            }
+        }
+        log.warn("MPLS label was not assigned successfully");
+        return null;
+    }
+
+    private List<FlowRuleBatchOperation> generateRules(MplsPathIntent intent,
+                                                       LinkResourceAllocations allocations,
+                                                       FlowRuleOperation operation) {
+
+        Iterator<Link> links = intent.path().links().iterator();
+        Link srcLink = links.next();
+        ConnectPoint prev = srcLink.dst();
+
+        Link link = links.next();
+        // List of flow rules to be installed
+        List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
+
+        // Ingress traffic
+        // Get the new MPLS label
+        MplsLabel mpls = getMplsLabel(allocations, link);
+        checkNotNull(mpls);
+        MplsLabel prevLabel = mpls;
+        rules.add(ingressFlow(prev.port(), link, intent, mpls, operation));
+
+        prev = link.dst();
+
+        while (links.hasNext()) {
+
+            link = links.next();
+
+            if (links.hasNext()) {
+                // Transit traffic
+                // Get the new MPLS label
+                mpls = getMplsLabel(allocations, link);
+                checkNotNull(mpls);
+                rules.add(transitFlow(prev.port(), link, intent,
+                                      prevLabel, mpls, operation));
+                prevLabel = mpls;
+
+            } else {
+                // Egress traffic
+                rules.add(egressFlow(prev.port(), link, intent,
+                                     prevLabel, operation));
+            }
+
+            prev = link.dst();
+        }
+        return Lists.newArrayList(new FlowRuleBatchOperation(rules, null, 0));
+    }
+
+    private FlowRuleBatchEntry ingressFlow(PortNumber inPort, Link link,
+                                           MplsPathIntent intent,
+                                           MplsLabel label,
+                                           FlowRuleOperation operation) {
+
+        TrafficSelector.Builder ingressSelector = DefaultTrafficSelector
+                .builder(intent.selector());
+        TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
+        ingressSelector.matchInPort(inPort);
+
+        if (intent.ingressLabel().isPresent()) {
+            ingressSelector.matchEthType(Ethernet.MPLS_UNICAST)
+                    .matchMplsLabel(intent.ingressLabel().get());
+
+            // Swap the MPLS label
+            treat.setMpls(label.label());
+        } else {
+            // Push and set the MPLS label
+            treat.pushMpls().setMpls(label.label());
+        }
+        // Add the output action
+        treat.setOutput(link.src().port());
+
+        return flowRuleBatchEntry(intent, link.src().deviceId(),
+                                  ingressSelector.build(), treat.build(),
+                                  operation);
+    }
+
+    private FlowRuleBatchEntry transitFlow(PortNumber inPort, Link link,
+                                           MplsPathIntent intent,
+                                           MplsLabel prevLabel,
+                                           MplsLabel outLabel,
+                                           FlowRuleOperation operation) {
+
+        // Ignore the ingress Traffic Selector and use only the MPLS label
+        // assigned in the previous link
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
+                .matchMplsLabel(prevLabel.label());
+        TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
+
+        // Set the new label only if the label on the packet is
+        // different
+        if (prevLabel.equals(outLabel)) {
+            treat.setMpls(outLabel.label());
+        }
+
+        treat.setOutput(link.src().port());
+        return flowRuleBatchEntry(intent, link.src().deviceId(),
+                                  selector.build(), treat.build(), operation);
+    }
+
+    private FlowRuleBatchEntry egressFlow(PortNumber inPort, Link link,
+                                          MplsPathIntent intent,
+                                          MplsLabel prevLabel,
+                                          FlowRuleOperation operation) {
+        // egress point: either set the egress MPLS label or pop the
+        // MPLS label based on the intent annotations
+
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchInPort(inPort).matchEthType(Ethernet.MPLS_UNICAST)
+                .matchMplsLabel(prevLabel.label());
+
+        // apply the intent's treatments
+        TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder(intent
+                .treatment());
+
+        if (intent.egressLabel().isPresent()) {
+            treat.setMpls(intent.egressLabel().get());
+        } else {
+            // if the ingress ethertype is defined, the egress traffic
+            // will be use that value, otherwise the IPv4 ethertype is used.
+            Criterion c = intent.selector().getCriterion(Type.ETH_TYPE);
+            if (c != null && c instanceof EthTypeCriterion) {
+                EthTypeCriterion ethertype = (EthTypeCriterion) c;
+                treat.popMpls((short) ethertype.ethType());
+            } else {
+                treat.popMpls(Ethernet.TYPE_IPV4);
+            }
+
+        }
+        treat.setOutput(link.src().port());
+        return flowRuleBatchEntry(intent, link.src().deviceId(),
+                                  selector.build(), treat.build(), operation);
+    }
+
+    protected FlowRuleBatchEntry flowRuleBatchEntry(MplsPathIntent intent,
+                                                    DeviceId deviceId,
+                                                    TrafficSelector selector,
+                                                    TrafficTreatment treat,
+                                                    FlowRuleOperation operation) {
+        FlowRule rule = new DefaultFlowRule(
+                                            deviceId,
+                                            selector,
+                                            treat,
+                                            123, // FIXME 123
+                                            appId,
+                                            0,
+                                            true);
+        return new FlowRuleBatchEntry(operation, rule, intent.id()
+                .fingerprint());
+
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
index f583ebd..fadb152 100644
--- a/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/LinkResourceManager.java
@@ -49,6 +49,9 @@
 import org.onosproject.net.resource.LinkResourceService;
 import org.onosproject.net.resource.LinkResourceStore;
 import org.onosproject.net.resource.LinkResourceStoreDelegate;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
+import org.onosproject.net.resource.MplsLabelResourceRequest;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceRequest;
 import org.onosproject.net.resource.ResourceType;
@@ -104,6 +107,7 @@
         return lambdas;
     }
 
+
     /**
      * Returns available lambdas on specified links.
      *
@@ -121,13 +125,36 @@
         return lambdas;
     }
 
+
+    /**
+     * Returns available MPLS label on specified link.
+     *
+     * @param link the link
+     * @return available MPLS labels on specified link
+     */
+    private Iterable<MplsLabel> getAvailableMplsLabels(Link link) {
+        Set<ResourceAllocation> resAllocs = store.getFreeResources(link);
+        if (resAllocs == null) {
+            return Collections.emptySet();
+        }
+        Set<MplsLabel> mplsLabels = new HashSet<>();
+        for (ResourceAllocation res : resAllocs) {
+            if (res.type() == ResourceType.MPLS_LABEL) {
+
+                mplsLabels.add(((MplsLabelResourceAllocation) res).mplsLabel());
+            }
+        }
+
+        return mplsLabels;
+    }
+
     @Override
     public LinkResourceAllocations requestResources(LinkResourceRequest req) {
         // TODO Concatenate multiple bandwidth requests.
         // TODO Support multiple lambda resource requests.
         // TODO Throw appropriate exception.
-
         Set<ResourceAllocation> allocs = new HashSet<>();
+        Map<Link, Set<ResourceAllocation>> allocsPerLink = new HashMap<>();
         for (ResourceRequest r : req.resources()) {
             switch (r.type()) {
             case BANDWIDTH:
@@ -144,6 +171,24 @@
                     return null;
                 }
                 break;
+            case MPLS_LABEL:
+                for (Link link : req.links()) {
+                    if (allocsPerLink.get(link) == null) {
+                        allocsPerLink.put(link,
+                                          new HashSet<ResourceAllocation>());
+                    }
+                    Iterator<MplsLabel> mplsIter = getAvailableMplsLabels(link)
+                            .iterator();
+                    if (mplsIter.hasNext()) {
+                        allocsPerLink.get(link)
+                                .add(new MplsLabelResourceAllocation(mplsIter
+                                             .next()));
+                    } else {
+                        log.info("Failed to allocate MPLS resource.");
+                        break;
+                    }
+                }
+                break;
             default:
                 break;
             }
@@ -151,7 +196,8 @@
 
         Map<Link, Set<ResourceAllocation>> allocations = new HashMap<>();
         for (Link link : req.links()) {
-            allocations.put(link, allocs);
+            allocations.put(link, new HashSet<ResourceAllocation>(allocs));
+            allocations.get(link).addAll(allocsPerLink.get(link));
         }
         LinkResourceAllocations result =
                 new DefaultLinkResourceAllocations(req, allocations);
@@ -203,6 +249,8 @@
             case LAMBDA:
                 result.add(new LambdaResourceRequest());
                 break;
+            case MPLS_LABEL:
+                result.add(new MplsLabelResourceRequest());
             default:
                 break;
             }
diff --git a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
index 2e18430..7099464 100644
--- a/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/group/impl/GroupManagerTest.java
@@ -24,6 +24,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.DefaultGroupId;
@@ -162,7 +163,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
@@ -244,7 +245,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
@@ -280,7 +281,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
             buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
@@ -338,7 +339,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                     tBuilder.build()));
         }
@@ -411,7 +412,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/MplsIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/MplsIntentCompilerTest.java
new file mode 100644
index 0000000..1a81225
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/MplsIntentCompilerTest.java
@@ -0,0 +1,175 @@
+package org.onosproject.net.intent.impl;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+
+import org.onlab.packet.MplsLabel;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.intent.AbstractIntentTest;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentTestsMocks;
+import org.onosproject.net.intent.MplsIntent;
+import org.onosproject.net.intent.MplsPathIntent;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.NetTestTools.APP_ID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+import static org.onosproject.net.PortNumber.portNumber;
+import static org.onosproject.net.intent.LinksHaveEntryWithSourceDestinationPairMatcher.linksHasPath;
+
+/**
+ * Unit tests for the HostToHost intent compiler.
+ */
+public class MplsIntentCompilerTest extends AbstractIntentTest {
+
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
+    private TrafficSelector selector = new IntentTestsMocks.MockSelector();
+    private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
+
+    /**
+     * Creates a PointToPoint intent based on ingress and egress device Ids.
+     *
+     * @param ingressIdString string for id of ingress device
+     * @param egressIdString  string for id of egress device
+     * @return PointToPointIntent for the two devices
+     */
+    private MplsIntent makeIntent(String ingressIdString,  Optional<MplsLabel> ingressLabel,
+                                          String egressIdString, Optional<MplsLabel> egressLabel) {
+
+        return new MplsIntent(APPID, selector, treatment,
+                                      connectPoint(ingressIdString, 1),
+                                      ingressLabel,
+                                      connectPoint(egressIdString, 1),
+                                      egressLabel);
+    }
+    /**
+     * Creates a compiler for HostToHost intents.
+     *
+     * @param hops string array describing the path hops to use when compiling
+     * @return HostToHost intent compiler
+     */
+    private MplsIntentCompiler makeCompiler(String[] hops) {
+        MplsIntentCompiler compiler =
+                new MplsIntentCompiler();
+        compiler.pathService = new IntentTestsMocks.MockPathService(hops);
+        return compiler;
+    }
+
+
+    /**
+     * Tests a pair of devices in an 8 hop path, forward direction.
+     */
+    @Test
+    public void testForwardPathCompilation() {
+        Optional<MplsLabel> ingressLabel = Optional.ofNullable(MplsLabel.mplsLabel(10));
+        Optional<MplsLabel> egressLabel = Optional.ofNullable(MplsLabel.mplsLabel(20));
+
+        MplsIntent intent = makeIntent("d1", ingressLabel, "d8", egressLabel);
+        assertThat(intent, is(notNullValue()));
+
+        String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+        MplsIntentCompiler compiler = makeCompiler(hops);
+        assertThat(compiler, is(notNullValue()));
+
+        List<Intent> result = compiler.compile(intent, null, null);
+        assertThat(result, is(Matchers.notNullValue()));
+        assertThat(result, hasSize(1));
+        Intent forwardResultIntent = result.get(0);
+        assertThat(forwardResultIntent instanceof MplsPathIntent, is(true));
+
+        if (forwardResultIntent instanceof MplsIntent) {
+            MplsPathIntent forwardPathIntent = (MplsPathIntent) forwardResultIntent;
+            // 7 links for the hops, plus one default lnk on ingress and egress
+            assertThat(forwardPathIntent.path().links(), hasSize(hops.length + 1));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d1", "d2"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d2", "d3"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d3", "d4"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d4", "d5"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d5", "d6"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d6", "d7"));
+            assertThat(forwardPathIntent.path().links(), linksHasPath("d7", "d8"));
+            assertEquals(forwardPathIntent.egressLabel(), egressLabel);
+            assertEquals(forwardPathIntent.ingressLabel(), ingressLabel);
+        }
+    }
+
+    /**
+     * Tests a pair of devices in an 8 hop path, forward direction.
+     */
+    @Test
+    public void testReversePathCompilation() {
+        Optional<MplsLabel> ingressLabel = Optional.ofNullable(MplsLabel.mplsLabel(10));
+        Optional<MplsLabel> egressLabel = Optional.ofNullable(MplsLabel.mplsLabel(20));
+
+        MplsIntent intent = makeIntent("d8", ingressLabel, "d1", egressLabel);
+        assertThat(intent, is(notNullValue()));
+
+        String[] hops = {"d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8"};
+        MplsIntentCompiler compiler = makeCompiler(hops);
+        assertThat(compiler, is(notNullValue()));
+
+        List<Intent> result = compiler.compile(intent, null, null);
+        assertThat(result, is(Matchers.notNullValue()));
+        assertThat(result, hasSize(1));
+        Intent reverseResultIntent = result.get(0);
+        assertThat(reverseResultIntent instanceof MplsPathIntent, is(true));
+
+        if (reverseResultIntent instanceof MplsIntent) {
+            MplsPathIntent reversePathIntent = (MplsPathIntent) reverseResultIntent;
+            assertThat(reversePathIntent.path().links(), hasSize(hops.length + 1));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d2", "d1"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d3", "d2"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d4", "d3"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d5", "d4"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d6", "d5"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d7", "d6"));
+            assertThat(reversePathIntent.path().links(), linksHasPath("d8", "d7"));
+            assertEquals(reversePathIntent.egressLabel(), egressLabel);
+            assertEquals(reversePathIntent.ingressLabel(), ingressLabel);
+        }
+    }
+
+    /**
+     * Tests compilation of the intent which designates two different ports on the same switch.
+     */
+    @Test
+    public void testSameSwitchDifferentPortsIntentCompilation() {
+        ConnectPoint src = new ConnectPoint(deviceId("1"), portNumber(1));
+        ConnectPoint dst = new ConnectPoint(deviceId("1"), portNumber(2));
+        MplsIntent intent = new MplsIntent(APP_ID, selector, treatment, src, Optional.empty(), dst, Optional.empty());
+
+        String[] hops = {"1"};
+        MplsIntentCompiler sut = makeCompiler(hops);
+
+        List<Intent> compiled = sut.compile(intent, null, null);
+
+        assertThat(compiled, hasSize(1));
+        assertThat(compiled.get(0), is(instanceOf(MplsPathIntent.class)));
+        Path path = ((MplsPathIntent) compiled.get(0)).path();
+
+        assertThat(path.links(), hasSize(2));
+        Link firstLink = path.links().get(0);
+        assertThat(firstLink, is(createEdgeLink(src, true)));
+        Link secondLink = path.links().get(1);
+        assertThat(secondLink, is(createEdgeLink(dst, false)));
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
index 0119e1f..73b053d 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
@@ -42,6 +42,8 @@
 import org.onosproject.net.resource.LinkResourceAllocations;
 import org.onosproject.net.resource.LinkResourceEvent;
 import org.onosproject.net.resource.LinkResourceStore;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocationException;
 import org.onosproject.net.resource.ResourceType;
@@ -105,9 +107,10 @@
     // Link annotation key name to use as max lambda
     private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
 
+    // Max MPLS labels: 2^20 – 1
+    private int maxMplsLabel = 0xFFFFF;
     private StoreSerializer serializer;
 
-
     void createTable(String tableName) {
         boolean tableReady = false;
         do {
@@ -150,6 +153,9 @@
         if (type == ResourceType.LAMBDA) {
             return getLambdaResourceCapacity(link);
         }
+        if (type == ResourceType.MPLS_LABEL) {
+            return getMplsResourceCapacity();
+        }
         return null;
     }
 
@@ -189,6 +195,17 @@
         return new BandwidthResourceAllocation(bandwidth);
     }
 
+    private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
+        Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
+        //Ignoring reserved labels of 0 through 15
+        for (int i = 16; i <= maxMplsLabel; i++) {
+            allocations.add(new MplsLabelResourceAllocation(MplsLabel
+                    .valueOf(i)));
+
+        }
+        return allocations;
+    }
+
     private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
         Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
         for (ResourceType type : ResourceType.values()) {
@@ -273,6 +290,34 @@
                 free.put(type, freeL);
                 break;
             }
+            case MPLS_LABEL:
+            {
+                Set<? extends ResourceAllocation> mpls = caps.get(type);
+                if (mpls == null || mpls.isEmpty()) {
+                    // nothing left
+                    break;
+                }
+                Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
+                for (ResourceAllocation r : mpls) {
+                    if (r instanceof MplsLabelResourceAllocation) {
+                        freeLabel.add((MplsLabelResourceAllocation) r);
+                    }
+                }
+
+                // enumerate current allocations, removing resources
+                for (LinkResourceAllocations alloc : allocations) {
+                    Set<ResourceAllocation> types = alloc
+                            .getResourceAllocation(link);
+                    for (ResourceAllocation a : types) {
+                        if (a instanceof MplsLabelResourceAllocation) {
+                            freeLabel.remove(a);
+                        }
+                    }
+                }
+
+                free.put(type, freeLabel);
+                break;
+            }
 
             default:
                 break;
@@ -298,7 +343,6 @@
                        encodeIntentAllocations(alloc));
     }
 
-
     @Override
     public void allocateResources(LinkResourceAllocations allocations) {
         checkNotNull(allocations);
@@ -313,8 +357,9 @@
         }
 
         BatchWriteRequest batch = tx.build();
-//        log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
-//        log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
+//         log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
+//         log.info("Link: {}",
+        // databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
 
         BatchWriteResult result = databaseService.batchWrite(batch);
         if (!result.isSuccessful()) {
@@ -407,6 +452,21 @@
                                     link,
                                     lambdaAllocation.lambda().toInt()));
                 }
+            } else if (req instanceof MplsLabelResourceAllocation) {
+
+                final MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
+                // check if allocation should be accepted
+                if (!avail.contains(req)) {
+                    // requested mpls label was not available
+                    throw new ResourceAllocationException(
+                                                          PositionalParameterStringFormatter
+                                                                  .format("Unable to allocate MPLS label for "
+                                                                          + "link {} MPLS label is {}",
+                                                                          link,
+                                                                          mplsAllocation
+                                                                                  .mplsLabel()
+                                                                                  .toString()));
+                }
             }
         }
         // all requests allocatable => add allocation
@@ -466,8 +526,7 @@
 
         // Issue events to force recompilation of intents.
 
-        final List<LinkResourceAllocations> releasedResources =
-                ImmutableList.of(allocations);
+        final List<LinkResourceAllocations> releasedResources = ImmutableList.of(allocations);
         return new LinkResourceEvent(
                 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
                 releasedResources);
@@ -485,32 +544,32 @@
     }
 
     private String toLinkDbKey(LinkKey linkid) {
-        // introduce cache if necessary
+//         introduce cache if necessary
         return linkid.toString();
-        // Note: Above is irreversible, if we need reverse conversion
-        // we may need something like below, due to String only limitation
-//        byte[] bytes = serializer.encode(linkid);
-//        StringBuilder builder = new StringBuilder(bytes.length * 4);
-//        boolean isFirst = true;
-//        for (byte b : bytes) {
-//            if (!isFirst) {
-//                builder.append(',');
-//            }
-//            builder.append(b);
-//            isFirst = false;
-//        }
-//        return builder.toString();
+//         Note: Above is irreversible, if we need reverse conversion
+//         we may need something like below, due to String only limitation
+//         byte[] bytes = serializer.encode(linkid);
+//         StringBuilder builder = new StringBuilder(bytes.length * 4);
+//         boolean isFirst = true;
+//         for (byte b : bytes) {
+//         if (!isFirst) {
+//         builder.append(',');
+//         }
+//         builder.append(b);
+//         isFirst = false;
+//         }
+//         return builder.toString();
     }
 
-//    private LinkKey toLinkKey(String linkKey) {
-//        String[] bytes = linkKey.split(",");
-//        ByteBuffer buf = ByteBuffer.allocate(bytes.length);
-//        for (String bs : bytes) {
-//            buf.put(Byte.parseByte(bs));
-//        }
-//        buf.flip();
-//        return serializer.decode(buf);
-//    }
+//     private LinkKey toLinkKey(String linkKey) {
+//     String[] bytes = linkKey.split(",");
+//     ByteBuffer buf = ByteBuffer.allocate(bytes.length);
+//     for (String bs : bytes) {
+//     buf.put(Byte.parseByte(bs));
+//     }
+//     buf.flip();
+//     return serializer.decode(buf);
+//     }
 
     private String toIntentDbKey(IntentId intentid) {
         return intentid.toString();
@@ -565,16 +624,16 @@
         Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
 
         return FluentIterable.from(all.values())
-            .transform(new Function<VersionedValue, LinkResourceAllocations>() {
+                .transform(new Function<VersionedValue, LinkResourceAllocations>() {
 
-                @Override
-                public LinkResourceAllocations apply(VersionedValue input) {
-                    if (input == null || input.value() == null) {
-                        return null;
-                    }
-                    return decodeIntentAllocations(input.value());
-                }
-            })
-            .filter(notNull());
+                               @Override
+                               public LinkResourceAllocations apply(VersionedValue input) {
+                                   if (input == null || input.value() == null) {
+                                       return null;
+                                   }
+                                   return decodeIntentAllocations(input.value());
+                               }
+                           })
+                           .filter(notNull());
     }
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
index 7344862..52494dd 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
@@ -43,6 +43,8 @@
 import org.onosproject.net.resource.LinkResourceAllocations;
 import org.onosproject.net.resource.LinkResourceEvent;
 import org.onosproject.net.resource.LinkResourceStore;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocationException;
 import org.onosproject.net.resource.ResourceType;
@@ -103,6 +105,9 @@
     // Link annotation key name to use as max lambda
     private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
 
+    // Max MPLS labels: 2^20 – 1
+    private int maxMplsLabel = 0xFFFFF;
+
     @Override
     @Activate
     public void activate() {
@@ -141,6 +146,9 @@
         if (type == ResourceType.LAMBDA) {
             return getLambdaResourceCapacity(link);
         }
+        if (type == ResourceType.MPLS_LABEL) {
+            return getMplsResourceCapacity();
+        }
         return null;
     }
 
@@ -180,6 +188,17 @@
         return new BandwidthResourceAllocation(bandwidth);
     }
 
+    private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
+        Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
+        //Ignoring reserved labels of 0 through 15
+        for (int i = 16; i <= maxMplsLabel; i++) {
+            allocations.add(new MplsLabelResourceAllocation(MplsLabel
+                    .valueOf(i)));
+
+        }
+        return allocations;
+    }
+
     private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
         Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
         for (ResourceType type : ResourceType.values()) {
@@ -275,6 +294,33 @@
                 break;
             }
 
+            case MPLS_LABEL:
+                Set<? extends ResourceAllocation> mpls = caps.get(type);
+                if (mpls == null || mpls.isEmpty()) {
+                    // nothing left
+                    break;
+                }
+                Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
+                for (ResourceAllocation r : mpls) {
+                    if (r instanceof MplsLabelResourceAllocation) {
+                        freeLabel.add((MplsLabelResourceAllocation) r);
+                    }
+                }
+
+                // enumerate current allocations, removing resources
+                for (LinkResourceAllocations alloc : allocations) {
+                    Set<ResourceAllocation> types = alloc
+                            .getResourceAllocation(link);
+                    for (ResourceAllocation a : types) {
+                        if (a instanceof MplsLabelResourceAllocation) {
+                            freeLabel.remove(a);
+                        }
+                    }
+                }
+
+                free.put(type, freeLabel);
+                break;
+
             default:
                 break;
             }
@@ -354,6 +400,18 @@
                                     link,
                                     lambdaAllocation.lambda().toInt()));
                 }
+            } else if (req instanceof MplsLabelResourceAllocation) {
+                MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
+                if (!avail.contains(req)) {
+                    throw new ResourceAllocationException(
+                                                          PositionalParameterStringFormatter
+                                                                  .format("Unable to allocate MPLS label for link "
+                                                                          + "{} MPLS label is {}",
+                                                                          link,
+                                                                          mplsAllocation
+                                                                                  .mplsLabel()
+                                                                                  .toString()));
+                }
             }
         }
         // all requests allocatable => add allocation
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 846fa75..4e9fe4f 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -87,6 +87,8 @@
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.MplsIntent;
+import org.onosproject.net.intent.MplsPathIntent;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
@@ -113,6 +115,9 @@
 import org.onosproject.net.resource.LambdaResourceAllocation;
 import org.onosproject.net.resource.LambdaResourceRequest;
 import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
+import org.onosproject.net.resource.MplsLabelResourceRequest;
 import org.onosproject.store.Timestamp;
 import org.onosproject.store.service.BatchReadRequest;
 import org.onosproject.store.service.BatchWriteRequest;
@@ -345,6 +350,14 @@
             .register(WriteStatus.class)
             .register(VersionedValue.class)
             .register(DefaultGroupId.class)
+            .register(
+                    MplsIntent.class,
+                    MplsPathIntent.class,
+                    MplsLabelResourceAllocation.class,
+                    MplsLabelResourceRequest.class,
+                    MplsLabel.class,
+                    org.onlab.packet.MplsLabel.class
+                    )
 
             .build();
 
diff --git a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
index 33d7118..f890754 100644
--- a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
+++ b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
@@ -25,6 +25,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.GroupId;
@@ -184,7 +185,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
@@ -244,7 +245,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
@@ -347,7 +348,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                     tBuilder.build()));
         }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
index 8f2b5f4..0b9b0cd 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowEntryBuilder.java
@@ -16,11 +16,13 @@
 package org.onosproject.provider.of.flow.impl;
 
 import com.google.common.collect.Lists;
+
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.Ip6Prefix;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.net.DeviceId;
@@ -309,7 +311,7 @@
         case MPLS_LABEL:
             @SuppressWarnings("unchecked")
             OFOxm<U32> labelId = (OFOxm<U32>) oxm;
-            builder.setMpls((int) labelId.getValue().getValue());
+            builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue()));
             break;
         case ARP_OP:
         case ARP_SHA:
@@ -471,6 +473,9 @@
                 break;
             case UDP_DST:
                 builder.matchUdpDst((short) match.get(MatchField.UDP_DST).getPort());
+            case MPLS_LABEL:
+                builder.matchMplsLabel(MplsLabel.mplsLabel((int) match.get(MatchField.MPLS_LABEL)
+                                            .getValue()));
                 break;
             case SCTP_SRC:
                 builder.matchSctpSrc((short) match.get(MatchField.SCTP_SRC).getPort());
@@ -538,10 +543,6 @@
                 mac = MacAddress.valueOf(match.get(MatchField.IPV6_ND_TLL).getLong());
                 builder.matchIPv6NDTargetLinkLayerAddress(mac);
                 break;
-            case MPLS_LABEL:
-                builder.matchMplsLabel((int) match.get(MatchField.MPLS_LABEL)
-                                            .getValue());
-                break;
             case IPV6_EXTHDR:
                 builder.matchIPv6ExthdrFlags((int) match.get(MatchField.IPV6_EXTHDR)
                                             .getValue());
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
index b21ea0b..490a157 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilder.java
@@ -362,7 +362,7 @@
                 break;
             case MPLS_LABEL:
                 Criteria.MplsCriterion mp = (Criteria.MplsCriterion) c;
-                mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label()));
+                mBuilder.setExact(MatchField.MPLS_LABEL, U32.of(mp.label().toInt()));
                 break;
             case IPV6_EXTHDR:
                 Criteria.IPv6ExthdrFlagsCriterion exthdrFlagsCriterion =
diff --git a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
index 8ff8e70..22a8345 100644
--- a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
+++ b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
@@ -16,8 +16,10 @@
 package org.onosproject.provider.of.group.impl;
 
 import com.google.common.collect.Lists;
+
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.core.DefaultGroupId;
 import org.onosproject.core.GroupId;
@@ -263,7 +265,7 @@
             case MPLS_LABEL:
                 @SuppressWarnings("unchecked")
                 OFOxm<U32> labelId = (OFOxm<U32>) oxm;
-                builder.setMpls((int) labelId.getValue().getValue());
+                builder.setMpls(MplsLabel.mplsLabel((int) labelId.getValue().getValue()));
                 break;
             case ARP_OP:
             case ARP_SHA:
diff --git a/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java b/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java
new file mode 100644
index 0000000..631325e
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java
@@ -0,0 +1,72 @@
+package org.onlab.packet;
+
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Representation of a MPLS label.
+ */
+public class MplsLabel {
+
+    private final int mplsLabel;
+
+    // An MPLS Label maximum 20 bits.
+    public static final int MAX_MPLS = 0xFFFFF;
+
+    protected MplsLabel(int value) {
+        this.mplsLabel = value;
+    }
+
+    public static MplsLabel mplsLabel(int value) {
+
+        if (value > MAX_MPLS) {
+            throw new IllegalArgumentException("value exceeds allowed maximum MPLS label value (0xFFFFF)");
+        }
+        return new MplsLabel(value);
+    }
+
+    public int toInt() {
+        return this.mplsLabel;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof MplsLabel) {
+
+            MplsLabel other = (MplsLabel) obj;
+
+            if (this.mplsLabel == other.mplsLabel) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return this.mplsLabel;
+    }
+
+    @Override
+    public String toString() {
+        return String.valueOf(this.mplsLabel);
+    }
+}
diff --git a/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index d270555..0be03d8 100644
--- a/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/web/api/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -285,7 +285,7 @@
         public ObjectNode formatCriterion(ObjectNode root, Criterion criterion) {
             final Criteria.MplsCriterion mplsCriterion =
                     (Criteria.MplsCriterion) criterion;
-            return root.put("label", mplsCriterion.label());
+            return root.put("label", mplsCriterion.label().toInt());
         }
     }
 
diff --git a/web/api/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java b/web/api/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
index 873424b..a8dc560 100644
--- a/web/api/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
+++ b/web/api/src/test/java/org/onosproject/codec/impl/CriterionCodecTest.java
@@ -22,6 +22,7 @@
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
@@ -374,7 +375,7 @@
      */
     @Test
     public void matchMplsLabelTest() {
-        Criterion criterion = Criteria.matchMplsLabel(0xffffe);
+        Criterion criterion = Criteria.matchMplsLabel(MplsLabel.mplsLabel(0xffffe));
         ObjectNode result = criterionCodec.encode(criterion, context);
         assertThat(result, matchesCriterion(criterion));
     }
diff --git a/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java b/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
index 3c5f119..beb9545 100644
--- a/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
+++ b/web/api/src/test/java/org/onosproject/codec/impl/CriterionJsonMatcher.java
@@ -397,7 +397,7 @@
      * @return true if the JSON matches the criterion, false otherwise.
      */
     private boolean matchCriterion(Criteria.MplsCriterion criterion) {
-        final int label = criterion.label();
+        final int label = criterion.label().toInt();
         final int jsonLabel = jsonCriterion.get("label").intValue();
         if (label != jsonLabel) {
             description.appendText("label was " + Integer.toString(jsonLabel));
diff --git a/web/api/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java b/web/api/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java
index 923573e..78685c1 100644
--- a/web/api/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java
+++ b/web/api/src/test/java/org/onosproject/codec/impl/InstructionCodecTest.java
@@ -20,6 +20,7 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip6Address;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
@@ -220,7 +221,7 @@
     public void modMplsLabelInstructionTest() {
         final L2ModificationInstruction.ModMplsLabelInstruction instruction =
                 (L2ModificationInstruction.ModMplsLabelInstruction)
-                        Instructions.modMplsLabel(99);
+                        Instructions.modMplsLabel(MplsLabel.mplsLabel(99));
         final ObjectNode instructionJson =
                 instructionCodec.encode(instruction, context);
         assertThat(instructionJson, matchesInstruction(instruction));
diff --git a/web/api/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java b/web/api/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
index 8814add..919d25d 100644
--- a/web/api/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
+++ b/web/api/src/test/java/org/onosproject/codec/impl/IntentCodecTest.java
@@ -21,6 +21,7 @@
 import org.junit.Test;
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
 import org.onosproject.core.ApplicationId;
@@ -54,8 +55,6 @@
 import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent;
 import static org.onosproject.net.NetTestTools.did;
 import static org.onosproject.net.NetTestTools.hid;
-
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.notNullValue;
 
@@ -123,7 +122,7 @@
         DeviceId did3 = did("device3");
         final TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchIPProtocol((byte) 3)
-                .matchMplsLabel(4)
+                .matchMplsLabel(MplsLabel.mplsLabel(4))
                 .matchOpticalSignalType((short) 5)
                 .matchLambda((short) 6)
                 .matchEthDst(MacAddress.BROADCAST)
@@ -131,7 +130,7 @@
                 .build();
         final TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .setLambda((short) 33)
-                .setMpls(44)
+                .setMpls(MplsLabel.mplsLabel(44))
                 .setOutput(PortNumber.CONTROLLER)
                 .setEthDst(MacAddress.BROADCAST)
                 .build();