Nicholas Dean
Committed by Brian O'Connor

ONOS-4802 sp2mp intents now apply treatment at the egress switch

Change-Id: Ibdd675f331e522c8b9f1d0e2e9fd5d6b93162fd1
......@@ -39,6 +39,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
private final Set<ConnectPoint> ingressPoints;
private final Set<ConnectPoint> egressPoints;
private final boolean egressTreatmentFlag;
/**
* Creates a new actionable intent capable of funneling the selected
......@@ -54,21 +55,23 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
* @param egressPoints egress points
* @param constraints optional list of constraints
* @param priority priority to use for the flows generated by this intent
* @param egressTreatment true if treatment should be applied by the egress device
* @throws NullPointerException {@code path} is null
*/
private LinkCollectionIntent(ApplicationId appId,
Key key,
TrafficSelector selector,
TrafficTreatment treatment,
Set<Link> links,
Set<ConnectPoint> ingressPoints,
Set<ConnectPoint> egressPoints,
List<Constraint> constraints,
int priority) {
Key key,
TrafficSelector selector,
TrafficTreatment treatment,
Set<Link> links,
Set<ConnectPoint> ingressPoints,
Set<ConnectPoint> egressPoints,
List<Constraint> constraints,
int priority, boolean egressTreatment) {
super(appId, key, resources(links), selector, treatment, constraints, priority);
this.links = links;
this.ingressPoints = ingressPoints;
this.egressPoints = egressPoints;
this.egressTreatmentFlag = egressTreatment;
}
/**
......@@ -79,6 +82,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
this.links = null;
this.ingressPoints = null;
this.egressPoints = null;
this.egressTreatmentFlag = false;
}
/**
......@@ -100,6 +104,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
Set<Link> links;
Set<ConnectPoint> ingressPoints;
Set<ConnectPoint> egressPoints;
boolean egressTreatmentFlag;
private Builder() {
// Hide constructor
......@@ -171,6 +176,17 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
return this;
}
/**
* Sets the intent to apply treatment at the egress rather than the
* ingress.
*
* @param treatmentOnEgress true applies treatment on egress device
* @return this builder
*/
public Builder applyTreatmentOnEgress(boolean treatmentOnEgress) {
this.egressTreatmentFlag = treatmentOnEgress;
return this;
}
/**
* Builds a single point to multi point intent from the
......@@ -189,7 +205,8 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
ingressPoints,
egressPoints,
constraints,
priority
priority,
egressTreatmentFlag
);
}
}
......@@ -223,6 +240,15 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
return egressPoints;
}
/**
* Returns whether treatment should be applied on egress.
*
* @return the egress treatment flag
*/
public boolean applyTreatmentOnEgress() {
return egressTreatmentFlag;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
......@@ -236,6 +262,7 @@ public final class LinkCollectionIntent extends ConnectivityIntent {
.add("links", links())
.add("ingress", ingressPoints())
.add("egress", egressPoints())
.add("treatementOnEgress", applyTreatmentOnEgress())
.toString();
}
}
}
\ No newline at end of file
......
......@@ -111,51 +111,75 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
private List<FlowRule> 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.stream()
.forEach(defaultTreatmentBuilder::setOutput);
TrafficTreatment defaultTreatment = defaultTreatmentBuilder.build();
TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
outPorts.stream()
.forEach(ingressTreatmentBuilder::setOutput);
TrafficTreatment ingressTreatment = ingressTreatmentBuilder.build();
TrafficTreatment outputOnlyTreatment = defaultTreatmentBuilder.build();
Set<PortNumber> ingressPorts = Collections.emptySet();
Set<PortNumber> egressPorts = Collections.emptySet();
TrafficSelector defaultTrafficSelector = applyTreatmentToSelector(intent.selector(), ingressTreatment);
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;
if (ingressPorts.contains(inPort)) {
selectorBuilder = DefaultTrafficSelector.builder(intent.selector());
treatment = ingressTreatment;
TrafficTreatment intentTreatment;
if (!intent.applyTreatmentOnEgress()) {
TrafficTreatment.Builder ingressTreatmentBuilder = DefaultTrafficTreatment.builder(intent.treatment());
outPorts.stream()
.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 {
selectorBuilder = DefaultTrafficSelector.builder(defaultTrafficSelector);
treatment = defaultTreatment;
if (outPorts.stream().allMatch(egressPorts::contains)) {
TrafficTreatment.Builder egressTreatmentBuilder =
DefaultTrafficTreatment.builder(intent.treatment());
outPorts.stream()
.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();
FlowRule rule = DefaultFlowRule.builder()
.forDevice(deviceId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(intent.priority())
.fromApp(appId)
.makePermanent()
.build();
.forDevice(deviceId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(intent.priority())
.fromApp(appId)
.makePermanent()
.build();
rules.add(rule);
}
return rules;
}
private TrafficSelector applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
private TrafficSelector.Builder applyTreatmentToSelector(TrafficSelector selector, TrafficTreatment treatment) {
TrafficSelector.Builder defaultSelectorBuilder = DefaultTrafficSelector.builder(selector);
treatment.allInstructions().forEach(instruction -> {
switch (instruction.type()) {
......@@ -317,6 +341,6 @@ public class LinkCollectionIntentCompiler implements IntentCompiler<LinkCollecti
throw new IntentCompilationException("Unknown instruction type");
}
});
return defaultSelectorBuilder.build();
return defaultSelectorBuilder;
}
}
}
\ No newline at end of file
......
......@@ -75,9 +75,10 @@ public class SinglePointToMultiPointIntentCompiler
.ingressPoints(ImmutableSet.of(intent.ingressPoint()))
.egressPoints(intent.egressPoints())
.priority(intent.priority())
.applyTreatmentOnEgress(true)
.constraints(intent.constraints())
.build();
return Collections.singletonList(result);
}
}
}
\ No newline at end of file
......