use of org.onosproject.core.GroupId in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method processEcmpHashedNextObjective.
/**
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
* a chain of groups. The hashed Next Objective passed in by the application
* has to be broken up into a group chain comprising of an
* L3 ECMP group as the top level group. Buckets of this group can point
* to a variety of groups in a group chain, depending on the whether
* MPLS labels are being pushed or not.
* <p>
* NOTE: We do not create MPLS ECMP groups as they are unimplemented in
* OF-DPA 2.0 (even though it is in the spec). Therefore we do not
* check the nextObjective meta to see what is matching before being
* sent to this nextObjective.
*
* @param nextObj the nextObjective of type HASHED
*/
protected void processEcmpHashedNextObjective(NextObjective nextObj) {
// storage for all group keys in the chain of groups created
List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
List<GroupInfo> unsentGroups = new ArrayList<>();
createEcmpHashBucketChains(nextObj, allGroupKeys, unsentGroups);
// now we can create the outermost L3 ECMP group
List<GroupBucket> l3ecmpGroupBuckets = new ArrayList<>();
for (GroupInfo gi : unsentGroups) {
// create ECMP bucket to point to the outer group
TrafficTreatment.Builder ttb = DefaultTrafficTreatment.builder();
ttb.group(new GroupId(gi.nextGroupDesc().givenGroupId()));
GroupBucket sbucket = DefaultGroupBucket.createSelectGroupBucket(ttb.build());
l3ecmpGroupBuckets.add(sbucket);
}
int l3ecmpIndex = getNextAvailableIndex();
int l3ecmpGroupId = L3_ECMP_TYPE | (TYPE_MASK & l3ecmpIndex);
GroupKey l3ecmpGroupKey = new DefaultGroupKey(appKryo.serialize(l3ecmpIndex));
GroupDescription l3ecmpGroupDesc = new DefaultGroupDescription(deviceId, SELECT, new GroupBuckets(l3ecmpGroupBuckets), l3ecmpGroupKey, l3ecmpGroupId, nextObj.appId());
GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, l3ecmpGroupBuckets.size(), false, deviceId);
// create objects for local and distributed storage
allGroupKeys.forEach(gKeyChain -> gKeyChain.addFirst(l3ecmpGroupKey));
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
// store l3ecmpGroupKey with the ofdpaGroupChain for the nextObjective
// that depends on it
updatePendingNextObjective(l3ecmpGroupKey, ofdpaGrp);
log.debug("Trying L3ECMP: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(l3ecmpGroupId), l3ecmpGroupKey, nextObj.id());
// finally we are ready to send the innermost groups
for (GroupInfo gi : unsentGroups) {
log.debug("Sending innermost group {} in group chain on device {} ", Integer.toHexString(gi.innerMostGroupDesc().givenGroupId()), deviceId);
updatePendingGroups(gi.nextGroupDesc().appCookie(), l3ecmpGce);
groupService.addGroup(gi.innerMostGroupDesc());
}
}
use of org.onosproject.core.GroupId 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.core.GroupId in project onos by opennetworkinglab.
the class FlowEntryBuilder method configureTreatmentBuilder.
/**
* Configures traffic treatment builder with a given collection of actions.
*
* @param actions a set of OpenFlow actions
* @param builder traffic treatment builder
* @param driverHandler driver handler
* @param deviceId device identifier
* @return configured traffic treatment builder
*/
public static TrafficTreatment.Builder configureTreatmentBuilder(List<OFAction> actions, TrafficTreatment.Builder builder, DriverHandler driverHandler, DeviceId deviceId) {
ExtensionTreatmentInterpreter interpreter;
if (driverHandler.hasBehaviour(ExtensionTreatmentInterpreter.class)) {
interpreter = driverHandler.behaviour(ExtensionTreatmentInterpreter.class);
} else {
interpreter = null;
}
for (OFAction act : actions) {
switch(act.getType()) {
case OUTPUT:
OFActionOutput out = (OFActionOutput) act;
builder.setOutput(PortNumber.portNumber(out.getPort().getPortNumber()));
break;
case SET_VLAN_VID:
OFActionSetVlanVid vlan = (OFActionSetVlanVid) act;
builder.setVlanId(VlanId.vlanId(vlan.getVlanVid().getVlan()));
break;
case SET_VLAN_PCP:
OFActionSetVlanPcp pcp = (OFActionSetVlanPcp) act;
builder.setVlanPcp(pcp.getVlanPcp().getValue());
break;
case SET_DL_DST:
OFActionSetDlDst dldst = (OFActionSetDlDst) act;
builder.setEthDst(MacAddress.valueOf(dldst.getDlAddr().getLong()));
break;
case SET_DL_SRC:
OFActionSetDlSrc dlsrc = (OFActionSetDlSrc) act;
builder.setEthSrc(MacAddress.valueOf(dlsrc.getDlAddr().getLong()));
break;
case SET_NW_DST:
OFActionSetNwDst nwdst = (OFActionSetNwDst) act;
IPv4Address di = nwdst.getNwAddr();
builder.setIpDst(Ip4Address.valueOf(di.getInt()));
break;
case SET_NW_SRC:
OFActionSetNwSrc nwsrc = (OFActionSetNwSrc) act;
IPv4Address si = nwsrc.getNwAddr();
builder.setIpSrc(Ip4Address.valueOf(si.getInt()));
break;
case EXPERIMENTER:
OFActionExperimenter exp = (OFActionExperimenter) act;
if (exp.getExperimenter() == 0x80005A06 || exp.getExperimenter() == 0x748771) {
OFActionCircuit ct = (OFActionCircuit) exp;
CircuitSignalID circuitSignalID = ((OFOxmOchSigid) ct.getField()).getValue();
builder.add(Instructions.modL0Lambda(Lambda.ochSignal(lookupGridType(circuitSignalID.getGridType()), lookupChannelSpacing(circuitSignalID.getChannelSpacing()), circuitSignalID.getChannelNumber(), circuitSignalID.getSpectralWidth())));
} else if (interpreter != null) {
builder.extension(interpreter.mapAction(exp), deviceId);
} else {
log.warn("Unsupported OFActionExperimenter {}", exp.getExperimenter());
}
break;
case SET_FIELD:
OFActionSetField setField = (OFActionSetField) act;
handleSetField(builder, setField, driverHandler, deviceId);
break;
case POP_MPLS:
OFActionPopMpls popMpls = (OFActionPopMpls) act;
builder.popMpls(new EthType(popMpls.getEthertype().getValue()));
break;
case PUSH_MPLS:
builder.pushMpls();
break;
case COPY_TTL_IN:
builder.copyTtlIn();
break;
case COPY_TTL_OUT:
builder.copyTtlOut();
break;
case DEC_MPLS_TTL:
builder.decMplsTtl();
break;
case DEC_NW_TTL:
builder.decNwTtl();
break;
case GROUP:
OFActionGroup group = (OFActionGroup) act;
builder.group(new GroupId(group.getGroup().getGroupNumber()));
break;
case SET_QUEUE:
OFActionSetQueue setQueue = (OFActionSetQueue) act;
builder.setQueue(setQueue.getQueueId());
break;
case ENQUEUE:
OFActionEnqueue enqueue = (OFActionEnqueue) act;
builder.setQueue(enqueue.getQueueId(), PortNumber.portNumber(enqueue.getPort().getPortNumber()));
break;
case STRIP_VLAN:
case POP_VLAN:
builder.popVlan();
break;
case PUSH_VLAN:
OFActionPushVlan pushVlan = (OFActionPushVlan) act;
builder.pushVlan(new EthType((short) pushVlan.getEthertype().getValue()));
break;
case METER:
OFActionMeter actionMeter = (OFActionMeter) act;
builder.meter(MeterId.meterId(actionMeter.getMeterId()));
break;
case SET_TP_DST:
case SET_TP_SRC:
case POP_PBB:
case PUSH_PBB:
case SET_MPLS_LABEL:
case SET_MPLS_TC:
case SET_MPLS_TTL:
case SET_NW_ECN:
case SET_NW_TOS:
case SET_NW_TTL:
default:
log.warn("Action type {} not yet implemented.", act.getType());
}
}
return builder;
}
use of org.onosproject.core.GroupId in project onos by opennetworkinglab.
the class GroupBucketEntryBuilder method build.
/**
* Builds a GroupBuckets.
*
* @return GroupBuckets object, a list of GroupBuckets
*/
public GroupBuckets build() {
List<GroupBucket> bucketList = Lists.newArrayList();
for (OFBucket bucket : ofBuckets) {
TrafficTreatment treatment = buildTreatment(bucket.getActions());
// TODO: Use GroupBucketEntry
GroupBucket groupBucket = null;
switch(type) {
case INDIRECT:
groupBucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
break;
case SELECT:
groupBucket = DefaultGroupBucket.createSelectGroupBucket(treatment, (short) bucket.getWeight());
break;
case FF:
PortNumber port = PortNumber.portNumber(bucket.getWatchPort().getPortNumber());
GroupId groupId = new GroupId(bucket.getWatchGroup().getGroupNumber());
groupBucket = DefaultGroupBucket.createFailoverGroupBucket(treatment, port, groupId);
break;
case ALL:
groupBucket = DefaultGroupBucket.createAllGroupBucket(treatment);
break;
default:
log.error("Unsupported Group type : {}", type);
}
if (groupBucket != null) {
bucketList.add(groupBucket);
}
}
return new GroupBuckets(bucketList);
}
use of org.onosproject.core.GroupId in project onos by opennetworkinglab.
the class SimpleVirtualGroupStore method storeGroupDescriptionInternal.
private void storeGroupDescriptionInternal(NetworkId networkId, GroupDescription groupDesc) {
// Check if a group is existing with the same key
if (getGroup(networkId, groupDesc.deviceId(), groupDesc.appCookie()) != null) {
return;
}
GroupId id = null;
if (groupDesc.givenGroupId() == null) {
// Get a new group identifier
id = new GroupId(getFreeGroupIdValue(networkId, groupDesc.deviceId()));
} else {
id = new GroupId(groupDesc.givenGroupId());
}
// Create a group entry object
StoredGroupEntry group = new DefaultGroup(id, groupDesc);
// Insert the newly created group entry into concurrent key and id maps
ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = getGroupKeyTable(networkId, groupDesc.deviceId());
keyTable.put(groupDesc.appCookie(), group);
ConcurrentMap<GroupId, StoredGroupEntry> idTable = getGroupIdTable(networkId, groupDesc.deviceId());
idTable.put(id, group);
notifyDelegate(networkId, new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED, group));
}
Aggregations