use of org.onosproject.net.pi.runtime.PiTableEntryHandle 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.net.pi.runtime.PiTableEntryHandle in project onos by opennetworkinglab.
the class P4RuntimeFlowRuleProgrammable method getOriginalDefaultEntry.
private PiTableEntry getOriginalDefaultEntry(PiTableId tableId) {
final PiTableEntryHandle handle = PiTableEntry.builder().forTable(tableId).withMatchKey(PiMatchKey.EMPTY).build().handle(deviceId);
final TimedEntry<PiTableEntry> originalDefaultEntry = defaultEntryMirror.get(handle);
if (originalDefaultEntry != null) {
return originalDefaultEntry.entry();
}
return null;
}
use of org.onosproject.net.pi.runtime.PiTableEntryHandle 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