use of org.onosproject.net.behaviour.NextGroup in project onos by opennetworkinglab.
the class PicaPipeline method processSpecific.
private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
log.debug("Processing specific forwarding objective");
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
if (ethType == null || ethType.ethType().toShort() != Ethernet.TYPE_IPV4) {
fail(fwd, ObjectiveError.UNSUPPORTED);
return Collections.emptySet();
}
List<FlowRule> ipflows = new ArrayList<FlowRule>();
for (Filter f : filters) {
TrafficSelector filteredSelector = DefaultTrafficSelector.builder().matchEthType(Ethernet.TYPE_IPV4).matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()).matchEthDst(f.mac()).matchVlanId(f.vlanId()).build();
TrafficTreatment tt = null;
if (fwd.nextId() != null) {
NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
if (next == null) {
log.error("next-id {} does not exist in store", fwd.nextId());
return Collections.emptySet();
}
tt = appKryo.deserialize(next.data());
if (tt == null) {
log.error("Error in deserializing next-id {}", fwd.nextId());
return Collections.emptySet();
}
}
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(filteredSelector).withTreatment(tt);
if (fwd.permanent()) {
ruleBuilder.makePermanent();
} else {
ruleBuilder.makeTemporary(fwd.timeout());
}
ruleBuilder.forTable(IP_UNICAST_TABLE);
ipflows.add(ruleBuilder.build());
}
return ipflows;
}
use of org.onosproject.net.behaviour.NextGroup in project onos by opennetworkinglab.
the class SpringOpenTTP method processVersatile.
private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
log.debug("Processing versatile forwarding objective in dev:{}", deviceId);
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
if (ethType == null) {
log.error("Versatile forwarding objective must include ethType");
fail(fwd, ObjectiveError.UNKNOWN);
return Collections.emptySet();
}
if (fwd.treatment() == null && fwd.nextId() == null) {
log.error("VERSATILE forwarding objective needs next objective ID " + "or treatment.");
return Collections.emptySet();
}
// emulation of ACL table (for versatile fwd objective) requires
// overriding any previous instructions
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
treatmentBuilder.wipeDeferred();
if (fwd.nextId() != null) {
NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
if (next != null) {
SpringOpenGroup soGroup = appKryo.deserialize(next.data());
if (soGroup.dummy) {
// need to convert to flow-actions
for (Instruction ins : soGroup.treatment.allInstructions()) {
treatmentBuilder.add(ins);
}
} else {
GroupKey key = soGroup.key;
Group group = groupService.getGroup(deviceId, key);
if (group == null) {
log.warn("The group left!");
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
treatmentBuilder.deferred().group(group.id());
log.debug("Adding OUTGROUP action");
}
}
}
if (fwd.treatment() != null) {
if (fwd.treatment().allInstructions().size() == 1 && fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
if (o.port() == PortNumber.CONTROLLER) {
treatmentBuilder.popVlan();
treatmentBuilder.punt();
} else {
treatmentBuilder.add(o);
}
} else {
for (Instruction ins : fwd.treatment().allInstructions()) {
treatmentBuilder.add(ins);
}
}
}
FlowRule.Builder ruleBuilder = DefaultFlowRule.builder().fromApp(fwd.appId()).withPriority(fwd.priority()).forDevice(deviceId).withSelector(fwd.selector()).withTreatment(treatmentBuilder.build());
if (fwd.permanent()) {
ruleBuilder.makePermanent();
} else {
ruleBuilder.makeTemporary(fwd.timeout());
}
ruleBuilder.forTable(aclTableId);
return Collections.singletonList(ruleBuilder.build());
}
use of org.onosproject.net.behaviour.NextGroup in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method addBucketToL2FloodGroup.
private void addBucketToL2FloodGroup(NextObjective nextObj, List<Deque<GroupKey>> allActiveKeys, List<GroupInfo> groupInfos, VlanId assignedVlan) {
Group l2FloodGroup = retrieveTopLevelGroup(allActiveKeys, deviceId, groupService, nextObj.id());
if (l2FloodGroup == null) {
log.warn("Can't find L2 flood group while adding bucket to it. NextObj = {}", nextObj);
fail(nextObj, ObjectiveError.GROUPMISSING);
return;
}
GroupKey l2floodGroupKey = l2FloodGroup.appCookie();
int l2floodGroupId = l2FloodGroup.id().id();
List<GroupBucket> newBuckets = generateNextGroupBuckets(groupInfos, ALL);
GroupDescription l2FloodGroupDescription = new DefaultGroupDescription(deviceId, ALL, new GroupBuckets(newBuckets), l2floodGroupKey, l2floodGroupId, nextObj.appId());
GroupChainElem l2FloodGroupChainElement = new GroupChainElem(l2FloodGroupDescription, groupInfos.size(), true, deviceId);
// ensure assignedVlan applies to the chosen group
VlanId floodGroupVlan = extractVlanIdFromGroupId(l2floodGroupId);
if (!floodGroupVlan.equals(assignedVlan)) {
log.warn("VLAN ID {} does not match Flood group {} to which bucket is " + "being added, for next:{} in dev:{}. Abort.", assignedVlan, Integer.toHexString(l2floodGroupId), nextObj.id(), deviceId);
fail(nextObj, ObjectiveError.BADPARAMS);
return;
}
List<Deque<GroupKey>> addedKeys = new ArrayList<>();
groupInfos.forEach(groupInfo -> {
// update original NextGroup with new bucket-chain
Deque<GroupKey> newBucketChain = new ArrayDeque<>();
newBucketChain.addFirst(groupInfo.nextGroupDesc().appCookie());
newBucketChain.addFirst(l2floodGroupKey);
addedKeys.add(newBucketChain);
log.debug("Adding to L2FLOOD: device:{} gid:{} group key:{} nextId:{}", deviceId, Integer.toHexString(l2floodGroupId), l2floodGroupKey, nextObj.id());
// send the innermost group
log.debug("Sending innermost group {} in group chain on device {} ", Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), l2FloodGroupChainElement);
DeviceId innerMostGroupDevice = groupInfo.innerMostGroupDesc().deviceId();
GroupKey innerMostGroupKey = groupInfo.innerMostGroupDesc().appCookie();
Group existsL2IGroup = groupService.getGroup(innerMostGroupDevice, innerMostGroupKey);
if (existsL2IGroup != null) {
// group already exist
processPendingAddGroupsOrNextObjs(innerMostGroupKey, true);
} else {
groupService.addGroup(groupInfo.innerMostGroupDesc());
}
});
updatePendingNextObjective(l2floodGroupKey, new OfdpaNextGroup(addedKeys, nextObj));
}
use of org.onosproject.net.behaviour.NextGroup in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method updateFlowObjectiveStore.
private void updateFlowObjectiveStore(Integer nextId, OfdpaNextGroup nextGrp) {
synchronized (flowObjectiveStore) {
// get fresh copy of what the store holds
NextGroup next = flowObjectiveStore.getNextGroup(nextId);
if (next == null || nextGrp.nextObjective().op() == Operation.ADD) {
flowObjectiveStore.putNextGroup(nextId, nextGrp);
return;
}
if (nextGrp.nextObjective().op() == Operation.ADD_TO_EXISTING) {
List<Deque<GroupKey>> allActiveKeys = appKryo.deserialize(next.data());
allActiveKeys = Lists.newArrayList(allActiveKeys);
// then it represents an empty group. Update by replacing empty chain.
if (allActiveKeys.size() == 1 && allActiveKeys.get(0).size() == 1) {
allActiveKeys.clear();
}
allActiveKeys.addAll(nextGrp.allKeys());
flowObjectiveStore.putNextGroup(nextId, new OfdpaNextGroup(allActiveKeys, nextGrp.nextObjective()));
}
}
}
use of org.onosproject.net.behaviour.NextGroup in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method verifyGroup.
/**
* Checks existing buckets in {@link NextGroup} to verify if they match
* the buckets in the given {@link NextObjective}. Adds or removes buckets
* to ensure that the buckets match up.
*
* @param nextObjective the next objective to verify
* @param next the representation of the existing group which has to be
* modified to match the given next objective
*/
protected void verifyGroup(NextObjective nextObjective, NextGroup next) {
if (nextObjective.type() == NextObjective.Type.SIMPLE) {
log.warn("verification not supported for indirect group");
fail(nextObjective, ObjectiveError.UNSUPPORTED);
return;
}
log.trace("Call to verify device:{} nextId:{}", deviceId, nextObjective.id());
List<Deque<GroupKey>> allActiveKeys = appKryo.deserialize(next.data());
List<TrafficTreatment> bucketsToCreate = Lists.newArrayList();
List<Integer> indicesToRemove = Lists.newArrayList();
// to detect missing buckets and/or duplicate buckets (to be removed)
for (TrafficTreatment bkt : nextObjective.next()) {
PortNumber portNumber = readOutPortFromTreatment(bkt);
int label = readLabelFromTreatment(bkt);
if (portNumber == null) {
log.warn("treatment {} of next objective {} has no outport.. " + "cannot remove bucket from group in dev: {}", bkt, nextObjective.id(), deviceId);
fail(nextObjective, ObjectiveError.BADPARAMS);
return;
}
List<Integer> existing = existingPortAndLabel(allActiveKeys, groupService, deviceId, portNumber, label);
if (existing.isEmpty()) {
// if it doesn't exist, mark this bucket for creation
bucketsToCreate.add(bkt);
}
if (existing.size() > 1) {
// if it exists but there are duplicates, mark the others for removal
existing.remove(0);
indicesToRemove.addAll(existing);
}
}
// (not duplicates) respect to the next objective
if (allActiveKeys.size() > nextObjective.next().size() && // ignore specific case of empty group
!(nextObjective.next().size() == 0 && allActiveKeys.size() == 1 && allActiveKeys.get(0).size() == 1)) {
log.warn("Mismatch detected between next and flowobjstore for device {}: " + "nextId:{}, nextObjective-size:{} next-size:{} .. correcting", deviceId, nextObjective.id(), nextObjective.next().size(), allActiveKeys.size());
List<Integer> otherIndices = indicesToRemoveFromNextGroup(allActiveKeys, nextObjective, groupService, deviceId);
// Filter out the indices not present
otherIndices = otherIndices.stream().filter(index -> !indicesToRemove.contains(index)).collect(Collectors.toList());
// Add all to the final list
indicesToRemove.addAll(otherIndices);
}
log.trace("Buckets to create {}", bucketsToCreate);
log.trace("Indices to remove {}", indicesToRemove);
if (!bucketsToCreate.isEmpty()) {
log.info("creating {} buckets as part of nextId: {} verification", bucketsToCreate.size(), nextObjective.id());
// create a nextObjective only with these buckets
NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder().withId(nextObjective.id()).withType(nextObjective.type()).withMeta(nextObjective.meta()).fromApp(nextObjective.appId());
bucketsToCreate.forEach(nextObjBuilder::addTreatment);
// According to the next type we call the proper add function
if (nextObjective.type() == NextObjective.Type.HASHED) {
if (isL2Hash(nextObjective)) {
addBucketToL2HashGroup(nextObjBuilder.addToExisting(), allActiveKeys);
} else {
addBucketToEcmpHashGroup(nextObjBuilder.addToExisting(), allActiveKeys);
}
} else {
addBucketToBroadcastGroup(nextObjBuilder.addToExisting(), allActiveKeys);
}
}
if (!indicesToRemove.isEmpty()) {
log.info("removing {} buckets as part of nextId: {} verification", indicesToRemove.size(), nextObjective.id());
List<Deque<GroupKey>> chainsToRemove = Lists.newArrayList();
indicesToRemove.forEach(index -> chainsToRemove.add(allActiveKeys.get(index)));
removeBucket(chainsToRemove, nextObjective);
}
log.trace("Checking mismatch with GroupStore device:{} nextId:{}", deviceId, nextObjective.id());
if (bucketsToCreate.isEmpty() && indicesToRemove.isEmpty()) {
// flowObjective store record is in-sync with nextObjective passed-in
// Nevertheless groupStore may not be in sync due to bug in the store
// - see CORD-1844. XXX When this bug is fixed, the rest of this verify
// method will not be required.
GroupKey topGroupKey = allActiveKeys.get(0).peekFirst();
Group topGroup = groupService.getGroup(deviceId, topGroupKey);
// topGroup should not be null - adding guard
if (topGroup == null) {
log.warn("topGroup {} not found in GroupStore device:{}, nextId:{}", topGroupKey, deviceId, nextObjective.id());
fail(nextObjective, ObjectiveError.GROUPMISSING);
return;
}
int actualGroupSize = topGroup.buckets().buckets().size();
int objGroupSize = nextObjective.next().size();
if (actualGroupSize != objGroupSize) {
log.warn("Mismatch detected in device:{}, nextId:{}, nextObjective-size" + ":{} group-size:{} .. correcting", deviceId, nextObjective.id(), objGroupSize, actualGroupSize);
}
if (actualGroupSize > objGroupSize) {
// Group in the device has more chains
List<GroupBucket> bucketsToRemove = Lists.newArrayList();
// check every bucket in the actual group
for (GroupBucket bucket : topGroup.buckets().buckets()) {
GroupInstruction g = (GroupInstruction) bucket.treatment().allInstructions().iterator().next();
// the group pointed to
GroupId gidToCheck = g.groupId();
boolean matches = false;
for (Deque<GroupKey> validChain : allActiveKeys) {
if (validChain.size() < 2) {
continue;
}
GroupKey pointedGroupKey = validChain.stream().collect(Collectors.toList()).get(1);
Group pointedGroup = groupService.getGroup(deviceId, pointedGroupKey);
if (pointedGroup != null && gidToCheck.equals(pointedGroup.id())) {
matches = true;
break;
}
}
if (!matches) {
log.warn("Removing bucket pointing to groupId:{}", gidToCheck);
bucketsToRemove.add(bucket);
}
}
// remove buckets for which there was no record in the obj store
if (bucketsToRemove.isEmpty()) {
log.warn("Mismatch detected but could not determine which" + "buckets to remove");
} else {
GroupBuckets removeBuckets = new GroupBuckets(bucketsToRemove);
groupService.removeBucketsFromGroup(deviceId, topGroupKey, removeBuckets, topGroupKey, nextObjective.appId());
}
} else if (actualGroupSize < objGroupSize) {
// Group in the device has less chains
// should also add buckets not in group-store but in obj-store
List<GroupBucket> bucketsToAdd = Lists.newArrayList();
// check every bucket in the obj
for (Deque<GroupKey> validChain : allActiveKeys) {
if (validChain.size() < 2) {
continue;
}
GroupKey pointedGroupKey = validChain.stream().collect(Collectors.toList()).get(1);
Group pointedGroup = groupService.getGroup(deviceId, pointedGroupKey);
if (pointedGroup == null) {
// group should exist, otherwise cannot be added as bucket
continue;
}
boolean matches = false;
for (GroupBucket bucket : topGroup.buckets().buckets()) {
GroupInstruction g = (GroupInstruction) bucket.treatment().allInstructions().iterator().next();
// the group pointed to
GroupId gidToCheck = g.groupId();
if (pointedGroup.id().equals(gidToCheck)) {
matches = true;
break;
}
}
if (!matches) {
log.warn("Adding bucket pointing to groupId:{}", pointedGroup);
TrafficTreatment t = DefaultTrafficTreatment.builder().group(pointedGroup.id()).build();
// Create the proper bucket according to the next type
if (nextObjective.type() == NextObjective.Type.HASHED) {
bucketsToAdd.add(DefaultGroupBucket.createSelectGroupBucket(t));
} else {
bucketsToAdd.add(DefaultGroupBucket.createAllGroupBucket(t));
}
}
}
if (bucketsToAdd.isEmpty()) {
log.warn("Mismatch detected but could not determine which " + "buckets to add");
} else {
GroupBuckets addBuckets = new GroupBuckets(bucketsToAdd);
groupService.addBucketsToGroup(deviceId, topGroupKey, addBuckets, topGroupKey, nextObjective.appId());
}
}
}
log.trace("Verify done for device:{} nextId:{}", deviceId, nextObjective.id());
pass(nextObjective);
}
Aggregations