Fix [ONOS-4857] and impement [ONOS-5143]
Change-Id: I7159ff9deaacaf10070e1535f4a80f2f846a5784
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java
new file mode 100644
index 0000000..9fbedb9
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionCompiler.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2016-present 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 com.google.common.collect.SetMultimap;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+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.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
+import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
+import org.onosproject.net.flow.instructions.L4ModificationInstruction;
+import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
+import org.onosproject.net.intent.IntentCompilationException;
+import org.onosproject.net.intent.LinkCollectionIntent;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Shared APIs and implementations for Link Collection compilers.
+ */
+public class LinkCollectionCompiler<T> {
+
+ /**
+ * Helper class to encapsulate treatment and selector.
+ */
+ protected class ForwardingInstructions {
+
+ private TrafficTreatment trafficTreatment;
+
+ private TrafficSelector trafficSelector;
+
+ public ForwardingInstructions(TrafficTreatment treatment, TrafficSelector selector) {
+
+ this.trafficTreatment = treatment;
+ this.trafficSelector = selector;
+
+ }
+
+ public TrafficTreatment treatment() {
+ return this.trafficTreatment;
+ }
+
+ public TrafficSelector selector() {
+ return this.trafficSelector;
+ }
+
+ }
+
+ /**
+ * Helper method to compute input and ouput ports.
+ *
+ * @param intent the related intents
+ * @param inputPorts the input ports to compute
+ * @param outputPorts the output ports to compute
+ */
+ protected void computePorts(LinkCollectionIntent intent,
+ SetMultimap<DeviceId, PortNumber> inputPorts,
+ SetMultimap<DeviceId, PortNumber> outputPorts) {
+
+ for (Link link : intent.links()) {
+ inputPorts.put(link.dst().deviceId(), link.dst().port());
+ outputPorts.put(link.src().deviceId(), link.src().port());
+ }
+
+ for (ConnectPoint ingressPoint : intent.ingressPoints()) {
+ inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
+ }
+
+ for (ConnectPoint egressPoint : intent.egressPoints()) {
+ outputPorts.put(egressPoint.deviceId(), egressPoint.port());
+ }
+
+ }
+
+ /**
+ * Helper method to compute ingress and egress ports.
+ *
+ * @param intent the related intents
+ * @param ingressPorts the ingress ports to compute
+ * @param egressPorts the egress ports to compute
+ */
+ protected void computePorts(LinkCollectionIntent intent,
+ DeviceId deviceId,
+ Set<PortNumber> ingressPorts,
+ Set<PortNumber> egressPorts) {
+
+ if (!intent.applyTreatmentOnEgress()) {
+ ingressPorts.addAll(intent.ingressPoints().stream()
+ .filter(point -> point.deviceId().equals(deviceId))
+ .map(ConnectPoint::port)
+ .collect(Collectors.toSet()));
+ } else {
+ egressPorts.addAll(intent.egressPoints().stream()
+ .filter(point -> point.deviceId().equals(deviceId))
+ .map(ConnectPoint::port)
+ .collect(Collectors.toSet()));
+ }
+
+ }
+
+ /**
+ * Creates the flows representations.
+ *
+ * @param intent the intent to compile
+ * @param deviceId the affected device
+ * @param inPorts the input ports
+ * @param outPorts the output ports
+ * @return the list of flows representations
+ */
+ protected List<T> createRules(LinkCollectionIntent intent, DeviceId deviceId,
+ Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
+ return null;
+ }
+
+
+ /**
+ * Computes treatment and selector which will be used
+ * in the flow representation (Rule, Objective).
+ *
+ * @param intent the intent to compile
+ * @param inPort the input port
+ * @param outPorts the output ports
+ * @param ingressPorts the ingress ports
+ * @param egressPorts the egress ports
+ * @return the forwarding instruction object which encapsulates treatment and selector
+ */
+ protected ForwardingInstructions createForwardingInstructions(LinkCollectionIntent intent, PortNumber inPort,
+ Set<PortNumber> outPorts,
+ Set<PortNumber> ingressPorts,
+ Set<PortNumber> egressPorts) {
+
+ TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
+ outPorts.forEach(defaultTreatmentBuilder::setOutput);
+ TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
+ TrafficSelector.Builder selectorBuilder;
+ TrafficTreatment treatment;
+ TrafficTreatment intentTreatment;
+
+ if (!intent.applyTreatmentOnEgress()) {
+ TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
+ outPorts.forEach(ingressTreatmentBuilder::setOutput);
+ intentTreatment = ingressTreatmentBuilder.build();
+
+ if (ingressPorts.contains(inPort)) {
+ selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
+ treatment = intentTreatment;
+ } else {
+ selectorBuilder = this.createSelectorFromFwdInstructions(
+ new ForwardingInstructions(intentTreatment, intent.selector())
+ );
+ treatment = outputOnlyTreatment;
+ }
+ } else {
+ if (outPorts.stream().allMatch(egressPorts::contains)) {
+ TrafficTreatment.Builder egressTreatmentBuilder =
+ DefaultTrafficTreatment.builder(intent.treatment());
+ outPorts.forEach(egressTreatmentBuilder::setOutput);
+
+ selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
+ treatment = egressTreatmentBuilder.build();
+ } else {
+ selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
+ treatment = outputOnlyTreatment;
+ }
+ }
+
+ TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
+
+ return new ForwardingInstructions(treatment, selector);
+
+ }
+
+ /**
+ * Update the selector builder using a L0 instruction.
+ *
+ * @param builder the builder to update
+ * @param l0instruction the l0 instruction to use
+ */
+ private void updateBuilder(TrafficSelector.Builder builder, L0ModificationInstruction l0instruction) {
+ throw new IntentCompilationException("L0 not supported");
+ }
+
+ /**
+ * Update the selector builder using a L1 instruction.
+ *
+ * @param builder the builder to update
+ * @param l1instruction the l1 instruction to use
+ */
+ private void updateBuilder(TrafficSelector.Builder builder, L1ModificationInstruction l1instruction) {
+ throw new IntentCompilationException("L1 not supported");
+ }
+
+ /**
+ * Update the selector builder using a L2 instruction.
+ *
+ * @param builder the builder to update
+ * @param l2instruction the l2 instruction to use
+ */
+ private void updateBuilder(TrafficSelector.Builder builder, L2ModificationInstruction l2instruction) {
+ switch (l2instruction.subtype()) {
+ case ETH_SRC:
+ case ETH_DST:
+ ModEtherInstruction ethInstr = (ModEtherInstruction) l2instruction;
+ switch (ethInstr.subtype()) {
+ case ETH_SRC:
+ builder.matchEthSrc(ethInstr.mac());
+ break;
+ case ETH_DST:
+ builder.matchEthDst(ethInstr.mac());
+ break;
+ default:
+ throw new IntentCompilationException("Bad eth subtype");
+ }
+ break;
+ case VLAN_ID:
+ ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2instruction;
+ builder.matchVlanId(vlanIdInstr.vlanId());
+ break;
+ case VLAN_PUSH:
+ //FIXME
+ break;
+ case VLAN_POP:
+ //TODO how do we handle dropped label? remove the selector?
+ throw new IntentCompilationException("Can't handle pop label");
+ case VLAN_PCP:
+ ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2instruction;
+ builder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
+ break;
+ case MPLS_LABEL:
+ case MPLS_PUSH:
+ //FIXME
+ ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2instruction;
+ builder.matchMplsLabel(mplsInstr.label());
+ break;
+ case MPLS_POP:
+ //TODO how do we handle dropped label? remove the selector?
+ throw new IntentCompilationException("Can't handle pop label");
+ case DEC_MPLS_TTL:
+ // no-op
+ break;
+ case MPLS_BOS:
+ ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2instruction;
+ builder.matchMplsBos(mplsBosInstr.mplsBos());
+ break;
+ case TUNNEL_ID:
+ ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2instruction;
+ builder.matchTunnelId(tunInstr.tunnelId());
+ break;
+ default:
+ throw new IntentCompilationException("Unknown L2 Modification instruction");
+ }
+
+ }
+
+ /**
+ * Update the selector builder using a L3 instruction.
+ *
+ * @param builder the builder to update
+ * @param l3instruction the l3 instruction to use
+ */
+ private void updateBuilder(TrafficSelector.Builder builder, L3ModificationInstruction l3instruction) {
+ // TODO check ethernet proto
+ switch (l3instruction.subtype()) {
+ case IPV4_SRC:
+ case IPV4_DST:
+ case IPV6_SRC:
+ case IPV6_DST:
+ ModIPInstruction ipInstr = (ModIPInstruction) l3instruction;
+ // TODO check if ip falls in original prefix
+ IpPrefix prefix = ipInstr.ip().toIpPrefix();
+ switch (ipInstr.subtype()) {
+ case IPV4_SRC:
+ builder.matchIPSrc(prefix);
+ break;
+ case IPV4_DST:
+ builder.matchIPSrc(prefix);
+ break;
+ case IPV6_SRC:
+ builder.matchIPv6Src(prefix);
+ break;
+ case IPV6_DST:
+ builder.matchIPv6Dst(prefix);
+ break;
+ default:
+ throw new IntentCompilationException("Bad type for IP instruction");
+ }
+ break;
+ case IPV6_FLABEL:
+ ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3instruction;
+ builder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
+ break;
+ case DEC_TTL:
+ // no-op
+ break;
+ case TTL_OUT:
+ // no-op
+ break;
+ case TTL_IN:
+ // no-op
+ break;
+ case ARP_SPA:
+ ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3instruction;
+ if (arpIpInstr.ip().isIp4()) {
+ builder.matchArpSpa((Ip4Address) arpIpInstr.ip());
+ } else {
+ throw new IntentCompilationException("IPv6 not supported for ARP");
+ }
+ break;
+ case ARP_SHA:
+ ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3instruction;
+ builder.matchArpSha(arpEthInstr.mac());
+ break;
+ case ARP_OP:
+ ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3instruction;
+ //FIXME is the long to int cast safe?
+ builder.matchArpOp((int) arpOpInstr.op());
+ break;
+ default:
+ throw new IntentCompilationException("Unknown L3 Modification instruction");
+ }
+ }
+
+ /**
+ * Update the selector builder using a L4 instruction.
+ *
+ * @param builder the builder to update
+ * @param l4instruction the l4 instruction to use
+ */
+ private void updateBuilder(TrafficSelector.Builder builder, L4ModificationInstruction l4instruction) {
+ if (l4instruction instanceof ModTransportPortInstruction) {
+ // TODO check IP proto
+ ModTransportPortInstruction l4mod = (ModTransportPortInstruction) l4instruction;
+ switch (l4mod.subtype()) {
+ case TCP_SRC:
+ builder.matchTcpSrc(l4mod.port());
+ break;
+ case TCP_DST:
+ builder.matchTcpDst(l4mod.port());
+ break;
+ case UDP_SRC:
+ builder.matchUdpSrc(l4mod.port());
+ break;
+ case UDP_DST:
+ builder.matchUdpDst(l4mod.port());
+ break;
+ default:
+ throw new IntentCompilationException("Unknown L4 Modification instruction");
+ }
+ } else {
+ throw new IntentCompilationException("Unknown L4 Modification instruction");
+ }
+ }
+
+ /**
+ * Computes the new traffic selector using the
+ * forwarding instructions.
+ *
+ * @param fwInstructions it encapsulates the instructions to compute the new selector
+ * @return the traffic selector builder
+ */
+ private TrafficSelector.Builder createSelectorFromFwdInstructions(ForwardingInstructions fwInstructions) {
+ TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(fwInstructions.selector());
+ fwInstructions.treatment().allInstructions().forEach(instruction -> {
+ switch (instruction.type()) {
+ case L0MODIFICATION:
+ updateBuilder(defaultSelectorBuilder, (L0ModificationInstruction) instruction);
+ break;
+ case L1MODIFICATION:
+ updateBuilder(defaultSelectorBuilder, (L1ModificationInstruction) instruction);
+ break;
+ case L2MODIFICATION:
+ updateBuilder(defaultSelectorBuilder, (L2ModificationInstruction) instruction);
+ break;
+ case L3MODIFICATION:
+ updateBuilder(defaultSelectorBuilder, (L3ModificationInstruction) instruction);
+ break;
+ case L4MODIFICATION:
+ updateBuilder(defaultSelectorBuilder, (L4ModificationInstruction) instruction);
+ break;
+ case NOACTION:
+ case OUTPUT:
+ case GROUP:
+ case QUEUE:
+ case TABLE:
+ case METER:
+ case METADATA:
+ case EXTENSION: // TODO is extension no-op or unsupported?
+ // Nothing to do
+ break;
+ default:
+ throw new IntentCompilationException("Unknown instruction type");
+ }
+ });
+ return defaultSelectorBuilder;
+ }
+
+}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
index 53c4287..7c2157c 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentCompiler.java
@@ -16,43 +16,22 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
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.Ip4Address;
-import org.onlab.packet.IpPrefix;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
-import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
-import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
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.instructions.L2ModificationInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsBosInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModMplsLabelInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModTunnelIdInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
-import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanPcpInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpEthInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpIPInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModArpOpInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
-import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
-import org.onosproject.net.flow.instructions.L4ModificationInstruction.ModTransportPortInstruction;
import org.onosproject.net.intent.FlowRuleIntent;
import org.onosproject.net.intent.Intent;
-import org.onosproject.net.intent.IntentCompilationException;
import org.onosproject.net.intent.IntentCompiler;
import org.onosproject.net.intent.LinkCollectionIntent;
@@ -60,10 +39,14 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
+/**
+ * Compiler to produce flow rules from link collections.
+ */
@Component(immediate = true)
-public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollectionIntent> {
+public class LinkCollectionIntentCompiler
+ extends LinkCollectionCompiler<FlowRule>
+ implements IntentCompiler<LinkCollectionIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentConfigurableRegistrator registrator;
@@ -86,21 +69,11 @@
@Override
public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
+
SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
- for (Link link : intent.links()) {
- inputPorts.put(link.dst().deviceId(), link.dst().port());
- outputPorts.put(link.src().deviceId(), link.src().port());
- }
-
- for (ConnectPoint ingressPoint : intent.ingressPoints()) {
- inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
- }
-
- for (ConnectPoint egressPoint : intent.egressPoints()) {
- outputPorts.put(egressPoint.deviceId(), egressPoint.port());
- }
+ computePorts(intent, inputPorts, outputPorts);
List<FlowRule> rules = new ArrayList<>();
for (DeviceId deviceId: outputPorts.keys()) {
@@ -109,235 +82,37 @@
return Collections.singletonList(new FlowRuleIntent(appId, rules, intent.resources()));
}
- private List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId,
+ @Override
+ protected List<FlowRule> createRules(LinkCollectionIntent intent, DeviceId deviceId,
Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
- TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
- outPorts.forEach(defaultTreatmentBuilder::setOutput);
- TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
- Set<PortNumber> ingressPorts = Collections.emptySet();
- Set<PortNumber> egressPorts = Collections.emptySet();
- if (!intent.applyTreatmentOnEgress()) {
- ingressPorts = intent.ingressPoints().stream()
- .filter(point -> point.deviceId().equals(deviceId))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet());
- } else {
- egressPorts = intent.egressPoints().stream()
- .filter(point -> point.deviceId().equals(deviceId))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet());
- }
+ Set<PortNumber> ingressPorts = Sets.newHashSet();
+ Set<PortNumber> egressPorts = Sets.newHashSet();
+
+ computePorts(intent, deviceId, ingressPorts, egressPorts);
List<FlowRule> rules = new ArrayList<>(inPorts.size());
- for (PortNumber inPort: inPorts) {
- TrafficSelector.Builder selectorBuilder;
- TrafficTreatment treatment;
- TrafficTreatment intentTreatment;
+ Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
+ Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
- if (!intent.applyTreatmentOnEgress()) {
- TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
- outPorts.forEach(ingressTreatmentBuilder::setOutput);
- intentTreatment = ingressTreatmentBuilder.build();
-
- if (ingressPorts.contains(inPort)) {
- selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
- treatment = intentTreatment;
- } else {
- selectorBuilder = applyTreatmentToSelector(intent.selector(), intentTreatment);
- treatment = outputOnlyTreatment;
- }
- } else {
- if (outPorts.stream().allMatch(egressPorts::contains)) {
- TrafficTreatment.Builder egressTreatmentBuilder =
- DefaultTrafficTreatment.builder(intent.treatment());
- outPorts.forEach(egressTreatmentBuilder::setOutput);
-
- selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
- treatment = egressTreatmentBuilder.build();
- } else {
- selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
- treatment = outputOnlyTreatment;
- }
+ inPorts.forEach(inport -> {
+ ForwardingInstructions instructions = this.createForwardingInstructions(intent,
+ inport,
+ outPorts,
+ copyIngressPorts,
+ copyEgressPorts);
+ FlowRule rule = DefaultFlowRule.builder()
+ .forDevice(deviceId)
+ .withSelector(instructions.selector())
+ .withTreatment(instructions.treatment())
+ .withPriority(intent.priority())
+ .fromApp(appId)
+ .makePermanent()
+ .build();
+ rules.add(rule);
}
- TrafficSelector selector = selectorBuilder.matchInPort(inPort).build();
-
- FlowRule rule = DefaultFlowRule.builder()
- .forDevice(deviceId)
- .withSelector(selector)
- .withTreatment(treatment)
- .withPriority(intent.priority())
- .fromApp(appId)
- .makePermanent()
- .build();
- rules.add(rule);
- }
+ );
return rules;
}
-
- private TrafficSelector.Builder applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
- TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(selector);
- treatment.allInstructions().forEach(instruction -> {
- switch (instruction.type()) {
- case L0MODIFICATION:
- case L1MODIFICATION:
- throw new IntentCompilationException("L0 and L1 mods not supported");
- case L2MODIFICATION:
- L2ModificationInstruction l2mod = (L2ModificationInstruction) instruction;
- switch (l2mod.subtype()) {
- case ETH_SRC:
- case ETH_DST:
- ModEtherInstruction ethInstr = (ModEtherInstruction) l2mod;
- switch (ethInstr.subtype()) {
- case ETH_SRC:
- defaultSelectorBuilder.matchEthSrc(ethInstr.mac());
- break;
- case ETH_DST:
- defaultSelectorBuilder.matchEthDst(ethInstr.mac());
- break;
- default:
- throw new IntentCompilationException("Bad eth subtype");
- }
- break;
- case VLAN_ID:
- ModVlanIdInstruction vlanIdInstr = (ModVlanIdInstruction) l2mod;
- defaultSelectorBuilder.matchVlanId(vlanIdInstr.vlanId());
- break;
- case VLAN_PUSH:
- //FIXME
- break;
- case VLAN_POP:
- //TODO how do we handle dropped label? remove the selector?
- throw new IntentCompilationException("Can't handle pop label");
- case VLAN_PCP:
- ModVlanPcpInstruction vlanPcpInstruction = (ModVlanPcpInstruction) l2mod;
- defaultSelectorBuilder.matchVlanPcp(vlanPcpInstruction.vlanPcp());
- break;
- case MPLS_LABEL:
- case MPLS_PUSH:
- //FIXME
- ModMplsLabelInstruction mplsInstr = (ModMplsLabelInstruction) l2mod;
- defaultSelectorBuilder.matchMplsLabel(mplsInstr.label());
- break;
- case MPLS_POP:
- //TODO how do we handle dropped label? remove the selector?
- throw new IntentCompilationException("Can't handle pop label");
- case DEC_MPLS_TTL:
- // no-op
- break;
- case MPLS_BOS:
- ModMplsBosInstruction mplsBosInstr = (ModMplsBosInstruction) l2mod;
- defaultSelectorBuilder.matchMplsBos(mplsBosInstr.mplsBos());
- break;
- case TUNNEL_ID:
- ModTunnelIdInstruction tunInstr = (ModTunnelIdInstruction) l2mod;
- defaultSelectorBuilder.matchTunnelId(tunInstr.tunnelId());
- break;
- default:
- throw new IntentCompilationException("Unknown L2 Modification instruction");
- }
- break;
- case L3MODIFICATION:
- L3ModificationInstruction l3mod = (L3ModificationInstruction) instruction;
- // TODO check ethernet proto
- switch (l3mod.subtype()) {
- case IPV4_SRC:
- case IPV4_DST:
- case IPV6_SRC:
- case IPV6_DST:
- ModIPInstruction ipInstr = (ModIPInstruction) l3mod;
- // TODO check if ip falls in original prefix
- IpPrefix prefix = ipInstr.ip().toIpPrefix();
- switch (ipInstr.subtype()) {
- case IPV4_SRC:
- defaultSelectorBuilder.matchIPSrc(prefix);
- break;
- case IPV4_DST:
- defaultSelectorBuilder.matchIPSrc(prefix);
- break;
- case IPV6_SRC:
- defaultSelectorBuilder.matchIPv6Src(prefix);
- break;
- case IPV6_DST:
- defaultSelectorBuilder.matchIPv6Dst(prefix);
- break;
- default:
- throw new IntentCompilationException("Bad type for IP instruction");
- }
- break;
- case IPV6_FLABEL:
- ModIPv6FlowLabelInstruction ipFlowInstr = (ModIPv6FlowLabelInstruction) l3mod;
- defaultSelectorBuilder.matchIPv6FlowLabel(ipFlowInstr.flowLabel());
- break;
- case DEC_TTL:
- // no-op
- break;
- case TTL_OUT:
- // no-op
- break;
- case TTL_IN:
- // no-op
- break;
- case ARP_SPA:
- ModArpIPInstruction arpIpInstr = (ModArpIPInstruction) l3mod;
- if (arpIpInstr.ip().isIp4()) {
- defaultSelectorBuilder.matchArpSpa((Ip4Address) arpIpInstr.ip());
- } else {
- throw new IntentCompilationException("IPv6 not supported for ARP");
- }
- break;
- case ARP_SHA:
- ModArpEthInstruction arpEthInstr = (ModArpEthInstruction) l3mod;
- defaultSelectorBuilder.matchArpSha(arpEthInstr.mac());
- break;
- case ARP_OP:
- ModArpOpInstruction arpOpInstr = (ModArpOpInstruction) l3mod;
- //FIXME is the long to int cast safe?
- defaultSelectorBuilder.matchArpOp((int) arpOpInstr.op());
- break;
- default:
- throw new IntentCompilationException("Unknown L3 Modification instruction");
- }
- break;
- case L4MODIFICATION:
- if (instruction instanceof ModTransportPortInstruction) {
- // TODO check IP proto
- ModTransportPortInstruction l4mod = (ModTransportPortInstruction) instruction;
- switch (l4mod.subtype()) {
- case TCP_SRC:
- defaultSelectorBuilder.matchTcpSrc(l4mod.port());
- break;
- case TCP_DST:
- defaultSelectorBuilder.matchTcpDst(l4mod.port());
- break;
- case UDP_SRC:
- defaultSelectorBuilder.matchUdpSrc(l4mod.port());
- break;
- case UDP_DST:
- defaultSelectorBuilder.matchUdpDst(l4mod.port());
- break;
- default:
- throw new IntentCompilationException("Unknown L4 Modification instruction");
- }
- } else {
- throw new IntentCompilationException("Unknown L4 Modification instruction");
- }
- break;
- case NOACTION:
- case OUTPUT:
- case GROUP:
- case QUEUE:
- case TABLE:
- case METER:
- case METADATA:
- case EXTENSION: // TODO is extension no-op or unsupported?
- // Nothing to do
- break;
- default:
- throw new IntentCompilationException("Unknown instruction type");
- }
- });
- return defaultSelectorBuilder;
- }
}
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
similarity index 67%
rename from core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java
rename to core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
index 09c7037a..7ffff6b 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectivesCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
@@ -16,7 +16,9 @@
package org.onosproject.net.intent.impl.compiler;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
@@ -24,14 +26,8 @@
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.Link;
import org.onosproject.net.PortNumber;
-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.DefaultNextObjective;
import org.onosproject.net.flowobjective.FlowObjectiveService;
@@ -47,13 +43,14 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Compiler to produce flow objectives from link collections.
*/
@Component(immediate = true)
-public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompiler<LinkCollectionIntent> {
+public class LinkCollectionIntentFlowObjectiveCompiler
+ extends LinkCollectionCompiler<Objective>
+ implements IntentCompiler<LinkCollectionIntent> {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected IntentConfigurableRegistrator registrator;
@@ -79,21 +76,11 @@
@Override
public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
+
SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
- for (Link link : intent.links()) {
- inputPorts.put(link.dst().deviceId(), link.dst().port());
- outputPorts.put(link.src().deviceId(), link.src().port());
- }
-
- for (ConnectPoint ingressPoint : intent.ingressPoints()) {
- inputPorts.put(ingressPoint.deviceId(), ingressPoint.port());
- }
-
- for (ConnectPoint egressPoint : intent.egressPoints()) {
- outputPorts.put(egressPoint.deviceId(), egressPoint.port());
- }
+ computePorts(intent, inputPorts, outputPorts);
List<Objective> objectives = new ArrayList<>();
List<DeviceId> devices = new ArrayList<>();
@@ -112,49 +99,46 @@
new FlowObjectiveIntent(appId, devices, objectives, intent.resources()));
}
- private List<Objective> createRules(LinkCollectionIntent intent, DeviceId deviceId,
+ @Override
+ protected List<Objective> createRules(LinkCollectionIntent intent, DeviceId deviceId,
Set<PortNumber> inPorts, Set<PortNumber> outPorts) {
- Set<PortNumber> ingressPorts = intent.ingressPoints().stream()
- .filter(point -> point.deviceId().equals(deviceId))
- .map(ConnectPoint::port)
- .collect(Collectors.toSet());
- TrafficTreatment.Builder defaultTreatmentBuilder = DefaultTrafficTreatment.builder();
- outPorts.forEach(defaultTreatmentBuilder::setOutput);
- TrafficTreatment defaultTreatment = defaultTreatmentBuilder.build();
+ Set<PortNumber> ingressPorts = Sets.newHashSet();
+ Set<PortNumber> egressPorts = Sets.newHashSet();
- TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
- outPorts.forEach(ingressTreatmentBuilder::setOutput);
- TrafficTreatment ingressTreatment = ingressTreatmentBuilder.build();
+ computePorts(intent, deviceId, ingressPorts, egressPorts);
List<Objective> objectives = new ArrayList<>(inPorts.size());
- for (PortNumber inPort: inPorts) {
- TrafficSelector selector = DefaultTrafficSelector.builder(intent.selector()).matchInPort(inPort).build();
- TrafficTreatment treatment;
- if (ingressPorts.contains(inPort)) {
- treatment = ingressTreatment;
- } else {
- treatment = defaultTreatment;
- }
+ Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
+ Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
+
+ inPorts.forEach(inport -> {
+ ForwardingInstructions instructions = this.createForwardingInstructions(intent,
+ inport,
+ outPorts,
+ copyIngressPorts,
+ copyEgressPorts);
NextObjective nextObjective = DefaultNextObjective.builder()
.withId(flowObjectiveService.allocateNextId())
- .addTreatment(treatment)
+ .addTreatment(instructions.treatment())
.withType(NextObjective.Type.SIMPLE)
.fromApp(appId)
.makePermanent().add();
objectives.add(nextObjective);
objectives.add(DefaultForwardingObjective.builder()
- .withSelector(selector)
+ .withSelector(instructions.selector())
.nextStep(nextObjective.id())
.withPriority(intent.priority())
.fromApp(appId)
.makePermanent()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.add());
- }
+ }
+ );
return objectives;
}
+
}