use of org.onosproject.net.group.GroupDescription in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method processSimpleNextObjective.
/**
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
* a chain of groups. The simple Next Objective passed in by the application
* is broken up into a group chain. The following chains can be created
* depending on the parameters in the Next Objective.
* 1. L2 Interface group (no chaining)
* 2. L3 Unicast group -> L2 Interface group
* 3. MPLS Interface group -> L2 Interface group
* 4. MPLS Swap group -> MPLS Interface group -> L2 Interface group
* 5. PW initiation group chain
*
* @param nextObj the nextObjective of type SIMPLE
*/
private void processSimpleNextObjective(NextObjective nextObj) {
TrafficTreatment treatment = nextObj.next().iterator().next();
// determine if plain L2 or L3->L2 or MPLS Swap -> MPLS Interface -> L2
boolean plainL2 = true;
boolean mplsSwap = false;
MplsLabel mplsLabel = null;
for (Instruction ins : treatment.allInstructions()) {
if (ins.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_DST || l2ins.subtype() == L2ModificationInstruction.L2SubType.ETH_SRC) {
plainL2 = false;
}
// a MPLS Swap group before the MPLS Interface Group
if (l2ins.subtype() == L2ModificationInstruction.L2SubType.MPLS_LABEL) {
mplsSwap = true;
mplsLabel = ((L2ModificationInstruction.ModMplsLabelInstruction) l2ins).label();
}
}
}
if (plainL2) {
createL2InterfaceGroup(nextObj);
return;
}
// In order to understand if it is a pseudowire related
// next objective we look for the tunnel id in the meta.
boolean isPw = false;
if (nextObj.meta() != null) {
TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) nextObj.meta().getCriterion(TUNNEL_ID);
if (tunnelIdCriterion != null) {
isPw = true;
}
}
if (mplsSwap && !isPw) {
log.debug("Creating a MPLS Swap -> MPLS Interface -> L2 Interface group chain.");
// break up simple next objective to GroupChain objects
GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(), nextObj.appId(), true, nextObj.meta());
if (groupInfo == null) {
log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId);
fail(nextObj, ObjectiveError.BADPARAMS);
return;
}
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
// l2 interface
gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
// mpls interface
gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
// creating the mpls swap group and adding it to the chain
int nextGid = groupInfo.nextGroupDesc().givenGroupId();
int index = getNextAvailableIndex();
GroupDescription swapGroupDescription = createMplsSwap(nextGid, OfdpaMplsGroupSubType.MPLS_SWAP_LABEL, index, mplsLabel, nextObj.appId());
// ensure swap group is added after L2L3 chain
GroupKey swapGroupKey = swapGroupDescription.appCookie();
GroupChainElem swapChainElem = new GroupChainElem(swapGroupDescription, 1, false, deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), swapChainElem);
gkeyChain.addFirst(swapGroupKey);
// ensure nextObjective waits on the outermost groupKey
List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList();
allGroupKeys.add(gkeyChain);
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
updatePendingNextObjective(swapGroupKey, ofdpaGrp);
// now we are ready to send the l2 groupDescription (inner), as all the stores
// that will get async replies have been updated. By waiting to update
// the stores, we prevent nasty race conditions.
groupService.addGroup(groupInfo.innerMostGroupDesc());
} else if (!isPw) {
boolean isMpls = false;
if (nextObj.meta() != null) {
isMpls = isNotMplsBos(nextObj.meta());
}
log.debug("Creating a {} -> L2 Interface group chain.", (isMpls) ? "MPLS Interface" : "L3 Unicast");
// break up simple next objective to GroupChain objects
GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(), nextObj.appId(), isMpls, nextObj.meta());
if (groupInfo == null) {
log.error("Could not process nextObj={} in dev:{}", nextObj.id(), deviceId);
fail(nextObj, ObjectiveError.BADPARAMS);
return;
}
// create object for local and distributed storage
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList();
allGroupKeys.add(gkeyChain);
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
// store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it
updatePendingNextObjective(groupInfo.nextGroupDesc().appCookie(), ofdpaGrp);
// now we are ready to send the l2 groupDescription (inner), as all the stores
// that will get async replies have been updated. By waiting to update
// the stores, we prevent nasty race conditions.
groupService.addGroup(groupInfo.innerMostGroupDesc());
} else {
// We handle the pseudo wire with a different a procedure.
// This procedure is meant to handle both initiation and
// termination of the pseudo wire.
processPwNextObjective(nextObj);
}
}
use of org.onosproject.net.group.GroupDescription 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.group.GroupDescription in project onos by opennetworkinglab.
the class Ofdpa2GroupHandler method addBucketToEcmpHashGroup.
private void addBucketToEcmpHashGroup(NextObjective nextObjective, List<Deque<GroupKey>> allActiveKeys) {
// storage for all group keys in the chain of groups created
List<Deque<GroupKey>> allGroupKeys = new ArrayList<>();
List<GroupInfo> unsentGroups = new ArrayList<>();
List<GroupBucket> newBuckets;
createEcmpHashBucketChains(nextObjective, allGroupKeys, unsentGroups);
// now we can create the buckets to add to the outermost L3 ECMP group
newBuckets = generateNextGroupBuckets(unsentGroups, SELECT);
// retrieve the original L3 ECMP group
Group l3ecmpGroup = retrieveTopLevelGroup(allActiveKeys, deviceId, groupService, nextObjective.id());
if (l3ecmpGroup == null) {
fail(nextObjective, ObjectiveError.GROUPMISSING);
return;
}
GroupKey l3ecmpGroupKey = l3ecmpGroup.appCookie();
int l3ecmpGroupId = l3ecmpGroup.id().id();
// Although GroupDescriptions are not necessary for adding buckets to
// existing groups, we still use one in the GroupChainElem. When the latter is
// processed, the info will be extracted for the bucketAdd call to groupService
GroupDescription l3ecmpGroupDesc = new DefaultGroupDescription(deviceId, SELECT, new GroupBuckets(newBuckets), l3ecmpGroupKey, l3ecmpGroupId, nextObjective.appId());
GroupChainElem l3ecmpGce = new GroupChainElem(l3ecmpGroupDesc, unsentGroups.size(), true, deviceId);
// update new bucket-chains
List<Deque<GroupKey>> addedKeys = new ArrayList<>();
for (Deque<GroupKey> newBucketChain : allGroupKeys) {
newBucketChain.addFirst(l3ecmpGroupKey);
addedKeys.add(newBucketChain);
}
updatePendingNextObjective(l3ecmpGroupKey, new OfdpaNextGroup(addedKeys, nextObjective));
log.debug("Adding to L3ECMP: device:{} gid:{} group key:{} nextId:{}", deviceId, Integer.toHexString(l3ecmpGroupId), l3ecmpGroupKey, nextObjective.id());
unsentGroups.forEach(groupInfo -> {
// send the innermost group
log.debug("Sending innermost group {} in group chain on device {} ", Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), l3ecmpGce);
groupService.addGroup(groupInfo.innerMostGroupDesc());
});
}
use of org.onosproject.net.group.GroupDescription 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.net.group.GroupDescription in project onos by opennetworkinglab.
the class Ofdpa3GroupHandler method processPwNextObjective.
@Override
protected void processPwNextObjective(NextObjective nextObjective) {
log.info("Started deploying nextObjective id={} for pseudowire", nextObjective.id());
TrafficTreatment treatment = nextObjective.next().iterator().next();
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
GroupChainElem groupChainElem;
GroupKey groupKey;
GroupDescription groupDescription;
// Now we separate the mpls actions from the l2/l3 actions
TrafficTreatment.Builder l2L3Treatment = DefaultTrafficTreatment.builder();
TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
createL2L3AndMplsTreatments(treatment, l2L3Treatment, mplsTreatment);
// We create the chain from mpls intf group to
// l2 intf group.
GroupInfo groupInfo = createL2L3ChainInternal(l2L3Treatment.build(), nextObjective.id(), nextObjective.appId(), true, nextObjective.meta(), false);
if (groupInfo == null) {
log.error("Could not process nextObj={} in dev:{}", nextObjective.id(), deviceId);
OfdpaPipelineUtility.fail(nextObjective, ObjectiveError.GROUPINSTALLATIONFAILED);
return;
}
// We update the chain with the last two groups;
gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
// We retrieve also all mpls instructions.
List<List<Instruction>> mplsInstructionSets = Lists.newArrayList();
List<Instruction> mplsInstructionSet = Lists.newArrayList();
L3ModificationInstruction l3Ins;
for (Instruction ins : treatment.allInstructions()) {
// Each mpls instruction set is delimited by a
// copy ttl outward action.
mplsInstructionSet.add(ins);
if (ins.type() == Instruction.Type.L3MODIFICATION) {
l3Ins = (L3ModificationInstruction) ins;
if (l3Ins.subtype() == TTL_OUT) {
mplsInstructionSets.add(mplsInstructionSet);
mplsInstructionSet = Lists.newArrayList();
}
}
}
if (mplsInstructionSets.size() > MAX_DEPTH_UNPROTECTED_PW) {
log.error("Next Objective for pseudo wire should have at " + "most {} mpls instruction sets. Next Objective Id:{}", MAX_DEPTH_UNPROTECTED_PW, nextObjective.id());
OfdpaPipelineUtility.fail(nextObjective, ObjectiveError.BADPARAMS);
return;
}
log.debug("Size of mpls instructions is {}.", mplsInstructionSets.size());
log.debug("mpls instructions sets are {}.", mplsInstructionSets);
int nextGid = groupInfo.nextGroupDesc().givenGroupId();
int index;
// this is for inter-co pws
if (mplsInstructionSets.size() == MAX_DEPTH_UNPROTECTED_PW) {
log.debug("Creating inter-co pw mpls chains with nextid {}", nextObjective.id());
// We deal with the label 2 group.
index = getNextAvailableIndex();
groupDescription = createMplsTunnelLabelGroup(nextGid, OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_2, index, mplsInstructionSets.get(2), nextObjective.appId());
groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
// We update the chain.
groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
gkeyChain.addFirst(groupKey);
// We have to create tunnel label group and
// l2 vpn group before to send the inner most
// group. We update the nextGid.
nextGid = groupDescription.givenGroupId();
groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
log.debug("Trying Label 2 Group: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
}
// inside a single co
if (mplsInstructionSets.size() == 2) {
log.debug("Creating leaf-leaf pw mpls chains with nextid {}", nextObjective.id());
// We deal with the label 1 group.
index = getNextAvailableIndex();
groupDescription = createMplsTunnelLabelGroup(nextGid, OfdpaMplsGroupSubType.MPLS_TUNNEL_LABEL_1, index, mplsInstructionSets.get(1), nextObjective.appId());
groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
gkeyChain.addFirst(groupKey);
// We have to create the l2 vpn group before
// to send the inner most group.
nextGid = groupDescription.givenGroupId();
groupInfo = new GroupInfo(groupInfo.innerMostGroupDesc(), groupDescription);
log.debug("Trying Label 1 Group: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
// Finally we create the l2 vpn group.
index = getNextAvailableIndex();
groupDescription = createMplsL2VpnGroup(nextGid, index, mplsInstructionSets.get(0), nextObjective.appId());
groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
gkeyChain.addFirst(groupKey);
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
updatePendingNextObjective(groupKey, ofdpaGrp);
log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
// Finally we send the innermost group.
log.debug("Sending innermost group {} in group chain on device {} ", Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
groupService.addGroup(groupInfo.innerMostGroupDesc());
}
// only one label is used
if (mplsInstructionSets.size() == 1) {
log.debug("Creating leaf-spine pw mpls chains with nextid {}", nextObjective.id());
// Finally we create the l2 vpn group.
index = getNextAvailableIndex();
groupDescription = createMplsL2VpnGroup(nextGid, index, mplsInstructionSets.get(0), nextObjective.appId());
groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
gkeyChain.addFirst(groupKey);
OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObjective);
updatePendingNextObjective(groupKey, ofdpaGrp);
log.debug("Trying L2 Vpn Group: device:{} gid:{} gkey:{} nextId:{}", deviceId, Integer.toHexString(nextGid), groupKey, nextObjective.id());
// Finally we send the innermost group.
log.debug("Sending innermost group {} in group chain on device {} ", Integer.toHexString(groupInfo.innerMostGroupDesc().givenGroupId()), deviceId);
groupService.addGroup(groupInfo.innerMostGroupDesc());
}
}
Aggregations