[AETHER-1248] Reset default entries

A default entry according to the P4RT spec should be reset to its original value
and not removed. The client can send a specially crafted write request with action field
unset to reset default actions to the original value

Change-Id: I451a3be395b212e14ae8eaf060cc048500705091
(cherry picked from commit 91217e420118075fc8b4f88341b08a127bec9595)
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 e8204a6..3d06c2e 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
@@ -156,23 +156,52 @@
             }
         }
 
-        if (!inconsistentEntries.isEmpty()) {
-            // Trigger clean up of inconsistent entries.
-            log.warn("Found {} inconsistent table entries on {}, removing them...",
-                     inconsistentEntries.size(), deviceId);
-            // Submit delete request and update mirror when done.
-            client.write(p4DeviceId, pipeconf)
-                    .entities(inconsistentEntries, DELETE)
-                    .submit().whenComplete((response, ex) -> {
+        // 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());
+                            response.success().size(), response.all().size());
                 }
-                tableMirror.applyWriteResponse(response);
+                // 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();