Search in sources :

Example 1 with PiActionProfileMember

use of org.onosproject.net.pi.runtime.PiActionProfileMember 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();
}
Also used : PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) PiUtils.getInterpreterOrNull(org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull) Device(org.onosproject.net.Device) PiPipeconf(org.onosproject.net.pi.model.PiPipeconf) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) PiActionProfileMemberId(org.onosproject.net.pi.runtime.PiActionProfileMemberId) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) Set(java.util.Set) GroupBucket(org.onosproject.net.group.GroupBucket) PiGroupKey(org.onosproject.net.pi.runtime.PiGroupKey) Sets(com.google.common.collect.Sets) String.format(java.lang.String.format) Group(org.onosproject.net.group.Group) Objects(java.util.Objects) PiAction(org.onosproject.net.pi.runtime.PiAction) PiFlowRuleTranslatorImpl.translateTreatment(org.onosproject.net.pi.impl.PiFlowRuleTranslatorImpl.translateTreatment) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) ACTION(org.onosproject.net.pi.runtime.PiTableAction.Type.ACTION) PiActionProfileModel(org.onosproject.net.pi.model.PiActionProfileModel) GroupDescription(org.onosproject.net.group.GroupDescription) PiActionProfileGroupId(org.onosproject.net.pi.runtime.PiActionProfileGroupId) PiActionProfileId(org.onosproject.net.pi.model.PiActionProfileId) PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiActionProfileId(org.onosproject.net.pi.model.PiActionProfileId) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) PiAction(org.onosproject.net.pi.runtime.PiAction) PiActionProfileModel(org.onosproject.net.pi.model.PiActionProfileModel) PiGroupKey(org.onosproject.net.pi.runtime.PiGroupKey) GroupBucket(org.onosproject.net.group.GroupBucket) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter)

Example 2 with PiActionProfileMember

use of org.onosproject.net.pi.runtime.PiActionProfileMember in project onos by opennetworkinglab.

the class P4RuntimeActionGroupProgrammable method asyncWritePiGroup.

private void asyncWritePiGroup(PiActionProfileGroup group, PiActionProfileGroupHandle groupHandle, Operation operation) {
    // Generate and submit  write request to write both members and groups.
    final Collection<PiActionProfileMember> members = extractAllMemberInstancesOrNull(group);
    if (members == null) {
        return;
    }
    final WriteRequest request = client.write(p4DeviceId, pipeconf);
    WRITE_LOCKS.get(deviceId).lock();
    try {
        if (operation == Operation.APPLY) {
            // First insert/update members, then group.
            members.forEach(m -> appendEntityToWriteRequestOrSkip(request, m.handle(deviceId), m, memberMirror, operation));
            appendEntityToWriteRequestOrSkip(request, groupHandle, group, groupMirror, operation);
        } else {
            // First remove group, then members.
            appendEntityToWriteRequestOrSkip(request, groupHandle, group, groupMirror, operation);
            members.forEach(m -> appendEntityToWriteRequestOrSkip(request, m.handle(deviceId), m, memberMirror, operation));
        }
        if (request.pendingUpdates().isEmpty()) {
            // Nothing to do.
            return;
        }
        // Optimistically update mirror before response arrives to make
        // sure any write after this sees the expected mirror state. If
        // anything goes wrong, mirror will be re-synced during
        // reconciliation.
        groupMirror.applyWriteRequest(request);
        memberMirror.applyWriteRequest(request);
        request.submit().whenComplete((r, ex) -> {
            if (ex != null) {
                log.error("Exception writing PI group to " + deviceId, ex);
            } else {
                log.debug("Completed write of PI group to {} " + "({} of {} updates succeeded)", deviceId, r.success().size(), r.all().size());
            }
        });
    } finally {
        WRITE_LOCKS.get(deviceId).unlock();
    }
}
Also used : WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember)

Example 3 with PiActionProfileMember

use of org.onosproject.net.pi.runtime.PiActionProfileMember in project onos by opennetworkinglab.

the class P4RuntimeGroupTest method testReadMembers.

@Test
public void testReadMembers() throws Exception {
    List<ActionProfileMember> members = Lists.newArrayList();
    MEMBER_IDS.forEach(id -> {
        byte outPort = (byte) (id - BASE_MEM_ID);
        ByteString bs = ByteString.copyFrom(new byte[] { 0, outPort });
        Action.Param param = Action.Param.newBuilder().setParamId(1).setValue(bs).build();
        Action action = Action.newBuilder().setActionId(SET_EGRESS_PORT_ID).addParams(param).build();
        ActionProfileMember actProfMember = ActionProfileMember.newBuilder().setActionProfileId(P4_INFO_ACT_PROF_ID).setMemberId(id).setAction(action).build();
        members.add(actProfMember);
    });
    List<ReadResponse> responses = Lists.newArrayList();
    responses.add(ReadResponse.newBuilder().addAllEntities(members.stream().map(m -> Entity.newBuilder().setActionProfileMember(m).build()).collect(Collectors.toList())).build());
    p4RuntimeServerImpl.willReturnReadResult(responses);
    CompletableFuture<Void> complete = p4RuntimeServerImpl.expectRequests(1);
    Collection<PiActionProfileMember> piMembers = client.read(P4_DEVICE_ID, PIPECONF).actionProfileMembers(ACT_PROF_ID).submitSync().all(PiActionProfileMember.class);
    complete.get(DEFAULT_TIMEOUT_TIME, TimeUnit.SECONDS);
    assertEquals(3, piMembers.size());
    assertTrue(GROUP_MEMBER_INSTANCES.containsAll(piMembers));
    assertTrue(piMembers.containsAll(GROUP_MEMBER_INSTANCES));
}
Also used : Action(p4.v1.P4RuntimeOuterClass.Action) PiAction(org.onosproject.net.pi.runtime.PiAction) ReadResponse(p4.v1.P4RuntimeOuterClass.ReadResponse) ByteString(com.google.protobuf.ByteString) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) ActionProfileMember(p4.v1.P4RuntimeOuterClass.ActionProfileMember) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) Test(org.junit.Test)

Example 4 with PiActionProfileMember

use of org.onosproject.net.pi.runtime.PiActionProfileMember in project onos by opennetworkinglab.

the class PiGroupTranslatorImplTest method testTranslateGroups.

/**
 * Test add group with buckets.
 */
@Test
public void testTranslateGroups() throws Exception {
    PiActionProfileGroup piGroup1 = PiGroupTranslatorImpl.translate(SELECT_GROUP, pipeconf, null);
    PiActionProfileGroup piGroup2 = PiGroupTranslatorImpl.translate(SELECT_GROUP, pipeconf, null);
    new EqualsTester().addEqualityGroup(piGroup1, piGroup2).testEquals();
    assertThat("Group ID must be equal", piGroup1.id().id(), is(equalTo(GROUP_ID.id())));
    assertThat("Action profile ID must be equal", piGroup1.actionProfile(), is(equalTo(INGRESS_WCMP_CONTROL_WCMP_SELECTOR)));
    // members installed
    Collection<PiActionProfileGroup.WeightedMember> weightedMembers = piGroup1.members();
    Collection<PiActionProfileMember> memberInstances = weightedMembers.stream().map(PiActionProfileGroup.WeightedMember::instance).filter(Objects::nonNull).collect(Collectors.toSet());
    assertThat("The number of group members must be equal", piGroup1.members().size(), is(expectedWeightedMembers.size()));
    assertThat("Group weighted members must be equal", weightedMembers.containsAll(expectedWeightedMembers) && expectedWeightedMembers.containsAll(weightedMembers));
    assertThat("Group member instances must be equal", memberInstances.containsAll(expectedMemberInstances) && expectedMemberInstances.containsAll(memberInstances));
}
Also used : EqualsTester(com.google.common.testing.EqualsTester) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) Test(org.junit.Test)

Example 5 with PiActionProfileMember

use of org.onosproject.net.pi.runtime.PiActionProfileMember in project onos by opennetworkinglab.

the class P4RuntimeActionGroupProgrammable method getGroups.

@Override
public Collection<Group> getGroups() {
    if (!setupBehaviour("getGroups()")) {
        return Collections.emptyList();
    }
    if (driverBoolProperty(READ_ACTION_GROUPS_FROM_MIRROR, DEFAULT_READ_ACTION_GROUPS_FROM_MIRROR)) {
        return getGroupsFromMirror();
    }
    // Dump groups and members from device for all action profiles.
    final P4RuntimeReadClient.ReadRequest request = client.read(p4DeviceId, pipeconf);
    pipeconf.pipelineModel().actionProfiles().stream().filter(piActionProfileModel -> piActionProfileModel.tables().stream().map(tableId -> pipeconf.pipelineModel().table(tableId)).allMatch(piTableModel -> piTableModel.isPresent() && !piTableModel.get().oneShotOnly())).map(PiActionProfileModel::id).forEach(id -> request.actionProfileGroups(id).actionProfileMembers(id));
    final P4RuntimeReadClient.ReadResponse response = request.submitSync();
    if (!response.isSuccess()) {
        // Error at client level.
        return Collections.emptyList();
    }
    final Collection<PiActionProfileGroup> groupsOnDevice = response.all(PiActionProfileGroup.class);
    final Map<PiActionProfileMemberHandle, PiActionProfileMember> membersOnDevice = response.all(PiActionProfileMember.class).stream().collect(toMap(m -> m.handle(deviceId), m -> m));
    // Sync mirrors.
    groupMirror.sync(deviceId, groupsOnDevice);
    memberMirror.sync(deviceId, membersOnDevice.values());
    // Retrieve the original PD group before translation.
    final List<Group> result = Lists.newArrayList();
    final List<PiActionProfileGroup> groupsToRemove = Lists.newArrayList();
    final Set<PiActionProfileMemberHandle> memberHandlesToKeep = Sets.newHashSet();
    for (PiActionProfileGroup piGroup : groupsOnDevice) {
        final Group pdGroup = checkAndForgeGroupEntry(piGroup, membersOnDevice);
        if (pdGroup == null) {
            // Entry is on device but is inconsistent with controller state.
            // Mark for removal.
            groupsToRemove.add(piGroup);
        } else {
            result.add(pdGroup);
            // Keep track of member handles used in groups.
            piGroup.members().stream().map(m -> PiActionProfileMemberHandle.of(deviceId, piGroup.actionProfile(), m.id())).forEach(memberHandlesToKeep::add);
        }
    }
    // Trigger clean up of inconsistent groups and members (if any). Also
    // take care of removing any orphan member, e.g. from a
    // partial/unsuccessful group insertion.
    final Set<PiActionProfileMemberHandle> memberHandlesToRemove = Sets.difference(membersOnDevice.keySet(), memberHandlesToKeep);
    final Set<PiActionProfileGroupHandle> groupHandlesToRemove = groupsToRemove.stream().map(g -> g.handle(deviceId)).collect(toSet());
    if (groupHandlesToRemove.size() + memberHandlesToRemove.size() > 0) {
        log.warn("Cleaning up {} action profile groups and " + "{} members on {}...", groupHandlesToRemove.size(), memberHandlesToRemove.size(), deviceId);
        client.write(p4DeviceId, pipeconf).delete(groupHandlesToRemove).delete(memberHandlesToRemove).submit().whenComplete((r, ex) -> {
            if (ex != null) {
                log.error("Exception removing inconsistent group/members", ex);
            } else {
                log.debug("Completed removal of inconsistent " + "groups/members ({} of {} updates succeeded)", r.success().size(), r.all().size());
                groupMirror.applyWriteResponse(r);
                memberMirror.applyWriteResponse(r);
            }
        });
    }
    // Done.
    return result;
}
Also used : P4RuntimeReadClient(org.onosproject.p4runtime.api.P4RuntimeReadClient) PiActionProfileGroupHandle(org.onosproject.net.pi.runtime.PiActionProfileGroupHandle) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) DefaultGroup(org.onosproject.net.group.DefaultGroup) GroupOperation(org.onosproject.net.group.GroupOperation) P4RuntimeActionProfileGroupMirror(org.onosproject.drivers.p4runtime.mirror.P4RuntimeActionProfileGroupMirror) Group(org.onosproject.net.group.Group) PiEntity(org.onosproject.net.pi.runtime.PiEntity) GroupStore(org.onosproject.net.group.GroupStore) GroupProgrammable(org.onosproject.net.group.GroupProgrammable) Lists(com.google.common.collect.Lists) Collectors.toMap(java.util.stream.Collectors.toMap) PiGroupTranslator(org.onosproject.net.pi.service.PiGroupTranslator) Map(java.util.Map) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) GroupOperations(org.onosproject.net.group.GroupOperations) Collectors.toSet(java.util.stream.Collectors.toSet) PiActionProfileMemberHandle(org.onosproject.net.pi.runtime.PiActionProfileMemberHandle) Striped(com.google.common.util.concurrent.Striped) PiTranslatedEntity(org.onosproject.net.pi.service.PiTranslatedEntity) P4RuntimeReadClient(org.onosproject.p4runtime.api.P4RuntimeReadClient) Collection(java.util.Collection) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) Set(java.util.Set) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) Collectors(java.util.stream.Collectors) Sets(com.google.common.collect.Sets) PiHandle(org.onosproject.net.pi.runtime.PiHandle) Objects(java.util.Objects) TimedEntry(org.onosproject.drivers.p4runtime.mirror.TimedEntry) List(java.util.List) Lock(java.util.concurrent.locks.Lock) P4RuntimeActionProfileMemberMirror(org.onosproject.drivers.p4runtime.mirror.P4RuntimeActionProfileMemberMirror) P4RuntimeMirror(org.onosproject.drivers.p4runtime.mirror.P4RuntimeMirror) Optional(java.util.Optional) PiActionProfileModel(org.onosproject.net.pi.model.PiActionProfileModel) DeviceId(org.onosproject.net.DeviceId) DefaultGroupDescription(org.onosproject.net.group.DefaultGroupDescription) GroupDescription(org.onosproject.net.group.GroupDescription) Collections(java.util.Collections) DefaultGroup(org.onosproject.net.group.DefaultGroup) Group(org.onosproject.net.group.Group) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) PiActionProfileMember(org.onosproject.net.pi.runtime.PiActionProfileMember) PiActionProfileGroup(org.onosproject.net.pi.runtime.PiActionProfileGroup) PiActionProfileGroupHandle(org.onosproject.net.pi.runtime.PiActionProfileGroupHandle) PiActionProfileMemberHandle(org.onosproject.net.pi.runtime.PiActionProfileMemberHandle)

Aggregations

PiActionProfileMember (org.onosproject.net.pi.runtime.PiActionProfileMember)6 Test (org.junit.Test)3 PiAction (org.onosproject.net.pi.runtime.PiAction)3 PiActionProfileGroup (org.onosproject.net.pi.runtime.PiActionProfileGroup)3 Sets (com.google.common.collect.Sets)2 Objects (java.util.Objects)2 Set (java.util.Set)2 Group (org.onosproject.net.group.Group)2 GroupDescription (org.onosproject.net.group.GroupDescription)2 PiActionProfileModel (org.onosproject.net.pi.model.PiActionProfileModel)2 Lists (com.google.common.collect.Lists)1 EqualsTester (com.google.common.testing.EqualsTester)1 Striped (com.google.common.util.concurrent.Striped)1 ByteString (com.google.protobuf.ByteString)1 String.format (java.lang.String.format)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 List (java.util.List)1 Map (java.util.Map)1 Optional (java.util.Optional)1