Pier Ventre
Committed by Gerrit Code Review

Fix [ONOS-4857] and impement [ONOS-5143]

Change-Id: I7159ff9deaacaf10070e1535f4a80f2f846a5784
/*
* 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;
}
}
......@@ -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.ArrayList;
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 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
@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 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
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());
}
List<FlowRule> rules = new ArrayList<>(inPorts.size());
for (PortNumber inPort: inPorts) {
TrafficSelector.Builder selectorBuilder;
TrafficTreatment treatment;
TrafficTreatment intentTreatment;
if (!intent.applyTreatmentOnEgress()) {
TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
outPorts.forEach(ingressTreatmentBuilder::setOutput);
intentTreatment = ingressTreatmentBuilder.build();
Set<PortNumber> ingressPorts = Sets.newHashSet();
Set<PortNumber> egressPorts = Sets.newHashSet();
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);
computePorts(intent, deviceId, ingressPorts, egressPorts);
selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
treatment = egressTreatmentBuilder.build();
} else {
selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
treatment = outputOnlyTreatment;
}
List<FlowRule> rules = new ArrayList<>(inPorts.size());
Set<PortNumber> copyIngressPorts = ImmutableSet.copyOf(ingressPorts);
Set<PortNumber> copyEgressPorts = ImmutableSet.copyOf(egressPorts);
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;
}
}
......
......@@ -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.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.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.ArrayList;
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 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile
@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 @@ public class LinkCollectionIntentFlowObjectivesCompiler implements IntentCompile
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;
}
}
......