Fixes [ONOS-5412] and implements [ONOS-5300]

Changes:
- Adds a new Interface for the selection algorithms;
- Re-implements FirstFit and Random selection;
- Adds a new option to select the algorithm;
- LabelAllocator provides a single interface;
- Fix MPLS encapsulation;

Change-Id: Ib07942355c45b7b9e7093fa85964c2ac20800b60
diff --git a/core/api/src/test/java/org/onosproject/net/resource/MockResourceService.java b/core/api/src/test/java/org/onosproject/net/resource/MockResourceService.java
index 6189b6b..436a763 100644
--- a/core/api/src/test/java/org/onosproject/net/resource/MockResourceService.java
+++ b/core/api/src/test/java/org/onosproject/net/resource/MockResourceService.java
@@ -36,6 +36,8 @@
 public class MockResourceService implements ResourceService {
 
     private final Map<Resource, ResourceConsumer> assignment = new HashMap<>();
+    public Set<Short> availableVlanLabels = new HashSet<>();
+    public Set<Integer> availableMplsLabels = new HashSet<>();
 
     @Override
     public List<ResourceAllocation> allocate(ResourceConsumer consumer, List<? extends Resource> resources) {
@@ -98,15 +100,45 @@
 
 
     /**
-     * It adds a number of VLAN ids in order to test the random behavior.
+     * Binds VLAN Ids to a parent resource, given a parent resource.
      *
      * @param parent the parent resource
-     * @return a set of VLAN ids
+     * @return the VLAN Ids allocated
      */
     private Collection<Resource> addVlanIds(DiscreteResourceId parent) {
         Collection<Resource> resources = new HashSet<>();
-        for (int i = VlanId.NO_VID + 1; i < VlanId.MAX_VLAN; i++) {
-            resources.add(Resources.discrete(parent).resource().child(VlanId.vlanId((short) i)));
+        if (!this.availableVlanLabels.isEmpty()) {
+            this.availableVlanLabels.forEach(label -> {
+                if (label > VlanId.NO_VID && label < VlanId.MAX_VLAN) {
+                    resources.add(Resources.discrete(parent).resource().child(VlanId.vlanId(label)));
+                }
+            });
+        } else {
+            for (int i = VlanId.NO_VID + 1; i < 1000; i++) {
+                resources.add(Resources.discrete(parent).resource().child(VlanId.vlanId((short) i)));
+            }
+        }
+        return resources;
+    }
+
+    /**
+     * Binds MPLS labels to a parent resource, given a parent resource.
+     *
+     * @param parent the parent resource
+     * @return the MPLS labels allocated
+     */
+    private Collection<Resource> addMplsLabels(DiscreteResourceId parent) {
+        Collection<Resource> resources = new HashSet<>();
+        if (!this.availableMplsLabels.isEmpty()) {
+            this.availableMplsLabels.forEach(label -> {
+                if (label < MplsLabel.MAX_MPLS) {
+                    resources.add(Resources.discrete(parent).resource().child(MplsLabel.mplsLabel(label)));
+                }
+            });
+        } else {
+            for (int i = 1; i < 1000; i++) {
+                resources.add(Resources.discrete(parent).resource().child(MplsLabel.mplsLabel(i)));
+            }
         }
         return resources;
     }
@@ -115,7 +147,7 @@
     public Set<Resource> getAvailableResources(DiscreteResourceId parent) {
         Collection<Resource> resources = new HashSet<>();
         resources.addAll(addVlanIds(parent));
-        resources.add(Resources.discrete(parent).resource().child(MplsLabel.mplsLabel(10)));
+        resources.addAll(addMplsLabels(parent));
         resources.add(Resources.discrete(parent).resource().child(TributarySlot.of(1)));
         resources.add(Resources.discrete(parent).resource().child(TributarySlot.of(2)));
         resources.add(Resources.discrete(parent).resource().child(TributarySlot.of(3)));
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
index fea1e7b..50578de 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.resource.impl.LabelAllocator;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
@@ -57,9 +58,15 @@
     private static final boolean DEFAULT_FLOW_OBJECTIVES = false;
     @Property(name = "useFlowObjectives",
             boolValue = DEFAULT_FLOW_OBJECTIVES,
-            label = "Indicates whether to use flow objective-based compilers")
+            label = "Indicates whether or not to use flow objective-based compilers")
     private boolean useFlowObjectives = DEFAULT_FLOW_OBJECTIVES;
 
+    private static final String DEFAULT_LABEL_SELECTION = "RANDOM";
+    @Property(name = "labelSelection",
+            value = DEFAULT_LABEL_SELECTION,
+            label = "Defines the label selection algorithm - RANDOM or FIRST_FIT")
+    private String labelSelection = DEFAULT_LABEL_SELECTION;
+
     private final Map<Class<Intent>, IntentCompiler<Intent>> flowRuleBased = Maps.newConcurrentMap();
     private final Map<Class<Intent>, IntentCompiler<Intent>> flowObjectiveBased = Maps.newConcurrentMap();
 
@@ -79,6 +86,7 @@
     public void modified(ComponentContext context) {
         if (context == null) {
             log.info("Settings: useFlowObjectives={}", useFlowObjectives);
+            log.info("Settings: labelSelection={}", labelSelection);
             return;
         }
 
@@ -95,13 +103,27 @@
             changeCompilers();
             log.info("Settings: useFlowObjectives={}", useFlowObjectives);
         }
+
+        String newLabelSelection;
+        try {
+            String s = Tools.get(context.getProperties(), "labelSelection");
+            newLabelSelection = isNullOrEmpty(s) ? labelSelection : s.trim();
+        } catch (ClassCastException e) {
+            newLabelSelection = labelSelection;
+        }
+
+        if (!labelSelection.equals(newLabelSelection) && LabelAllocator.isInEnum(newLabelSelection)) {
+            labelSelection = newLabelSelection;
+            changeLabelSelections();
+            log.info("Settings: labelSelection={}", labelSelection);
+        }
     }
 
     /**
      * Registers the specified compiler for the given intent class.
      *
-     * @param cls       intent class
-     * @param compiler  intent compiler
+     * @param cls       the intent class
+     * @param compiler  the intent compiler
      * @param flowBased true if the compiler is flow based
      * @param <T>       the type of intent
      */
@@ -121,7 +143,7 @@
     /**
      * Unregisters the compiler for the specified intent class.
      *
-     * @param cls       intent class
+     * @param cls       the intent class
      * @param flowBased true if the compiler is flow based
      * @param <T>       the type of intent
      */
@@ -147,4 +169,8 @@
         }
     }
 
+    private void changeLabelSelections() {
+        PathCompiler.labelAllocator.setLabelSelection(labelSelection);
+    }
+
 }
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java
index b831fef..b236d59 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java
@@ -15,16 +15,15 @@
  */
 package org.onosproject.net.intent.impl.compiler;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
-import org.apache.commons.lang.math.RandomUtils;
 import org.onlab.packet.EthType;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
+import org.onlab.util.Identifier;
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.EncapsulationType;
 import org.onosproject.net.Link;
 import org.onosproject.net.LinkKey;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -40,21 +39,15 @@
 import org.onosproject.net.intent.IntentCompilationException;
 import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.intent.constraint.EncapsulationConstraint;
-import org.onosproject.net.resource.Resource;
-import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceService;
-import org.onosproject.net.resource.Resources;
+import org.onosproject.net.resource.impl.LabelAllocator;
 import org.slf4j.Logger;
 
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import static org.onosproject.net.LinkKey.linkKey;
 
@@ -64,7 +57,10 @@
 
 public class PathCompiler<T> {
 
-    public static final boolean RANDOM_SELECTION = true;
+    private static final String ERROR_VLAN = "No VLAN Ids available for ";
+    private static final String ERROR_MPLS = "No available MPLS labels for ";
+
+    static LabelAllocator labelAllocator;
 
     /**
      * Defines methods used to create objects representing flows.
@@ -88,108 +84,46 @@
         return i == links.size() - 2;
     }
 
-    private Map<LinkKey, VlanId> assignVlanId(PathCompilerCreateFlow creator, PathIntent intent) {
-        Set<LinkKey> linkRequest =
-                Sets.newHashSetWithExpectedSize(intent.path()
-                        .links().size() - 2);
-        for (int i = 1; i <= intent.path().links().size() - 2; i++) {
-            LinkKey link = linkKey(intent.path().links().get(i));
-            linkRequest.add(link);
-            // add the inverse link. I want that the VLANID is reserved both for
-            // the direct and inverse link
-            linkRequest.add(linkKey(link.dst(), link.src()));
-        }
-
-        Map<LinkKey, VlanId> vlanIds = findVlanIds(creator, linkRequest);
-        if (vlanIds.isEmpty()) {
-            creator.log().warn("No VLAN IDs available");
-            return Collections.emptyMap();
-        }
-
-        //same VLANID is used for both directions
-        Set<Resource> resources = vlanIds.entrySet().stream()
-                .flatMap(x -> Stream.of(
-                        Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
-                                .resource(),
-                        Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
-                                .resource()
-                ))
-                .collect(Collectors.toSet());
-        List<ResourceAllocation> allocations =
-                creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources));
-        if (allocations.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        return vlanIds;
-    }
-
     /**
-     * Implements the first fit selection behavior.
+     * Returns the ethertype match needed. If the selector provides
+     * an ethertype, it will be used. IPv4 will be used otherwise.
      *
-     * @param available the set of available VLAN ids.
-     * @return the chosen VLAN id.
+     * @param selector the traffic selector.
+     * @return the ethertype we should match against
      */
-    private VlanId firsFitSelection(Set<VlanId> available) {
-        if (!available.isEmpty()) {
-            return available.iterator().next();
+    private EthType getEthType(TrafficSelector selector) {
+        Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
+        if (c != null && c instanceof EthTypeCriterion) {
+            EthTypeCriterion ethertype = (EthTypeCriterion) c;
+            return ethertype.ethType();
+        } else {
+            return EthType.EtherType.IPV4.ethType();
         }
-        return VlanId.vlanId(VlanId.NO_VID);
     }
 
     /**
-     * Implements the random selection behavior.
+     * Creates the flow rules for the path intent using VLAN
+     * encapsulation.
      *
-     * @param available the set of available VLAN ids.
-     * @return the chosen VLAN id.
+     * @param creator the flowrules creator
+     * @param flows the list of flows to fill
+     * @param devices the devices on the path
+     * @param intent the PathIntent to compile
      */
-    private VlanId randomSelection(Set<VlanId> available) {
-        if (!available.isEmpty()) {
-            int size = available.size();
-            int index = RandomUtils.nextInt(size);
-            return Iterables.get(available, index);
-        }
-        return VlanId.vlanId(VlanId.NO_VID);
-    }
-
-    /**
-    * Select a VLAN id from the set of available VLAN ids.
-    *
-    * @param available the set of available VLAN ids.
-    * @return the chosen VLAN id.
-    */
-    private VlanId selectVlanId(Set<VlanId> available) {
-        return RANDOM_SELECTION ? randomSelection(available) : firsFitSelection(available);
-    }
-
-    private Map<LinkKey, VlanId> findVlanIds(PathCompilerCreateFlow creator, Set<LinkKey> links) {
-        Map<LinkKey, VlanId> vlanIds = new HashMap<>();
-        for (LinkKey link : links) {
-            Set<VlanId> forward = findVlanId(creator, link.src());
-            Set<VlanId> backward = findVlanId(creator, link.dst());
-            Set<VlanId> common = Sets.intersection(forward, backward);
-            if (common.isEmpty()) {
-                continue;
-            }
-            VlanId selected = selectVlanId(common);
-            if (selected.toShort() == VlanId.NO_VID) {
-                continue;
-            }
-            vlanIds.put(link, selected);
-        }
-        return vlanIds;
-    }
-
-    private Set<VlanId> findVlanId(PathCompilerCreateFlow creator, ConnectPoint cp) {
-        return creator.resourceService().getAvailableResourceValues(
-                Resources.discrete(cp.deviceId(), cp.port()).id(),
-                VlanId.class);
-    }
-
     private void manageVlanEncap(PathCompilerCreateFlow<T> creator, List<T> flows,
                                  List<DeviceId> devices,
                                  PathIntent intent) {
-        Map<LinkKey, VlanId> vlanIds = assignVlanId(creator, intent);
+
+        Set<Link> linksSet = Sets.newConcurrentHashSet();
+        for (int i = 1; i <= intent.path().links().size() - 2; i++) {
+            linksSet.add(intent.path().links().get(i));
+        }
+
+        Map<LinkKey, Identifier<?>> vlanIds = labelAllocator.assignLabelToLinks(
+                linksSet,
+                intent.id(),
+                EncapsulationType.VLAN
+        );
 
         Iterator<Link> links = intent.path().links().iterator();
         Link srcLink = links.next();
@@ -197,9 +131,9 @@
         Link link = links.next();
 
         // Ingress traffic
-        VlanId vlanId = vlanIds.get(linkKey(link));
+        VlanId vlanId = (VlanId) vlanIds.get(linkKey(link));
         if (vlanId == null) {
-            throw new IntentCompilationException("No available VLAN ID for " + link);
+            throw new IntentCompilationException(ERROR_VLAN + link);
         }
         VlanId prevVlanId = vlanId;
 
@@ -227,9 +161,9 @@
 
             if (links.hasNext()) {
                 // Transit traffic
-                VlanId egressVlanId = vlanIds.get(linkKey(link));
+                VlanId egressVlanId = (VlanId) vlanIds.get(linkKey(link));
                 if (egressVlanId == null) {
-                    throw new IntentCompilationException("No available VLAN ID for " + link);
+                    throw new IntentCompilationException(ERROR_VLAN + link);
                 }
 
                 TrafficSelector transitSelector = DefaultTrafficSelector.builder()
@@ -284,68 +218,29 @@
         }
     }
 
-    private Map<LinkKey, MplsLabel> assignMplsLabel(PathCompilerCreateFlow creator, PathIntent intent) {
-                Set<LinkKey> linkRequest =
-                Sets.newHashSetWithExpectedSize(intent.path()
-                        .links().size() - 2);
-        for (int i = 1; i <= intent.path().links().size() - 2; i++) {
-            LinkKey link = linkKey(intent.path().links().get(i));
-            linkRequest.add(link);
-            // add the inverse link. I want that the VLANID is reserved both for
-            // the direct and inverse link
-            linkRequest.add(linkKey(link.dst(), link.src()));
-        }
-
-        Map<LinkKey, MplsLabel> labels = findMplsLabels(creator, linkRequest);
-        if (labels.isEmpty()) {
-            throw new IntentCompilationException("No available MPLS Label");
-        }
-
-        // for short term solution: same label is used for both directions
-        // TODO: introduce the concept of Tx and Rx resources of a port
-        Set<Resource> resources = labels.entrySet().stream()
-                .flatMap(x -> Stream.of(
-                        Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue())
-                                .resource(),
-                        Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue())
-                                .resource()
-                ))
-                .collect(Collectors.toSet());
-        List<ResourceAllocation> allocations =
-                creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources));
-        if (allocations.isEmpty()) {
-            return Collections.emptyMap();
-        }
-
-        return labels;
-    }
-
-    private Map<LinkKey, MplsLabel> findMplsLabels(PathCompilerCreateFlow creator, Set<LinkKey> links) {
-        Map<LinkKey, MplsLabel> labels = new HashMap<>();
-        for (LinkKey link : links) {
-            Set<MplsLabel> forward = findMplsLabel(creator, link.src());
-            Set<MplsLabel> backward = findMplsLabel(creator, link.dst());
-            Set<MplsLabel> common = Sets.intersection(forward, backward);
-            if (common.isEmpty()) {
-                continue;
-            }
-            labels.put(link, common.iterator().next());
-        }
-
-        return labels;
-    }
-
-    private Set<MplsLabel> findMplsLabel(PathCompilerCreateFlow creator, ConnectPoint cp) {
-        return creator.resourceService().getAvailableResourceValues(
-                Resources.discrete(cp.deviceId(), cp.port()).id(),
-                MplsLabel.class);
-    }
-
+    /**
+     * Creates the flow rules for the path intent using MPLS
+     * encapsulation.
+     *
+     * @param creator the flowrules creator
+     * @param flows the list of flows to fill
+     * @param devices the devices on the path
+     * @param intent the PathIntent to compile
+     */
     private void manageMplsEncap(PathCompilerCreateFlow<T> creator, List<T> flows,
                                            List<DeviceId> devices,
                                            PathIntent intent) {
-        Map<LinkKey, MplsLabel> mplsLabels = assignMplsLabel(creator, intent);
 
+        Set<Link> linksSet = Sets.newConcurrentHashSet();
+        for (int i = 1; i <= intent.path().links().size() - 2; i++) {
+            linksSet.add(intent.path().links().get(i));
+        }
+
+        Map<LinkKey, Identifier<?>> mplsLabels = labelAllocator.assignLabelToLinks(
+                linksSet,
+                intent.id(),
+                EncapsulationType.MPLS
+        );
         Iterator<Link> links = intent.path().links().iterator();
         Link srcLink = links.next();
 
@@ -353,9 +248,9 @@
         // List of flow rules to be installed
 
         // Ingress traffic
-        MplsLabel mplsLabel = mplsLabels.get(linkKey(link));
+        MplsLabel mplsLabel = (MplsLabel) mplsLabels.get(linkKey(link));
         if (mplsLabel == null) {
-            throw new IntentCompilationException("No available MPLS Label for " + link);
+            throw new IntentCompilationException(ERROR_MPLS + link);
         }
         MplsLabel prevMplsLabel = mplsLabel;
 
@@ -382,12 +277,10 @@
 
             if (links.hasNext()) {
                 // Transit traffic
-                MplsLabel transitMplsLabel = mplsLabels.get(linkKey(link));
+                MplsLabel transitMplsLabel = (MplsLabel) mplsLabels.get(linkKey(link));
                 if (transitMplsLabel == null) {
-                    throw new IntentCompilationException("No available MPLS label for " + link);
+                    throw new IntentCompilationException(ERROR_MPLS + link);
                 }
-                prevMplsLabel = transitMplsLabel;
-
                 TrafficSelector transitSelector = DefaultTrafficSelector.builder()
                         .matchInPort(prev.port())
                         .matchEthType(Ethernet.MPLS_UNICAST)
@@ -395,12 +288,13 @@
 
                 TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder();
 
-                // Set the new MPLS Label only if the previous one is different
+                // Set the new MPLS label only if the previous one is different
                 if (!prevMplsLabel.equals(transitMplsLabel)) {
                     transitTreat.setMpls(transitMplsLabel);
                 }
                 creator.createFlow(transitSelector,
                         transitTreat.build(), prev, link.src(), intent.priority(), true, flows, devices);
+                prevMplsLabel = transitMplsLabel;
                 prev = link.dst();
             } else {
                 TrafficSelector.Builder egressSelector = DefaultTrafficSelector.builder()
@@ -428,14 +322,7 @@
                 if (mplsCriterion.isPresent()) {
                     egressTreat.setMpls(mplsCriterion.get().label());
                 } else {
-                    egressTreat.popMpls(outputEthType(intent.selector()));
-                }
-
-
-                if (mplsCriterion.isPresent()) {
-                    egressTreat.setMpls(mplsCriterion.get().label());
-                } else {
-                    egressTreat.popVlan();
+                    egressTreat.popMpls(getEthType(intent.selector()));
                 }
 
                 creator.createFlow(egressSelector.build(),
@@ -446,23 +333,6 @@
 
     }
 
-    private MplsLabel getMplsLabel(Map<LinkKey, MplsLabel> labels, LinkKey link) {
-        return labels.get(link);
-    }
-
-    // if the ingress ethertype is defined, the egress traffic
-    // will be use that value, otherwise the IPv4 ethertype is used.
-    private EthType outputEthType(TrafficSelector selector) {
-        Criterion c = selector.getCriterion(Criterion.Type.ETH_TYPE);
-        if (c != null && c instanceof EthTypeCriterion) {
-            EthTypeCriterion ethertype = (EthTypeCriterion) c;
-            return ethertype.ethType();
-        } else {
-            return EthType.EtherType.IPV4.ethType();
-        }
-    }
-
-
     /**
      * Compiles an intent down to flows.
      *
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
index fdcdd00..ddc7f21 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java
@@ -36,6 +36,7 @@
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator;
 import org.slf4j.Logger;
 
 import java.util.LinkedList;
@@ -67,6 +68,7 @@
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
         registrator.registerCompiler(PathIntent.class, this, false);
+        labelAllocator = new LabelAllocator(resourceService);
     }
 
     @Deactivate
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
index ac1c051..3f0fc19 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java
@@ -40,6 +40,7 @@
 import org.onosproject.net.intent.IntentCompiler;
 import org.onosproject.net.intent.PathIntent;
 import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator;
 import org.slf4j.Logger;
 
 import java.util.LinkedList;
@@ -73,6 +74,7 @@
     public void activate() {
         appId = coreService.registerApplication("org.onosproject.net.intent");
         registrator.registerCompiler(PathIntent.class, this, true);
+        labelAllocator = new LabelAllocator(resourceService);
     }
 
     @Deactivate
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/LabelAllocator.java b/core/net/src/main/java/org/onosproject/net/resource/impl/LabelAllocator.java
new file mode 100644
index 0000000..4086768
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/LabelAllocator.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.resource.impl;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import org.apache.commons.lang.math.RandomUtils;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Identifier;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.resource.Resource;
+import org.onosproject.net.resource.ResourceAllocation;
+import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.Resources;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Helper class which interacts with the ResourceService and provides
+ * a unified API to allocate MPLS labels and VLAN Ids.
+ */
+public final class LabelAllocator {
+
+    private enum Behavior {
+        /**
+         * Random selection.
+         */
+        RANDOM,
+        /**
+         * First fit selection.
+         */
+        FIRST_FIT
+    }
+
+    private static final Behavior[] BEHAVIORS = Behavior.values();
+
+    private ResourceService resourceService;
+    private LabelSelection labelSelection;
+
+    /**
+     * Creates a new label allocator. Random is the
+     * default behavior.
+     *
+     * @param rs the resource service
+     */
+    public LabelAllocator(ResourceService rs) {
+        this.resourceService = rs;
+        this.labelSelection = this.getLabelSelection(Behavior.RANDOM);
+    }
+
+    /**
+     * Checks if a given string is a valid Behavior.
+     *
+     * @param value the string to check
+     * @return true if value is a valid Behavior, false otherwise
+     */
+    public static boolean isInEnum(String value) {
+        for (Behavior b : BEHAVIORS) {
+            if (b.name().equals(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Changes the selection behavior.
+     *
+     * @param type the behavior type
+     */
+    public void setLabelSelection(String type) {
+        if (isInEnum(type)) {
+            this.labelSelection = this.getLabelSelection(type);
+        }
+    }
+
+    /**
+     * Retrieves the label selection behavior.
+     *
+     * @return the label selection behavior in use
+     */
+    public LabelSelection getLabelSelection() {
+        return this.labelSelection;
+    }
+
+    /**
+     * Returns the label selection behavior, given a behavior type.
+     *
+     * @param type the behavior type
+     * @return the label selection behavior in use
+     */
+    private LabelSelection getLabelSelection(String type) {
+        Behavior behavior = Behavior.valueOf(type);
+        return this.getLabelSelection(behavior);
+    }
+
+    /**
+     * Creates a new LabelSelection. Random is
+     * the default label selection behavior.
+     *
+     * @param type the behavior type
+     * @return the object implementing the behavior
+     */
+    private LabelSelection getLabelSelection(Behavior type) {
+        LabelSelection selection = null;
+        switch (type) {
+            case FIRST_FIT:
+                selection = new FirstFitSelection();
+                break;
+            case RANDOM:
+            default:
+                selection = new RandomSelection();
+                break;
+        }
+        return selection;
+    }
+
+    /**
+     * Looks for available Ids.
+     *
+     * @param links the links where to look for Ids
+     * @param  type the encapsulation type
+     * @return the mappings between key and id
+     */
+    private Map<LinkKey, Identifier<?>> findAvailableIDs(Set<LinkKey> links, EncapsulationType type) {
+
+        Map<LinkKey, Identifier<?>> ids = Maps.newHashMap();
+        for (LinkKey link : links) {
+            Set<Identifier<?>> availableIDsatSrc = getAvailableIDs(link.src(), type);
+            Set<Identifier<?>> availableIDsatDst = getAvailableIDs(link.dst(), type);
+            Set<Identifier<?>> common = Sets.intersection(availableIDsatSrc, availableIDsatDst);
+            if (common.isEmpty()) {
+                continue;
+            }
+            Identifier<?> selected = labelSelection.select(common);
+            if (selected == null) {
+                continue;
+            }
+            ids.put(link, selected);
+        }
+        return ids;
+    }
+
+    /**
+     * Looks for available Ids associated to the given connection point.
+     *
+     * @param cp the connection point
+     * @param type the type of Id
+     * @return the set of available Ids
+     */
+    private Set<Identifier<?>> getAvailableIDs(ConnectPoint cp, EncapsulationType type) {
+        return resourceService.getAvailableResourceValues(
+                Resources.discrete(cp.deviceId(), cp.port()).id(), getEncapsulationClass(type)
+        );
+    }
+
+    /**
+     * Method to map the encapsulation type to identifier class.
+     * VLAN is the default encapsulation.
+     *
+     * @param type the type of encapsulation
+     * @return the id class
+     */
+    private Class getEncapsulationClass(EncapsulationType type) {
+        Class idType;
+        switch (type) {
+            case MPLS:
+                idType = MplsLabel.class;
+                break;
+            case VLAN:
+            default:
+                idType = VlanId.class;
+        }
+        return idType;
+    }
+
+    /**
+     * Allocates labels and associates them to links.
+     *
+     * @param links the links where labels will be allocated
+     * @param id the intent Id
+     * @param type the encapsulation type
+     * @return the list of links and associated labels
+     */
+    public Map<LinkKey, Identifier<?>> assignLabelToLinks(Set<Link> links, IntentId id, EncapsulationType type) {
+
+        Set<LinkKey> linkRequest = Sets.newHashSet();
+
+        links.forEach(link -> {
+            linkRequest.add(LinkKey.linkKey(link));
+        });
+
+        Map<LinkKey, Identifier<?>> availableIds = findAvailableIDs(linkRequest, type);
+        if (availableIds.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        Set<Resource> resources = availableIds.entrySet().stream()
+                .flatMap(x -> Stream.of(
+                        Resources.discrete(
+                                x.getKey().src().deviceId(),
+                                x.getKey().src().port(),
+                                x.getValue()
+                        ).resource(),
+                        Resources.discrete(
+                                x.getKey().dst().deviceId(),
+                                x.getKey().dst().port(),
+                                x.getValue()
+                        ).resource()
+                ))
+                .collect(Collectors.toSet());
+
+        List<ResourceAllocation> allocations = resourceService.allocate(id, ImmutableList.copyOf(resources));
+
+        if (allocations.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        return ImmutableMap.copyOf(availableIds);
+    }
+
+    /**
+     * Allocates labels and associates them to source
+     * and destination ports of a link.
+     *
+     * @param links the links on which labels will be reserved
+     * @param id the intent Id
+     * @param type the encapsulation type
+     * @return the list of ports and associated labels
+     */
+    public Map<ConnectPoint, Identifier<?>> assignLabelToPorts(Set<Link> links, IntentId id, EncapsulationType type) {
+        Map<LinkKey, Identifier<?>> allocation = this.assignLabelToLinks(links, id, type);
+        if (allocation.isEmpty()) {
+            return Collections.emptyMap();
+        }
+        Map<ConnectPoint, Identifier<?>> finalAllocation = Maps.newHashMap();
+        allocation.forEach((key, value) -> {
+            finalAllocation.putIfAbsent(key.src(), value);
+            finalAllocation.putIfAbsent(key.dst(), value);
+        });
+        return ImmutableMap.copyOf(finalAllocation);
+    }
+
+    /**
+     * Interface for selection algorithms of the labels.
+     */
+    public interface LabelSelection {
+
+        /**
+         * Picks an element from values using a particular algorithm.
+         *
+         * @param values the values to select from
+         * @return the selected identifier if values are present, null otherwise
+         */
+        Identifier<?> select(Set<Identifier<?>> values);
+
+    }
+
+    /**
+     * Random label selection.
+     */
+    public static class RandomSelection implements LabelSelection {
+
+        /**
+         * Selects an identifier from a given set of values using
+         * the random selection algorithm.
+         *
+         * @param values the values to select from
+         * @return the selected identifier if values are present, null otherwise
+         */
+        @Override
+        public Identifier<?> select(Set<Identifier<?>> values) {
+            if (!values.isEmpty()) {
+                int size = values.size();
+                int index = RandomUtils.nextInt(size);
+                return Iterables.get(values, index);
+            }
+            return null;
+        }
+    }
+
+    /**
+     * First fit label selection.
+     */
+    public static class FirstFitSelection implements LabelSelection {
+
+        /**
+         * Selects an identifier from a given set of values using
+         * the first fir selection algorithm.
+         *
+         * @param values the values to select from
+         * @return the selected identifier if values are present, null otherwise.
+         */
+        @Override
+        public Identifier<?> select(Set<Identifier<?>> values) {
+            if (!values.isEmpty()) {
+                return values.iterator().next();
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
index a636fd4..e9f5170 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/PathIntentCompilerTest.java
@@ -163,7 +163,8 @@
     private PathIntent constraintMplsIntent;
 
     /**
-     * Configures objects used in all the test cases.
+     * Configures mock objects used in all the test cases.
+     * Creates the intents to test as well.
      */
     @Before
     public void setUp() {
@@ -914,14 +915,12 @@
     }
 
     /**
-     * Tests the random selection of VlanIds in the PathCompiler.
+     * Tests the random selection of VLAN Ids in the PathCompiler.
      * It can fail randomly (it is unlikely)
      */
     @Test
     public void testRandomVlanSelection() {
 
-        if (PathCompiler.RANDOM_SELECTION) {
-
             sut.activate();
 
             List<Intent> compiled = sut.compile(constraintVlanIntent, Collections.emptyList());
@@ -969,7 +968,6 @@
 
             sut.deactivate();
 
-        }
 
     }
 
@@ -1043,8 +1041,10 @@
                 .findFirst()
                 .get();
         verifyIdAndPriority(rule1, d1p0.deviceId());
-        assertThat(rule1.selector(), is(DefaultTrafficSelector.builder(selector)
-                .matchInPort(d1p0.port()).build()));
+        assertThat(rule1.selector(), is(DefaultTrafficSelector
+                                                .builder(selector)
+                                                .matchInPort(d1p0.port())
+                                                .build()));
         MplsLabel mplsLabelToEncap = verifyMplsEncapTreatment(rule1.treatment(), d1p1, true, false);
 
         FlowRule rule2 = rules.stream()
@@ -1053,7 +1053,7 @@
                 .get();
         verifyIdAndPriority(rule2, d2p0.deviceId());
         verifyMplsEncapSelector(rule2.selector(), d2p0, mplsLabelToEncap);
-        verifyMplsEncapTreatment(rule2.treatment(), d2p1, false, false);
+        mplsLabelToEncap = verifyMplsEncapTreatment(rule2.treatment(), d2p1, false, false);
 
         FlowRule rule3 = rules.stream()
                 .filter(x -> x.deviceId().equals(d3p0.deviceId()))
@@ -1077,19 +1077,29 @@
         assertThat((ruleOutput.iterator().next()).port(), is(egress.port()));
         MplsLabel mplsToEncap = MplsLabel.mplsLabel(0);
         if (isIngress && !isEgress) {
-            Set<L2ModificationInstruction.ModMplsLabelInstruction> mplsRules =
-                    trafficTreatment.allInstructions().stream()
-                            .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
-                            .map(x -> (L2ModificationInstruction.ModMplsLabelInstruction) x)
-                            .collect(Collectors.toSet());
+            Set<L2ModificationInstruction.ModMplsLabelInstruction> mplsRules = trafficTreatment
+                    .allInstructions()
+                    .stream()
+                    .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
+                    .map(x -> (L2ModificationInstruction.ModMplsLabelInstruction) x)
+                    .collect(Collectors.toSet());
             assertThat(mplsRules, hasSize(1));
             L2ModificationInstruction.ModMplsLabelInstruction mplsRule = mplsRules.iterator().next();
-            assertThat(mplsRule.mplsLabel().toInt(), greaterThan(0));
-            mplsToEncap = mplsRule.mplsLabel();
+            assertThat(mplsRule.label().toInt(), greaterThan(0));
+            assertThat(mplsRule.label().toInt(), lessThan(MplsLabel.MAX_MPLS));
+            mplsToEncap = mplsRule.label();
         } else if (!isIngress && !isEgress) {
-            assertThat(trafficTreatment.allInstructions().stream()
-                               .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
-                               .collect(Collectors.toSet()), hasSize(0));
+            Set<L2ModificationInstruction.ModMplsLabelInstruction> mplsRules = trafficTreatment
+                    .allInstructions()
+                    .stream()
+                    .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
+                    .map(x -> (L2ModificationInstruction.ModMplsLabelInstruction) x)
+                    .collect(Collectors.toSet());
+            assertThat(mplsRules, hasSize(1));
+            L2ModificationInstruction.ModMplsLabelInstruction mplsRule = mplsRules.iterator().next();
+            assertThat(mplsRule.label().toInt(), greaterThan(0));
+            assertThat(mplsRule.label().toInt(), lessThan(MplsLabel.MAX_MPLS));
+            mplsToEncap = mplsRule.label();
         } else {
             assertThat(trafficTreatment.allInstructions().stream()
                                .filter(treat -> treat instanceof L2ModificationInstruction.ModMplsLabelInstruction)
@@ -1099,7 +1109,6 @@
                                .collect(Collectors.toSet()), hasSize(1));
 
         }
-
         return mplsToEncap;
 
     }
diff --git a/core/net/src/test/java/org/onosproject/net/resource/impl/LabelAllocatorTest.java b/core/net/src/test/java/org/onosproject/net/resource/impl/LabelAllocatorTest.java
new file mode 100644
index 0000000..4c47735
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/resource/impl/LabelAllocatorTest.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.net.resource.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onlab.util.Identifier;
+import org.onosproject.core.IdGenerator;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.Link;
+import org.onosproject.net.LinkKey;
+import org.onosproject.net.intent.IntentId;
+import org.onosproject.net.intent.MockIdGenerator;
+import org.onosproject.net.resource.MockResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator.FirstFitSelection;
+import org.onosproject.net.resource.impl.LabelAllocator.LabelSelection;
+import org.onosproject.net.resource.impl.LabelAllocator.RandomSelection;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.PID;
+import static org.onosproject.net.NetTestTools.connectPoint;
+
+/**
+ * Unit tests for LabelAllocator.
+ */
+public class LabelAllocatorTest {
+
+    private LabelAllocator allocator;
+    private MockResourceService resourceService;
+    private IdGenerator idGenerator = new MockIdGenerator();
+
+    private final ConnectPoint d1p0 = connectPoint("s1", 0);
+    private final ConnectPoint d1p1 = connectPoint("s1", 1);
+    private final ConnectPoint d2p0 = connectPoint("s2", 0);
+    private final ConnectPoint d2p1 = connectPoint("s2", 1);
+
+    private final List<Link> links = Arrays.asList(
+            createEdgeLink(d1p0, true),
+            DefaultLink.builder().providerId(PID).src(d1p1).dst(d2p1).type(DIRECT).build(),
+            createEdgeLink(d2p0, false)
+    );
+
+    private final String firstFit = "FIRST_FIT";
+    private final String random = "RANDOM";
+    private final String wrong = "BLAHBLAHBLAH";
+
+    @Before
+    public void setUp() {
+        this.resourceService = new MockResourceService();
+        this.allocator = new LabelAllocator(this.resourceService);
+    }
+
+    @After
+    public void tearDown() {
+
+    }
+
+    /**
+     * To test changes to the selection behavior.
+     */
+    @Test
+    public void testChangeBehavior() {
+        // It has to be an instance of LabelSelection
+        assertThat(this.allocator.getLabelSelection(), instanceOf(LabelSelection.class));
+        // By default we have Random Selection
+        assertThat(this.allocator.getLabelSelection(), instanceOf(RandomSelection.class));
+        // We change to FirstFit and we test the change
+        this.allocator.setLabelSelection(firstFit);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(FirstFitSelection.class));
+        // We change to Random and we test the change
+        this.allocator.setLabelSelection(random);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(RandomSelection.class));
+        // We put a wrong type and we should have a Random selection
+        this.allocator.setLabelSelection(wrong);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(RandomSelection.class));
+    }
+
+    /**
+     * To test the first fit behavior with VLAN Id. In the First step
+     * we use the default set, for the first selection the selected label
+     * has to be 1. In the Second step we change the default set and for
+     * the first fit selection the selected has to be 2.
+     */
+    @Test
+    public void testFirstFitBehaviorVlan() {
+        // We change to FirstFit and we test the change
+        this.allocator.setLabelSelection(firstFit);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(FirstFitSelection.class));
+        // We test the behavior for VLAN
+        Map<LinkKey, Identifier<?>> allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.VLAN);
+        Identifier<?> id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a VlanId
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        VlanId vlanId = (VlanId) id;
+        assertTrue(VlanId.NO_VID < vlanId.toShort() && vlanId.toShort() < VlanId.MAX_VLAN);
+        // value will be always 1
+        assertEquals(1, vlanId.toShort());
+
+        // We change the available Ids
+        this.resourceService.availableVlanLabels = ImmutableSet.of(
+                (short) 100,
+                (short) 11,
+                (short) 20,
+                (short) 2,
+                (short) 3
+        );
+        // We test again the behavior for VLAN
+        allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.VLAN);
+        id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a VlanId
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        vlanId = (VlanId) id;
+        assertTrue(VlanId.NO_VID < vlanId.toShort() && vlanId.toShort() < VlanId.MAX_VLAN);
+        // value will be always 2
+        assertEquals(2, vlanId.toShort());
+    }
+
+    /**
+     * To test the first fit behavior with MPLS label. In the First step
+     * we use the default set, for the first selection the selected label
+     * has to be 1. In the Second step we change the default set and for
+     * the first fit selection the selected has to be 100.
+     */
+    @Test
+    public void testFirstFitBehaviorMpls() {
+        // We change to FirstFit and we test the change
+        this.allocator.setLabelSelection(firstFit);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(FirstFitSelection.class));
+        // We test the behavior for MPLS
+        Map<LinkKey, Identifier<?>> allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.MPLS);
+        Identifier<?> id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a Mplslabel
+        assertThat(id, instanceOf(MplsLabel.class));
+        // value should not be a forbidden value
+        MplsLabel mplsLabel = (MplsLabel) id;
+        assertTrue(0 < mplsLabel.toInt() && mplsLabel.toInt() < MplsLabel.MAX_MPLS);
+        // value will be always 1
+        assertEquals(1, mplsLabel.toInt());
+
+        // We change the available Ids
+        this.resourceService.availableMplsLabels = ImmutableSet.of(
+                100,
+                200,
+                1000
+        );
+        // We test again the behavior for MPLS
+        allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.MPLS);
+        id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a Mplslabel
+        assertThat(id, instanceOf(MplsLabel.class));
+        // value should not be a forbidden value
+        mplsLabel = (MplsLabel) id;
+        assertTrue(0 < mplsLabel.toInt() && mplsLabel.toInt() < MplsLabel.MAX_MPLS);
+        // value will be always 100
+        assertEquals(100, mplsLabel.toInt());
+    }
+
+    /**
+     * To test the random behavior with VLAN Id. We make two selection,
+     * we test that these two selection are different.
+     */
+    @Test
+    public void testRandomBehaviorVlan() {
+        // Verify the random behavior
+        assertThat(this.allocator.getLabelSelection(), instanceOf(RandomSelection.class));
+        // We test the behavior for VLAN
+        Map<LinkKey, Identifier<?>> allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.VLAN);
+        Identifier<?> id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a VlanId
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        Short value = Short.parseShort(id.toString());
+        VlanId prevVlanId = VlanId.vlanId(value);
+        assertTrue(VlanId.NO_VID < prevVlanId.toShort() && prevVlanId.toShort() < VlanId.MAX_VLAN);
+
+        allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.VLAN);
+         id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a VlanId
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        VlanId vlanId = (VlanId) id;
+        assertTrue(VlanId.NO_VID < vlanId.toShort() && vlanId.toShort() < VlanId.MAX_VLAN);
+        assertNotEquals(vlanId, prevVlanId);
+
+    }
+
+    /**
+     * To test random behavior with MPLS label. We make two selection,
+     * we test that these two selection are different.
+     */
+    @Test
+    public void testRandomBehaviorMpls() {
+        // Verify the random behavior
+        assertThat(this.allocator.getLabelSelection(), instanceOf(RandomSelection.class));
+        // We test the behavior for MPLS
+        Map<LinkKey, Identifier<?>> allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.MPLS);
+        Identifier<?> id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a Mplslabel
+        assertThat(id, instanceOf(MplsLabel.class));
+        // value should not be a forbidden value
+        MplsLabel prevMplsId = (MplsLabel) id;
+        assertTrue(0 < prevMplsId.toInt() && prevMplsId.toInt() < MplsLabel.MAX_MPLS);
+
+        allocation = this.allocator.assignLabelToLinks(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.MPLS);
+        id = allocation.get(LinkKey.linkKey(d1p1, d2p1));
+        // value has to be a Mplslabel
+        assertThat(id, instanceOf(MplsLabel.class));
+        // value should not be a forbidden value
+        MplsLabel mplsId = (MplsLabel) id;
+        assertTrue(0 < mplsId.toInt() && mplsId.toInt() < MplsLabel.MAX_MPLS);
+        assertNotEquals(prevMplsId, mplsId);
+
+    }
+
+    /**
+     * To test the port key based API.
+     */
+    @Test
+    public void testPortKey() {
+        // Verify the first behavior
+        this.allocator.setLabelSelection(firstFit);
+        assertThat(this.allocator.getLabelSelection(), instanceOf(FirstFitSelection.class));
+        // We test the behavior for VLAN
+        Map<ConnectPoint, Identifier<?>> allocation = this.allocator.assignLabelToPorts(
+                ImmutableSet.copyOf(links.subList(1, 2)),
+                IntentId.valueOf(idGenerator.getNewId()),
+                EncapsulationType.VLAN);
+        Identifier<?> id = allocation.get(new ConnectPoint(d1p1.elementId(), d1p1.port()));
+        // value has to be a VlanId
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        VlanId prevVlanId = (VlanId) id;
+        assertTrue(VlanId.NO_VID < prevVlanId.toShort() && prevVlanId.toShort() < VlanId.MAX_VLAN);
+        // value has to be 1
+        assertEquals(1, prevVlanId.toShort());
+        // verify same applies for d2p1
+        id = allocation.get(new ConnectPoint(d2p1.elementId(), d2p1.port()));
+        assertThat(id, instanceOf(VlanId.class));
+        // value should not be a forbidden value
+        VlanId vlanId = (VlanId) id;
+        assertTrue(VlanId.NO_VID < vlanId.toShort() && vlanId.toShort() < VlanId.MAX_VLAN);
+        // value has to be 1
+        assertEquals(prevVlanId, vlanId);
+    }
+
+
+
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java b/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java
index 82f951f..6a1418d 100644
--- a/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java
+++ b/utils/misc/src/main/java/org/onlab/packet/MplsLabel.java
@@ -15,18 +15,18 @@
  */
 package org.onlab.packet;
 
+import org.onlab.util.Identifier;
+
 /**
  * Representation of a MPLS label.
  */
-public class MplsLabel {
-
-    private final int mplsLabel;
+public final class MplsLabel extends Identifier<Integer> {
 
     // An MPLS Label maximum 20 bits.
     public static final int MAX_MPLS = 0xFFFFF;
 
     protected MplsLabel(int value) {
-        this.mplsLabel = value;
+        super(value);
     }
 
     public static MplsLabel mplsLabel(int value) {
@@ -39,35 +39,27 @@
         return new MplsLabel(value);
     }
 
+    /**
+     * Creates a MplsLabel object using the supplied decimal string.
+     *
+     * @param value the MPLS identifier expressed as string
+     * @return Mplslabel object created from the string
+     */
+    public static MplsLabel mplsLabel(String value) {
+        try {
+            return MplsLabel.mplsLabel(Integer.parseInt(value));
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
     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;
+        return this.id();
     }
 
     @Override
     public String toString() {
-        return String.valueOf(this.mplsLabel);
+        return String.valueOf(this.identifier);
     }
+
 }