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();
}
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);
}
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();
}
}
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;
}
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();
}
Aggregations