diff --git a/core/api/src/main/java/org/onosproject/net/intent/FlowObjectiveIntent.java b/core/api/src/main/java/org/onosproject/net/intent/FlowObjectiveIntent.java index 18dcb6e3c1..55c883a7e9 100644 --- a/core/api/src/main/java/org/onosproject/net/intent/FlowObjectiveIntent.java +++ b/core/api/src/main/java/org/onosproject/net/intent/FlowObjectiveIntent.java @@ -17,19 +17,25 @@ package org.onosproject.net.intent; import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; import org.onosproject.core.ApplicationId; +import org.onosproject.net.DeviceId; import org.onosproject.net.NetworkResource; import org.onosproject.net.flowobjective.Objective; import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkArgument; /** * Intent expressed as (and backed by) a collection of flow objectives through * which the intent is to be accomplished. */ -public class FlowObjectiveIntent extends Intent { +public final class FlowObjectiveIntent extends Intent { - private final Collection objectives; + private final List objectives; + private final List devices; /** * Constructor for serialization. @@ -37,6 +43,7 @@ public class FlowObjectiveIntent extends Intent { protected FlowObjectiveIntent() { super(); this.objectives = null; + this.devices = null; } /** @@ -44,13 +51,15 @@ public class FlowObjectiveIntent extends Intent { * resources. * * @param appId application id + * @param devices list of target devices; in same order as the objectives * @param objectives backing flow objectives * @param resources backing network resources */ public FlowObjectiveIntent(ApplicationId appId, - Collection objectives, + List devices, + List objectives, Collection resources) { - this(appId, null, objectives, resources); + this(appId, null, devices, objectives, resources); } /** @@ -59,14 +68,20 @@ public class FlowObjectiveIntent extends Intent { * * @param appId application id * @param key intent key + * @param devices list of target devices; in same order as the objectives * @param objectives backing flow objectives * @param resources backing network resources */ - public FlowObjectiveIntent(ApplicationId appId, Key key, - Collection objectives, + public FlowObjectiveIntent(ApplicationId appId, + Key key, + List devices, + List objectives, Collection resources) { super(appId, key, resources, DEFAULT_INTENT_PRIORITY); - this.objectives = objectives; + checkArgument(devices.size() == objectives.size(), + "Number of devices and objectives does not match"); + this.objectives = ImmutableList.copyOf(objectives); + this.devices = ImmutableList.copyOf(devices); } /** @@ -74,10 +89,19 @@ public class FlowObjectiveIntent extends Intent { * * @return flow objectives */ - Collection objectives() { + public List objectives() { return objectives; } + /** + * Returns the list of devices for the flow objectives. + * + * @return devices + */ + public List devices() { + return devices; + } + @Override public boolean isInstallable() { @@ -91,7 +115,8 @@ public class FlowObjectiveIntent extends Intent { .add("key", key()) .add("appId", appId()) .add("resources", resources()) - .add("objectives", objectives) + .add("device", devices()) + .add("objectives", objectives()) .toString(); } } diff --git a/core/api/src/test/java/org/onosproject/net/intent/FlowObjectiveIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/FlowObjectiveIntentTest.java index ec3e334e90..54f9aa7b6a 100644 --- a/core/api/src/test/java/org/onosproject/net/intent/FlowObjectiveIntentTest.java +++ b/core/api/src/test/java/org/onosproject/net/intent/FlowObjectiveIntentTest.java @@ -16,11 +16,13 @@ package org.onosproject.net.intent; -import com.google.common.collect.ImmutableSet; -import com.google.common.testing.EqualsTester; +import java.util.Collection; +import java.util.List; + import org.junit.Test; import org.onosproject.core.ApplicationId; import org.onosproject.core.DefaultApplicationId; +import org.onosproject.net.DeviceId; import org.onosproject.net.NetworkResource; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; @@ -30,7 +32,9 @@ import org.onosproject.net.flowobjective.DefaultForwardingObjective; import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.Objective; -import java.util.Collection; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.testing.EqualsTester; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -52,8 +56,9 @@ public class FlowObjectiveIntentTest extends IntentTest { .withSelector(DefaultTrafficSelector.builder().matchEthType((short) 123).build()) .withTreatment(DefaultTrafficTreatment.emptyTreatment()) .withFlag(ForwardingObjective.Flag.VERSATILE).add(); - private static final Collection OBJECTIVES = ImmutableSet.of(FO1, FO2); + private static final List OBJECTIVES = ImmutableList.of(FO1, FO2); private static final Collection RESOURCES = ImmutableSet.of(); + private static final List DEVICE = ImmutableList.of(DeviceId.NONE, DeviceId.NONE); /** * Tests basics of construction and getters. @@ -61,7 +66,7 @@ public class FlowObjectiveIntentTest extends IntentTest { @Test public void basics() { FlowObjectiveIntent intent = - new FlowObjectiveIntent(APP_ID, KEY, OBJECTIVES, RESOURCES); + new FlowObjectiveIntent(APP_ID, KEY, DEVICE, OBJECTIVES, RESOURCES); assertEquals("incorrect app id", APP_ID, intent.appId()); assertEquals("incorrect key", KEY, intent.key()); assertEquals("incorrect objectives", OBJECTIVES, intent.objectives()); @@ -89,11 +94,11 @@ public class FlowObjectiveIntentTest extends IntentTest { @Override protected Intent createOne() { - return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES); + return new FlowObjectiveIntent(APP_ID, DEVICE, OBJECTIVES, RESOURCES); } @Override protected Intent createAnother() { - return new FlowObjectiveIntent(APP_ID, OBJECTIVES, RESOURCES); + return new FlowObjectiveIntent(APP_ID, DEVICE, OBJECTIVES, RESOURCES); } -} \ No newline at end of file +} diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java new file mode 100644 index 0000000000..7514250012 --- /dev/null +++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathCompiler.java @@ -0,0 +1,274 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.net.intent.impl.compiler; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.onlab.packet.VlanId; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.Link; +import org.onosproject.net.LinkKey; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flow.criteria.Criterion; +import org.onosproject.net.flow.criteria.VlanIdCriterion; +import org.onosproject.net.flow.instructions.L2ModificationInstruction; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.intent.constraint.EncapsulationConstraint; +import org.onosproject.net.intent.impl.IntentCompilationException; +import org.onosproject.net.newresource.Resource; +import org.onosproject.net.newresource.ResourceService; +import org.onosproject.net.newresource.Resources; +import org.slf4j.Logger; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Sets; + +import static org.onosproject.net.LinkKey.linkKey; + +/** + * Shared APIs and implementations for path compilers. + */ + +public class PathCompiler { + + /** + * Defines methods used to create objects representing flows. + */ + public interface PathCompilerCreateFlow { + + void createFlow(TrafficSelector originalSelector, + TrafficTreatment originalTreatment, + ConnectPoint ingress, ConnectPoint egress, + int priority, + boolean applyTreatment, + List flows, + List devices); + + Logger log(); + + ResourceService resourceService(); + } + + private boolean isLast(List links, int i) { + return i == links.size() - 2; + } + + private Map assignVlanId(PathCompilerCreateFlow creator, PathIntent intent) { + Set linkRequest = + Sets.newHashSetWithExpectedSize(intent.path() + .links().size() - 2); + for (int i = 1; i <= intent.path().links().size() - 2; i++) { + LinkKey link = linkKey(intent.path().links().get(i)); + linkRequest.add(link); + // add the inverse link. I want that the VLANID is reserved both for + // the direct and inverse link + linkRequest.add(linkKey(link.dst(), link.src())); + } + + Map vlanIds = findVlanIds(creator, linkRequest); + if (vlanIds.isEmpty()) { + creator.log().warn("No VLAN IDs available"); + return Collections.emptyMap(); + } + + //same VLANID is used for both directions + Set resources = vlanIds.entrySet().stream() + .flatMap(x -> Stream.of( + Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue()) + .resource(), + Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue()) + .resource() + )) + .collect(Collectors.toSet()); + List allocations = + creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources)); + if (allocations.isEmpty()) { + Collections.emptyMap(); + } + + return vlanIds; + } + + private Map findVlanIds(PathCompilerCreateFlow creator, Set links) { + Map vlanIds = new HashMap<>(); + for (LinkKey link : links) { + Set forward = findVlanId(creator, link.src()); + Set backward = findVlanId(creator, link.dst()); + Set common = Sets.intersection(forward, backward); + if (common.isEmpty()) { + continue; + } + vlanIds.put(link, common.iterator().next()); + } + return vlanIds; + } + + private Set findVlanId(PathCompilerCreateFlow creator, ConnectPoint cp) { + return creator.resourceService().getAvailableResourceValues( + Resources.discrete(cp.deviceId(), cp.port()).id(), + VlanId.class); + } + + private void manageVlanEncap(PathCompilerCreateFlow creator, List flows, + List devices, + PathIntent intent) { + Map vlanIds = assignVlanId(creator, intent); + + Iterator links = intent.path().links().iterator(); + Link srcLink = links.next(); + + Link link = links.next(); + + // Ingress traffic + VlanId vlanId = vlanIds.get(linkKey(link)); + if (vlanId == null) { + throw new IntentCompilationException("No available VLAN ID for " + link); + } + VlanId prevVlanId = vlanId; + + Optional vlanCriterion = intent.selector().criteria() + .stream().filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID) + .map(criterion -> (VlanIdCriterion) criterion) + .findAny(); + + //Push VLAN if selector does not include VLAN + TrafficTreatment.Builder treatBuilder = DefaultTrafficTreatment.builder(); + if (!vlanCriterion.isPresent()) { + treatBuilder.pushVlan(); + } + //Tag the traffic with the new encapsulation VLAN + treatBuilder.setVlanId(vlanId); + creator.createFlow(intent.selector(), treatBuilder.build(), + srcLink.dst(), link.src(), intent.priority(), true, + flows, devices); + + ConnectPoint prev = link.dst(); + + while (links.hasNext()) { + + link = links.next(); + + if (links.hasNext()) { + // Transit traffic + VlanId egressVlanId = vlanIds.get(linkKey(link)); + if (egressVlanId == null) { + throw new IntentCompilationException("No available VLAN ID for " + link); + } + prevVlanId = egressVlanId; + + TrafficSelector transitSelector = DefaultTrafficSelector.builder() + .matchInPort(prev.port()) + .matchVlanId(prevVlanId).build(); + + TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder(); + + // Set the new vlanId only if the previous one is different + if (!prevVlanId.equals(egressVlanId)) { + transitTreat.setVlanId(egressVlanId); + } + creator.createFlow(transitSelector, + transitTreat.build(), prev, link.src(), + intent.priority(), true, flows, devices); + prev = link.dst(); + } else { + // Egress traffic + TrafficSelector egressSelector = DefaultTrafficSelector.builder() + .matchInPort(prev.port()) + .matchVlanId(prevVlanId).build(); + TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment()); + + Optional modVlanIdInstruction = intent.treatment() + .allInstructions().stream().filter( + instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction) + .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny(); + + Optional popVlanInstruction = intent.treatment() + .allInstructions().stream().filter( + instruction -> instruction instanceof L2ModificationInstruction.PopVlanInstruction) + .map(x -> (L2ModificationInstruction.PopVlanInstruction) x).findAny(); + + if (!modVlanIdInstruction.isPresent() && !popVlanInstruction.isPresent()) { + if (vlanCriterion.isPresent()) { + egressTreat.setVlanId(vlanCriterion.get().vlanId()); + } else { + egressTreat.popVlan(); + } + } + + creator.createFlow(egressSelector, + egressTreat.build(), prev, link.src(), + intent.priority(), true, flows, devices); + } + } + } + + /** + * Compiles an intent down to flows. + * + * @param creator how to create the flows + * @param intent intent to process + * @param flows list of generated flows + * @param devices list of devices that correspond to the flows + */ + public void compile(PathCompilerCreateFlow creator, + PathIntent intent, + List flows, + List devices) { + // Note: right now recompile is not considered + // TODO: implement recompile behavior + + List links = intent.path().links(); + + Optional encapConstraint = intent.constraints().stream() + .filter(constraint -> constraint instanceof EncapsulationConstraint) + .map(x -> (EncapsulationConstraint) x).findAny(); + //if no encapsulation or is involved only a single switch use the default behaviour + if (!encapConstraint.isPresent() || links.size() == 1) { + for (int i = 0; i < links.size() - 1; i++) { + ConnectPoint ingress = links.get(i).dst(); + ConnectPoint egress = links.get(i + 1).src(); + creator.createFlow(intent.selector(), intent.treatment(), + ingress, egress, intent.priority(), + isLast(links, i), flows, devices); + } + } + + encapConstraint.map(EncapsulationConstraint::encapType) + .map(type -> { + switch (type) { + case VLAN: + manageVlanEncap(creator, flows, devices, intent); + // TODO: implement MPLS case here + default: + // Nothing to do + } + return 0; + }); + } + +} diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java index cad9cb7bd9..045b0eff3e 100644 --- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java +++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentCompiler.java @@ -15,57 +15,43 @@ */ package org.onosproject.net.intent.impl.compiler; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Sets; +import java.util.LinkedList; +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.packet.VlanId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.ConnectPoint; -import org.onosproject.net.Link; -import org.onosproject.net.LinkKey; +import org.onosproject.net.DeviceId; import org.onosproject.net.flow.DefaultFlowRule; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; -import org.onosproject.net.flow.criteria.Criterion; -import org.onosproject.net.flow.criteria.VlanIdCriterion; -import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentCompiler; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.PathIntent; -import org.onosproject.net.intent.constraint.EncapsulationConstraint; -import org.onosproject.net.intent.impl.IntentCompilationException; -import org.onosproject.net.newresource.Resource; import org.onosproject.net.newresource.ResourceService; -import org.onosproject.net.newresource.Resources; import org.onosproject.net.resource.link.LinkResourceAllocations; import org.slf4j.Logger; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import com.google.common.collect.ImmutableList; -import static org.onosproject.net.LinkKey.linkKey; import static org.slf4j.LoggerFactory.getLogger; @Component(immediate = true) -public class PathIntentCompiler implements IntentCompiler { +public class PathIntentCompiler + extends PathCompiler + implements IntentCompiler, + PathCompiler.PathCompilerCreateFlow { private final Logger log = getLogger(getClass()); @@ -94,47 +80,30 @@ public class PathIntentCompiler implements IntentCompiler { @Override public List compile(PathIntent intent, List installable, Set resources) { - // Note: right now recompile is not considered - // TODO: implement recompile behavior - List links = intent.path().links(); - - Optional encapConstraint = intent.constraints().stream() - .filter(constraint -> constraint instanceof EncapsulationConstraint) - .map(x -> (EncapsulationConstraint) x).findAny(); - //if no encapsulation or is involved only a single switch use the default behaviour - if (!encapConstraint.isPresent() || links.size() == 1) { - List rules = new LinkedList<>(); - for (int i = 0; i < links.size() - 1; i++) { - ConnectPoint ingress = links.get(i).dst(); - ConnectPoint egress = links.get(i + 1).src(); - FlowRule rule = createFlowRule(intent.selector(), intent.treatment(), - ingress, egress, intent.priority(), - isLast(links, i)); - rules.add(rule); - } - - return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); - } - - List rules = encapConstraint.map(EncapsulationConstraint::encapType) - .map(type -> { - switch (type) { - case VLAN: - return manageVlanEncap(intent); - // TODO: implement MPLS case here - default: - return Collections.emptyList(); - } - }) - .orElse(Collections.emptyList()); + List rules = new LinkedList<>(); + List devices = new LinkedList<>(); + compile(this, intent, rules, devices); return ImmutableList.of(new FlowRuleIntent(appId, null, rules, intent.resources())); } - private FlowRule createFlowRule(TrafficSelector originalSelector, TrafficTreatment originalTreatment, - ConnectPoint ingress, ConnectPoint egress, - int priority, boolean applyTreatment) { + @Override + public Logger log() { + return log; + } + + @Override + public ResourceService resourceService() { + return resourceService; + } + + @Override + public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment, + ConnectPoint ingress, ConnectPoint egress, + int priority, boolean applyTreatment, + List rules, + List devices) { TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) .matchInPort(ingress.port()) .build(); @@ -147,164 +116,13 @@ public class PathIntentCompiler implements IntentCompiler { } TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build(); - return DefaultFlowRule.builder() + rules.add(DefaultFlowRule.builder() .forDevice(ingress.deviceId()) .withSelector(selector) .withTreatment(treatment) .withPriority(priority) .fromApp(appId) .makePermanent() - .build(); - } - - private List manageVlanEncap(PathIntent intent) { - Map vlanIds = assignVlanId(intent); - - Iterator links = intent.path().links().iterator(); - Link srcLink = links.next(); - - Link link = links.next(); - // List of flow rules to be installed - List rules = new LinkedList<>(); - - // Ingress traffic - VlanId vlanId = vlanIds.get(linkKey(link)); - if (vlanId == null) { - throw new IntentCompilationException("No available VLAN ID for " + link); - } - VlanId prevVlanId = vlanId; - - Optional vlanCriterion = intent.selector().criteria() - .stream().filter(criterion -> criterion.type() == Criterion.Type.VLAN_VID) - .map(criterion -> (VlanIdCriterion) criterion) - .findAny(); - - //Push VLAN if selector does not include VLAN - TrafficTreatment.Builder treatBuilder = DefaultTrafficTreatment.builder(); - if (!vlanCriterion.isPresent()) { - treatBuilder.pushVlan(); - } - //Tag the traffic with the new encapsulation VLAN - treatBuilder.setVlanId(vlanId); - rules.add(createFlowRule(intent.selector(), treatBuilder.build(), - srcLink.dst(), link.src(), intent.priority(), true)); - - ConnectPoint prev = link.dst(); - - while (links.hasNext()) { - - link = links.next(); - - if (links.hasNext()) { - // Transit traffic - VlanId egressVlanId = vlanIds.get(linkKey(link)); - if (egressVlanId == null) { - throw new IntentCompilationException("No available VLAN ID for " + link); - } - prevVlanId = egressVlanId; - - TrafficSelector transitSelector = DefaultTrafficSelector.builder() - .matchInPort(prev.port()) - .matchVlanId(prevVlanId).build(); - - TrafficTreatment.Builder transitTreat = DefaultTrafficTreatment.builder(); - - // Set the new vlanId only if the previous one is different - if (!prevVlanId.equals(egressVlanId)) { - transitTreat.setVlanId(egressVlanId); - } - rules.add(createFlowRule(transitSelector, - transitTreat.build(), prev, link.src(), intent.priority(), true)); - prev = link.dst(); - } else { - // Egress traffic - TrafficSelector egressSelector = DefaultTrafficSelector.builder() - .matchInPort(prev.port()) - .matchVlanId(prevVlanId).build(); - TrafficTreatment.Builder egressTreat = DefaultTrafficTreatment.builder(intent.treatment()); - - Optional modVlanIdInstruction = intent.treatment() - .allInstructions().stream().filter( - instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction) - .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny(); - - Optional popVlanInstruction = intent.treatment() - .allInstructions().stream().filter( - instruction -> instruction instanceof L2ModificationInstruction.PopVlanInstruction) - .map(x -> (L2ModificationInstruction.PopVlanInstruction) x).findAny(); - - if (!modVlanIdInstruction.isPresent() && !popVlanInstruction.isPresent()) { - if (vlanCriterion.isPresent()) { - egressTreat.setVlanId(vlanCriterion.get().vlanId()); - } else { - egressTreat.popVlan(); - } - } - - rules.add(createFlowRule(egressSelector, - egressTreat.build(), prev, link.src(), intent.priority(), true)); - } - } - return rules; - - } - - private Map assignVlanId(PathIntent intent) { - Set linkRequest = Sets.newHashSetWithExpectedSize(intent.path() - .links().size() - 2); - for (int i = 1; i <= intent.path().links().size() - 2; i++) { - LinkKey link = linkKey(intent.path().links().get(i)); - linkRequest.add(link); - // add the inverse link. I want that the VLANID is reserved both for - // the direct and inverse link - linkRequest.add(linkKey(link.dst(), link.src())); - } - - Map vlanIds = findVlanIds(linkRequest); - if (vlanIds.isEmpty()) { - log.warn("No VLAN IDs available"); - return Collections.emptyMap(); - } - - //same VLANID is used for both directions - Set resources = vlanIds.entrySet().stream() - .flatMap(x -> Stream.of( - Resources.discrete(x.getKey().src().deviceId(), x.getKey().src().port(), x.getValue()) - .resource(), - Resources.discrete(x.getKey().dst().deviceId(), x.getKey().dst().port(), x.getValue()) - .resource() - )) - .collect(Collectors.toSet()); - List allocations = - resourceService.allocate(intent.id(), ImmutableList.copyOf(resources)); - if (allocations.isEmpty()) { - Collections.emptyMap(); - } - - return vlanIds; - } - - private Map findVlanIds(Set links) { - Map vlanIds = new HashMap<>(); - for (LinkKey link : links) { - Set forward = findVlanId(link.src()); - Set backward = findVlanId(link.dst()); - Set common = Sets.intersection(forward, backward); - if (common.isEmpty()) { - continue; - } - vlanIds.put(link, common.iterator().next()); - } - return vlanIds; - } - - private Set findVlanId(ConnectPoint cp) { - return resourceService.getAvailableResourceValues( - Resources.discrete(cp.deviceId(), cp.port()).id(), - VlanId.class); - } - - private boolean isLast(List links, int i) { - return i == links.size() - 2; + .build()); } } diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java new file mode 100644 index 0000000000..25cae1876f --- /dev/null +++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/PathIntentFlowObjectiveCompiler.java @@ -0,0 +1,130 @@ +/* + * Copyright 2016 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.net.intent.impl.compiler; + +import java.util.LinkedList; +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.onosproject.core.ApplicationId; +import org.onosproject.core.CoreService; +import org.onosproject.net.ConnectPoint; +import org.onosproject.net.DeviceId; +import org.onosproject.net.flow.DefaultTrafficSelector; +import org.onosproject.net.flow.DefaultTrafficTreatment; +import org.onosproject.net.flow.TrafficSelector; +import org.onosproject.net.flow.TrafficTreatment; +import org.onosproject.net.flowobjective.DefaultForwardingObjective; +import org.onosproject.net.flowobjective.ForwardingObjective; +import org.onosproject.net.flowobjective.Objective; +import org.onosproject.net.intent.FlowObjectiveIntent; +import org.onosproject.net.intent.Intent; +import org.onosproject.net.intent.IntentCompiler; +import org.onosproject.net.intent.IntentExtensionService; +import org.onosproject.net.intent.PathIntent; +import org.onosproject.net.newresource.ResourceService; +import org.onosproject.net.resource.link.LinkResourceAllocations; +import org.slf4j.Logger; + +import com.google.common.collect.ImmutableList; + +import static org.slf4j.LoggerFactory.getLogger; + +@Component(immediate = true) +public class PathIntentFlowObjectiveCompiler + extends PathCompiler + implements IntentCompiler, + PathCompiler.PathCompilerCreateFlow { + + private final Logger log = getLogger(getClass()); + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected CoreService coreService; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected IntentExtensionService intentManager; + + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) + protected ResourceService resourceService; + + private ApplicationId appId; + + @Activate + public void activate() { + appId = coreService.registerApplication("org.onosproject.net.intent"); + //intentManager.registerCompiler(PathIntent.class, this); + } + + @Deactivate + public void deactivate() { + //intentManager.unregisterCompiler(PathIntent.class); + } + + @Override + public List compile(PathIntent intent, List installable, + Set resources) { + + List objectives = new LinkedList<>(); + List devices = new LinkedList<>(); + compile(this, intent, objectives, devices); + + return ImmutableList.of(new FlowObjectiveIntent(appId, devices, objectives, intent.resources())); + } + + @Override + public Logger log() { + return log; + } + + @Override + public ResourceService resourceService() { + return resourceService; + } + + @Override + public void createFlow(TrafficSelector originalSelector, TrafficTreatment originalTreatment, + ConnectPoint ingress, ConnectPoint egress, + int priority, boolean applyTreatment, + List objectives, + List devices) { + TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector) + .matchInPort(ingress.port()) + .build(); + + TrafficTreatment.Builder treatmentBuilder; + if (applyTreatment) { + treatmentBuilder = DefaultTrafficTreatment.builder(originalTreatment); + } else { + treatmentBuilder = DefaultTrafficTreatment.builder(); + } + TrafficTreatment treatment = treatmentBuilder.setOutput(egress.port()).build(); + + objectives.add(DefaultForwardingObjective.builder() + .withSelector(selector) + .withTreatment(treatment) + .withPriority(priority) + .fromApp(appId) + .makePermanent() + .withFlag(ForwardingObjective.Flag.SPECIFIC) + .add()); + devices.add(ingress.deviceId()); + } +}