In order to implement VOLTHA VOL-949 task (https://jira.opencord.org/browse/VOL-949) , OltPipeline (pmc-olt driver) must support meter, transition and also QinQ vlan push instructions.

Change-Id: Ie027469fa190a78b0c8366da55431ebc62e699ef
This commit is contained in:
Gamze Abaka 2018-09-12 10:55:35 +00:00 committed by Saurav Das
parent 65f27f1aae
commit dadae72079
5 changed files with 248 additions and 76 deletions

View File

@ -195,6 +195,8 @@ public class DefaultVirtualMeterProvider extends AbstractVirtualProvider
break; break;
case METER_REMOVED: case METER_REMOVED:
break; break;
case METER_REFERENCE_COUNT_ZERO:
break;
default: default:
log.warn("Unknown meter event {}", event.type()); log.warn("Unknown meter event {}", event.type());
} }

View File

@ -42,7 +42,12 @@ public class MeterEvent extends AbstractEvent<MeterEvent.Type, Meter> {
/** /**
* A meter was finally removed from device. * A meter was finally removed from device.
*/ */
METER_REMOVED METER_REMOVED,
/**
* Meter is not used by any flow. It can be deleted.
*/
METER_REFERENCE_COUNT_ZERO
} }

View File

@ -375,6 +375,10 @@ public class MeterManager
log.info("Meter removed {}", event.subject()); log.info("Meter removed {}", event.subject());
post(new MeterEvent(MeterEvent.Type.METER_REMOVED, event.subject())); post(new MeterEvent(MeterEvent.Type.METER_REMOVED, event.subject()));
break; break;
case METER_REFERENCE_COUNT_ZERO:
log.info("Meter reference count zero {}", event.subject());
post(new MeterEvent(MeterEvent.Type.METER_REFERENCE_COUNT_ZERO, event.subject()));
break;
default: default:
log.warn("Unknown meter event {}", event.type()); log.warn("Unknown meter event {}", event.type());
} }

View File

@ -285,6 +285,9 @@ public class DistributedMeterStore extends AbstractStore<MeterEvent, MeterStoreD
m.setLife(meter.life()); m.setLife(meter.life());
// TODO: Prune if drops to zero. // TODO: Prune if drops to zero.
m.setReferenceCount(meter.referenceCount()); m.setReferenceCount(meter.referenceCount());
if (meter.referenceCount() == 0) {
notifyDelegate(new MeterEvent(MeterEvent.Type.METER_REFERENCE_COUNT_ZERO, m));
}
return new MeterData(m, null, v.origin()); return new MeterData(m, null, v.origin());
}); });
} }

View File

@ -19,6 +19,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause; import com.google.common.cache.RemovalCause;
import com.google.common.cache.RemovalNotification; import com.google.common.cache.RemovalNotification;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@ -82,6 +83,8 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.Arrays;
import java.util.Objects;
import static org.slf4j.LoggerFactory.getLogger; import static org.slf4j.LoggerFactory.getLogger;
@ -94,6 +97,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
private static final Integer QQ_TABLE = 1; private static final Integer QQ_TABLE = 1;
private static final short MCAST_VLAN = 4000; private static final short MCAST_VLAN = 4000;
private static final String OLTCOOKIES = "olt-cookies-must-be-unique"; private static final String OLTCOOKIES = "olt-cookies-must-be-unique";
private static final int NO_ACTION_PRIORITY = 500;
private final Logger log = getLogger(getClass()); private final Logger log = getLogger(getClass());
private ServiceDirectory serviceDirectory; private ServiceDirectory serviceDirectory;
@ -231,7 +235,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
List<Instruction> instructions = treatment.allInstructions(); List<Instruction> instructions = treatment.allInstructions();
Optional<Instruction> vlanIntruction = instructions.stream() Optional<Instruction> vlanInstruction = instructions.stream()
.filter(i -> i.type() == Instruction.Type.L2MODIFICATION) .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
.filter(i -> ((L2ModificationInstruction) i).subtype() == .filter(i -> ((L2ModificationInstruction) i).subtype() ==
L2ModificationInstruction.L2SubType.VLAN_PUSH || L2ModificationInstruction.L2SubType.VLAN_PUSH ||
@ -239,12 +243,12 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
L2ModificationInstruction.L2SubType.VLAN_POP) L2ModificationInstruction.L2SubType.VLAN_POP)
.findAny(); .findAny();
if (!vlanIntruction.isPresent()) {
if (!vlanInstruction.isPresent()) {
installNoModificationRules(fwd); installNoModificationRules(fwd);
} else { } else {
L2ModificationInstruction vlanIns = L2ModificationInstruction vlanIns =
(L2ModificationInstruction) vlanIntruction.get(); (L2ModificationInstruction) vlanInstruction.get();
if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) { if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
installUpstreamRules(fwd); installUpstreamRules(fwd);
} else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) { } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
@ -409,62 +413,114 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
} }
private void installDownstreamRules(ForwardingObjective fwd) { private void installDownstreamRules(ForwardingObjective fwd) {
List<Pair<Instruction, Instruction>> vlanOps =
vlanOps(fwd,
L2ModificationInstruction.L2SubType.VLAN_POP);
if (vlanOps == null) {
return;
}
Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream"); Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
if (output == null) { if (output == null) {
return; return;
} }
Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
TrafficSelector selector = fwd.selector(); TrafficSelector selector = fwd.selector();
Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID); Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID); Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT); Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
long cvid = ((VlanIdCriterion) innerVlan).vlanId().toShort(); if (outerVlan == null || innerVlanCriterion == null || inport == null) {
long outPort = output.port().toLong() & 0x0FFFFFFFFL;
Criterion metadata = Criteria.matchMetadata((cvid << 32) | outPort);
if (outerVlan == null || inport == null) {
log.error("Forwarding objective is underspecified: {}", fwd); log.error("Forwarding objective is underspecified: {}", fwd);
fail(fwd, ObjectiveError.BADPARAMS); fail(fwd, ObjectiveError.BADPARAMS);
return; return;
} }
Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId()); VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
Criterion innerVid = Criteria.matchVlanId(innerVlan);
long cvid = innerVlan.toShort();
long outPort = output.port().toLong() & 0x0FFFFFFFFL;
Criterion metadata = Criteria.matchMetadata((cvid << 32) | outPort);
TrafficSelector outerSelector = buildSelector(inport, outerVlan, metadata);
if (innerVlan.toShort() == VlanId.ANY_VALUE) {
installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Criteria.matchVlanId(VlanId.ANY)));
} else {
installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid));
}
}
private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
TrafficSelector outerSelector, TrafficSelector innerSelector) {
List<Pair<Instruction, Instruction>> vlanOps =
vlanOps(fwd,
L2ModificationInstruction.L2SubType.VLAN_POP);
if (vlanOps == null || vlanOps.isEmpty()) {
return;
}
Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
TrafficTreatment innerTreatment;
VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
if (VlanId.NONE.equals(setVlanId)) {
innerTreatment = (buildTreatment(true, output, popAndRewrite.getLeft(), fetchMeter(fwd),
fetchTransition(fwd)));
} else {
innerTreatment = (buildTreatment(true, output, popAndRewrite.getLeft(), popAndRewrite.getRight(),
fetchMeter(fwd), fetchTransition(fwd)));
}
//match: in port (nni), s-tag, metadata
//action: pop vlan (s-tag), go to table 1
FlowRule.Builder outer = DefaultFlowRule.builder() FlowRule.Builder outer = DefaultFlowRule.builder()
.fromApp(fwd.appId()) .fromApp(fwd.appId())
.forDevice(deviceId) .forDevice(deviceId)
.makePermanent() .makePermanent()
.withPriority(fwd.priority()) .withPriority(fwd.priority())
.withSelector(buildSelector(inport, outerVlan, metadata)) .withSelector(outerSelector)
.withTreatment(buildTreatment(popAndRewrite.getLeft(), .withTreatment(buildTreatment(popAndRewrite.getLeft(),
Instructions.transition(QQ_TABLE))); Instructions.transition(QQ_TABLE)));
//match: in port (nni), c-tag
//action: deferred: output, immediate: pop, meter, go to 64 - 127 (technology profile)
FlowRule.Builder inner = DefaultFlowRule.builder() FlowRule.Builder inner = DefaultFlowRule.builder()
.fromApp(fwd.appId()) .fromApp(fwd.appId())
.forDevice(deviceId) .forDevice(deviceId)
.forTable(QQ_TABLE) .forTable(QQ_TABLE)
.makePermanent() .makePermanent()
.withPriority(fwd.priority()) .withPriority(fwd.priority())
.withSelector(buildSelector(inport, innerVid)) .withSelector(innerSelector)
.withTreatment(buildTreatment(popAndRewrite.getLeft(), .withTreatment(innerTreatment);
output)); applyRules(fwd, inner, outer);
}
private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
TrafficSelector outerSelector, TrafficSelector innerSelector) {
//match: in port (nni), s-tag and metadata
//action: deferred: pop vlan (s-tag), immediate: go to table 1
FlowRule.Builder outer = DefaultFlowRule.builder()
.fromApp(fwd.appId())
.forDevice(deviceId)
.makePermanent()
.withPriority(fwd.priority())
.withSelector(outerSelector)
.withTreatment(buildTreatment(true, Instructions.popVlan(),
Instructions.transition(QQ_TABLE)));
//match: in port (nni) and s-tag
//action: deferred: output, immediate : none, meter, go to 64 - 127 (technology profile)
FlowRule.Builder inner = DefaultFlowRule.builder()
.fromApp(fwd.appId())
.forDevice(deviceId)
.forTable(QQ_TABLE)
.makePermanent()
.withPriority(fwd.priority())
.withSelector(innerSelector)
.withTreatment(buildTreatment(true, output, fetchMeter(fwd), fetchTransition(fwd)));
applyRules(fwd, inner, outer); applyRules(fwd, inner, outer);
} }
private void installUpstreamRules(ForwardingObjective fwd) { private void installUpstreamRules(ForwardingObjective fwd) {
@ -472,7 +528,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
vlanOps(fwd, vlanOps(fwd,
L2ModificationInstruction.L2SubType.VLAN_PUSH); L2ModificationInstruction.L2SubType.VLAN_PUSH);
if (vlanOps == null) { if (vlanOps == null || vlanOps.isEmpty()) {
return; return;
} }
@ -483,31 +539,41 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
} }
Pair<Instruction, Instruction> innerPair = vlanOps.remove(0); Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
Pair<Instruction, Instruction> outerPair = vlanOps.remove(0); Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
// Add the VLAN_PUSH treatment if we're matching on VlanId.NONE boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID); boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
boolean push = false;
if (vlanMatchCriterion != null) {
push = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
}
TrafficTreatment treatment; if (anyValueVlanStatus) {
if (push) { installUpstreamRulesForAnyVlan(fwd, output, outerPair);
treatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), } else {
installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
}
}
private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
Pair<Instruction, Instruction> innerPair,
Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
TrafficTreatment innerTreatment;
if (noneValueVlanStatus) {
innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(),
Instructions.transition(QQ_TABLE)); Instructions.transition(QQ_TABLE));
} else { } else {
treatment = buildTreatment(innerPair.getRight(), Instructions.transition(QQ_TABLE)); innerTreatment = buildTreatment(innerPair.getRight(), Instructions.transition(QQ_TABLE));
} }
//match: in port, vlanId (0 or None)
//action:
//if vlanId None, push & set c-tag go to table 1
//if vlanId 0 or any specific vlan, set c-tag go to table 1
FlowRule.Builder inner = DefaultFlowRule.builder() FlowRule.Builder inner = DefaultFlowRule.builder()
.fromApp(fwd.appId()) .fromApp(fwd.appId())
.forDevice(deviceId) .forDevice(deviceId)
.makePermanent() .makePermanent()
.withPriority(fwd.priority()) .withPriority(fwd.priority())
.withSelector(fwd.selector()) .withSelector(fwd.selector())
.withTreatment(treatment); .withTreatment(innerTreatment);
PortCriterion inPort = (PortCriterion) PortCriterion inPort = (PortCriterion)
fwd.selector().getCriterion(Criterion.Type.IN_PORT); fwd.selector().getCriterion(Criterion.Type.IN_PORT);
@ -515,20 +581,91 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
innerPair.getRight()).vlanId(); innerPair.getRight()).vlanId();
//match: in port, c-tag
//action: deferred: output, immediate: push s-tag, meter, go to 64 - 127 (technology profile id)
FlowRule.Builder outer = DefaultFlowRule.builder() FlowRule.Builder outer = DefaultFlowRule.builder()
.fromApp(fwd.appId()) .fromApp(fwd.appId())
.forDevice(deviceId) .forDevice(deviceId)
.forTable(QQ_TABLE) .forTable(QQ_TABLE)
.makePermanent() .makePermanent()
.withPriority(fwd.priority()) .withPriority(fwd.priority())
.withSelector(buildSelector(inPort, .withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)))
Criteria.matchVlanId(cVlanId))) .withTreatment(buildTreatment(true, output, outerPair.getLeft(), outerPair.getRight(),
.withTreatment(buildTreatment(outerPair.getLeft(), fetchMeter(fwd), fetchTransition(fwd)));
outerPair.getRight(),
output));
applyRules(fwd, inner, outer); applyRules(fwd, inner, outer);
}
private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
Pair<Instruction, Instruction> outerPair) {
log.debug("Installing upstream rules for any value vlan");
//match: in port and any-vlan (coming from OLT app.)
//action: go to table 1
FlowRule.Builder inner = DefaultFlowRule.builder()
.fromApp(fwd.appId())
.forDevice(deviceId)
.makePermanent()
.withPriority(fwd.priority())
.withSelector(fwd.selector())
.withTreatment(buildTreatment(Instructions.transition(QQ_TABLE)));
TrafficSelector defaultSelector = DefaultTrafficSelector.builder()
.matchInPort(((PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT)).port())
.build();
//drop the packets that don't have vlan
//match: in port
//action: no action
FlowRule.Builder defaultInner = DefaultFlowRule.builder()
.fromApp(fwd.appId())
.forDevice(deviceId)
.makePermanent()
.withPriority(NO_ACTION_PRIORITY)
.withSelector(defaultSelector)
.withTreatment(DefaultTrafficTreatment.emptyTreatment());
Instruction qinqInstruction = Instructions.pushVlan(EthType.EtherType.QINQ.ethType());
//match: in port and any-vlan (coming from OLT app.)
//action: deferred: output, immediate: push:QinQ, vlanId (s-tag), meter, go to 64-127 (technology profile id)
FlowRule.Builder outer = DefaultFlowRule.builder()
.fromApp(fwd.appId())
.forDevice(deviceId)
.forTable(QQ_TABLE)
.makePermanent()
.withPriority(fwd.priority())
.withSelector(fwd.selector())
.withTreatment(buildTreatment(true, output, qinqInstruction, outerPair.getRight(),
fetchMeter(fwd), fetchTransition(fwd)));
applyRules(fwd, inner, defaultInner, outer);
}
private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
// Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
boolean noneValueVlanStatus = false;
if (vlanMatchCriterion != null) {
noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
}
return noneValueVlanStatus;
}
private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
.filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
.filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
.findAny().orElse(null);
if (anyValueVlanCriterion == null) {
log.debug("Any value vlan match criteria is not found");
return false;
}
return true;
} }
private Instruction fetchOutput(ForwardingObjective fwd, String direction) { private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
@ -544,18 +681,42 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
return output; return output;
} }
private Instruction fetchMeter(ForwardingObjective fwd) {
Instruction meter = fwd.treatment().metered();
if (meter == null) {
log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
return null;
}
log.debug("Meter instruction is found.");
return meter;
}
private Instruction fetchTransition(ForwardingObjective fwd) {
Instruction transition = fwd.treatment().tableTransition();
if (transition == null) {
log.debug("Table / transition instruction is not found for the forwarding objective {}", fwd);
return null;
}
log.debug("Transition instruction is found.");
return transition;
}
private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd, private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
L2ModificationInstruction.L2SubType type) { L2ModificationInstruction.L2SubType type) {
List<Pair<Instruction, Instruction>> vlanOps = findVlanOps( List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
fwd.treatment().allInstructions(), type); fwd.treatment().allInstructions(), type);
if (vlanOps == null) { if (vlanOps == null || vlanOps.isEmpty()) {
String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
? "downstream" : "upstream"; ? "downstream" : "upstream";
log.error("Missing vlan operations in {} forwarding: {}", direction, fwd); log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
fail(fwd, ObjectiveError.BADPARAMS); fail(fwd, ObjectiveError.BADPARAMS);
return null; return ImmutableList.of();
} }
return vlanOps; return vlanOps;
} }
@ -572,7 +733,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
instructions); instructions);
if (vlanPushs.size() != vlanSets.size()) { if (vlanPushs.size() != vlanSets.size()) {
return null; return ImmutableList.of();
} }
List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList(); List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
@ -618,6 +779,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
TrafficTreatment treatment = buildTreatment(output); TrafficTreatment treatment = buildTreatment(output);
buildAndApplyRule(filter, selector, treatment); buildAndApplyRule(filter, selector, treatment);
} }
private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector, private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
TrafficTreatment treatment) { TrafficTreatment treatment) {
FlowRule rule = DefaultFlowRule.builder() FlowRule rule = DefaultFlowRule.builder()
@ -647,36 +809,18 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
applyFlowRules(opsBuilder, filter); applyFlowRules(opsBuilder, filter);
} }
private void applyRules(ForwardingObjective fwd, private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
FlowRule.Builder outer) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
switch (fwd.op()) { switch (fwd.op()) {
case ADD: case ADD:
builder.add(outer.build()); for (FlowRule.Builder fwdBuilder : fwdBuilders) {
builder.add(fwdBuilder.build());
}
break; break;
case REMOVE: case REMOVE:
builder.remove(outer.build()); for (FlowRule.Builder fwdBuilder : fwdBuilders) {
break; builder.remove(fwdBuilder.build());
case ADD_TO_EXISTING: }
break;
case REMOVE_FROM_EXISTING:
break;
default:
log.warn("Unknown forwarding operation: {}", fwd.op());
}
applyFlowRules(builder, fwd);
}
private void applyRules(ForwardingObjective fwd,
FlowRule.Builder inner, FlowRule.Builder outer) {
FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
switch (fwd.op()) {
case ADD:
builder.add(inner.build()).add(outer.build());
break;
case REMOVE:
builder.remove(inner.build()).remove(outer.build());
break; break;
case ADD_TO_EXISTING: case ADD_TO_EXISTING:
break; break;
@ -723,6 +867,20 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
return sBuilder.build(); return sBuilder.build();
} }
private TrafficTreatment buildTreatment(boolean isDeferred, Instruction deferredInst, Instruction... instructions) {
TrafficTreatment.Builder dBuilder = DefaultTrafficTreatment.builder();
Arrays.stream(instructions).filter(Objects::nonNull).forEach(treatment -> dBuilder.add(treatment));
if (isDeferred) {
dBuilder.deferred();
dBuilder.add(deferredInst);
}
return dBuilder.build();
}
private TrafficTreatment buildTreatment(Instruction... instructions) { private TrafficTreatment buildTreatment(Instruction... instructions) {
@ -749,7 +907,7 @@ public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
@Override @Override
public void event(GroupEvent event) { public void event(GroupEvent event) {
if (event.type() == GroupEvent.Type.GROUP_ADDED || if (event.type() == GroupEvent.Type.GROUP_ADDED ||
event.type() == GroupEvent.Type.GROUP_UPDATED) { event.type() == GroupEvent.Type.GROUP_UPDATED) {
GroupKey key = event.subject().appCookie(); GroupKey key = event.subject().appCookie();
NextObjective obj = pendingGroups.getIfPresent(key); NextObjective obj = pendingGroups.getIfPresent(key);