use of org.onosproject.net.group.GroupBucket in project onos by opennetworkinglab.
the class GroupManagerTest method groupOperationFaliure.
private void groupOperationFaliure(DeviceId deviceId) {
PortNumber[] ports1 = { PortNumber.portNumber(31), PortNumber.portNumber(32) };
PortNumber[] ports2 = { PortNumber.portNumber(41), PortNumber.portNumber(42) };
// Test Group creation before AUDIT process
GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
List<GroupBucket> buckets = new ArrayList<>();
List<PortNumber> outPorts = new ArrayList<>();
outPorts.addAll(Arrays.asList(ports1));
outPorts.addAll(Arrays.asList(ports2));
for (PortNumber portNumber : outPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber).setEthDst(MacAddress.valueOf("00:00:00:00:00:02")).setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")).pushMpls().setMpls(MplsLabel.mplsLabel(106));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
}
GroupBuckets groupBuckets = new GroupBuckets(buckets);
GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId, Group.Type.SELECT, groupBuckets, key, null, appId);
groupService.addGroup(newGroupDesc);
// Test initial group audit process
GroupId gId1 = new GroupId(1);
Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId);
GroupId gId2 = new GroupId(2);
// Non zero reference count will make the group manager to queue
// the extraneous groups until reference count is zero.
Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 2, deviceId);
List<Group> groupEntries = Arrays.asList(group1, group2);
providerService.pushGroupMetrics(deviceId, groupEntries);
Group createdGroup = groupService.getGroup(deviceId, key);
// Group Add failure test
GroupOperation groupAddOp = GroupOperation.createAddGroupOperation(createdGroup.id(), createdGroup.type(), createdGroup.buckets());
providerService.groupOperationFailed(deviceId, groupAddOp);
internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADD_FAILED));
// Group Mod failure test
groupService.addGroup(newGroupDesc);
createdGroup = groupService.getGroup(deviceId, key);
assertNotNull(createdGroup);
GroupOperation groupModOp = GroupOperation.createModifyGroupOperation(createdGroup.id(), createdGroup.type(), createdGroup.buckets());
providerService.groupOperationFailed(deviceId, groupModOp);
internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATE_FAILED));
// Group Delete failure test
groupService.addGroup(newGroupDesc);
createdGroup = groupService.getGroup(deviceId, key);
assertNotNull(createdGroup);
GroupOperation groupDelOp = GroupOperation.createDeleteGroupOperation(createdGroup.id(), createdGroup.type());
providerService.groupOperationFailed(deviceId, groupDelOp);
internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED));
}
use of org.onosproject.net.group.GroupBucket in project onos by opennetworkinglab.
the class GroupManagerTest method testRemoveBuckets.
// Test group remove bucket operations
private void testRemoveBuckets(DeviceId deviceId) {
GroupKey removeKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
GroupKey prevKey = new DefaultGroupKey("group1AddBuckets".getBytes());
Group createdGroup = groupService.getGroup(deviceId, prevKey);
List<GroupBucket> buckets = new ArrayList<>();
buckets.addAll(createdGroup.buckets().buckets());
PortNumber[] removePorts = { PortNumber.portNumber(31), PortNumber.portNumber(32) };
List<PortNumber> outPorts = new ArrayList<>();
outPorts.addAll(Arrays.asList(removePorts));
List<GroupBucket> removeBuckets = new ArrayList<>();
for (PortNumber portNumber : outPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber).setEthDst(MacAddress.valueOf("00:00:00:00:00:02")).setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")).pushMpls().setMpls(MplsLabel.mplsLabel(106));
removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
buckets.remove(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
}
GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets);
groupService.removeBucketsFromGroup(deviceId, prevKey, groupRemoveBuckets, removeKey, appId);
GroupBuckets updatedBuckets = new GroupBuckets(buckets);
List<GroupOperation> expectedGroupOps = Collections.singletonList(GroupOperation.createModifyGroupOperation(createdGroup.id(), Group.Type.SELECT, updatedBuckets));
if (deviceId.equals(DID)) {
internalProvider.validate(deviceId, expectedGroupOps);
} else {
this.validate(deviceId, expectedGroupOps);
}
Group existingGroup = groupService.getGroup(deviceId, removeKey);
List<Group> groupEntries = Collections.singletonList(existingGroup);
providerService.pushGroupMetrics(deviceId, groupEntries);
internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
}
use of org.onosproject.net.group.GroupBucket in project onos by opennetworkinglab.
the class GroupManagerTest method testAddBuckets.
// Test group add bucket operations
private void testAddBuckets(DeviceId deviceId) {
GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes());
GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes());
Group createdGroup = groupService.getGroup(deviceId, prevKey);
List<GroupBucket> buckets = new ArrayList<>();
buckets.addAll(createdGroup.buckets().buckets());
PortNumber[] addPorts = { PortNumber.portNumber(51), PortNumber.portNumber(52) };
List<PortNumber> outPorts;
outPorts = new ArrayList<>();
outPorts.addAll(Arrays.asList(addPorts));
List<GroupBucket> addBuckets;
addBuckets = new ArrayList<>();
for (PortNumber portNumber : outPorts) {
TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
tBuilder.setOutput(portNumber).setEthDst(MacAddress.valueOf("00:00:00:00:00:02")).setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")).pushMpls().setMpls(MplsLabel.mplsLabel(106));
addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
}
GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
groupService.addBucketsToGroup(deviceId, prevKey, groupAddBuckets, addKey, appId);
GroupBuckets updatedBuckets = new GroupBuckets(buckets);
List<GroupOperation> expectedGroupOps = Collections.singletonList(GroupOperation.createModifyGroupOperation(createdGroup.id(), Group.Type.SELECT, updatedBuckets));
if (deviceId.equals(DID)) {
internalProvider.validate(deviceId, expectedGroupOps);
} else {
this.validate(deviceId, expectedGroupOps);
}
Group existingGroup = groupService.getGroup(deviceId, addKey);
List<Group> groupEntries = Collections.singletonList(existingGroup);
providerService.pushGroupMetrics(deviceId, groupEntries);
internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED));
}
use of org.onosproject.net.group.GroupBucket in project onos by opennetworkinglab.
the class PiGroupTranslatorImpl method translate.
/**
* Returns a PI action profile group equivalent to the given group, for the
* given pipeconf and device.
*
* @param group group
* @param pipeconf pipeconf
* @param device device
* @return PI action profile group
* @throws PiTranslationException if the group cannot be translated
*/
static PiActionProfileGroup translate(Group group, PiPipeconf pipeconf, Device device) throws PiTranslationException {
if (!SUPPORTED_GROUP_TYPES.contains(group.type())) {
throw new PiTranslationException(format("group type %s not supported", group.type()));
}
// TODO: define proper field in group class.
if (!(group.appCookie() instanceof PiGroupKey)) {
throw new PiTranslationException("group app cookie is not PI (class should be PiGroupKey)");
}
final PiGroupKey groupKey = (PiGroupKey) group.appCookie();
final PiActionProfileId actionProfileId = groupKey.actionProfileId();
// Check validity of action profile against pipeconf.
final PiActionProfileModel actionProfileModel = pipeconf.pipelineModel().actionProfiles(actionProfileId).orElseThrow(() -> new PiTranslationException(format("no such action profile '%s'", actionProfileId)));
if (!actionProfileModel.hasSelector()) {
throw new PiTranslationException(format("action profile '%s' does not support dynamic selection", actionProfileId));
}
// Check if the table associated with the action profile supports only
// one-shot action profile programming.
boolean isTableOneShot = actionProfileModel.tables().stream().map(tableId -> pipeconf.pipelineModel().table(tableId)).allMatch(piTableModel -> piTableModel.isPresent() && piTableModel.get().oneShotOnly());
if (isTableOneShot) {
throw new PiTranslationException(format("Table associated to action profile '%s' supports only one-shot action profile programming", actionProfileId));
}
// Check group validity.
if (actionProfileModel.maxGroupSize() > 0 && group.buckets().buckets().size() > actionProfileModel.maxGroupSize()) {
throw new PiTranslationException(format("too many buckets, max group size for action profile '%s' is %d", actionProfileId, actionProfileModel.maxGroupSize()));
}
// If not INDIRECT, we set the maximum group size as specified in the
// model, however this might be highly inefficient for some HW targets
// which pre-allocate resources for the whole group.
final int maxGroupSize = group.type() == GroupDescription.Type.INDIRECT ? 1 : actionProfileModel.maxGroupSize();
final PiActionProfileGroup.Builder piActionGroupBuilder = PiActionProfileGroup.builder().withId(PiActionProfileGroupId.of(group.id().id())).withActionProfileId(groupKey.actionProfileId()).withMaxSize(maxGroupSize);
// Translate group buckets to PI group members
final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
short bucketIdx = 0;
for (GroupBucket bucket : group.buckets().buckets()) {
/*
FIXME: the way member IDs are computed can cause collisions!
Problem: In P4Runtime action profile members, i.e. action buckets,
are associated to a numeric ID chosen at member insertion time. This
ID must be unique for the whole action profile (i.e. the group table
in OpenFlow). In ONOS, GroupBucket doesn't specify any ID.
Solutions:
- Change GroupBucket API to force application wanting to perform
group operations to specify a member id.
- Maintain state to dynamically allocate/deallocate member IDs, e.g.
in a dedicated service, or in a P4Runtime Group Provider.
Hack: Statically derive member ID by combining groupId and position
of the bucket in the list.
*/
final int memberId = Objects.hash(group.id(), bucketIdx);
if (memberId == 0) {
throw new PiTranslationException("GroupBucket produces PiActionProfileMember " + "with invalid ID 0");
}
bucketIdx++;
final PiTableAction tableAction = translateTreatment(bucket.treatment(), interpreter, groupKey.tableId(), pipeconf.pipelineModel());
if (tableAction == null) {
throw new PiTranslationException("bucket treatment translator returned null");
}
if (tableAction.type() != ACTION) {
throw new PiTranslationException(format("action of type '%s' cannot be used in action profile members", tableAction.type()));
}
final PiActionProfileMember member = PiActionProfileMember.builder().forActionProfile(groupKey.actionProfileId()).withId(PiActionProfileMemberId.of(memberId)).withAction((PiAction) tableAction).build();
// NOTE Indirect groups have weight set to -1 which is not supported
// by P4RT - setting to 1 to avoid problems with the p4rt server.
final int weight = group.type() == GroupDescription.Type.INDIRECT ? 1 : bucket.weight();
piActionGroupBuilder.addMember(member, weight);
}
return piActionGroupBuilder.build();
}
use of org.onosproject.net.group.GroupBucket in project onos by opennetworkinglab.
the class SimpleGroupStore method addOrUpdateGroupEntry.
/**
* Stores a new group entry, or updates an existing entry.
*
* @param group group entry
*/
@Override
public void addOrUpdateGroupEntry(Group group) {
// check if this new entry is an update to an existing entry
StoredGroupEntry existing = (groupEntriesById.get(group.deviceId()) != null) ? groupEntriesById.get(group.deviceId()).get(group.id()) : null;
GroupEvent event = null;
if (existing != null) {
synchronized (existing) {
for (GroupBucket bucket : group.buckets().buckets()) {
Optional<GroupBucket> matchingBucket = existing.buckets().buckets().stream().filter((existingBucket) -> (existingBucket.equals(bucket))).findFirst();
if (matchingBucket.isPresent()) {
((StoredGroupBucketEntry) matchingBucket.get()).setPackets(bucket.packets());
((StoredGroupBucketEntry) matchingBucket.get()).setBytes(bucket.bytes());
} else {
log.warn("addOrUpdateGroupEntry: No matching " + "buckets to update stats");
}
}
existing.setLife(group.life());
existing.setPackets(group.packets());
existing.setBytes(group.bytes());
if (existing.state() == GroupState.PENDING_ADD) {
existing.setState(GroupState.ADDED);
event = new GroupEvent(Type.GROUP_ADDED, existing);
} else {
if (existing.state() == GroupState.PENDING_UPDATE) {
existing.setState(GroupState.ADDED);
}
event = new GroupEvent(Type.GROUP_UPDATED, existing);
}
}
}
if (event != null) {
notifyDelegate(event);
}
}
Aggregations