use of org.onosproject.net.flow.instructions.Instructions.GroupInstruction 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);
}
use of org.onosproject.net.flow.instructions.Instructions.GroupInstruction in project onos by opennetworkinglab.
the class InstructionJsonMatcher method matchesSafely.
@Override
public boolean matchesSafely(JsonNode jsonInstruction, Description description) {
// check type
final JsonNode jsonTypeNode = jsonInstruction.get("type");
final String jsonType = jsonTypeNode.textValue();
final String type = instruction.type().name();
if (!jsonType.equals(type)) {
description.appendText("type was " + type);
return false;
}
if (instruction instanceof ModMplsHeaderInstruction) {
return matchModMplsHeaderInstruction(jsonInstruction, description);
} else if (instruction instanceof OutputInstruction) {
return matchOutputInstruction(jsonInstruction, description);
} else if (instruction instanceof GroupInstruction) {
return matchGroupInstruction(jsonInstruction, description);
} else if (instruction instanceof MeterInstruction) {
return matchMeterInstruction(jsonInstruction, description);
} else if (instruction instanceof SetQueueInstruction) {
return matchSetQueueInstruction(jsonInstruction, description);
} else if (instruction instanceof ModOchSignalInstruction) {
return matchModOchSingalInstruction(jsonInstruction, description);
} else if (instruction instanceof ModEtherInstruction) {
return matchModEtherInstruction(jsonInstruction, description);
} else if (instruction instanceof ModVlanIdInstruction) {
return matchModVlanIdInstruction(jsonInstruction, description);
} else if (instruction instanceof ModVlanPcpInstruction) {
return matchModVlanPcpInstruction(jsonInstruction, description);
} else if (instruction instanceof ModIPInstruction) {
return matchModIpInstruction(jsonInstruction, description);
} else if (instruction instanceof ModIPv6FlowLabelInstruction) {
return matchModIPv6FlowLabelInstruction(jsonInstruction, description);
} else if (instruction instanceof ModMplsLabelInstruction) {
return matchModMplsLabelInstruction(jsonInstruction, description);
} else if (instruction instanceof ModOduSignalIdInstruction) {
return matchModOduSingalIdInstruction(jsonInstruction, description);
} else if (instruction instanceof PiInstruction) {
return matchPiInstruction(jsonInstruction, description);
} else if (instruction instanceof NoActionInstruction) {
return true;
}
return false;
}
use of org.onosproject.net.flow.instructions.Instructions.GroupInstruction in project onos by opennetworkinglab.
the class InstructionJsonMatcher method matchGroupInstruction.
/**
* Matches the contents of a group instruction.
*
* @param instructionJson JSON instruction to match
* @param description Description object used for recording errors
* @return true if contents match, false otherwise
*/
private boolean matchGroupInstruction(JsonNode instructionJson, Description description) {
final String jsonType = instructionJson.get("type").textValue();
GroupInstruction instructionToMatch = (GroupInstruction) instruction;
if (!instructionToMatch.type().name().equals(jsonType)) {
description.appendText("type was " + jsonType);
return false;
}
final int jsonGroupId = instructionJson.get("groupId").intValue();
if (instructionToMatch.groupId().id() != jsonGroupId) {
description.appendText("groupId was " + jsonGroupId);
return false;
}
return true;
}
use of org.onosproject.net.flow.instructions.Instructions.GroupInstruction in project onos by opennetworkinglab.
the class FlowModBuilderVer13 method buildActions.
private List<OFAction> buildActions(List<Instruction> treatments) {
if (treatment == null) {
return Collections.emptyList();
}
boolean tableFound = false;
List<OFAction> actions = new LinkedList<>();
for (Instruction i : treatments) {
switch(i.type()) {
case NOACTION:
return Collections.emptyList();
case L0MODIFICATION:
actions.add(buildL0Modification(i));
break;
case L1MODIFICATION:
actions.add(buildL1Modification(i));
break;
case L2MODIFICATION:
actions.add(buildL2Modification(i));
break;
case L3MODIFICATION:
actions.add(buildL3Modification(i));
break;
case L4MODIFICATION:
actions.add(buildL4Modification(i));
break;
case OUTPUT:
OutputInstruction out = (OutputInstruction) i;
OFActionOutput.Builder action = factory().actions().buildOutput().setPort(OFPort.of((int) out.port().toLong()));
if (out.port().equals(PortNumber.CONTROLLER)) {
action.setMaxLen(OFPCML_NO_BUFFER);
}
actions.add(action.build());
break;
case GROUP:
GroupInstruction group = (GroupInstruction) i;
OFActionGroup.Builder groupBuilder = factory().actions().buildGroup().setGroup(OFGroup.of(group.groupId().id()));
actions.add(groupBuilder.build());
break;
case QUEUE:
SetQueueInstruction queue = (SetQueueInstruction) i;
OFActionSetQueue.Builder queueBuilder = factory().actions().buildSetQueue().setQueueId(queue.queueId());
actions.add(queueBuilder.build());
break;
case TABLE:
// FIXME: should not occur here.
tableFound = true;
break;
case EXTENSION:
actions.add(buildExtensionAction(((Instructions.ExtensionInstructionWrapper) i).extensionInstruction()));
break;
default:
log.warn("Instruction type {} not yet implemented.", i.type());
}
}
if (tableFound && actions.isEmpty()) {
// a goto instruction for the next table
return Collections.emptyList();
}
return actions;
}
Aggregations