Search in sources :

Example 1 with WriteRequest

use of org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest in project onos by opennetworkinglab.

the class P4RuntimeFlowRuleProgrammable method getFlowEntries.

@Override
public Collection<FlowEntry> getFlowEntries() {
    if (!setupBehaviour("getFlowEntries()")) {
        return Collections.emptyList();
    }
    if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
        return getFlowEntriesFromMirror();
    }
    final ImmutableList.Builder<FlowEntry> result = ImmutableList.builder();
    final List<PiTableEntry> inconsistentEntries = Lists.newArrayList();
    // Read table entries from device.
    final Collection<PiTableEntry> deviceEntries = getAllTableEntriesFromDevice();
    if (deviceEntries == null) {
        // Potential error at the client level.
        return Collections.emptyList();
    }
    // Synchronize mirror with the device state.
    tableMirror.sync(deviceId, deviceEntries);
    if (deviceEntries.isEmpty()) {
        // Nothing to do.
        return Collections.emptyList();
    }
    final Map<PiTableEntryHandle, PiCounterCellData> counterCellMap = readEntryCounters(deviceEntries);
    // Forge flow entries with counter values.
    for (PiTableEntry entry : deviceEntries) {
        final PiTableEntryHandle handle = entry.handle(deviceId);
        final FlowEntry flowEntry = forgeFlowEntry(entry, handle, counterCellMap.get(handle));
        if (flowEntry == null) {
            // program via default_action, which cannot be removed.)
            if (!isOriginalDefaultEntry(entry)) {
                inconsistentEntries.add(entry);
            }
        } else {
            result.add(flowEntry);
        }
    }
    // Default entries need to be treated in a different way according to the spec:
    // the client can modify (reset or update) them but cannot remove the entries
    List<PiTableEntry> inconsistentDefaultEntries = Lists.newArrayList();
    List<PiTableEntry> tempDefaultEntries = inconsistentEntries.stream().filter(PiTableEntry::isDefaultAction).collect(Collectors.toList());
    inconsistentEntries.removeAll(tempDefaultEntries);
    // Once we have removed the default entry from inconsistentEntries we need to
    // craft for each default entry a copy without the action field. According to
    // the spec leaving the action field unset will reset the original default entry.
    tempDefaultEntries.forEach(piTableEntry -> {
        PiTableEntry resetEntry = PiTableEntry.builder().forTable(piTableEntry.table()).build();
        inconsistentDefaultEntries.add(resetEntry);
    });
    // Clean up of inconsistent entries.
    if (!inconsistentEntries.isEmpty() || !inconsistentDefaultEntries.isEmpty()) {
        WriteRequest writeRequest = client.write(p4DeviceId, pipeconf);
        // Trigger remove of inconsistent entries.
        if (!inconsistentEntries.isEmpty()) {
            log.warn("Found {} inconsistent table entries on {}, removing them...", inconsistentEntries.size(), deviceId);
            writeRequest = writeRequest.entities(inconsistentEntries, DELETE);
        }
        // Trigger reset of inconsistent default entries.
        if (!inconsistentDefaultEntries.isEmpty()) {
            log.warn("Found {} inconsistent default table entries on {}, resetting them...", inconsistentDefaultEntries.size(), deviceId);
            writeRequest = writeRequest.entities(inconsistentDefaultEntries, MODIFY);
        }
        // Submit delete request for non-default entries and modify request
        // for default entries. Updates mirror when done.
        writeRequest.submit().whenComplete((response, ex) -> {
            if (ex != null) {
                log.error("Exception removing inconsistent table entries", ex);
            } else {
                log.debug("Successfully removed {} out of {} inconsistent entries", response.success().size(), response.all().size());
            }
            // We can use the entity as the handle does not contain the action field
            // so the key will be removed even if the table entry is different
            response.success().forEach(entity -> tableMirror.remove((PiTableEntryHandle) entity.handle()));
        });
    }
    return result.build();
}
Also used : PiCounterCellData(org.onosproject.net.pi.runtime.PiCounterCellData) ImmutableList(com.google.common.collect.ImmutableList) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) FlowEntry(org.onosproject.net.flow.FlowEntry) DefaultFlowEntry(org.onosproject.net.flow.DefaultFlowEntry) PiTableEntryHandle(org.onosproject.net.pi.runtime.PiTableEntryHandle)

Example 2 with WriteRequest

use of org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest in project onos by opennetworkinglab.

the class P4RuntimeMeterProgrammable method getMeters.

@Override
public CompletableFuture<Collection<Meter>> getMeters() {
    if (!setupBehaviour("getMeters()")) {
        return CompletableFuture.completedFuture(Collections.emptyList());
    }
    Collection<PiMeterCellConfig> piMeterCellConfigs;
    Set<PiMeterId> meterIds = new HashSet<>();
    for (PiMeterModel mode : pipelineModel.meters()) {
        meterIds.add(mode.id());
    }
    piMeterCellConfigs = client.read(p4DeviceId, pipeconf).meterCells(meterIds).submitSync().all(PiMeterCellConfig.class).stream().filter(piMeterCellConfig -> !piMeterCellConfig.isDefaultConfig()).collect(Collectors.toList());
    meterMirror.sync(deviceId, piMeterCellConfigs);
    if (piMeterCellConfigs.isEmpty()) {
        return CompletableFuture.completedFuture(Collections.emptyList());
    }
    List<PiMeterCellId> inconsistentOrDefaultCells = Lists.newArrayList();
    List<Meter> meters = Lists.newArrayList();
    // Check the consistency of meter config
    for (PiMeterCellConfig config : piMeterCellConfigs) {
        PiMeterCellHandle handle = PiMeterCellHandle.of(deviceId, config);
        DefaultMeter meter = (DefaultMeter) forgeMeter(config, handle);
        if (meter == null) {
            // A default config cannot be used to forge meter
            // because meter has at least 1 band while default config has no band
            inconsistentOrDefaultCells.add(config.cellId());
        } else {
            meters.add(meter);
        }
    }
    // Reset all inconsistent meter cells to the default config
    if (!inconsistentOrDefaultCells.isEmpty()) {
        WriteRequest request = client.write(p4DeviceId, pipeconf);
        for (PiMeterCellId cellId : inconsistentOrDefaultCells) {
            PiMeterCellHandle handle = PiMeterCellHandle.of(deviceId, cellId);
            appendEntryToWriteRequestOrSkip(request, handle, PiMeterCellConfig.reset(cellId));
        }
        request.submit().whenComplete((response, ex) -> {
            if (ex != null) {
                log.error("Exception resetting inconsistent meter entries", ex);
            } else {
                log.debug("Successfully removed {} out of {} inconsistent meter entries", response.success().size(), response.all().size());
            }
            response.success().forEach(entity -> meterMirror.remove((PiMeterCellHandle) entity.handle()));
        });
    }
    return CompletableFuture.completedFuture(meters);
}
Also used : PiMeterId(org.onosproject.net.pi.model.PiMeterId) PiMeterCellId(org.onosproject.net.pi.runtime.PiMeterCellId) DefaultMeter(org.onosproject.net.meter.DefaultMeter) Meter(org.onosproject.net.meter.Meter) PiMeterCellConfig(org.onosproject.net.pi.runtime.PiMeterCellConfig) PiMeterModel(org.onosproject.net.pi.model.PiMeterModel) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) DefaultMeter(org.onosproject.net.meter.DefaultMeter) PiMeterCellHandle(org.onosproject.net.pi.runtime.PiMeterCellHandle) HashSet(java.util.HashSet)

Example 3 with WriteRequest

use of org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest 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 4 with WriteRequest

use of org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest in project onos by opennetworkinglab.

the class P4RuntimeMeterProgrammable method processMeterOp.

private boolean processMeterOp(MeterOperation meterOp) {
    PiMeterCellConfig piMeterCellConfig;
    final PiMeterCellHandle handle = PiMeterCellHandle.of(deviceId, (PiMeterCellId) meterOp.meter().meterCellId());
    boolean result = true;
    WRITE_LOCKS.get(deviceId).lock();
    try {
        switch(meterOp.type()) {
            case ADD:
            case MODIFY:
                // Create a config for modify operation
                try {
                    piMeterCellConfig = translator.translate(meterOp.meter(), pipeconf);
                } catch (PiTranslationException e) {
                    log.warn("Unable translate meter, aborting meter operation {}: {}", meterOp.type(), e.getMessage());
                    log.debug("exception", e);
                    return false;
                }
                translator.learn(handle, new PiTranslatedEntity<>(meterOp.meter(), piMeterCellConfig, handle));
                break;
            case REMOVE:
                // Create a empty config for reset operation
                PiMeterCellId piMeterCellId = (PiMeterCellId) meterOp.meter().meterCellId();
                piMeterCellConfig = PiMeterCellConfig.reset(piMeterCellId);
                translator.forget(handle);
                break;
            default:
                log.warn("Meter Operation type {} not supported", meterOp.type());
                return false;
        }
        WriteRequest request = client.write(p4DeviceId, pipeconf);
        appendEntryToWriteRequestOrSkip(request, handle, piMeterCellConfig);
        if (!request.pendingUpdates().isEmpty()) {
            result = request.submitSync().isSuccess();
            if (result) {
                meterMirror.applyWriteRequest(request);
            }
        }
    } finally {
        WRITE_LOCKS.get(deviceId).unlock();
    }
    return result;
}
Also used : PiMeterCellId(org.onosproject.net.pi.runtime.PiMeterCellId) PiMeterCellConfig(org.onosproject.net.pi.runtime.PiMeterCellConfig) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) PiMeterCellHandle(org.onosproject.net.pi.runtime.PiMeterCellHandle)

Example 5 with WriteRequest

use of org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest in project onos by opennetworkinglab.

the class P4RuntimeFlowRuleProgrammable method processFlowRules.

private Collection<FlowRule> processFlowRules(Collection<FlowRule> rules, Operation driverOperation) {
    if (!setupBehaviour("processFlowRules()") || rules.isEmpty()) {
        return Collections.emptyList();
    }
    // Created batched write request.
    final WriteRequest request = client.write(p4DeviceId, pipeconf);
    // For each rule, translate to PI and append to write request.
    final Map<PiHandle, FlowRule> handleToRuleMap = Maps.newHashMap();
    final List<FlowRule> skippedRules = Lists.newArrayList();
    final CompletableFuture<WriteResponse> futureResponse;
    WRITE_LOCKS.get(deviceId).lock();
    try {
        for (FlowRule rule : rules) {
            // Translate.
            final PiTableEntry entry;
            try {
                entry = translator.translate(rule, pipeconf);
            } catch (PiTranslationException e) {
                log.warn("Unable to translate flow rule for pipeconf '{}': {} [{}]", pipeconf.id(), e.getMessage(), rule);
                // Next rule.
                continue;
            }
            final PiTableEntryHandle handle = entry.handle(deviceId);
            handleToRuleMap.put(handle, rule);
            // Update translation store.
            if (driverOperation.equals(APPLY)) {
                translator.learn(handle, new PiTranslatedEntity<>(rule, entry, handle));
            } else {
                translator.forget(handle);
            }
            // Append entry to batched write request (returns false), or skip (true)
            if (appendEntryToWriteRequestOrSkip(request, handle, entry, driverOperation)) {
                skippedRules.add(rule);
            }
        }
        if (request.pendingUpdates().isEmpty()) {
            // All good. No need to write on device.
            return rules;
        }
        // Update mirror.
        tableMirror.applyWriteRequest(request);
        // Async submit request to server.
        futureResponse = request.submit();
    } finally {
        WRITE_LOCKS.get(deviceId).unlock();
    }
    // Wait for response.
    final WriteResponse response = Futures.getUnchecked(futureResponse);
    // Derive successfully applied flow rule from response.
    final List<FlowRule> appliedRules = getAppliedFlowRules(response, handleToRuleMap, driverOperation);
    // Return skipped and applied rules.
    return ImmutableList.<FlowRule>builder().addAll(skippedRules).addAll(appliedRules).build();
}
Also used : PiHandle(org.onosproject.net.pi.runtime.PiHandle) WriteRequest(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest) WriteResponse(org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteResponse) PiTableEntry(org.onosproject.net.pi.runtime.PiTableEntry) FlowRule(org.onosproject.net.flow.FlowRule) PiTranslationException(org.onosproject.net.pi.service.PiTranslationException) PiTableEntryHandle(org.onosproject.net.pi.runtime.PiTableEntryHandle)

Aggregations

WriteRequest (org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteRequest)5 PiMeterCellConfig (org.onosproject.net.pi.runtime.PiMeterCellConfig)2 PiMeterCellHandle (org.onosproject.net.pi.runtime.PiMeterCellHandle)2 PiMeterCellId (org.onosproject.net.pi.runtime.PiMeterCellId)2 PiTableEntry (org.onosproject.net.pi.runtime.PiTableEntry)2 PiTableEntryHandle (org.onosproject.net.pi.runtime.PiTableEntryHandle)2 PiTranslationException (org.onosproject.net.pi.service.PiTranslationException)2 ImmutableList (com.google.common.collect.ImmutableList)1 HashSet (java.util.HashSet)1 DefaultFlowEntry (org.onosproject.net.flow.DefaultFlowEntry)1 FlowEntry (org.onosproject.net.flow.FlowEntry)1 FlowRule (org.onosproject.net.flow.FlowRule)1 DefaultMeter (org.onosproject.net.meter.DefaultMeter)1 Meter (org.onosproject.net.meter.Meter)1 PiMeterId (org.onosproject.net.pi.model.PiMeterId)1 PiMeterModel (org.onosproject.net.pi.model.PiMeterModel)1 PiActionProfileMember (org.onosproject.net.pi.runtime.PiActionProfileMember)1 PiCounterCellData (org.onosproject.net.pi.runtime.PiCounterCellData)1 PiHandle (org.onosproject.net.pi.runtime.PiHandle)1 WriteResponse (org.onosproject.p4runtime.api.P4RuntimeWriteClient.WriteResponse)1