ONOS-631 #Initial MPLS intent implementation

Change-Id: I6f906b953f06f395cc67e612648802e333c0e581
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
index 0119e1f..73b053d 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DistributedLinkResourceStore.java
@@ -42,6 +42,8 @@
 import org.onosproject.net.resource.LinkResourceAllocations;
 import org.onosproject.net.resource.LinkResourceEvent;
 import org.onosproject.net.resource.LinkResourceStore;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocationException;
 import org.onosproject.net.resource.ResourceType;
@@ -105,9 +107,10 @@
     // Link annotation key name to use as max lambda
     private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
 
+    // Max MPLS labels: 2^20 – 1
+    private int maxMplsLabel = 0xFFFFF;
     private StoreSerializer serializer;
 
-
     void createTable(String tableName) {
         boolean tableReady = false;
         do {
@@ -150,6 +153,9 @@
         if (type == ResourceType.LAMBDA) {
             return getLambdaResourceCapacity(link);
         }
+        if (type == ResourceType.MPLS_LABEL) {
+            return getMplsResourceCapacity();
+        }
         return null;
     }
 
@@ -189,6 +195,17 @@
         return new BandwidthResourceAllocation(bandwidth);
     }
 
+    private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
+        Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
+        //Ignoring reserved labels of 0 through 15
+        for (int i = 16; i <= maxMplsLabel; i++) {
+            allocations.add(new MplsLabelResourceAllocation(MplsLabel
+                    .valueOf(i)));
+
+        }
+        return allocations;
+    }
+
     private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
         Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
         for (ResourceType type : ResourceType.values()) {
@@ -273,6 +290,34 @@
                 free.put(type, freeL);
                 break;
             }
+            case MPLS_LABEL:
+            {
+                Set<? extends ResourceAllocation> mpls = caps.get(type);
+                if (mpls == null || mpls.isEmpty()) {
+                    // nothing left
+                    break;
+                }
+                Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
+                for (ResourceAllocation r : mpls) {
+                    if (r instanceof MplsLabelResourceAllocation) {
+                        freeLabel.add((MplsLabelResourceAllocation) r);
+                    }
+                }
+
+                // enumerate current allocations, removing resources
+                for (LinkResourceAllocations alloc : allocations) {
+                    Set<ResourceAllocation> types = alloc
+                            .getResourceAllocation(link);
+                    for (ResourceAllocation a : types) {
+                        if (a instanceof MplsLabelResourceAllocation) {
+                            freeLabel.remove(a);
+                        }
+                    }
+                }
+
+                free.put(type, freeLabel);
+                break;
+            }
 
             default:
                 break;
@@ -298,7 +343,6 @@
                        encodeIntentAllocations(alloc));
     }
 
-
     @Override
     public void allocateResources(LinkResourceAllocations allocations) {
         checkNotNull(allocations);
@@ -313,8 +357,9 @@
         }
 
         BatchWriteRequest batch = tx.build();
-//        log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
-//        log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
+//         log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
+//         log.info("Link: {}",
+        // databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
 
         BatchWriteResult result = databaseService.batchWrite(batch);
         if (!result.isSuccessful()) {
@@ -407,6 +452,21 @@
                                     link,
                                     lambdaAllocation.lambda().toInt()));
                 }
+            } else if (req instanceof MplsLabelResourceAllocation) {
+
+                final MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
+                // check if allocation should be accepted
+                if (!avail.contains(req)) {
+                    // requested mpls label was not available
+                    throw new ResourceAllocationException(
+                                                          PositionalParameterStringFormatter
+                                                                  .format("Unable to allocate MPLS label for "
+                                                                          + "link {} MPLS label is {}",
+                                                                          link,
+                                                                          mplsAllocation
+                                                                                  .mplsLabel()
+                                                                                  .toString()));
+                }
             }
         }
         // all requests allocatable => add allocation
@@ -466,8 +526,7 @@
 
         // Issue events to force recompilation of intents.
 
-        final List<LinkResourceAllocations> releasedResources =
-                ImmutableList.of(allocations);
+        final List<LinkResourceAllocations> releasedResources = ImmutableList.of(allocations);
         return new LinkResourceEvent(
                 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
                 releasedResources);
@@ -485,32 +544,32 @@
     }
 
     private String toLinkDbKey(LinkKey linkid) {
-        // introduce cache if necessary
+//         introduce cache if necessary
         return linkid.toString();
-        // Note: Above is irreversible, if we need reverse conversion
-        // we may need something like below, due to String only limitation
-//        byte[] bytes = serializer.encode(linkid);
-//        StringBuilder builder = new StringBuilder(bytes.length * 4);
-//        boolean isFirst = true;
-//        for (byte b : bytes) {
-//            if (!isFirst) {
-//                builder.append(',');
-//            }
-//            builder.append(b);
-//            isFirst = false;
-//        }
-//        return builder.toString();
+//         Note: Above is irreversible, if we need reverse conversion
+//         we may need something like below, due to String only limitation
+//         byte[] bytes = serializer.encode(linkid);
+//         StringBuilder builder = new StringBuilder(bytes.length * 4);
+//         boolean isFirst = true;
+//         for (byte b : bytes) {
+//         if (!isFirst) {
+//         builder.append(',');
+//         }
+//         builder.append(b);
+//         isFirst = false;
+//         }
+//         return builder.toString();
     }
 
-//    private LinkKey toLinkKey(String linkKey) {
-//        String[] bytes = linkKey.split(",");
-//        ByteBuffer buf = ByteBuffer.allocate(bytes.length);
-//        for (String bs : bytes) {
-//            buf.put(Byte.parseByte(bs));
-//        }
-//        buf.flip();
-//        return serializer.decode(buf);
-//    }
+//     private LinkKey toLinkKey(String linkKey) {
+//     String[] bytes = linkKey.split(",");
+//     ByteBuffer buf = ByteBuffer.allocate(bytes.length);
+//     for (String bs : bytes) {
+//     buf.put(Byte.parseByte(bs));
+//     }
+//     buf.flip();
+//     return serializer.decode(buf);
+//     }
 
     private String toIntentDbKey(IntentId intentid) {
         return intentid.toString();
@@ -565,16 +624,16 @@
         Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
 
         return FluentIterable.from(all.values())
-            .transform(new Function<VersionedValue, LinkResourceAllocations>() {
+                .transform(new Function<VersionedValue, LinkResourceAllocations>() {
 
-                @Override
-                public LinkResourceAllocations apply(VersionedValue input) {
-                    if (input == null || input.value() == null) {
-                        return null;
-                    }
-                    return decodeIntentAllocations(input.value());
-                }
-            })
-            .filter(notNull());
+                               @Override
+                               public LinkResourceAllocations apply(VersionedValue input) {
+                                   if (input == null || input.value() == null) {
+                                       return null;
+                                   }
+                                   return decodeIntentAllocations(input.value());
+                               }
+                           })
+                           .filter(notNull());
     }
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
index 7344862..52494dd 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/HazelcastLinkResourceStore.java
@@ -43,6 +43,8 @@
 import org.onosproject.net.resource.LinkResourceAllocations;
 import org.onosproject.net.resource.LinkResourceEvent;
 import org.onosproject.net.resource.LinkResourceStore;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocation;
 import org.onosproject.net.resource.ResourceAllocationException;
 import org.onosproject.net.resource.ResourceType;
@@ -103,6 +105,9 @@
     // Link annotation key name to use as max lambda
     private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
 
+    // Max MPLS labels: 2^20 – 1
+    private int maxMplsLabel = 0xFFFFF;
+
     @Override
     @Activate
     public void activate() {
@@ -141,6 +146,9 @@
         if (type == ResourceType.LAMBDA) {
             return getLambdaResourceCapacity(link);
         }
+        if (type == ResourceType.MPLS_LABEL) {
+            return getMplsResourceCapacity();
+        }
         return null;
     }
 
@@ -180,6 +188,17 @@
         return new BandwidthResourceAllocation(bandwidth);
     }
 
+    private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
+        Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
+        //Ignoring reserved labels of 0 through 15
+        for (int i = 16; i <= maxMplsLabel; i++) {
+            allocations.add(new MplsLabelResourceAllocation(MplsLabel
+                    .valueOf(i)));
+
+        }
+        return allocations;
+    }
+
     private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
         Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
         for (ResourceType type : ResourceType.values()) {
@@ -275,6 +294,33 @@
                 break;
             }
 
+            case MPLS_LABEL:
+                Set<? extends ResourceAllocation> mpls = caps.get(type);
+                if (mpls == null || mpls.isEmpty()) {
+                    // nothing left
+                    break;
+                }
+                Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
+                for (ResourceAllocation r : mpls) {
+                    if (r instanceof MplsLabelResourceAllocation) {
+                        freeLabel.add((MplsLabelResourceAllocation) r);
+                    }
+                }
+
+                // enumerate current allocations, removing resources
+                for (LinkResourceAllocations alloc : allocations) {
+                    Set<ResourceAllocation> types = alloc
+                            .getResourceAllocation(link);
+                    for (ResourceAllocation a : types) {
+                        if (a instanceof MplsLabelResourceAllocation) {
+                            freeLabel.remove(a);
+                        }
+                    }
+                }
+
+                free.put(type, freeLabel);
+                break;
+
             default:
                 break;
             }
@@ -354,6 +400,18 @@
                                     link,
                                     lambdaAllocation.lambda().toInt()));
                 }
+            } else if (req instanceof MplsLabelResourceAllocation) {
+                MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
+                if (!avail.contains(req)) {
+                    throw new ResourceAllocationException(
+                                                          PositionalParameterStringFormatter
+                                                                  .format("Unable to allocate MPLS label for link "
+                                                                          + "{} MPLS label is {}",
+                                                                          link,
+                                                                          mplsAllocation
+                                                                                  .mplsLabel()
+                                                                                  .toString()));
+                }
             }
         }
         // all requests allocatable => add allocation
diff --git a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
index 846fa75..4e9fe4f 100644
--- a/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onosproject/store/serializers/KryoNamespaces.java
@@ -87,6 +87,8 @@
 import org.onosproject.net.intent.IntentState;
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.MplsIntent;
+import org.onosproject.net.intent.MplsPathIntent;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.OpticalConnectivityIntent;
 import org.onosproject.net.intent.OpticalPathIntent;
@@ -113,6 +115,9 @@
 import org.onosproject.net.resource.LambdaResourceAllocation;
 import org.onosproject.net.resource.LambdaResourceRequest;
 import org.onosproject.net.resource.LinkResourceRequest;
+import org.onosproject.net.resource.MplsLabel;
+import org.onosproject.net.resource.MplsLabelResourceAllocation;
+import org.onosproject.net.resource.MplsLabelResourceRequest;
 import org.onosproject.store.Timestamp;
 import org.onosproject.store.service.BatchReadRequest;
 import org.onosproject.store.service.BatchWriteRequest;
@@ -345,6 +350,14 @@
             .register(WriteStatus.class)
             .register(VersionedValue.class)
             .register(DefaultGroupId.class)
+            .register(
+                    MplsIntent.class,
+                    MplsPathIntent.class,
+                    MplsLabelResourceAllocation.class,
+                    MplsLabelResourceRequest.class,
+                    MplsLabel.class,
+                    org.onlab.packet.MplsLabel.class
+                    )
 
             .build();
 
diff --git a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
index 33d7118..f890754 100644
--- a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
+++ b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
@@ -25,6 +25,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.DefaultApplicationId;
 import org.onosproject.core.GroupId;
@@ -184,7 +185,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
@@ -244,7 +245,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
                                                         tBuilder.build()));
         }
@@ -347,7 +348,7 @@
                     .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
                     .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
                     .pushMpls()
-                    .setMpls(106);
+                    .setMpls(MplsLabel.mplsLabel(106));
             buckets.add(DefaultGroupBucket.createSelectGroupBucket(
                     tBuilder.build()));
         }