No need to map table counters in PI pipeline interpreter

This is related to ONOS-7595. In a recent P4Runtime update, it has been
made explicit that tables can support at most 1 direct counter. Hence,
the pipeline interpreter no longer needs to provide a mapping between a
table and one of potentially many counters. If needed, such mapping can
be derived from the pipeline model (i.e. the p4info)

Change-Id: Ibdece52f35a4d187ab9dbeb90f5527b6285e9788
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 352eca8..00fe9380 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
@@ -29,7 +29,6 @@
 import org.onosproject.net.flow.FlowEntry;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.FlowRuleProgrammable;
-import org.onosproject.net.pi.model.PiCounterId;
 import org.onosproject.net.pi.model.PiPipelineInterpreter;
 import org.onosproject.net.pi.model.PiPipelineModel;
 import org.onosproject.net.pi.model.PiTableId;
@@ -87,6 +86,11 @@
     private static final String READ_FROM_MIRROR = "tableReadFromMirror";
     private static final boolean DEFAULT_READ_FROM_MIRROR = false;
 
+    // If true, we read counters when reading table entries (if table has
+    // counters). Otherwise, we don't.
+    private static final String SUPPORT_TABLE_COUNTERS = "supportTableCounters";
+    private static final boolean DEFAULT_SUPPORT_TABLE_COUNTERS = true;
+
     // If true, we read all direct counters of a table with one request.
     // Otherwise, we send as many requests as the number of table entries.
     private static final String READ_ALL_DIRECT_COUNTERS = "tableReadAllDirectCounters";
@@ -166,13 +170,8 @@
             }
 
             // Read table direct counters (if any).
-            final Map<PiTableEntry, PiCounterCellData> counterCellMap;
-            if (interpreter.mapTableCounter(piTableId).isPresent()) {
-                PiCounterId piCounterId = interpreter.mapTableCounter(piTableId).get();
-                counterCellMap = readEntryCounters(piCounterId, installedEntries);
-            } else {
-                counterCellMap = Collections.emptyMap();
-            }
+            final Map<PiTableEntry, PiCounterCellData> counterCellMap =
+                    readEntryCounters(installedEntries);
 
             // Forge flow entries with counter values.
             for (PiTableEntry installedEntry : installedEntries) {
@@ -391,7 +390,12 @@
     }
 
     private Map<PiTableEntry, PiCounterCellData> readEntryCounters(
-            PiCounterId counterId, Collection<PiTableEntry> tableEntries) {
+            Collection<PiTableEntry> tableEntries) {
+        if (!driverBoolProperty(SUPPORT_TABLE_COUNTERS,
+                                DEFAULT_SUPPORT_TABLE_COUNTERS)) {
+            return Collections.emptyMap();
+        }
+
         Collection<PiCounterCellData> cellDatas;
         try {
             if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS,
@@ -403,6 +407,7 @@
                 cellDatas = Collections.emptyList();
             } else {
                 Set<PiCounterCellId> cellIds = tableEntries.stream()
+                        .filter(e -> tableHasCounter(e.table()))
                         .map(PiCounterCellId::ofDirect)
                         .collect(Collectors.toSet());
                 cellDatas = client.readCounterCells(cellIds, pipeconf).get();
@@ -412,13 +417,18 @@
         } catch (InterruptedException | ExecutionException e) {
             if (!(e.getCause() instanceof StatusRuntimeException)) {
                 // gRPC errors are logged in the client.
-                log.error("Exception while reading counter '{}' from {}: {}",
-                          counterId, deviceId, e);
+                log.error("Exception while reading table counters from {}: {}",
+                          deviceId, e);
             }
             return Collections.emptyMap();
         }
     }
 
+    private boolean tableHasCounter(PiTableId tableId) {
+        return pipelineModel.table(tableId).isPresent() &&
+                !pipelineModel.table(tableId).get().counters().isEmpty();
+    }
+
     enum Operation {
         APPLY, REMOVE
     }