Search in sources :

Example 1 with PiPipelineInterpreter

use of org.onosproject.net.pi.model.PiPipelineInterpreter 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 PiPipelineInterpreter

use of org.onosproject.net.pi.model.PiPipelineInterpreter in project onos by opennetworkinglab.

the class PiFlowRuleTranslatorImpl method translate.

/**
 * Returns a PI table entry equivalent to the given flow rule, for the given
 * pipeconf and device.
 *
 * @param rule     flow rule
 * @param pipeconf pipeconf
 * @param device   device
 * @return PI table entry
 * @throws PiTranslationException if the flow rule cannot be translated
 */
static PiTableEntry translate(FlowRule rule, PiPipeconf pipeconf, Device device) throws PiTranslationException {
    PiPipelineModel pipelineModel = pipeconf.pipelineModel();
    // Retrieve interpreter, if any.
    final PiPipelineInterpreter interpreter = getInterpreterOrNull(device, pipeconf);
    // Get table model.
    final PiTableId piTableId = translateTableId(rule.table(), interpreter);
    final PiTableModel tableModel = getTableModel(piTableId, pipelineModel);
    // Translate selector.
    final PiMatchKey piMatchKey;
    final boolean needPriority;
    if (rule.selector().criteria().isEmpty()) {
        piMatchKey = PiMatchKey.EMPTY;
        needPriority = false;
    } else {
        final Collection<PiFieldMatch> fieldMatches = translateFieldMatches(interpreter, rule.selector(), tableModel);
        piMatchKey = PiMatchKey.builder().addFieldMatches(fieldMatches).build();
        // FIXME: P4Runtime limit
        // Need to ignore priority if no TCAM lookup match field
        needPriority = tableModel.matchFields().stream().anyMatch(match -> match.matchType() == PiMatchType.TERNARY || match.matchType() == PiMatchType.RANGE || match.matchType() == PiMatchType.OPTIONAL);
    }
    // Translate treatment.
    final PiTableAction piTableAction = translateTreatment(rule.treatment(), interpreter, piTableId, pipelineModel);
    // Build PI entry.
    final PiTableEntry.Builder tableEntryBuilder = PiTableEntry.builder();
    tableEntryBuilder.forTable(piTableId).withMatchKey(piMatchKey);
    if (piTableAction != null) {
        tableEntryBuilder.withAction(piTableAction);
    }
    if (needPriority) {
        // FIXME: move priority check to P4Runtime driver.
        final int newPriority;
        if (rule.priority() > MAX_PI_PRIORITY) {
            log.warn("Flow rule priority too big, setting translated priority to max value {}: {}", MAX_PI_PRIORITY, rule);
            newPriority = MAX_PI_PRIORITY;
        } else {
            newPriority = MIN_PI_PRIORITY + rule.priority();
        }
        tableEntryBuilder.withPriority(newPriority);
    }
    if (!rule.isPermanent()) {
        if (tableModel.supportsAging()) {
            tableEntryBuilder.withTimeout(rule.timeout());
        } else {
            log.debug("Flow rule is temporary, but table '{}' doesn't support " + "aging, translating to permanent.", tableModel.id());
        }
    }
    return tableEntryBuilder.build();
}
Also used : PiTableId(org.onosproject.net.pi.model.PiTableId) PiOptionalFieldMatch(org.onosproject.net.pi.runtime.PiOptionalFieldMatch) PiUtils.getInterpreterOrNull(org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull) PiPipeconf(org.onosproject.net.pi.model.PiPipeconf) ImmutableByteSequence(org.onlab.util.ImmutableByteSequence) LoggerFactory(org.slf4j.LoggerFactory) PiActionParam(org.onosproject.net.pi.runtime.PiActionParam) PiActionParamModel(org.onosproject.net.pi.model.PiActionParamModel) PiPipelineModel(org.onosproject.net.pi.model.PiPipelineModel) PiMatchKey(org.onosproject.net.pi.runtime.PiMatchKey) PiUtils.translateTableId(org.onosproject.net.pi.impl.PiUtils.translateTableId) ImmutableByteSequence.prefixOnes(org.onlab.util.ImmutableByteSequence.prefixOnes) TrafficSelector(org.onosproject.net.flow.TrafficSelector) PiInstruction(org.onosproject.net.flow.instructions.PiInstruction) PiTableModel(org.onosproject.net.pi.model.PiTableModel) PiCriterion(org.onosproject.net.flow.criteria.PiCriterion) Map(java.util.Map) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) PiExactFieldMatch(org.onosproject.net.pi.runtime.PiExactFieldMatch) PiFieldMatch(org.onosproject.net.pi.runtime.PiFieldMatch) Criterion(org.onosproject.net.flow.criteria.Criterion) TrafficTreatment(org.onosproject.net.flow.TrafficTreatment) PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) Logger(org.slf4j.Logger) Device(org.onosproject.net.Device) PiActionModel(org.onosproject.net.pi.model.PiActionModel) Instruction(org.onosproject.net.flow.instructions.Instruction) PiMatchFieldModel(org.onosproject.net.pi.model.PiMatchFieldModel) Collection(java.util.Collection) PiRangeFieldMatch(org.onosproject.net.pi.runtime.PiRangeFieldMatch) Set(java.util.Set) PiMatchFieldId(org.onosproject.net.pi.model.PiMatchFieldId) Maps(com.google.common.collect.Maps) Sets(com.google.common.collect.Sets) PiMatchType(org.onosproject.net.pi.model.PiMatchType) String.format(java.lang.String.format) PiTernaryFieldMatch(org.onosproject.net.pi.runtime.PiTernaryFieldMatch) ByteSequenceTrimException(org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException) PROTOCOL_INDEPENDENT(org.onosproject.net.flow.criteria.Criterion.Type.PROTOCOL_INDEPENDENT) PiAction(org.onosproject.net.pi.runtime.PiAction) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) CriterionTranslatorHelper.translateCriterion(org.onosproject.net.pi.impl.CriterionTranslatorHelper.translateCriterion) FlowRule(org.onosproject.net.flow.FlowRule) StringJoiner(java.util.StringJoiner) PiTableType(org.onosproject.net.pi.model.PiTableType) PiLpmFieldMatch(org.onosproject.net.pi.runtime.PiLpmFieldMatch) PiActionSet(org.onosproject.net.pi.runtime.PiActionSet) PiTableModel(org.onosproject.net.pi.model.PiTableModel) PiMatchKey(org.onosproject.net.pi.runtime.PiMatchKey) PiTableAction(org.onosproject.net.pi.runtime.PiTableAction) PiTableId(org.onosproject.net.pi.model.PiTableId) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) PiFieldMatch(org.onosproject.net.pi.runtime.PiFieldMatch) PiPipelineModel(org.onosproject.net.pi.model.PiPipelineModel)

Example 3 with PiPipelineInterpreter

use of org.onosproject.net.pi.model.PiPipelineInterpreter in project onos by opennetworkinglab.

the class PiReplicationGroupTranslatorImpl method logicalToPipelineSpecific.

private static PortNumber logicalToPipelineSpecific(PortNumber logicalPort, Device device) throws PiTranslationException {
    if (!device.is(PiPipelineInterpreter.class)) {
        throw new PiTranslationException("missing interpreter, cannot map logical port " + logicalPort.toString());
    }
    final PiPipelineInterpreter interpreter = device.as(PiPipelineInterpreter.class);
    Optional<Long> mappedPort = interpreter.mapLogicalPort(logicalPort);
    if (!mappedPort.isPresent()) {
        throw new PiTranslationException("interpreter cannot map logical port " + logicalPort.toString());
    }
    return PortNumber.portNumber(mappedPort.get());
}
Also used : PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException)

Example 4 with PiPipelineInterpreter

use of org.onosproject.net.pi.model.PiPipelineInterpreter in project onos by opennetworkinglab.

the class P4RuntimeTableStatisticsDiscovery method getTableStatistics.

@Override
public List<TableStatisticsEntry> getTableStatistics() {
    if (!setupBehaviour("getTableStatistics()")) {
        return Collections.emptyList();
    }
    FlowRuleService flowService = handler().get(FlowRuleService.class);
    PiPipelineInterpreter interpreter = getInterpreter(handler());
    PiPipelineModel model = pipeconf.pipelineModel();
    List<TableStatisticsEntry> tableStatsList;
    List<FlowEntry> rules = newArrayList(flowService.getFlowEntries(deviceId));
    Map<PiTableId, Integer> piTableFlowCount = piFlowRuleCounting(model, interpreter, rules);
    Map<PiTableId, Long> piTableMatchCount = piMatchedCounting(model, interpreter, rules);
    tableStatsList = generatePiFlowTableStatistics(piTableFlowCount, piTableMatchCount, model, deviceId);
    return tableStatsList;
}
Also used : PiTableId(org.onosproject.net.pi.model.PiTableId) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) FlowRuleService(org.onosproject.net.flow.FlowRuleService) FlowEntry(org.onosproject.net.flow.FlowEntry) PiPipelineModel(org.onosproject.net.pi.model.PiPipelineModel) DefaultTableStatisticsEntry(org.onosproject.net.flow.DefaultTableStatisticsEntry) TableStatisticsEntry(org.onosproject.net.flow.TableStatisticsEntry)

Example 5 with PiPipelineInterpreter

use of org.onosproject.net.pi.model.PiPipelineInterpreter in project onos by opennetworkinglab.

the class P4RuntimePacketProvider method handleP4RuntimeEvent.

private void handleP4RuntimeEvent(P4RuntimeEvent event) {
    // FIXME we need the device ID into p4RuntimeEvnetSubject to check for mastsership
    if (!(event.subject() instanceof P4RuntimePacketIn) || event.type() != P4RuntimeEvent.Type.PACKET_IN) {
        log.debug("Unrecognized event type {}, discarding", event.type());
        // Not a packet-in event, ignore it.
        return;
    }
    P4RuntimePacketIn eventSubject = (P4RuntimePacketIn) event.subject();
    DeviceId deviceId = eventSubject.deviceId();
    Device device = deviceService.getDevice(eventSubject.deviceId());
    if (device == null) {
        log.warn("Unable to process packet-in from {}, device is null in the core", deviceId);
        return;
    }
    if (!device.is(PiPipelineInterpreter.class)) {
        log.warn("Unable to process packet-in from {}, device has no PiPipelineInterpreter behaviour", deviceId);
        return;
    }
    PiPacketOperation operation = eventSubject.packetOperation();
    InboundPacket inPkt;
    try {
        inPkt = device.as(PiPipelineInterpreter.class).mapInboundPacket(operation, deviceId);
    } catch (PiPipelineInterpreter.PiInterpreterException e) {
        log.warn("Unable to interpret inbound packet from {}: {}", deviceId, e.getMessage());
        return;
    }
    if (log.isTraceEnabled()) {
        final EthType.EtherType etherType = getEtherType(inPkt.unparsed());
        log.trace("Received PACKET-IN <<< device={} ingress_port={} eth_type={}", inPkt.receivedFrom().deviceId(), inPkt.receivedFrom().port(), etherType.ethType().toString());
    }
    if (inPkt == null) {
        log.debug("Received null inbound packet. Ignoring.");
        return;
    }
    OutboundPacket outPkt = new DefaultOutboundPacket(eventSubject.deviceId(), null, operation.data().asReadOnlyBuffer());
    PacketContext pktCtx = new P4RuntimePacketContext(System.currentTimeMillis(), inPkt, outPkt, false);
    // Pushing the packet context up for processing.
    providerService.processPacket(pktCtx);
}
Also used : DeviceId(org.onosproject.net.DeviceId) Device(org.onosproject.net.Device) DefaultOutboundPacket(org.onosproject.net.packet.DefaultOutboundPacket) OutboundPacket(org.onosproject.net.packet.OutboundPacket) DefaultOutboundPacket(org.onosproject.net.packet.DefaultOutboundPacket) EthType(org.onlab.packet.EthType) P4RuntimePacketIn(org.onosproject.p4runtime.api.P4RuntimePacketIn) InboundPacket(org.onosproject.net.packet.InboundPacket) PiPacketOperation(org.onosproject.net.pi.runtime.PiPacketOperation) PiPipelineInterpreter(org.onosproject.net.pi.model.PiPipelineInterpreter) DefaultPacketContext(org.onosproject.net.packet.DefaultPacketContext) PacketContext(org.onosproject.net.packet.PacketContext)

Aggregations

PiPipelineInterpreter (org.onosproject.net.pi.model.PiPipelineInterpreter)7 Device (org.onosproject.net.Device)5 Sets (com.google.common.collect.Sets)3 String.format (java.lang.String.format)3 Set (java.util.Set)3 PiUtils.getInterpreterOrNull (org.onosproject.net.pi.impl.PiUtils.getInterpreterOrNull)3 PiPipeconf (org.onosproject.net.pi.model.PiPipeconf)3 PiPipelineModel (org.onosproject.net.pi.model.PiPipelineModel)3 PiTableId (org.onosproject.net.pi.model.PiTableId)3 PiAction (org.onosproject.net.pi.runtime.PiAction)3 PiTranslationException (org.onosproject.net.pi.service.PiTranslationException)3 Maps (com.google.common.collect.Maps)2 Collection (java.util.Collection)2 Map (java.util.Map)2 StringJoiner (java.util.StringJoiner)2 ImmutableByteSequence (org.onlab.util.ImmutableByteSequence)2 ByteSequenceTrimException (org.onlab.util.ImmutableByteSequence.ByteSequenceTrimException)2 ImmutableByteSequence.prefixOnes (org.onlab.util.ImmutableByteSequence.prefixOnes)2 DeviceId (org.onosproject.net.DeviceId)2 FlowRule (org.onosproject.net.flow.FlowRule)2