Add support for vlan based intents in the Corsa driver

Changes:
- Improves processSpecific in AbstractCorsaPipeline in order to support
Intents without an explicit match on the Ethertype;
- Implements vlan based circuits in CorsaPipelineV3 through the management
of the FwdObjective without Treatment;
- Distinguish Groups from simple actions;
- Corsa group are identified using the actions of the treatment;
- handling of the pending next similar to DefaultSingleTablePipeline

Change-Id: Iff0f70d56c64193524c6640f31ffb3f5629499dc
This commit is contained in:
Pier Ventre 2016-07-20 15:37:19 +02:00
parent f97e13d0a1
commit db67355aaf
3 changed files with 203 additions and 28 deletions

View File

@ -93,14 +93,14 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
private ServiceDirectory serviceDirectory; private ServiceDirectory serviceDirectory;
protected FlowRuleService flowRuleService; protected FlowRuleService flowRuleService;
private CoreService coreService; private CoreService coreService;
private GroupService groupService; protected GroupService groupService;
protected MeterService meterService; protected MeterService meterService;
private FlowObjectiveStore flowObjectiveStore; protected FlowObjectiveStore flowObjectiveStore;
protected DeviceId deviceId; protected DeviceId deviceId;
protected ApplicationId appId; protected ApplicationId appId;
protected DeviceService deviceService; protected DeviceService deviceService;
private KryoNamespace appKryo = new KryoNamespace.Builder() protected KryoNamespace appKryo = new KryoNamespace.Builder()
.register(GroupKey.class) .register(GroupKey.class)
.register(DefaultGroupKey.class) .register(DefaultGroupKey.class)
.register(CorsaGroup.class) .register(CorsaGroup.class)
@ -108,6 +108,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
.build("AbstractCorsaPipeline"); .build("AbstractCorsaPipeline");
private Cache<GroupKey, NextObjective> pendingGroups; private Cache<GroupKey, NextObjective> pendingGroups;
protected Cache<Integer, NextObjective> pendingNext;
private ScheduledExecutorService groupChecker = private ScheduledExecutorService groupChecker =
Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
@ -131,6 +133,16 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
} }
}).build(); }).build();
pendingNext = CacheBuilder.newBuilder()
.expireAfterWrite(20, TimeUnit.SECONDS)
.removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
if (notification.getCause() == RemovalCause.EXPIRED) {
notification.getValue().context()
.ifPresent(c -> c.onError(notification.getValue(),
ObjectiveError.FLOWINSTALLATIONFAILED));
}
}).build();
groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS); groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
coreService = serviceDirectory.get(CoreService.class); coreService = serviceDirectory.get(CoreService.class);
@ -304,6 +316,7 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
@Override @Override
public void forward(ForwardingObjective fwd) { public void forward(ForwardingObjective fwd) {
Collection<FlowRule> rules; Collection<FlowRule> rules;
FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder(); FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
@ -354,16 +367,20 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
log.debug("Processing specific forwarding objective"); log.debug("Processing specific forwarding objective");
TrafficSelector selector = fwd.selector(); TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType = EthTypeCriterion ethTypeCriterion =
(EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
if (ethType != null) { VlanIdCriterion vlanIdCriterion =
short et = ethType.ethType().toShort(); (VlanIdCriterion) selector.getCriterion(Criterion.Type.VLAN_VID);
if (ethTypeCriterion != null) {
short et = ethTypeCriterion.ethType().toShort();
if (et == Ethernet.TYPE_IPV4) { if (et == Ethernet.TYPE_IPV4) {
return processSpecificRoute(fwd); return processSpecificRoute(fwd);
} else if (et == Ethernet.TYPE_VLAN) { } else if (et == Ethernet.TYPE_VLAN) {
/* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */ /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
return processSpecificSwitch(fwd); return processSpecificSwitch(fwd);
} }
} else if (vlanIdCriterion != null) {
return processSpecificSwitch(fwd);
} }
fail(fwd, ObjectiveError.UNSUPPORTED); fail(fwd, ObjectiveError.UNSUPPORTED);
@ -464,6 +481,41 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
//Hook for modifying Route flow rule //Hook for modifying Route flow rule
protected abstract Builder processSpecificRoutingRule(Builder rb); protected abstract Builder processSpecificRoutingRule(Builder rb);
protected enum CorsaTrafficTreatmentType {
/**
* If the treatment has to be handled as group.
*/
GROUP,
/**
* If the treatment has to be handled as simple set of actions.
*/
ACTIONS
}
/**
* Helper class to encapsulate both traffic treatment and
* type of treatment.
*/
protected class CorsaTrafficTreatment {
private CorsaTrafficTreatmentType type;
private TrafficTreatment trafficTreatment;
public CorsaTrafficTreatment(CorsaTrafficTreatmentType treatmentType, TrafficTreatment trafficTreatment) {
this.type = treatmentType;
this.trafficTreatment = trafficTreatment;
}
public CorsaTrafficTreatmentType type() {
return type;
}
public TrafficTreatment treatment() {
return trafficTreatment;
}
}
@Override @Override
public void next(NextObjective nextObjective) { public void next(NextObjective nextObjective) {
switch (nextObjective.type()) { switch (nextObjective.type()) {
@ -471,20 +523,25 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
Collection<TrafficTreatment> treatments = nextObjective.next(); Collection<TrafficTreatment> treatments = nextObjective.next();
if (treatments.size() == 1) { if (treatments.size() == 1) {
TrafficTreatment treatment = treatments.iterator().next(); TrafficTreatment treatment = treatments.iterator().next();
treatment = processNextTreatment(treatment); CorsaTrafficTreatment corsaTreatment = processNextTreatment(treatment);
GroupBucket bucket =
DefaultGroupBucket.createIndirectGroupBucket(treatment);
final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id())); final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
GroupDescription groupDescription if (corsaTreatment.type() == CorsaTrafficTreatmentType.GROUP) {
= new DefaultGroupDescription(deviceId, GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(corsaTreatment.treatment());
GroupDescription.Type.INDIRECT, GroupBuckets buckets = new GroupBuckets(Collections.singletonList(bucket));
new GroupBuckets(Collections // group id == null, let group service determine group id
.singletonList(bucket)), GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
key, GroupDescription.Type.INDIRECT,
null, // let group service determine group id buckets,
nextObjective.appId()); key,
groupService.addGroup(groupDescription); null,
pendingGroups.put(key, nextObjective); nextObjective.appId());
groupService.addGroup(groupDescription);
pendingGroups.put(key, nextObjective);
} else if (corsaTreatment.type() == CorsaTrafficTreatmentType.ACTIONS) {
pendingNext.put(nextObjective.id(), nextObjective);
flowObjectiveStore.putNextGroup(nextObjective.id(), new CorsaGroup(key));
nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
}
} }
break; break;
case HASHED: case HASHED:
@ -501,8 +558,8 @@ public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour imp
} }
//Hook for altering the NextObjective treatment //Hook for altering the NextObjective treatment
protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
return treatment; return new CorsaTrafficTreatment(CorsaTrafficTreatmentType.GROUP, treatment);
} }
//Init helper: Table Miss = Drop //Init helper: Table Miss = Drop

View File

@ -30,9 +30,12 @@ import org.onosproject.net.flow.criteria.EthCriterion;
import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.PortCriterion; import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion; import org.onosproject.net.flow.criteria.VlanIdCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flowobjective.FilteringObjective; import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.NextObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
import org.onosproject.net.meter.Band; import org.onosproject.net.meter.Band;
import org.onosproject.net.meter.DefaultBand; import org.onosproject.net.meter.DefaultBand;
import org.onosproject.net.meter.DefaultMeterRequest; import org.onosproject.net.meter.DefaultMeterRequest;
@ -69,9 +72,11 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
protected MeterId defaultMeterId = null; protected MeterId defaultMeterId = null;
@Override @Override
protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
treatment.immediate().stream() treatment.immediate().stream()
.filter(i -> { .filter(i -> {
switch (i.type()) { switch (i.type()) {
@ -87,7 +92,48 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
return false; return false;
} }
}).forEach(i -> tb.add(i)); }).forEach(i -> tb.add(i));
return tb.build();
TrafficTreatment t = tb.build();
boolean isPresentModVlanId = false;
boolean isPresentModEthSrc = false;
boolean isPresentModEthDst = false;
boolean isPresentOutpuPort = false;
for (Instruction instruction : t.immediate()) {
switch (instruction.type()) {
case L2MODIFICATION:
L2ModificationInstruction l2i = (L2ModificationInstruction) instruction;
if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) {
isPresentModVlanId = true;
}
if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) {
L2ModificationInstruction.L2SubType subType = l2i.subtype();
if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) {
isPresentModEthSrc = true;
} else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) {
isPresentModEthDst = true;
}
}
case OUTPUT:
isPresentOutpuPort = true;
default:
}
}
CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS;
/**
* This represents the allowed group for CorsaPipelinev3
*/
if (isPresentModVlanId &&
isPresentModEthSrc &&
isPresentModEthDst &&
isPresentOutpuPort) {
type = CorsaTrafficTreatmentType.GROUP;
}
CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t);
return corsaTreatment;
} }
@Override @Override
@ -115,9 +161,37 @@ public class CorsaPipelineV3 extends AbstractCorsaPipeline {
.withPriority(fwd.priority()) .withPriority(fwd.priority())
.forDevice(deviceId) .forDevice(deviceId)
.withSelector(filteredSelector) .withSelector(filteredSelector)
.withTreatment(fwd.treatment())
.forTable(VLAN_CIRCUIT_TABLE); .forTable(VLAN_CIRCUIT_TABLE);
if (fwd.treatment() != null) {
ruleBuilder.withTreatment(fwd.treatment());
} else {
if (fwd.nextId() != null) {
NextObjective nextObjective = pendingNext.getIfPresent(fwd.nextId());
if (nextObjective != null) {
pendingNext.invalidate(fwd.nextId());
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
.setVlanPcp((byte) 0)
.setQueue(0)
.meter(defaultMeterId);
nextObjective.next().forEach(trafficTreatment -> {
trafficTreatment.allInstructions().forEach(instruction -> {
treatment.add(instruction);
});
});
ruleBuilder.withTreatment(treatment.build());
} else {
log.warn("The group left!");
fwd.context().ifPresent(c -> c.onError(fwd, ObjectiveError.GROUPMISSING));
return ImmutableSet.of();
}
} else {
log.warn("Missing NextObjective ID for ForwardingObjective {}", fwd.id());
fail(fwd, ObjectiveError.BADPARAMS);
return ImmutableSet.of();
}
}
if (fwd.permanent()) { if (fwd.permanent()) {
ruleBuilder.makePermanent(); ruleBuilder.makePermanent();
} else { } else {

View File

@ -29,6 +29,7 @@ import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.criteria.Criterion; import org.onosproject.net.flow.criteria.Criterion;
import org.onosproject.net.flow.criteria.IPCriterion; import org.onosproject.net.flow.criteria.IPCriterion;
import org.onosproject.net.flow.criteria.IPProtocolCriterion; import org.onosproject.net.flow.criteria.IPProtocolCriterion;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.flow.instructions.Instructions;
import org.onosproject.net.flow.instructions.L2ModificationInstruction; import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.ForwardingObjective;
@ -226,16 +227,14 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 {
} }
@Override @Override
protected TrafficTreatment processNextTreatment(TrafficTreatment treatment) { protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder(); TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
tb.add(Instructions.popVlan());
treatment.immediate().stream() treatment.immediate().stream()
.filter(i -> { .filter(i -> {
switch (i.type()) { switch (i.type()) {
case L2MODIFICATION: case L2MODIFICATION:
L2ModificationInstruction l2i = (L2ModificationInstruction) i; L2ModificationInstruction l2i = (L2ModificationInstruction) i;
if (l2i.subtype() == VLAN_ID || if (l2i.subtype() == VLAN_ID ||
l2i.subtype() == VLAN_POP ||
l2i.subtype() == VLAN_POP || l2i.subtype() == VLAN_POP ||
l2i.subtype() == ETH_DST || l2i.subtype() == ETH_DST ||
l2i.subtype() == ETH_SRC) { l2i.subtype() == ETH_SRC) {
@ -247,6 +246,51 @@ public class CorsaPipelineV39 extends CorsaPipelineV3 {
return false; return false;
} }
}).forEach(i -> tb.add(i)); }).forEach(i -> tb.add(i));
return tb.build();
TrafficTreatment t = tb.build();
boolean isPresentModVlanId = false;
boolean isPresentModEthSrc = false;
boolean isPresentModEthDst = false;
boolean isPresentOutpuPort = false;
for (Instruction instruction : t.immediate()) {
switch (instruction.type()) {
case L2MODIFICATION:
L2ModificationInstruction l2i = (L2ModificationInstruction) instruction;
if (l2i instanceof L2ModificationInstruction.ModVlanIdInstruction) {
isPresentModVlanId = true;
}
if (l2i instanceof L2ModificationInstruction.ModEtherInstruction) {
L2ModificationInstruction.L2SubType subType = l2i.subtype();
if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC)) {
isPresentModEthSrc = true;
} else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST)) {
isPresentModEthDst = true;
}
}
case OUTPUT:
isPresentOutpuPort = true;
default:
}
}
CorsaTrafficTreatmentType type = CorsaTrafficTreatmentType.ACTIONS;
/**
* These are the allowed groups for CorsaPipelinev39
*/
if (isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) {
type = CorsaTrafficTreatmentType.GROUP;
} else if ((!isPresentModVlanId && isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
(!isPresentModVlanId && !isPresentModEthSrc && isPresentModEthDst && isPresentOutpuPort) ||
(!isPresentModVlanId && !isPresentModEthSrc && !isPresentModEthDst && isPresentOutpuPort)) {
type = CorsaTrafficTreatmentType.GROUP;
TrafficTreatment.Builder tb2 = DefaultTrafficTreatment.builder(t);
tb2.add(Instructions.popVlan());
t = tb2.build();
}
CorsaTrafficTreatment corsaTreatment = new CorsaTrafficTreatment(type, t);
return corsaTreatment;
} }
} }