【ONOS-1223】【ONOS-1870】the implements of label resource APIs.it include
commands
used to test
if there is any bug,LabelResourceManager,LabelResourceStore using
copycat,and junit test code.
the distribution strategy is that the master of devices handle all the
requests if applied label belongs to it.except for query request.
label store uses copycat instead of hazelcast to keep strong consistency

Change-Id: I77bde6a96f33098063573d37ed1ba787ae21973f
diff --git a/cli/src/main/java/org/onosproject/cli/net/ApplyGlobalLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/ApplyGlobalLabelResourceCommand.java
new file mode 100644
index 0000000..6cf924a
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ApplyGlobalLabelResourceCommand.java
@@ -0,0 +1,39 @@
+package org.onosproject.cli.net;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.resource.DefaultLabelResource;
+import org.onosproject.net.resource.LabelResource;
+import org.onosproject.net.resource.LabelResourceService;
+
+@Command(scope = "onos", name = "apply-global-label-resource-pool",
+      description = "Apply global labels from global resource pool")
+public class ApplyGlobalLabelResourceCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "applyNum",
+            description = "Applying number means how many labels applications want to use.",
+            required = true, multiValued = false)
+    String applyNum = null;
+
+    private static final String FMT = "deviceid=%s, labelresourceid=%s";
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        Collection<LabelResource> result =
+                lrs.applyFromGlobalPool(Long.parseLong(applyNum));
+        if (result.size() > 0) {
+            for (Iterator<LabelResource> iterator = result.iterator(); iterator
+                    .hasNext();) {
+                DefaultLabelResource defaultLabelResource = (DefaultLabelResource) iterator
+                        .next();
+                print(FMT, defaultLabelResource.deviceId().toString(),
+                      defaultLabelResource.labelResourceId().toString());
+            }
+        }
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/ApplyLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/ApplyLabelResourceCommand.java
new file mode 100644
index 0000000..06cd8e6
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ApplyLabelResourceCommand.java
@@ -0,0 +1,44 @@
+package org.onosproject.cli.net;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.resource.DefaultLabelResource;
+import org.onosproject.net.resource.LabelResource;
+import org.onosproject.net.resource.LabelResourceService;
+
+@Command(scope = "onos", name = "apply-label-resource-pool",
+      description = "Apply label resource from device pool by specific device id")
+public class ApplyLabelResourceCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "deviceId",
+            description = "Device identity",
+            required = true, multiValued = false)
+    String deviceId = null;
+    @Argument(index = 1, name = "applyNum",
+            description = "Applying number means how many labels applications want to use.",
+            required = true, multiValued = false)
+    String applyNum = null;
+
+    private static final String FMT = "deviceid=%s, labelresourceid=%s";
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        Collection<LabelResource> result = lrs.applyFromDevicePool(DeviceId
+                .deviceId(deviceId), Long.parseLong(applyNum));
+        if (result.size() > 0) {
+            for (Iterator<LabelResource> iterator = result.iterator(); iterator
+                    .hasNext();) {
+                DefaultLabelResource defaultLabelResource = (DefaultLabelResource) iterator
+                        .next();
+                print(FMT, defaultLabelResource.deviceId().toString(),
+                      defaultLabelResource.labelResourceId().toString());
+            }
+        }
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/CreateGlobalLabelResourcePoolCommand.java b/cli/src/main/java/org/onosproject/cli/net/CreateGlobalLabelResourcePoolCommand.java
new file mode 100644
index 0000000..0be80cf
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/CreateGlobalLabelResourcePoolCommand.java
@@ -0,0 +1,32 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.resource.LabelResourceAdminService;
+import org.onosproject.net.resource.LabelResourceId;
+
+/**
+ * create label resource pool by specific device id.
+ */
+@Command(scope = "onos", name = "create-global-label-resource-pool",
+description = "Creates global label resource pool.")
+public class CreateGlobalLabelResourcePoolCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "beginLabel",
+            description = "The first label of global label resource pool.",
+            required = true, multiValued = false)
+    String beginLabel = null;
+    @Argument(index = 1, name = "endLabel",
+            description = "The last label of global label resource pool.",
+            required = true, multiValued = false)
+    String endLabel = null;
+
+    @Override
+    protected void execute() {
+        LabelResourceAdminService lrs = get(LabelResourceAdminService.class);
+        lrs.createGlobalPool(LabelResourceId.labelResourceId(Long
+                .parseLong(beginLabel)), LabelResourceId.labelResourceId(Long
+                .parseLong(endLabel)));
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/CreateLabelResourcePoolCommand.java b/cli/src/main/java/org/onosproject/cli/net/CreateLabelResourcePoolCommand.java
new file mode 100644
index 0000000..5a7d6b4
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/CreateLabelResourcePoolCommand.java
@@ -0,0 +1,33 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.resource.LabelResourceAdminService;
+import org.onosproject.net.resource.LabelResourceId;
+
+/**
+ * create label resource pool by specific device id.
+ */
+@Command(scope = "onos", name = "create-label-resource-pool",
+     description = "Creates label resource pool by a specific device id")
+public class CreateLabelResourcePoolCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "deviceId", description = "Device identity", required = true, multiValued = false)
+    String deviceId = null;
+    @Argument(index = 1, name = "beginLabel",
+            description = "The first label of global label resource pool.", required = true, multiValued = false)
+    String beginLabel = null;
+    @Argument(index = 2, name = "endLabel",
+            description = "The last label of global label resource pool.", required = true, multiValued = false)
+    String endLabel = null;
+
+    @Override
+    protected void execute() {
+        LabelResourceAdminService lrs = get(LabelResourceAdminService.class);
+        lrs.createDevicePool(DeviceId.deviceId(deviceId), LabelResourceId
+                .labelResourceId(Long.parseLong(beginLabel)), LabelResourceId
+                .labelResourceId(Long.parseLong(endLabel)));
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DestroyGlobalLabelResourcePoolCommand.java b/cli/src/main/java/org/onosproject/cli/net/DestroyGlobalLabelResourcePoolCommand.java
new file mode 100644
index 0000000..8921044
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/DestroyGlobalLabelResourcePoolCommand.java
@@ -0,0 +1,16 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.resource.LabelResourceAdminService;
+
+@Command(scope = "onos", name = "destroy-global-label-resource-pool",
+description = "Destroys global label resource pool")
+public class DestroyGlobalLabelResourcePoolCommand extends AbstractShellCommand {
+    @Override
+    protected void execute() {
+        LabelResourceAdminService lrs = get(LabelResourceAdminService.class);
+        lrs.destroyGlobalPool();
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/DestroyLabelResourcePoolCommand.java b/cli/src/main/java/org/onosproject/cli/net/DestroyLabelResourcePoolCommand.java
new file mode 100644
index 0000000..7965dc6
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/DestroyLabelResourcePoolCommand.java
@@ -0,0 +1,21 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.resource.LabelResourceAdminService;
+
+@Command(scope = "onos", name = "destroy-label-resource-pool",
+    description = "Destroys label resource pool by a specific device id")
+public class DestroyLabelResourcePoolCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "deviceId", description = "Device identity", required = true, multiValued = false)
+    String deviceId = null;
+
+    @Override
+    protected void execute() {
+        LabelResourceAdminService lrs = get(LabelResourceAdminService.class);
+        lrs.destroyDevicePool(DeviceId.deviceId(deviceId));
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/GetGlobalLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/GetGlobalLabelResourceCommand.java
new file mode 100644
index 0000000..5ff98ba
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/GetGlobalLabelResourceCommand.java
@@ -0,0 +1,27 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.resource.LabelResourcePool;
+import org.onosproject.net.resource.LabelResourceService;
+
+@Command(scope = "onos", name = "get-global-label-resource-pool",
+      description = "Gets global label resource pool information.")
+public class GetGlobalLabelResourceCommand extends AbstractShellCommand {
+    private static final String FMT = "deviceid=%s, beginLabel=%s,"
+            + "endLabel=%s, totalNum=%s, usedNum=%s, currentUsedMaxLabelId=%s,"
+            + "releaseLabelIds=%s";
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        LabelResourcePool pool = lrs.getGlobalLabelResourcePool();
+        if (pool != null) {
+            print(FMT, pool.deviceId().toString(), pool.beginLabel(),
+                  pool.endLabel(), pool.totalNum(), pool.usedNum(),
+                  pool.currentUsedMaxLabelId(), pool.releaseLabelId()
+                          .toString());
+        }
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/GetLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/GetLabelResourceCommand.java
new file mode 100644
index 0000000..cd10add
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/GetLabelResourceCommand.java
@@ -0,0 +1,35 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.resource.LabelResourcePool;
+import org.onosproject.net.resource.LabelResourceService;
+
+@Command(scope = "onos", name = "get-label-resource-pool",
+      description = "Gets label resource pool information by a specific device id")
+public class GetLabelResourceCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "deviceId",
+            description = "Device identity", required = true, multiValued = false)
+    String deviceId = null;
+    private static final String FMT = "deviceid=%s, beginLabel=%s,"
+            + "endLabel=%s, totalNum=%s, usedNum=%s, currentUsedMaxLabelId=%s,"
+            + "releaseLabelIds=%s";
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        LabelResourcePool pool = lrs.getDeviceLabelResourcePool(DeviceId
+                .deviceId(deviceId));
+        if (pool != null) {
+            print(FMT, pool.deviceId().toString(), pool.beginLabel(),
+                  pool.endLabel(), pool.totalNum(), pool.usedNum(),
+                  pool.currentUsedMaxLabelId(), pool.releaseLabelId()
+                          .toString());
+        } else {
+            print(FMT, deviceId, null, null, null, null, null, null);
+        }
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/ReleaseGlobalLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/ReleaseGlobalLabelResourceCommand.java
new file mode 100644
index 0000000..9596061
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ReleaseGlobalLabelResourceCommand.java
@@ -0,0 +1,33 @@
+package org.onosproject.cli.net;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.resource.LabelResourceId;
+import org.onosproject.net.resource.LabelResourceService;
+
+@Command(scope = "onos", name = "release-global-label-resource-pool",
+description = "Releases labels to global label resource pool.")
+public class ReleaseGlobalLabelResourceCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "releaseLabelIds",
+            description = "Represents for the label ids that are released. They are splited by dot symbol",
+            required = true, multiValued = false)
+    String releaseLabelIds = null;
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        Set<LabelResourceId> release = new HashSet<LabelResourceId>();
+        String[] labelIds = releaseLabelIds.split(",");
+        LabelResourceId resource = null;
+        for (int i = 0; i < labelIds.length; i++) {
+            resource = LabelResourceId.labelResourceId(Long.parseLong(labelIds[i]));
+            release.add(resource);
+        }
+        lrs.releaseToGlobalPool(release);
+    }
+
+}
diff --git a/cli/src/main/java/org/onosproject/cli/net/ReleaseLabelResourceCommand.java b/cli/src/main/java/org/onosproject/cli/net/ReleaseLabelResourceCommand.java
new file mode 100644
index 0000000..55c44c4
--- /dev/null
+++ b/cli/src/main/java/org/onosproject/cli/net/ReleaseLabelResourceCommand.java
@@ -0,0 +1,44 @@
+package org.onosproject.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.resource.DefaultLabelResource;
+import org.onosproject.net.resource.LabelResource;
+import org.onosproject.net.resource.LabelResourceId;
+import org.onosproject.net.resource.LabelResourceService;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+@Command(scope = "onos", name = "release-label-resource-pool",
+description = "Releases label ids to label resource pool by a specific device id")
+public class ReleaseLabelResourceCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "deviceId",
+            description = "Device identity",
+            required = true, multiValued = false)
+    String deviceId = null;
+    @Argument(index = 1, name = "releaseLabelIds",
+            description = "Represents for the label ids that are released. They are splited by dot symbol",
+            required = true, multiValued = false)
+    String releaseLabelIds = null;
+
+    @Override
+    protected void execute() {
+        LabelResourceService lrs = get(LabelResourceService.class);
+        Multimap<DeviceId, LabelResource> map = ArrayListMultimap
+                .create();
+        String[] labelIds = releaseLabelIds.split(",");
+        DefaultLabelResource resource = null;
+        for (int i = 0; i < labelIds.length; i++) {
+            resource = new DefaultLabelResource(
+                                                DeviceId.deviceId(deviceId),
+                                                LabelResourceId.labelResourceId(Long
+                                                        .parseLong(labelIds[i])));
+            map.put(DeviceId.deviceId(deviceId), resource);
+        }
+        lrs.releaseToDevicePool(map);
+    }
+
+}
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 8a303dc..d530ca8 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -38,7 +38,6 @@
                 <ref component-id="cfgCommandCompleter"/>
                 <ref component-id="componentNameCompleter"/>
                 <ref component-id="componentPropertyNameCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -67,7 +66,6 @@
             <action class="org.onosproject.cli.net.DriversListCommand"/>
             <completers>
                 <ref component-id="driverNameCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -78,14 +76,12 @@
             <action class="org.onosproject.cli.net.DevicePortsListCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.DeviceRemoveCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -94,14 +90,12 @@
                 <ref component-id="deviceIdCompleter"/>
                 <ref component-id="nodeIdCompleter"/>
                 <ref component-id="roleCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.AnnotateDeviceCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -109,7 +103,6 @@
             <action class="org.onosproject.cli.net.LinksListCommand"/>
             <completers>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -121,7 +114,6 @@
             <completers>
                 <ref component-id="deviceIdCompleter"/>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -133,7 +125,6 @@
             <completers>
                 <ref component-id="appIdWithIntentNameCompleter"/>
                 <ref component-id="intentIdCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -141,7 +132,6 @@
             <completers>
                 <ref component-id="hostIdCompleter"/>
                 <ref component-id="hostIdCompleter"/>
-                <null/>
             </completers>
             <optional-completers>
                 <entry key="-t" value-ref="ethTypeCompleter"/>
@@ -157,7 +147,6 @@
             <completers>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
-                <null/>
             </completers>
             <optional-completers>
                 <entry key="-t" value-ref="ethTypeCompleter"/>
@@ -173,7 +162,6 @@
             <completers>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
-                <null/>
             </completers>
             <optional-completers>
                 <entry key="-a" value-ref="allAppNameCompleter"/>
@@ -219,7 +207,6 @@
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="nullCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -228,14 +215,12 @@
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="nullCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.RandomIntentCommand"/>
             <completers>
                 <ref component-id="nullCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -243,7 +228,6 @@
             <completers>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -251,7 +235,6 @@
             <completers>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -281,14 +264,12 @@
             <action class="org.onosproject.cli.net.ClusterDevicesCommand"/>
             <completers>
                 <ref component-id="clusterIdCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
             <action class="org.onosproject.cli.net.ClusterLinksCommand"/>
             <completers>
                 <ref component-id="clusterIdCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -299,7 +280,6 @@
             <action class="org.onosproject.cli.net.HostRemoveCommand"/>
             <completers>
                 <ref component-id="hostIdCompleter"/>
-                <null/>
             </completers>
         </command>
         <command>
@@ -319,7 +299,6 @@
             <completers>
                 <ref component-id="flowRuleStatusCompleter"/>
                 <ref component-id="deviceIdCompleter"/>
-                <null/>
             </completers>
         </command>
 
@@ -338,7 +317,6 @@
             <completers>
                 <ref component-id="connectPointCompleter"/>
                 <ref component-id="connectPointCompleter"/>
-                <null/>
             </completers>
             <optional-completers>
                 <entry key="-t" value-ref="ethTypeCompleter"/>
@@ -349,6 +327,37 @@
                 <entry key="-a" value-ref="allAppNameCompleter"/>
             </optional-completers>
         </command>
+        
+        <command>
+            <action class="org.onosproject.cli.net.GetGlobalLabelResourceCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.GetLabelResourceCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.CreateGlobalLabelResourcePoolCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.CreateLabelResourcePoolCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.DestroyGlobalLabelResourcePoolCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.DestroyGlobalLabelResourcePoolCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.ReleaseGlobalLabelResourceCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.ReleaseLabelResourceCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.ApplyGlobalLabelResourceCommand"/>
+        </command>
+        <command>
+            <action class="org.onosproject.cli.net.ApplyLabelResourceCommand"/>
+        </command>
     </command-bundle>
 
     <bean id="appCommandCompleter" class="org.onosproject.cli.app.ApplicationCommandCompleter"/>
diff --git a/core/api/src/test/java/org/onosproject/net/resource/DefaultLabelResourceTest.java b/core/api/src/test/java/org/onosproject/net/resource/DefaultLabelResourceTest.java
new file mode 100644
index 0000000..0e5ec27
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/resource/DefaultLabelResourceTest.java
@@ -0,0 +1,31 @@
+package org.onosproject.net.resource;
+
+import org.junit.Test;
+import org.onosproject.event.AbstractEventTest;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Tests of default label resource.
+ */
+public class DefaultLabelResourceTest extends AbstractEventTest {
+
+    @Test
+    public void testEquality() {
+        String deviceId1 = "of:001";
+        String deviceId2 = "of:002";
+        long labelResourceId1 = 100;
+        long labelResourceId2 = 200;
+        DefaultLabelResource h1 = new DefaultLabelResource(deviceId1,
+                                                           labelResourceId1);
+        DefaultLabelResource h2 = new DefaultLabelResource(deviceId1,
+                                                           labelResourceId1);
+        DefaultLabelResource h3 = new DefaultLabelResource(deviceId2,
+                                                           labelResourceId2);
+        DefaultLabelResource h4 = new DefaultLabelResource(deviceId2,
+                                                           labelResourceId2);
+
+        new EqualsTester().addEqualityGroup(h1, h2).addEqualityGroup(h3, h4)
+                .testEquals();
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/net/resource/LabelResourcePoolTest.java b/core/api/src/test/java/org/onosproject/net/resource/LabelResourcePoolTest.java
new file mode 100644
index 0000000..f4d91c1
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/resource/LabelResourcePoolTest.java
@@ -0,0 +1,23 @@
+package org.onosproject.net.resource;
+
+import org.junit.Test;
+import org.onosproject.event.AbstractEventTest;
+
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Tests of the label resource pool.
+ */
+public class LabelResourcePoolTest extends AbstractEventTest {
+
+    @Test
+    public void testEquality() {
+        LabelResourcePool h1 = new LabelResourcePool("of:001", 0, 100);
+        LabelResourcePool h2 = new LabelResourcePool("of:001", 0, 100);
+        LabelResourcePool h3 = new LabelResourcePool("of:002", 0, 100);
+        LabelResourcePool h4 = new LabelResourcePool("of:002", 0, 100);
+        new EqualsTester().addEqualityGroup(h1, h2).addEqualityGroup(h3, h4)
+                .testEquals();
+    }
+
+}
diff --git a/core/api/src/test/java/org/onosproject/net/resource/LabelResourceRequestTest.java b/core/api/src/test/java/org/onosproject/net/resource/LabelResourceRequestTest.java
new file mode 100644
index 0000000..bc538b2
--- /dev/null
+++ b/core/api/src/test/java/org/onosproject/net/resource/LabelResourceRequestTest.java
@@ -0,0 +1,44 @@
+package org.onosproject.net.resource;
+
+import java.util.Collections;
+
+import org.junit.Test;
+import org.onosproject.event.AbstractEventTest;
+import org.onosproject.net.DeviceId;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.testing.EqualsTester;
+
+/**
+ * Tests of the label resource request.
+ */
+public class LabelResourceRequestTest extends AbstractEventTest {
+
+    @Test
+    public void testEquality() {
+        DeviceId deviceId1 = DeviceId.deviceId("of:0001");
+        DeviceId deviceId2 = DeviceId.deviceId("of:0002");
+        long apply = 2;
+        ImmutableSet<LabelResource> releaseCollection = ImmutableSet
+                .copyOf(Collections.emptySet());
+        LabelResourceRequest h1 = new LabelResourceRequest(
+                                                           deviceId1,
+                                                           LabelResourceRequest.Type.APPLY,
+                                                           apply, null);
+        LabelResourceRequest h2 = new LabelResourceRequest(
+                                                           deviceId1,
+                                                           LabelResourceRequest.Type.APPLY,
+                                                           apply, null);
+        LabelResourceRequest h3 = new LabelResourceRequest(
+                                                           deviceId2,
+                                                           LabelResourceRequest.Type.RELEASE,
+                                                           0, releaseCollection);
+        LabelResourceRequest h4 = new LabelResourceRequest(
+                                                           deviceId2,
+                                                           LabelResourceRequest.Type.RELEASE,
+                                                           0, releaseCollection);
+
+        new EqualsTester().addEqualityGroup(h1, h2).addEqualityGroup(h3, h4)
+                .testEquals();
+    }
+}
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/LabelResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/LabelResourceManager.java
new file mode 100644
index 0000000..2971d97
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/LabelResourceManager.java
@@ -0,0 +1,251 @@
+package org.onosproject.net.resource.impl;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+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.apache.felix.scr.annotations.Service;
+import org.onosproject.event.AbstractListenerRegistry;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceEvent.Type;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.provider.AbstractProviderRegistry;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.resource.LabelResource;
+import org.onosproject.net.resource.LabelResourceAdminService;
+import org.onosproject.net.resource.LabelResourceDelegate;
+import org.onosproject.net.resource.LabelResourceEvent;
+import org.onosproject.net.resource.LabelResourceId;
+import org.onosproject.net.resource.LabelResourceListener;
+import org.onosproject.net.resource.LabelResourcePool;
+import org.onosproject.net.resource.LabelResourceProvider;
+import org.onosproject.net.resource.LabelResourceProviderRegistry;
+import org.onosproject.net.resource.LabelResourceProviderService;
+import org.onosproject.net.resource.LabelResourceService;
+import org.onosproject.net.resource.LabelResourceStore;
+import org.slf4j.Logger;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.Multimap;
+
+/**
+ * provides implementation of the label resource NB &amp; SB APIs.
+ *
+ */
+@Component(immediate = true)
+@Service
+public class LabelResourceManager
+        extends
+        AbstractProviderRegistry<LabelResourceProvider, LabelResourceProviderService>
+        implements LabelResourceService, LabelResourceAdminService,
+        LabelResourceProviderRegistry {
+    private final Logger log = getLogger(getClass());
+    private final LabelResourceDelegate delegate = new InternalLabelResourceDelegate();
+
+    private final AbstractListenerRegistry<LabelResourceEvent, LabelResourceListener> listenerRegistry
+                            = new AbstractListenerRegistry<>();
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LabelResourceStore store;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    private DeviceListener deviceListener = new InternalDeviceListener();
+
+    @Activate
+    public void activate() {
+        store.setDelegate(delegate);
+        eventDispatcher.addSink(LabelResourceEvent.class, listenerRegistry);
+        deviceService.addListener(deviceListener);
+        log.info("Started");
+
+    }
+
+    @Deactivate
+    public void deactivate() {
+        deviceService.removeListener(deviceListener);
+        store.unsetDelegate(delegate);
+        eventDispatcher.removeSink(LabelResourceEvent.class);
+        log.info("Stopped");
+    }
+
+    @Override
+    public boolean createDevicePool(DeviceId deviceId,
+                                    LabelResourceId beginLabel,
+                                    LabelResourceId endLabel) {
+        checkNotNull(deviceId, "deviceId is not null");
+        checkNotNull(beginLabel, "beginLabel is not null");
+        checkNotNull(endLabel, "beginLabel is not null");
+        checkArgument(beginLabel.labelId() < 0 || endLabel.labelId() < 0,
+                      "The value of beginLabel and the value of endLabel must be both positive number.");
+        checkArgument(beginLabel.labelId() > endLabel.labelId(),
+                      "The value of endLabel must be greater than the value of endLabel.");
+        return store.createDevicePool(deviceId, beginLabel, endLabel);
+    }
+
+    @Override
+    public boolean createGlobalPool(LabelResourceId beginLabel,
+                                    LabelResourceId endLabel) {
+        checkNotNull(beginLabel, "beginLabel is not null");
+        checkNotNull(endLabel, "beginLabel is not null");
+        checkArgument(beginLabel.labelId() < 0 || endLabel.labelId() < 0,
+                      "The value of beginLabel and the value of endLabel must be both positive number.");
+        checkArgument(beginLabel.labelId() > endLabel.labelId(),
+                      "The value of endLabel must be greater than the value of endLabel.");
+        return store.createGlobalPool(beginLabel, endLabel);
+    }
+
+    @Override
+    public boolean destroyDevicePool(DeviceId deviceId) {
+        checkNotNull(deviceId, "deviceId is not null");
+        return store.destroyDevicePool(deviceId);
+    }
+
+    @Override
+    public boolean destroyGlobalPool() {
+        return store.destroyGlobalPool();
+    }
+
+    @Override
+    public Collection<LabelResource> applyFromDevicePool(DeviceId deviceId,
+                                                         long applyNum) {
+        checkNotNull(deviceId, "deviceId is not null");
+        checkNotNull(applyNum, "applyNum is not null");
+        return store.applyFromDevicePool(deviceId, applyNum);
+    }
+
+    @Override
+    public Collection<LabelResource> applyFromGlobalPool(long applyNum) {
+        checkNotNull(applyNum, "applyNum is not null");
+        return store.applyFromGlobalPool(applyNum);
+    }
+
+    @Override
+    public boolean releaseToDevicePool(Multimap<DeviceId, LabelResource> release) {
+        checkNotNull(release, "release is not null");
+        return store.releaseToDevicePool(release);
+    }
+
+    @Override
+    public boolean releaseToGlobalPool(Set<LabelResourceId> release) {
+        checkNotNull(release, "release is not null");
+        return store.releaseToGlobalPool(release);
+    }
+
+    @Override
+    public boolean isDevicePoolFull(DeviceId deviceId) {
+        checkNotNull(deviceId, "deviceId is not null");
+        return store.isDevicePoolFull(deviceId);
+    }
+
+    @Override
+    public boolean isGlobalPoolFull() {
+        return store.isGlobalPoolFull();
+    }
+
+    @Override
+    public long getFreeNumOfDevicePool(DeviceId deviceId) {
+        checkNotNull(deviceId, "deviceId is not null");
+        return store.getFreeNumOfDevicePool(deviceId);
+    }
+
+    @Override
+    public long getFreeNumOfGlobalPool() {
+        return store.getFreeNumOfGlobalPool();
+    }
+
+    @Override
+    public LabelResourcePool getDeviceLabelResourcePool(DeviceId deviceId) {
+        checkNotNull(deviceId, "deviceId is not null");
+        return store.getDeviceLabelResourcePool(deviceId);
+    }
+
+    @Override
+    public LabelResourcePool getGlobalLabelResourcePool() {
+        return store.getGlobalLabelResourcePool();
+    }
+
+    @Override
+    public void addListener(LabelResourceListener listener) {
+        listenerRegistry.addListener(listener);
+    }
+
+    @Override
+    public void removeListener(LabelResourceListener listener) {
+        listenerRegistry.removeListener(listener);
+
+    }
+
+    private void post(LabelResourceEvent event) {
+        if (event != null) {
+            eventDispatcher.post(event);
+        }
+    }
+
+    private class InternalLabelResourceDelegate
+            implements LabelResourceDelegate {
+
+        @Override
+        public void notify(LabelResourceEvent event) {
+            post(event);
+        }
+
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        @Override
+        public void event(DeviceEvent event) {
+            Device device = event.subject();
+            if (Type.DEVICE_REMOVED.equals(event.type())) {
+                destroyDevicePool(device.id());
+            }
+        }
+    }
+
+    private class InternalLabelResourceProviderService
+            extends AbstractProviderService<LabelResourceProvider>
+            implements LabelResourceProviderService {
+
+        protected InternalLabelResourceProviderService(LabelResourceProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void deviceLabelResourcePoolDetected(DeviceId deviceId,
+                                                    LabelResourceId beginLabel,
+                                                    LabelResourceId endLabel) {
+            checkNotNull(deviceId, "deviceId is not null");
+            checkNotNull(beginLabel, "beginLabel is not null");
+            checkNotNull(endLabel, "endLabel is not null");
+            createDevicePool(deviceId, beginLabel, endLabel);
+        }
+
+        @Override
+        public void deviceLabelResourcePoolDestroyed(DeviceId deviceId) {
+            checkNotNull(deviceId, "deviceId is not null");
+            destroyDevicePool(deviceId);
+        }
+
+    }
+
+    @Override
+    protected LabelResourceProviderService createProviderService(LabelResourceProvider provider) {
+        return new InternalLabelResourceProviderService(provider);
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLabelResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLabelResourceStore.java
new file mode 100644
index 0000000..ce122c0
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLabelResourceStore.java
@@ -0,0 +1,578 @@
+package org.onosproject.store.resource.impl;
+
+import static org.onlab.util.Tools.groupedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+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.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.cluster.ClusterService;
+import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.resource.DefaultLabelResource;
+import org.onosproject.net.resource.LabelResource;
+import org.onosproject.net.resource.LabelResourceDelegate;
+import org.onosproject.net.resource.LabelResourceEvent;
+import org.onosproject.net.resource.LabelResourceEvent.Type;
+import org.onosproject.net.resource.LabelResourceId;
+import org.onosproject.net.resource.LabelResourcePool;
+import org.onosproject.net.resource.LabelResourceRequest;
+import org.onosproject.net.resource.LabelResourceStore;
+import org.onosproject.store.AbstractStore;
+import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
+import org.onosproject.store.cluster.messaging.ClusterMessage;
+import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
+import org.onosproject.store.flow.ReplicaInfo;
+import org.onosproject.store.flow.ReplicaInfoService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.serializers.KryoSerializer;
+import org.onosproject.store.serializers.impl.DistributedStoreSerializers;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+/**
+ * Manages label resources using copycat.
+ */
+@Component(immediate = true, enabled = true)
+@Service
+public class DistributedLabelResourceStore
+        extends AbstractStore<LabelResourceEvent, LabelResourceDelegate>
+        implements LabelResourceStore {
+    private final Logger log = getLogger(getClass());
+
+    private static final String POOL_MAP_NAME = "labelresourcepool";
+
+    private static final String GLOBAL_RESOURCE_POOL_DEVICE_ID = "global_resource_pool_device_id";
+    // primary data:
+    // read/write needs to be locked
+    private final ReentrantReadWriteLock resourcePoolLock = new ReentrantReadWriteLock();
+
+    private ConsistentMap<DeviceId, LabelResourcePool> resourcePool = null;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ReplicaInfoService replicaInfoManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterCommunicationService clusterCommunicator;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ClusterService clusterService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    private ExecutorService messageHandlingExecutor;
+    private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 8;
+    private static final long PEER_REQUEST_TIMEOUT_MS = 5000;
+
+    protected static final KryoSerializer SERIALIZER = new KryoSerializer() {
+        @Override
+        protected void setupKryoPool() {
+            serializerPool = KryoNamespace.newBuilder()
+                    .register(DistributedStoreSerializers.STORE_COMMON)
+                    .nextId(DistributedStoreSerializers.STORE_CUSTOM_BEGIN)
+                    .register(LabelResourceEvent.class)
+                    .register(LabelResourcePool.class).register(DeviceId.class)
+                    .register(LabelResourceRequest.class)
+                    .register(LabelResourceRequest.Type.class)
+                    .register(LabelResourceEvent.Type.class)
+                    .register(DefaultLabelResource.class)
+                    .register(LabelResourceId.class).build();
+        }
+    };
+
+    @Activate
+    public void activate() {
+
+        resourcePool = storageService
+                .<DeviceId, LabelResourcePool>consistentMapBuilder()
+                .withName(POOL_MAP_NAME).withSerializer(new Serializer() {
+                    KryoNamespace kryo = new KryoNamespace.Builder()
+                            .register(KryoNamespaces.API).build();
+
+                    @Override
+                    public <T> byte[] encode(T object) {
+                        return kryo.serialize(object);
+                    }
+
+                    @Override
+                    public <T> T decode(byte[] bytes) {
+                        return kryo.deserialize(bytes);
+                    }
+                }).withPartitionsDisabled().build();
+        messageHandlingExecutor = Executors
+                .newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE,
+                                    groupedThreads("onos/store/flow",
+                                                   "message-handlers"));
+        clusterCommunicator
+                .addSubscriber(LabelResourceMessageSubjects.LABEL_POOL_CREATED,
+                               new ClusterMessageHandler() {
+
+                                   @Override
+                                   public void handle(ClusterMessage message) {
+                                       LabelResourcePool operation = SERIALIZER
+                                               .decode(message.payload());
+                                       log.trace("received get flow entry request for {}",
+                                                 operation);
+                                       boolean b = internalCreate(operation);
+                                           message.respond(SERIALIZER.encode(b));
+                                   }
+                               }, messageHandlingExecutor);
+        clusterCommunicator
+                .addSubscriber(LabelResourceMessageSubjects.LABEL_POOL_DESTROYED,
+                               new ClusterMessageHandler() {
+
+                                   @Override
+                                   public void handle(ClusterMessage message) {
+                                       DeviceId deviceId = SERIALIZER
+                                               .decode(message.payload());
+                                       log.trace("received get flow entry request for {}",
+                                                 deviceId);
+                                       boolean b = internalDestroy(deviceId);
+                                           message.respond(SERIALIZER.encode(b));
+                                   }
+                               }, messageHandlingExecutor);
+        clusterCommunicator
+                .addSubscriber(LabelResourceMessageSubjects.LABEL_POOL_APPLY,
+                               new ClusterMessageHandler() {
+
+                                   @Override
+                                   public void handle(ClusterMessage message) {
+                                       LabelResourceRequest request = SERIALIZER
+                                               .decode(message.payload());
+                                       log.trace("received get flow entry request for {}",
+                                                 request);
+                                       final Collection<LabelResource> resource = internalApply(request);
+                                           message.respond(SERIALIZER
+                                                   .encode(resource));
+                                   }
+                               }, messageHandlingExecutor);
+        clusterCommunicator
+                .addSubscriber(LabelResourceMessageSubjects.LABEL_POOL_RELEASE,
+                               new ClusterMessageHandler() {
+
+                                   @Override
+                                   public void handle(ClusterMessage message) {
+                                       LabelResourceRequest request = SERIALIZER
+                                               .decode(message.payload());
+                                       log.trace("received get flow entry request for {}",
+                                                 request);
+                                       final boolean isSuccess = internalRelease(request);
+                                           message.respond(SERIALIZER
+                                                   .encode(isSuccess));
+                                   }
+                               }, messageHandlingExecutor);
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        clusterCommunicator
+                .removeSubscriber(LabelResourceMessageSubjects.LABEL_POOL_CREATED);
+        clusterCommunicator
+                .removeSubscriber(LabelResourceMessageSubjects.LABEL_POOL_APPLY);
+        clusterCommunicator
+                .removeSubscriber(LabelResourceMessageSubjects.LABEL_POOL_DESTROYED);
+        clusterCommunicator
+                .removeSubscriber(LabelResourceMessageSubjects.LABEL_POOL_RELEASE);
+        messageHandlingExecutor.shutdown();
+        log.info("Stopped");
+    }
+
+    @Override
+    public boolean createDevicePool(DeviceId deviceId,
+                                    LabelResourceId beginLabel,
+                                    LabelResourceId endLabel) {
+        LabelResourcePool pool = new LabelResourcePool(deviceId.toString(),
+                                                       beginLabel.labelId(),
+                                                       endLabel.labelId());
+        return this.create(pool);
+    }
+
+    @Override
+    public boolean createGlobalPool(LabelResourceId beginLabel,
+                                    LabelResourceId endLabel) {
+        LabelResourcePool pool = new LabelResourcePool(
+                                                       GLOBAL_RESOURCE_POOL_DEVICE_ID,
+                                                       beginLabel.labelId(),
+                                                       endLabel.labelId());
+        return this.internalCreate(pool);
+    }
+
+    private boolean create(LabelResourcePool pool) {
+        Device device = (Device) deviceService.getDevice(pool.deviceId());
+        if (device == null) {
+            return false;
+        }
+
+        ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(pool
+                .deviceId());
+
+        if (!replicaInfo.master().isPresent()) {
+            log.warn("Failed to getFlowEntries: No master for {}", pool);
+            return false;
+        }
+
+        if (replicaInfo.master().get()
+                .equals(clusterService.getLocalNode().id())) {
+            return internalCreate(pool);
+        }
+
+        log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
+                  replicaInfo.master().orNull(), pool.deviceId());
+
+        return complete(clusterCommunicator
+                .sendAndReceive(pool,
+                                LabelResourceMessageSubjects.LABEL_POOL_CREATED,
+                                SERIALIZER::encode, SERIALIZER::decode,
+                                replicaInfo.master().get()));
+    }
+
+    private boolean internalCreate(LabelResourcePool pool) {
+        resourcePoolLock.writeLock().lock();
+        LabelResourcePool poolOld = resourcePool.get(pool.deviceId()).value();
+        if (poolOld == null) {
+            resourcePool.put(pool.deviceId(), pool);
+            resourcePoolLock.writeLock().unlock();
+            LabelResourceEvent event = new LabelResourceEvent(
+                                                              Type.POOL_CREATED,
+                                                              pool);
+            notifyDelegate(event);
+            return true;
+        }
+        resourcePoolLock.writeLock().unlock();
+        return false;
+    }
+
+    @Override
+    public boolean destroyDevicePool(DeviceId deviceId) {
+        Device device = (Device) deviceService.getDevice(deviceId);
+        if (device == null) {
+            return false;
+        }
+        ReplicaInfo replicaInfo = replicaInfoManager
+                .getReplicaInfoFor(deviceId);
+
+        if (!replicaInfo.master().isPresent()) {
+            log.warn("Failed to getFlowEntries: No master for {}", deviceId);
+            return false;
+        }
+
+        if (replicaInfo.master().get()
+                .equals(clusterService.getLocalNode().id())) {
+            return internalDestroy(deviceId);
+        }
+
+        log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
+                  replicaInfo.master().orNull(), deviceId);
+
+        return complete(clusterCommunicator
+                .sendAndReceive(deviceId,
+                                LabelResourceMessageSubjects.LABEL_POOL_DESTROYED,
+                                SERIALIZER::encode, SERIALIZER::decode,
+                                replicaInfo.master().get()));
+    }
+
+    private boolean internalDestroy(DeviceId deviceId) {
+        LabelResourcePool poolOld = resourcePool.get(deviceId).value();
+        if (poolOld != null) {
+            resourcePool.remove(deviceId);
+            LabelResourceEvent event = new LabelResourceEvent(
+                                                              Type.POOL_CREATED,
+                                                              poolOld);
+            notifyDelegate(event);
+        }
+        log.info("success to destroy the label resource pool of device id {}",
+                 deviceId);
+        return true;
+    }
+
+    @Override
+    public Collection<LabelResource> applyFromDevicePool(DeviceId deviceId,
+                                                         long applyNum) {
+        Device device = (Device) deviceService.getDevice(deviceId);
+        if (device == null) {
+            return Collections.emptyList();
+        }
+        LabelResourceRequest request = new LabelResourceRequest(
+                                                                deviceId,
+                                                                LabelResourceRequest.Type.APPLY,
+                                                                applyNum, null);
+        ReplicaInfo replicaInfo = replicaInfoManager
+                .getReplicaInfoFor(deviceId);
+
+        if (!replicaInfo.master().isPresent()) {
+            log.warn("Failed to getFlowEntries: No master for {}", deviceId);
+            return Collections.emptyList();
+        }
+
+        if (replicaInfo.master().get()
+                .equals(clusterService.getLocalNode().id())) {
+            return internalApply(request);
+        }
+
+        log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
+                  replicaInfo.master().orNull(), deviceId);
+
+        return complete(clusterCommunicator
+                .sendAndReceive(request,
+                                LabelResourceMessageSubjects.LABEL_POOL_APPLY,
+                                SERIALIZER::encode, SERIALIZER::decode,
+                                replicaInfo.master().get()));
+    }
+
+    private Collection<LabelResource> internalApply(LabelResourceRequest request) {
+        resourcePoolLock.writeLock().lock();
+        DeviceId deviceId = request.deviceId();
+        long applyNum = request.applyNum();
+        LabelResourcePool pool = resourcePool.get(deviceId).value();
+        Collection<LabelResource> result = new HashSet<LabelResource>();
+        long freeNum = this.getFreeNumOfDevicePool(deviceId);
+        if (applyNum > freeNum) {
+            log.info("the free number of the label resource pool of deviceId {} is not enough.");
+            resourcePoolLock.writeLock().unlock();
+            return Collections.emptyList();
+        }
+        Set<LabelResource> releaseLabels = new HashSet<LabelResource>(
+                                                                      pool.releaseLabelId());
+        long tmp = releaseLabels.size() > applyNum ? applyNum : releaseLabels
+                .size();
+        LabelResource resource = null;
+        for (int i = 0; i < tmp; i++) {
+            Iterator<LabelResource> it = releaseLabels.iterator();
+            if (it.hasNext()) {
+                resource = it.next();
+                releaseLabels.remove(resource);
+            }
+            result.add(resource);
+        }
+        for (long j = pool.currentUsedMaxLabelId().labelId(); j < pool
+                .currentUsedMaxLabelId().labelId() + applyNum - tmp; j++) {
+            resource = new DefaultLabelResource(deviceId,
+                                                LabelResourceId
+                                                        .labelResourceId(j));
+            result.add(resource);
+        }
+        long beginLabel = pool.beginLabel().labelId();
+        long endLabel = pool.endLabel().labelId();
+        long totalNum = pool.totalNum();
+        long current = pool.currentUsedMaxLabelId().labelId() + applyNum - tmp;
+        long usedNum = pool.usedNum() + applyNum;
+        ImmutableSet<LabelResource> freeLabel = ImmutableSet
+                .copyOf(releaseLabels);
+        LabelResourcePool newPool = new LabelResourcePool(deviceId.toString(),
+                                                          beginLabel, endLabel,
+                                                          totalNum, usedNum,
+                                                          current, freeLabel);
+        resourcePool.put(deviceId, newPool);
+        log.info("success to apply label resource");
+        resourcePoolLock.writeLock().unlock();
+        return result;
+    }
+
+    @Override
+    public boolean releaseToDevicePool(Multimap<DeviceId, LabelResource> release) {
+        Map<DeviceId, Collection<LabelResource>> maps = release.asMap();
+        Set<DeviceId> deviceIdSet = maps.keySet();
+        LabelResourceRequest request = null;
+        for (Iterator<DeviceId> it = deviceIdSet.iterator(); it.hasNext();) {
+            DeviceId deviceId = (DeviceId) it.next();
+            Device device = (Device) deviceService.getDevice(deviceId);
+            if (device == null) {
+                continue;
+            }
+            ImmutableSet<LabelResource> collection = ImmutableSet.copyOf(maps
+                    .get(deviceId));
+            request = new LabelResourceRequest(
+                                               deviceId,
+                                               LabelResourceRequest.Type.RELEASE,
+                                               0, collection);
+            ReplicaInfo replicaInfo = replicaInfoManager
+                    .getReplicaInfoFor(deviceId);
+
+            if (!replicaInfo.master().isPresent()) {
+                log.warn("Failed to getFlowEntries: No master for {}", deviceId);
+                return false;
+            }
+
+            if (replicaInfo.master().get()
+                    .equals(clusterService.getLocalNode().id())) {
+                return internalRelease(request);
+            }
+
+            log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
+                      replicaInfo.master().orNull(), deviceId);
+
+            return complete(clusterCommunicator
+                    .sendAndReceive(request,
+                                    LabelResourceMessageSubjects.LABEL_POOL_RELEASE,
+                                    SERIALIZER::encode, SERIALIZER::decode,
+                                    replicaInfo.master().get()));
+        }
+        return false;
+    }
+
+    private boolean internalRelease(LabelResourceRequest request) {
+        resourcePoolLock.writeLock().lock();
+        DeviceId deviceId = request.deviceId();
+        Collection<LabelResource> release = request.releaseCollection();
+        LabelResourcePool pool = resourcePool.get(deviceId).value();
+        if (pool == null) {
+            resourcePoolLock.writeLock().unlock();
+            log.info("the label resource pool of device id {} does not exist");
+            return false;
+        }
+        Set<LabelResource> storeSet = new HashSet<LabelResource>(
+                                                                 pool.releaseLabelId());
+        LabelResource labelResource = null;
+        long realReleasedNum = 0;
+        for (Iterator<LabelResource> it = release.iterator(); it.hasNext();) {
+            labelResource = it.next();
+            if (labelResource.labelResourceId().labelId() < pool.beginLabel()
+                    .labelId()
+                    || labelResource.labelResourceId().labelId() > pool
+                            .endLabel().labelId()) {
+                continue;
+            }
+            if (pool.currentUsedMaxLabelId().labelId() > labelResource
+                    .labelResourceId().labelId()
+                    || !storeSet.contains(labelResource)) {
+                storeSet.add(labelResource);
+                realReleasedNum++;
+            }
+        }
+        long beginNum = pool.beginLabel().labelId();
+        long endNum = pool.endLabel().labelId();
+        long totalNum = pool.totalNum();
+        long usedNum = pool.usedNum() - realReleasedNum;
+        long current = pool.currentUsedMaxLabelId().labelId();
+        ImmutableSet<LabelResource> s = ImmutableSet.copyOf(storeSet);
+        LabelResourcePool newPool = new LabelResourcePool(deviceId.toString(),
+                                                          beginNum, endNum,
+                                                          totalNum, usedNum,
+                                                          current, s);
+        resourcePool.put(deviceId, newPool);
+        log.info("success to release label resource");
+        resourcePoolLock.writeLock().unlock();
+        return true;
+    }
+
+    @Override
+    public boolean isDevicePoolFull(DeviceId deviceId) {
+        LabelResourcePool pool = resourcePool.get(deviceId).value();
+        if (pool == null) {
+            return true;
+        }
+        return pool.currentUsedMaxLabelId() == pool.endLabel()
+                && pool.releaseLabelId().size() == 0 ? true : false;
+    }
+
+    @Override
+    public long getFreeNumOfDevicePool(DeviceId deviceId) {
+        LabelResourcePool pool = resourcePool.get(deviceId).value();
+        if (pool == null) {
+            return 0;
+        }
+        return pool.endLabel().labelId()
+                - pool.currentUsedMaxLabelId().labelId()
+                + pool.releaseLabelId().size();
+    }
+
+    @Override
+    public LabelResourcePool getDeviceLabelResourcePool(DeviceId deviceId) {
+        return resourcePool.get(deviceId).value();
+    }
+
+    @Override
+    public boolean destroyGlobalPool() {
+        return this.internalDestroy(DeviceId
+                .deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID));
+    }
+
+    @Override
+    public Collection<LabelResource> applyFromGlobalPool(long applyNum) {
+        LabelResourceRequest request = new LabelResourceRequest(
+                                                                DeviceId.deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID),
+                                                                LabelResourceRequest.Type.APPLY,
+                                                                applyNum, null);
+        return this.internalApply(request);
+    }
+
+    @Override
+    public boolean releaseToGlobalPool(Set<LabelResourceId> release) {
+        Set<LabelResource> set = new HashSet<LabelResource>();
+        DefaultLabelResource resource = null;
+        for (LabelResourceId labelResource : release) {
+            resource = new DefaultLabelResource(
+                                                DeviceId.deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID),
+                                                labelResource);
+            set.add(resource);
+        }
+        LabelResourceRequest request = new LabelResourceRequest(
+                                                                DeviceId.deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID),
+                                                                LabelResourceRequest.Type.APPLY,
+                                                                0,
+                                                                ImmutableSet
+                                                                        .copyOf(set));
+        return this.internalRelease(request);
+    }
+
+    @Override
+    public boolean isGlobalPoolFull() {
+        return this.isDevicePoolFull(DeviceId
+                .deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID));
+    }
+
+    @Override
+    public long getFreeNumOfGlobalPool() {
+        return this.getFreeNumOfDevicePool(DeviceId
+                .deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID));
+    }
+
+    @Override
+    public LabelResourcePool getGlobalLabelResourcePool() {
+        return this.getDeviceLabelResourcePool(DeviceId
+                .deviceId(GLOBAL_RESOURCE_POOL_DEVICE_ID));
+    }
+
+    private <T> T complete(Future<T> future) {
+        try {
+            return future.get(PEER_REQUEST_TIMEOUT_MS,
+                                                TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.error("Interrupted while waiting for operation to complete.", e);
+            return null;
+        } catch (TimeoutException | ExecutionException e) {
+            log.error("Failed remote operation", e);
+            return null;
+        }
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/LabelResourceMessageSubjects.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/LabelResourceMessageSubjects.java
new file mode 100644
index 0000000..68bce92
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/LabelResourceMessageSubjects.java
@@ -0,0 +1,17 @@
+package org.onosproject.store.resource.impl;
+
+import org.onosproject.store.cluster.messaging.MessageSubject;
+
+public final class LabelResourceMessageSubjects {
+
+    private LabelResourceMessageSubjects() {
+    }
+    public static final MessageSubject LABEL_POOL_CREATED
+                        = new MessageSubject("label-resource-pool-created");
+    public static final MessageSubject LABEL_POOL_DESTROYED
+                        = new MessageSubject("label-resource-pool-destroyed");
+    public static final MessageSubject LABEL_POOL_APPLY
+                        = new MessageSubject("label-resource-pool-apply");
+    public static final MessageSubject LABEL_POOL_RELEASE
+                        = new MessageSubject("label-resource-pool-release");
+}