Add path intent compiler that generates flow objective intents
Change-Id: I11bee398d927f0e3f32b7cf81d98cfe5816db477
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 18dcb6e..55c883a 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<Objective> objectives;
+ private final List<Objective> objectives;
+ private final List<DeviceId> devices;
/**
* Constructor for serialization.
@@ -37,6 +43,7 @@
protected FlowObjectiveIntent() {
super();
this.objectives = null;
+ this.devices = null;
}
/**
@@ -44,13 +51,15 @@
* 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<Objective> objectives,
+ List<DeviceId> devices,
+ List<Objective> objectives,
Collection<NetworkResource> resources) {
- this(appId, null, objectives, resources);
+ this(appId, null, devices, objectives, resources);
}
/**
@@ -59,14 +68,20 @@
*
* @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<Objective> objectives,
+ public FlowObjectiveIntent(ApplicationId appId,
+ Key key,
+ List<DeviceId> devices,
+ List<Objective> objectives,
Collection<NetworkResource> 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 @@
*
* @return flow objectives
*/
- Collection<Objective> objectives() {
+ public List<Objective> objectives() {
return objectives;
}
+ /**
+ * Returns the list of devices for the flow objectives.
+ *
+ * @return devices
+ */
+ public List<DeviceId> devices() {
+ return devices;
+ }
+
@Override
public boolean isInstallable() {
@@ -91,7 +115,8 @@
.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 ec3e334..54f9aa7 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.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 @@
.withSelector(DefaultTrafficSelector.builder().matchEthType((short) 123).build())
.withTreatment(DefaultTrafficTreatment.emptyTreatment())
.withFlag(ForwardingObjective.Flag.VERSATILE).add();
- private static final Collection<Objective> OBJECTIVES = ImmutableSet.of(FO1, FO2);
+ private static final List<Objective> OBJECTIVES = ImmutableList.of(FO1, FO2);
private static final Collection<NetworkResource> RESOURCES = ImmutableSet.of();
+ private static final List<DeviceId> DEVICE = ImmutableList.of(DeviceId.NONE, DeviceId.NONE);
/**
* Tests basics of construction and getters.
@@ -61,7 +66,7 @@
@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 @@
@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 0000000..7514250
--- /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<T> {
+
+ /**
+ * Defines methods used to create objects representing flows.
+ */
+ public interface PathCompilerCreateFlow<T> {
+
+ void createFlow(TrafficSelector originalSelector,
+ TrafficTreatment originalTreatment,
+ ConnectPoint ingress, ConnectPoint egress,
+ int priority,
+ boolean applyTreatment,
+ List<T> flows,
+ List<DeviceId> devices);
+
+ Logger log();
+
+ ResourceService resourceService();
+ }
+
+ private boolean isLast(List<Link> links, int i) {
+ return i == links.size() - 2;
+ }
+
+ private Map<LinkKey, VlanId> assignVlanId(PathCompilerCreateFlow creator, PathIntent intent) {
+ Set<LinkKey> 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<LinkKey, VlanId> 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<Resource> 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<org.onosproject.net.newresource.ResourceAllocation> allocations =
+ creator.resourceService().allocate(intent.id(), ImmutableList.copyOf(resources));
+ if (allocations.isEmpty()) {
+ Collections.emptyMap();
+ }
+
+ return vlanIds;
+ }
+
+ private Map<LinkKey, VlanId> findVlanIds(PathCompilerCreateFlow creator, Set<LinkKey> links) {
+ Map<LinkKey, VlanId> vlanIds = new HashMap<>();
+ for (LinkKey link : links) {
+ Set<VlanId> forward = findVlanId(creator, link.src());
+ Set<VlanId> backward = findVlanId(creator, link.dst());
+ Set<VlanId> common = Sets.intersection(forward, backward);
+ if (common.isEmpty()) {
+ continue;
+ }
+ vlanIds.put(link, common.iterator().next());
+ }
+ return vlanIds;
+ }
+
+ private Set<VlanId> findVlanId(PathCompilerCreateFlow creator, ConnectPoint cp) {
+ return creator.resourceService().getAvailableResourceValues(
+ Resources.discrete(cp.deviceId(), cp.port()).id(),
+ VlanId.class);
+ }
+
+ private void manageVlanEncap(PathCompilerCreateFlow<T> creator, List<T> flows,
+ List<DeviceId> devices,
+ PathIntent intent) {
+ Map<LinkKey, VlanId> vlanIds = assignVlanId(creator, intent);
+
+ Iterator<Link> 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<VlanIdCriterion> 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<L2ModificationInstruction.ModVlanIdInstruction> modVlanIdInstruction = intent.treatment()
+ .allInstructions().stream().filter(
+ instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction)
+ .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny();
+
+ Optional<L2ModificationInstruction.PopVlanInstruction> 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<T> creator,
+ PathIntent intent,
+ List<T> flows,
+ List<DeviceId> devices) {
+ // Note: right now recompile is not considered
+ // TODO: implement recompile behavior
+
+ List<Link> links = intent.path().links();
+
+ Optional<EncapsulationConstraint> 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 cad9cb7..045b0ef 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<PathIntent> {
+public class PathIntentCompiler
+ extends PathCompiler<FlowRule>
+ implements IntentCompiler<PathIntent>,
+ PathCompiler.PathCompilerCreateFlow<FlowRule> {
private final Logger log = getLogger(getClass());
@@ -94,47 +80,30 @@
@Override
public List<Intent> compile(PathIntent intent, List<Intent> installable,
Set<LinkResourceAllocations> resources) {
- // Note: right now recompile is not considered
- // TODO: implement recompile behavior
- List<Link> links = intent.path().links();
-
- Optional<EncapsulationConstraint> 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<FlowRule> 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<FlowRule> rules = encapConstraint.map(EncapsulationConstraint::encapType)
- .map(type -> {
- switch (type) {
- case VLAN:
- return manageVlanEncap(intent);
- // TODO: implement MPLS case here
- default:
- return Collections.<FlowRule>emptyList();
- }
- })
- .orElse(Collections.emptyList());
+ List<FlowRule> rules = new LinkedList<>();
+ List<DeviceId> 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<FlowRule> rules,
+ List<DeviceId> devices) {
TrafficSelector selector = DefaultTrafficSelector.builder(originalSelector)
.matchInPort(ingress.port())
.build();
@@ -147,164 +116,13 @@
}
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<FlowRule> manageVlanEncap(PathIntent intent) {
- Map<LinkKey, VlanId> vlanIds = assignVlanId(intent);
-
- Iterator<Link> links = intent.path().links().iterator();
- Link srcLink = links.next();
-
- Link link = links.next();
- // List of flow rules to be installed
- List<FlowRule> 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<VlanIdCriterion> 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<L2ModificationInstruction.ModVlanIdInstruction> modVlanIdInstruction = intent.treatment()
- .allInstructions().stream().filter(
- instruction -> instruction instanceof L2ModificationInstruction.ModVlanIdInstruction)
- .map(x -> (L2ModificationInstruction.ModVlanIdInstruction) x).findAny();
-
- Optional<L2ModificationInstruction.PopVlanInstruction> 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<LinkKey, VlanId> assignVlanId(PathIntent intent) {
- Set<LinkKey> 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<LinkKey, VlanId> vlanIds = findVlanIds(linkRequest);
- if (vlanIds.isEmpty()) {
- log.warn("No VLAN IDs available");
- return Collections.emptyMap();
- }
-
- //same VLANID is used for both directions
- Set<Resource> 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<org.onosproject.net.newresource.ResourceAllocation> allocations =
- resourceService.allocate(intent.id(), ImmutableList.copyOf(resources));
- if (allocations.isEmpty()) {
- Collections.emptyMap();
- }
-
- return vlanIds;
- }
-
- private Map<LinkKey, VlanId> findVlanIds(Set<LinkKey> links) {
- Map<LinkKey, VlanId> vlanIds = new HashMap<>();
- for (LinkKey link : links) {
- Set<VlanId> forward = findVlanId(link.src());
- Set<VlanId> backward = findVlanId(link.dst());
- Set<VlanId> common = Sets.intersection(forward, backward);
- if (common.isEmpty()) {
- continue;
- }
- vlanIds.put(link, common.iterator().next());
- }
- return vlanIds;
- }
-
- private Set<VlanId> findVlanId(ConnectPoint cp) {
- return resourceService.getAvailableResourceValues(
- Resources.discrete(cp.deviceId(), cp.port()).id(),
- VlanId.class);
- }
-
- private boolean isLast(List<Link> 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 0000000..25cae18
--- /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<Objective>
+ implements IntentCompiler<PathIntent>,
+ PathCompiler.PathCompilerCreateFlow<Objective> {
+
+ 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<Intent> compile(PathIntent intent, List<Intent> installable,
+ Set<LinkResourceAllocations> resources) {
+
+ List<Objective> objectives = new LinkedList<>();
+ List<DeviceId> 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<Objective> objectives,
+ List<DeviceId> 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());
+ }
+}