Brian O'Connor

Applied some fixes to Intents

- Use classname instead of class in IntentId
- Added hashcode and equals to LambdaResourceAllocation
- Untrack resources in IntentManger during uninstall
- Refactored common code in OpticalPathIntentInstaller
- Copied SimpleLinkResourceStore to DistributedLinkResourceStore
- Added a few unserializable files to KryoNamespaces

Change-Id: Ic35d102244972d5cf0c64482fd99e8c9bb1293a6
......@@ -19,6 +19,7 @@ import org.onlab.onos.core.ApplicationId;
import org.onlab.onos.net.NetworkResource;
import org.onlab.onos.net.flow.BatchOperationTarget;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
......@@ -93,9 +94,10 @@ public abstract class Intent implements BatchOperationTarget {
* @param fields intent fields
* @return intent identifier
*/
protected static IntentId id(Object... fields) {
protected static IntentId id(Class<?> intentClass, Object... fields) {
// FIXME: spread the bits across the full long spectrum
return IntentId.valueOf(Objects.hash(fields));
return IntentId.valueOf(Objects.hash(intentClass.getName(),
Arrays.hashCode(fields)));
}
/**
......
......@@ -15,6 +15,8 @@
*/
package org.onlab.onos.net.resource;
import java.util.Objects;
/**
* Representation of allocated lambda resource.
*/
......@@ -45,4 +47,21 @@ public class LambdaResourceAllocation extends LambdaResourceRequest
public Lambda lambda() {
return lambda;
}
@Override
public int hashCode() {
return Objects.hash(lambda);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final LambdaResourceAllocation other = (LambdaResourceAllocation) obj;
return Objects.equals(this.lambda, other.lambda);
}
}
......
......@@ -407,6 +407,8 @@ public class IntentManager
List<Intent> installables = store.getInstallableIntents(intent.id());
if (installables != null) {
for (Intent installable : installables) {
trackerService.removeTrackedResources(intent.id(),
installable.resources());
List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
uninstallWork.addAll(batches);
}
......
......@@ -94,7 +94,26 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
@Override
public List<FlowRuleBatchOperation> install(OpticalPathIntent intent) {
LinkResourceAllocations allocations = assignWavelength(intent);
return generateRules(intent, allocations, FlowRuleOperation.ADD);
}
@Override
public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
return generateRules(intent, allocations, FlowRuleOperation.REMOVE);
}
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
intent.path().links())
.addLambdaRequest();
LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
return retLambda;
}
private List<FlowRuleBatchOperation> generateRules(OpticalPathIntent intent,
LinkResourceAllocations allocations,
FlowRuleOperation operation) {
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
......@@ -128,7 +147,7 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
rules.add(new FlowRuleBatchEntry(operation, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
......@@ -136,28 +155,20 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
TrafficTreatment.Builder treatmentLast = builder();
treatmentLast.setOutput(intent.dst().port());
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
treatmentLast.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
rules.add(new FlowRuleBatchEntry(operation, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
intent.path().links())
.addLambdaRequest();
LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
return retLambda;
}
/*private Lambda assignWavelength(List<Link> links) {
// TODO More wavelength assignment algorithm
int wavenum = 0;
......@@ -194,64 +205,4 @@ public class OpticalPathIntentInstaller implements IntentInstaller<OpticalPathIn
}
return false;
}*/
@Override
public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
selectorBuilder.matchInport(intent.src().port());
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
ConnectPoint prev = intent.src();
//TODO throw exception if the lambda was not retrieved successfully
for (Link link : intent.path().links()) {
Lambda la = null;
for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
if (allocation.type() == ResourceType.LAMBDA) {
la = ((LambdaResourceAllocation) allocation).lambda();
break;
}
}
if (la == null) {
log.info("Lambda was not retrieved successfully");
return null;
}
treatmentBuilder.setOutput(link.src().port());
treatmentBuilder.setLambda((short) la.toInt());
FlowRule rule = new DefaultFlowRule(prev.deviceId(),
selectorBuilder.build(),
treatmentBuilder.build(),
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
prev = link.dst();
selectorBuilder.matchInport(link.dst().port());
selectorBuilder.matchLambda((short) la.toInt());
}
// build the last T port rule
TrafficTreatment treatmentLast = builder()
.setOutput(intent.dst().port()).build();
FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
selectorBuilder.build(),
treatmentLast,
100,
appId,
100,
true);
rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
return Lists.newArrayList(new FlowRuleBatchOperation(rules));
}
}
......
/*
* Copyright 2014 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onlab.onos.store.resource.impl;
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.Service;
import org.onlab.onos.net.Link;
import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.resource.Bandwidth;
import org.onlab.onos.net.resource.BandwidthResourceAllocation;
import org.onlab.onos.net.resource.Lambda;
import org.onlab.onos.net.resource.LambdaResourceAllocation;
import org.onlab.onos.net.resource.LinkResourceAllocations;
import org.onlab.onos.net.resource.LinkResourceStore;
import org.onlab.onos.net.resource.ResourceAllocation;
import org.onlab.onos.net.resource.ResourceType;
import org.slf4j.Logger;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Manages link resources using trivial in-memory structures implementation.
*/
@Component(immediate = true)
@Service
public class DistributedLinkResourceStore implements LinkResourceStore {
private final Logger log = getLogger(getClass());
private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap;
private Map<Link, Set<LinkResourceAllocations>> allocatedResources;
private Map<Link, Set<ResourceAllocation>> freeResources;
@Activate
public void activate() {
linkResourceAllocationsMap = new HashMap<>();
allocatedResources = new HashMap<>();
freeResources = new HashMap<>();
log.info("Started");
}
@Deactivate
public void deactivate() {
log.info("Stopped");
}
/**
* Returns free resources for a given link obtaining from topology
* information.
*
* @param link the target link
* @return free resources
*/
private Set<ResourceAllocation> readOriginalFreeResources(Link link) {
// TODO read capacity and lambda resources from topology
Set<ResourceAllocation> allocations = new HashSet<>();
for (int i = 1; i <= 100; i++) {
allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
}
allocations.add(new BandwidthResourceAllocation(Bandwidth.valueOf(1000000)));
return allocations;
}
/**
* Finds and returns {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object from a given
* set.
*
* @param freeRes a set of ResourceAllocation object.
* @return {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object if found, otherwise
* {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object with 0 bandwidth
*
*/
private BandwidthResourceAllocation getBandwidth(Set<ResourceAllocation> freeRes) {
for (ResourceAllocation res : freeRes) {
if (res.type() == ResourceType.BANDWIDTH) {
return (BandwidthResourceAllocation) res;
}
}
return new BandwidthResourceAllocation(Bandwidth.valueOf(0));
}
/**
* Subtracts given resources from free resources for given link.
*
* @param link the target link
* @param allocations the resources to be subtracted
*/
private void subtractFreeResources(Link link, LinkResourceAllocations allocations) {
// TODO Use lock or version for updating freeResources.
checkNotNull(link);
Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
Set<ResourceAllocation> subRes = allocations.getResourceAllocation(link);
for (ResourceAllocation res : subRes) {
switch (res.type()) {
case BANDWIDTH:
BandwidthResourceAllocation ba = getBandwidth(freeRes);
double requestedBandwidth =
((BandwidthResourceAllocation) res).bandwidth().toDouble();
double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth;
checkState(newBandwidth >= 0.0);
freeRes.remove(ba);
freeRes.add(new BandwidthResourceAllocation(
Bandwidth.valueOf(newBandwidth)));
break;
case LAMBDA:
checkState(freeRes.remove(res));
break;
default:
break;
}
}
freeResources.put(link, freeRes);
}
/**
* Adds given resources to free resources for given link.
*
* @param link the target link
* @param allocations the resources to be added
*/
private void addFreeResources(Link link, LinkResourceAllocations allocations) {
// TODO Use lock or version for updating freeResources.
Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
Set<ResourceAllocation> addRes = allocations.getResourceAllocation(link);
for (ResourceAllocation res : addRes) {
switch (res.type()) {
case BANDWIDTH:
BandwidthResourceAllocation ba = getBandwidth(freeRes);
double requestedBandwidth =
((BandwidthResourceAllocation) res).bandwidth().toDouble();
double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth;
freeRes.remove(ba);
freeRes.add(new BandwidthResourceAllocation(
Bandwidth.valueOf(newBandwidth)));
break;
case LAMBDA:
checkState(freeRes.add(res));
break;
default:
break;
}
}
freeResources.put(link, freeRes);
}
@Override
public Set<ResourceAllocation> getFreeResources(Link link) {
checkNotNull(link);
Set<ResourceAllocation> freeRes = freeResources.get(link);
if (freeRes == null) {
freeRes = readOriginalFreeResources(link);
}
return freeRes;
}
@Override
public void allocateResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
linkResourceAllocationsMap.put(allocations.intendId(), allocations);
for (Link link : allocations.links()) {
subtractFreeResources(link, allocations);
Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
if (linkAllocs == null) {
linkAllocs = new HashSet<>();
}
linkAllocs.add(allocations);
allocatedResources.put(link, linkAllocs);
}
}
@Override
public void releaseResources(LinkResourceAllocations allocations) {
checkNotNull(allocations);
linkResourceAllocationsMap.remove(allocations);
for (Link link : allocations.links()) {
addFreeResources(link, allocations);
Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
if (linkAllocs == null) {
log.error("Missing resource allocation.");
} else {
linkAllocs.remove(allocations);
}
allocatedResources.put(link, linkAllocs);
}
}
@Override
public LinkResourceAllocations getAllocations(IntentId intentId) {
checkNotNull(intentId);
return linkResourceAllocationsMap.get(intentId);
}
@Override
public Iterable<LinkResourceAllocations> getAllocations(Link link) {
checkNotNull(link);
Set<LinkResourceAllocations> result = allocatedResources.get(link);
if (result == null) {
result = Collections.emptySet();
}
return Collections.unmodifiableSet(result);
}
@Override
public Iterable<LinkResourceAllocations> getAllocations() {
return Collections.unmodifiableCollection(linkResourceAllocationsMap.values());
}
}
/**
* Implementation of distributed packet store.
*/
package org.onlab.onos.store.resource.impl;
\ No newline at end of file
......@@ -71,11 +71,14 @@ import org.onlab.onos.net.intent.IntentId;
import org.onlab.onos.net.intent.IntentState;
import org.onlab.onos.net.intent.LinkCollectionIntent;
import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
import org.onlab.onos.net.intent.OpticalConnectivityIntent;
import org.onlab.onos.net.intent.OpticalPathIntent;
import org.onlab.onos.net.intent.PathIntent;
import org.onlab.onos.net.intent.PointToPointIntent;
import org.onlab.onos.net.link.DefaultLinkDescription;
import org.onlab.onos.net.packet.DefaultOutboundPacket;
import org.onlab.onos.net.provider.ProviderId;
import org.onlab.onos.net.resource.LinkResourceRequest;
import org.onlab.onos.store.Timestamp;
import org.onlab.packet.ChassisId;
import org.onlab.packet.IpAddress;
......@@ -182,7 +185,10 @@ public final class KryoNamespaces {
HostToHostIntent.class,
PointToPointIntent.class,
MultiPointToSinglePointIntent.class,
LinkCollectionIntent.class
LinkCollectionIntent.class,
OpticalConnectivityIntent.class,
OpticalPathIntent.class,
LinkResourceRequest.class
)
.register(DefaultApplicationId.class, new DefaultApplicationIdSerializer())
.register(URI.class, new URISerializer())
......