More robust P4Runtime group handling
This patch solves the PENDING_UPDATE and PENDING_ADD_RETRY issue
observed on the ONS EU topology.
The P4Runtime action profile group handling has been re-implemented to
be robust against inconsistencies of the device mirror, which is now
periodically synchronized with the device state. Similarly, we implement
a routine in the P4RuntimeClient to cleanup unused action profile
members.
This patch includes also:
- Refactor PI handle classes to allow creating handles without the
entity instance
- Use list instead of collections in P4RuntimeClient methods, as order
of updates sent and/or entities received from the device is important
Change-Id: I2e7964ce90f43d66680131b47ab52aca32ab55d2
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
index 85a87fe..d0acdee 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/P4RuntimeFlowRuleProgrammable.java
@@ -140,6 +140,11 @@
streamEntries(), streamDefaultEntries())
// Ignore entries from constant tables.
.filter(e -> !tableIsConstant(e.table()))
+ // Device implementation might return duplicate entries. For
+ // example if reading only default ones is not supported and
+ // non-default entries are returned, by using distinct() we are
+ // robust against that possibility.
+ .distinct()
.collect(Collectors.toList());
if (deviceEntries.isEmpty()) {
@@ -148,7 +153,6 @@
// Synchronize mirror with the device state.
syncMirror(deviceEntries);
- // Read table direct counters for non default-entries (if any).
// TODO: ONOS-7596 read counters with table entries
final Map<PiTableEntry, PiCounterCellData> counterCellMap =
readEntryCounters(deviceEntries);
@@ -229,7 +233,12 @@
log.warn("Table entry handle not found in translation store: {}", handle);
return null;
}
-
+ if (!translatedEntity.get().translated().equals(entry)) {
+ log.warn("Table entry obtained from device {} is different from " +
+ "one in in translation store: device={}, store={}",
+ deviceId, entry, translatedEntity.get().translated());
+ return null;
+ }
if (timedEntry == null) {
log.warn("Table entry handle not found in device mirror: {}", handle);
return null;
@@ -460,6 +469,7 @@
cellDatas = Collections.emptyList();
} else {
Set<PiCounterCellId> cellIds = tableEntries.stream()
+ // Ignore counter for default entry.
.filter(e -> !e.isDefaultAction())
.filter(e -> tableHasCounter(e.table()))
.map(PiCounterCellId::ofDirect)