Merge "Prototype bandwidth reservation"
diff --git a/apps/calendar/src/main/java/org/onlab/onos/calendar/BandwidthCalendarResource.java b/apps/calendar/src/main/java/org/onlab/onos/calendar/BandwidthCalendarResource.java
index c534371..cd8cc5c 100644
--- a/apps/calendar/src/main/java/org/onlab/onos/calendar/BandwidthCalendarResource.java
+++ b/apps/calendar/src/main/java/org/onlab/onos/calendar/BandwidthCalendarResource.java
@@ -15,18 +15,29 @@
  */
 package org.onlab.onos.calendar;
 
-import org.onlab.onos.net.ConnectPoint;
-import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.intent.IntentService;
-import org.onlab.rest.BaseResource;
+import java.net.URI;
 
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.Response;
-import java.net.URI;
+
+import org.onlab.onos.core.ApplicationId;
+import org.onlab.onos.core.CoreService;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
+import org.onlab.onos.net.resource.BandwidthResourceRequest;
+import org.onlab.packet.Ethernet;
+import org.onlab.rest.BaseResource;
 
 import static org.onlab.onos.net.PortNumber.portNumber;
+import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
 
 /**
  * Web resource for triggering calendared intents.
@@ -47,12 +58,33 @@
         ConnectPoint srcPoint = new ConnectPoint(deviceId(src), portNumber(srcPort));
         ConnectPoint dstPoint = new ConnectPoint(deviceId(dst), portNumber(dstPort));
 
+        TrafficSelector selector = buildTrafficSelector();
+        TrafficTreatment treatment = builder().build();
+
+        Intent intent = new PointToPointIntentWithBandwidthConstraint(
+                appId(), selector, treatment,
+                srcPoint, dstPoint, new BandwidthResourceRequest(Double.parseDouble(bandwidth)));
+        service.submit(intent);
+
         return Response.ok("Yo! We got src=" + srcPoint + "; dst=" + dstPoint +
                                    "; bw=" + bandwidth + "; intent service " + service).build();
     }
 
+    private TrafficSelector buildTrafficSelector() {
+        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
+        Short ethType = Ethernet.TYPE_IPV4;
+
+        selectorBuilder.matchEthType(ethType);
+
+        return selectorBuilder.build();
+    }
+
     private DeviceId deviceId(String dpid) {
         return DeviceId.deviceId(URI.create("of:" + dpid));
     }
 
+    protected ApplicationId appId() {
+        return get(CoreService.class).registerApplication("org.onlab.onos.calendar");
+    }
+
 }
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentWithBandwidthConstraintCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentWithBandwidthConstraintCommand.java
new file mode 100644
index 0000000..1207f1a
--- /dev/null
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentWithBandwidthConstraintCommand.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.onlab.onos.cli.net;
+
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
+import org.onlab.onos.net.resource.BandwidthResourceRequest;
+
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.PortNumber.portNumber;
+import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
+
+/**
+ * Installs point-to-point connectivity intents.
+ */
+@Command(scope = "onos", name = "add-point-intent-bw",
+         description = "Installs point-to-point connectivity intent with bandwidth constraint")
+public class AddPointToPointIntentWithBandwidthConstraintCommand extends ConnectivityIntentCommand {
+
+    @Argument(index = 0, name = "ingressDevice",
+              description = "Ingress Device/Port Description",
+              required = true, multiValued = false)
+    String ingressDeviceString = null;
+
+    @Argument(index = 1, name = "egressDevice",
+              description = "Egress Device/Port Description",
+              required = true, multiValued = false)
+    String egressDeviceString = null;
+
+    @Argument(index = 2, name = "bandwidth",
+            description = "Bandwidth",
+            required = true, multiValued = false)
+    String bandwidthString = null;
+
+    @Override
+    protected void execute() {
+        IntentService service = get(IntentService.class);
+
+        DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
+        PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
+        ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
+
+        DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
+        PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
+        ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
+
+        long bandwidth = Long.parseLong(bandwidthString);
+
+        TrafficSelector selector = buildTrafficSelector();
+        TrafficTreatment treatment = builder().build();
+
+        Intent intent = new PointToPointIntentWithBandwidthConstraint(
+                appId(), selector, treatment,
+                ingress, egress, new BandwidthResourceRequest(bandwidth));
+        service.submit(intent);
+    }
+
+    /**
+     * Extracts the port number portion of the ConnectPoint.
+     *
+     * @param deviceString string representing the device/port
+     * @return port number as a string, empty string if the port is not found
+     */
+    private String getPortNumber(String deviceString) {
+        int slash = deviceString.indexOf('/');
+        if (slash <= 0) {
+            return "";
+        }
+        return deviceString.substring(slash + 1, deviceString.length());
+    }
+
+    /**
+     * Extracts the device ID portion of the ConnectPoint.
+     *
+     * @param deviceString string representing the device/port
+     * @return device ID string
+     */
+    private String getDeviceId(String deviceString) {
+        int slash = deviceString.indexOf('/');
+        if (slash <= 0) {
+            return "";
+        }
+        return deviceString.substring(0, slash);
+    }
+}
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
index b9b071f..b61a646 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/ConnectivityIntentCommand.java
@@ -47,8 +47,8 @@
      */
     protected TrafficSelector buildTrafficSelector() {
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
-
         Short ethType = Ethernet.TYPE_IPV4;
+
         if (!Strings.isNullOrEmpty(ethTypeString)) {
             EthType ethTypeParameter = EthType.valueOf(ethTypeString);
             ethType = ethTypeParameter.value();
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 418ee26..f8b6a13 100644
--- a/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/cli/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -116,6 +116,17 @@
             </optional-completers>
         </command>
         <command>
+            <action class="org.onlab.onos.cli.net.AddPointToPointIntentWithBandwidthConstraintCommand"/>
+            <completers>
+                <ref component-id="connectPointCompleter"/>
+                <ref component-id="connectPointCompleter"/>
+                <null/>
+            </completers>
+            <optional-completers>
+                <entry key="-t" value-ref="ethTypeCompleter"/>
+            </optional-completers>
+        </command>
+        <command>
             <action class="org.onlab.onos.cli.net.AddOpticalIntentCommand"/>
             <completers>
                 <ref component-id="connectPointCompleter"/>
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
index 721a8fd..0789db0 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
@@ -20,6 +20,7 @@
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.resource.LinkResourceRequest;
 
 /**
  * Abstraction of explicitly path specified connectivity intent.
@@ -27,6 +28,7 @@
 public class PathIntent extends ConnectivityIntent {
 
     private final Path path;
+    private final LinkResourceRequest[] resourceRequests;
 
     /**
      * Creates a new point-to-point intent with the supplied ingress/egress
@@ -39,10 +41,11 @@
      * @throws NullPointerException {@code path} is null
      */
     public PathIntent(ApplicationId appId, TrafficSelector selector,
-                      TrafficTreatment treatment, Path path) {
+                      TrafficTreatment treatment, Path path, LinkResourceRequest[] resourceRequests) {
         super(id(PathIntent.class, selector, treatment, path), appId,
               resources(path.links()), selector, treatment);
         this.path = path;
+        this.resourceRequests = resourceRequests;
     }
 
     /**
@@ -51,6 +54,7 @@
     protected PathIntent() {
         super();
         this.path = null;
+        this.resourceRequests = new LinkResourceRequest[0];
     }
 
     /**
@@ -67,6 +71,10 @@
         return true;
     }
 
+    public LinkResourceRequest[] resourceRequests() {
+        return resourceRequests;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntentWithBandwidthConstraint.java b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntentWithBandwidthConstraint.java
new file mode 100644
index 0000000..d5c4d57
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntentWithBandwidthConstraint.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.onlab.onos.net.intent;
+
+import org.onlab.onos.core.ApplicationId;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.resource.BandwidthResourceRequest;
+
+import com.google.common.base.MoreObjects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Abstraction of point-to-point connectivity.
+ */
+public class PointToPointIntentWithBandwidthConstraint extends ConnectivityIntent {
+
+    private final ConnectPoint ingressPoint;
+    private final ConnectPoint egressPoint;
+    private final BandwidthResourceRequest bandwidthResourceRequest;
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports.
+     *
+     * @param appId        application identifier
+     * @param selector     traffic selector
+     * @param treatment    treatment
+     * @param ingressPoint ingress port
+     * @param egressPoint  egress port
+     * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
+     */
+    public PointToPointIntentWithBandwidthConstraint(ApplicationId appId, TrafficSelector selector,
+                                                     TrafficTreatment treatment,
+                                                     ConnectPoint ingressPoint,
+                                                     ConnectPoint egressPoint,
+                                                     BandwidthResourceRequest bandwidthResourceRequest) {
+        super(id(PointToPointIntentWithBandwidthConstraint.class, selector,
+                 treatment, ingressPoint, egressPoint, bandwidthResourceRequest.bandwidth()),
+              appId, null, selector, treatment);
+        this.ingressPoint = checkNotNull(ingressPoint);
+        this.egressPoint = checkNotNull(egressPoint);
+        this.bandwidthResourceRequest = bandwidthResourceRequest;
+    }
+
+    /**
+     * Constructor for serializer.
+     */
+    protected PointToPointIntentWithBandwidthConstraint() {
+        super();
+        this.ingressPoint = null;
+        this.egressPoint = null;
+        bandwidthResourceRequest = new BandwidthResourceRequest(0.0);
+    }
+
+    /**
+     * Returns the port on which the ingress traffic should be connected to
+     * the egress.
+     *
+     * @return ingress port
+     */
+    public ConnectPoint ingressPoint() {
+        return ingressPoint;
+    }
+
+    /**
+     * Returns the port on which the traffic should egress.
+     *
+     * @return egress port
+     */
+    public ConnectPoint egressPoint() {
+        return egressPoint;
+    }
+
+    public BandwidthResourceRequest bandwidthRequest() {
+        return this.bandwidthResourceRequest;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("id", id())
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingress", ingressPoint)
+                .add("egress", egressPoint)
+                .add("bandwidth", bandwidthResourceRequest.bandwidth().toString())
+                .toString();
+    }
+
+}
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
index 21efe49..02ca0f5 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
@@ -15,11 +15,12 @@
  */
 package org.onlab.onos.net.intent;
 
-import static org.junit.Assert.assertEquals;
-
 import org.junit.Test;
 import org.onlab.onos.net.NetTestTools;
 import org.onlab.onos.net.Path;
+import org.onlab.onos.net.resource.LinkResourceRequest;
+
+import static org.junit.Assert.assertEquals;
 
 public class PathIntentTest extends ConnectivityIntentTest {
     // 111:11 --> 222:22
@@ -39,11 +40,11 @@
 
     @Override
     protected PathIntent createOne() {
-        return new PathIntent(APPID, MATCH, NOP, PATH1);
+        return new PathIntent(APPID, MATCH, NOP, PATH1, new LinkResourceRequest[0]);
     }
 
     @Override
     protected PathIntent createAnother() {
-        return new PathIntent(APPID, MATCH, NOP, PATH2);
+        return new PathIntent(APPID, MATCH, NOP, PATH2, new LinkResourceRequest[0]);
     }
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
index e045cec..37cf84b 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
@@ -15,6 +15,10 @@
  */
 package org.onlab.onos.net.intent.impl;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -32,13 +36,10 @@
 import org.onlab.onos.net.intent.IntentExtensionService;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.topology.LinkWeight;
+import org.onlab.onos.net.resource.LinkResourceRequest;
 import org.onlab.onos.net.topology.PathService;
 import org.onlab.onos.net.topology.TopologyEdge;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
 import static org.onlab.onos.net.flow.DefaultTrafficSelector.builder;
 
 /**
@@ -85,7 +86,7 @@
         TrafficSelector selector = builder(intent.selector())
                 .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
         return new PathIntent(intent.appId(), selector, intent.treatment(),
-                              path);
+                              path, new LinkResourceRequest[0]);
     }
 
     private Path getPath(HostId one, HostId two) {
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
index d0666cc..ad8ea08 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PathIntentInstaller.java
@@ -15,9 +15,6 @@
  */
 package org.onlab.onos.net.intent.impl;
 
-import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
-import static org.slf4j.LoggerFactory.getLogger;
-
 import java.util.Iterator;
 import java.util.List;
 
@@ -41,10 +38,15 @@
 import org.onlab.onos.net.intent.IntentExtensionService;
 import org.onlab.onos.net.intent.IntentInstaller;
 import org.onlab.onos.net.intent.PathIntent;
+import org.onlab.onos.net.resource.LinkResourceAllocations;
+import org.onlab.onos.net.resource.LinkResourceService;
 import org.slf4j.Logger;
 
 import com.google.common.collect.Lists;
 
+import static org.onlab.onos.net.flow.DefaultTrafficTreatment.builder;
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * Installer for {@link PathIntent packet path connectivity intents}.
  */
@@ -59,6 +61,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkResourceService resourceService;
+
     private ApplicationId appId;
 
     @Activate
@@ -74,6 +79,11 @@
 
     @Override
     public List<FlowRuleBatchOperation> install(PathIntent intent) {
+        LinkResourceAllocations allocations = allocateBandwidth(intent);
+        if (allocations == null) {
+            log.debug("Insufficient bandwidth available to install path intent {}", intent);
+            return null;
+        }
         TrafficSelector.Builder builder =
                 DefaultTrafficSelector.builder(intent.selector());
         Iterator<Link> links = intent.path().links().iterator();
@@ -117,6 +127,10 @@
         return Lists.newArrayList(new FlowRuleBatchOperation(rules));
     }
 
+    private LinkResourceAllocations allocateBandwidth(PathIntent intent) {
+        return resourceService.requestResources(intent.resourceRequests()[0]);
+    }
+
     // TODO refactor below this line... ----------------------------
 
     /**
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
index 5c79d5c..893b7ea 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
@@ -15,6 +15,10 @@
  */
 package org.onlab.onos.net.intent.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -31,15 +35,12 @@
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.resource.LinkResourceRequest;
 import org.onlab.onos.net.topology.LinkWeight;
 import org.onlab.onos.net.topology.Topology;
 import org.onlab.onos.net.topology.TopologyEdge;
 import org.onlab.onos.net.topology.TopologyService;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
 import static java.util.Arrays.asList;
 
 /**
@@ -76,7 +77,7 @@
         links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
 
         return asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
-                                                       path.annotations()), intent));
+                path.annotations()), intent));
     }
 
     /**
@@ -89,7 +90,8 @@
     private Intent createPathIntent(Path path,
                                     PointToPointIntent intent) {
         return new PathIntent(intent.appId(),
-                              intent.selector(), intent.treatment(), path);
+                              intent.selector(), intent.treatment(), path,
+                              new LinkResourceRequest[0]);
     }
 
     /**
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentWithBandwidthConstraintCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentWithBandwidthConstraintCompiler.java
new file mode 100644
index 0000000..a192a9f
--- /dev/null
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentWithBandwidthConstraintCompiler.java
@@ -0,0 +1,146 @@
+package org.onlab.onos.net.intent.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DefaultEdgeLink;
+import org.onlab.onos.net.DefaultPath;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.Path;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentCompiler;
+import org.onlab.onos.net.intent.IntentExtensionService;
+import org.onlab.onos.net.intent.PathIntent;
+import org.onlab.onos.net.intent.PointToPointIntent;
+import org.onlab.onos.net.intent.PointToPointIntentWithBandwidthConstraint;
+import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.resource.BandwidthResourceRequest;
+import org.onlab.onos.net.resource.DefaultLinkResourceRequest;
+import org.onlab.onos.net.resource.LinkResourceRequest;
+import org.onlab.onos.net.resource.LinkResourceService;
+import org.onlab.onos.net.resource.ResourceRequest;
+import org.onlab.onos.net.resource.ResourceType;
+import org.onlab.onos.net.topology.LinkWeight;
+import org.onlab.onos.net.topology.Topology;
+import org.onlab.onos.net.topology.TopologyEdge;
+import org.onlab.onos.net.topology.TopologyService;
+
+/**
+ * A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}.
+ */
+@Component(immediate = true)
+public class PointToPointIntentWithBandwidthConstraintCompiler
+        implements IntentCompiler<PointToPointIntentWithBandwidthConstraint> {
+
+    private static final ProviderId PID = new ProviderId("core", "org.onlab.onos.core", true);
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentExtensionService intentManager;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TopologyService topologyService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkResourceService resourceService;
+
+    @Activate
+    public void activate() {
+        intentManager.registerCompiler(PointToPointIntentWithBandwidthConstraint.class, this);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        intentManager.unregisterCompiler(PointToPointIntent.class);
+    }
+
+    @Override
+    public List<Intent> compile(PointToPointIntentWithBandwidthConstraint intent) {
+        Path path = getPath(intent.ingressPoint(), intent.egressPoint(), intent.bandwidthRequest());
+
+        List<Link> links = new ArrayList<>();
+        links.add(DefaultEdgeLink.createEdgeLink(intent.ingressPoint(), true));
+        links.addAll(path.links());
+        links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
+
+        return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
+                                                              path.annotations()),
+                                              intent));
+    }
+
+    /**
+     * Creates a path intent from the specified path and original
+     * connectivity intent.
+     *
+     * @param path   path to create an intent for
+     * @param intent original intent
+     */
+    private Intent createPathIntent(Path path,
+                                    PointToPointIntentWithBandwidthConstraint intent) {
+        LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
+                path.links())
+                // TODO - this seems awkward, maybe allow directly attaching a BandwidthRequest
+                .addBandwidthRequest(intent.bandwidthRequest().bandwidth().toDouble());
+        LinkResourceRequest bandwidthRequest  = request.build();
+        LinkResourceRequest[] bandwidthRequests = {bandwidthRequest};
+        return new PathIntent(intent.appId(),
+                              intent.selector(), intent.treatment(), path,
+                              bandwidthRequests);
+    }
+
+    /**
+     * Computes a path between two ConnectPoints.
+     *
+     * @param one start of the path
+     * @param two end of the path
+     * @return Path between the two
+     * @throws org.onlab.onos.net.intent.impl.PathNotFoundException if a path cannot be found
+     */
+    private Path getPath(ConnectPoint one, ConnectPoint two, final BandwidthResourceRequest bandwidthRequest) {
+        Topology topology = topologyService.currentTopology();
+        LinkWeight weight = new LinkWeight() {
+            @Override
+            public double weight(TopologyEdge edge) {
+                if (bandwidthRequest != null) {
+                    double allocatedBandwidth = 0.0;
+                    Iterable<ResourceRequest> availableResources = resourceService.getAvailableResources(edge.link());
+                    for (ResourceRequest availableResource : availableResources) {
+                        if (availableResource.type() == ResourceType.BANDWIDTH) {
+                            BandwidthResourceRequest bandwidthRequest = (BandwidthResourceRequest) availableResource;
+                            allocatedBandwidth += bandwidthRequest.bandwidth().toDouble();
+                        }
+                    }
+
+                    // TODO this needs to be discovered from switch/ports somehow
+                    double maxBandwidth = 1000;
+
+                    double availableBandwidth = maxBandwidth - allocatedBandwidth;
+                    if (availableBandwidth >= bandwidthRequest.bandwidth().toDouble()) {
+                        return 1;
+                    } else {
+                        return -1;
+                    }
+                } else {
+                    return 1;
+                }
+            }
+        };
+
+        Set<Path> paths = topologyService.getPaths(topology,
+                one.deviceId(),
+                two.deviceId(),
+                weight);
+
+        if (paths.isEmpty()) {
+            throw new PathNotFoundException("No packet path from " + one + " to " + two);
+        }
+        // TODO: let's be more intelligent about this eventually
+        return paths.iterator().next();
+    }
+}
diff --git a/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java b/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
index bdd0761..4f84b82 100644
--- a/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/resource/impl/LinkResourceManager.java
@@ -17,6 +17,7 @@
 
 import static org.slf4j.LoggerFactory.getLogger;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -50,6 +51,8 @@
 
     private final Logger log = getLogger(getClass());
 
+    LinkResourceAllocations savedAllocations;
+
     @Activate
     public void activate() {
         log.info("Started");
@@ -64,6 +67,8 @@
         return Sets.newHashSet(Lambda.valueOf(7));
     }
 
+    double usedBandwidth = 0.0;
+
     @Override
     public LinkResourceAllocations requestResources(LinkResourceRequest req) {
         // TODO implement it using a resource data store.
@@ -75,6 +80,7 @@
                 log.info("requestResources() always returns requested bandwidth");
                 BandwidthResourceRequest br = (BandwidthResourceRequest) r;
                 alloc = new BandwidthResourceAllocation(br.bandwidth());
+                usedBandwidth += br.bandwidth().toDouble();
                 break;
             case LAMBDA:
                 log.info("requestResources() always returns lambda 7");
@@ -92,7 +98,8 @@
         for (Link link : req.links()) {
             allocations.put(link, Sets.newHashSet(alloc));
         }
-        return new DefaultLinkResourceAllocations(req, allocations);
+        savedAllocations = new DefaultLinkResourceAllocations(req, allocations);
+        return savedAllocations;
     }
 
     @Override
@@ -115,8 +122,11 @@
 
     @Override
     public Iterable<LinkResourceAllocations> getAllocations(Link link) {
-        // TODO Auto-generated method stub
-        return null;
+        ArrayList<LinkResourceAllocations> retval = new ArrayList<>(0);
+        if (savedAllocations != null) {
+            retval.add(savedAllocations);
+        }
+        return retval;
     }
 
     @Override
@@ -127,8 +137,10 @@
 
     @Override
     public Iterable<ResourceRequest> getAvailableResources(Link link) {
-        // TODO Auto-generated method stub
-        return null;
+        BandwidthResourceRequest bw = new BandwidthResourceRequest(usedBandwidth);
+        ArrayList<ResourceRequest> result = new ArrayList<>();
+        result.add(bw);
+        return result;
     }
 
     @Override