Driver properties for P4RuntimeFlowRuleProgrammable

Change-Id: I7f9415742543d6989dbe9b319e4a8d0eb5d25cd3
diff --git a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
index a64bc2f..8783adc 100644
--- a/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
+++ b/drivers/p4runtime/src/main/java/org/onosproject/drivers/p4runtime/AbstractP4RuntimeHandlerBehaviour.java
@@ -30,6 +30,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Abstract implementation of a behaviour handler for a P4Runtime device.
  */
@@ -51,9 +53,10 @@
     protected PiTranslationService piTranslationService;
 
     /**
-     * Initializes this behaviour attributes. Returns true if the operation was successful, false otherwise. This method
-     * assumes that the P4runtime controller already has a client for this device and that the device has been created
-     * in the core.
+     * Initializes this behaviour attributes. Returns true if the operation was
+     * successful, false otherwise. This method assumes that the P4runtime
+     * controller already has a client for this device and that the device has
+     * been created in the core.
      *
      * @return true if successful, false otherwise
      */
@@ -88,7 +91,8 @@
     }
 
     /**
-     * Create a P4Runtime client for this device. Returns true if the operation was successful, false otherwise.
+     * Create a P4Runtime client for this device. Returns true if the operation
+     * was successful, false otherwise.
      *
      * @return true if successful, false otherwise
      */
@@ -117,4 +121,21 @@
 
         return true;
     }
+
+    /**
+     * Returns the value of the given driver property, if present,
+     * otherwise returns the given default value.
+     *
+     * @param propName property name
+     * @param defaultVal default value
+     * @return boolean
+     */
+    protected boolean driverBoolProperty(String propName, boolean defaultVal) {
+        checkNotNull(propName);
+        if (handler().driver().getProperty(propName) == null) {
+            return defaultVal;
+        } else {
+            return Boolean.parseBoolean(handler().driver().getProperty(propName));
+        }
+    }
 }
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 2126dfa..bcc298d 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
@@ -16,9 +16,9 @@
 
 package org.onosproject.drivers.p4runtime;
 
-import com.google.common.cache.LoadingCache;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import io.grpc.StatusRuntimeException;
@@ -45,8 +45,8 @@
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Map;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
@@ -75,22 +75,24 @@
     // before inserting the new one, otherwise we issue a MODIFY operation. This
     // is useful fore devices that do not support MODIFY operations for table
     // entries.
-    // TODO: make this attribute configurable by child drivers (e.g. BMv2 or Tofino)
-    private boolean deleteEntryBeforeUpdate = true;
+    private static final String DELETE_BEFORE_UPDATE = "tableDeleteBeforeUpdate";
+    private static final boolean DEFAULT_DELETE_BEFORE_UPDATE = false;
 
-    // If true, we ignore re-installing rules that are already exists the
+    // If true, we ignore re-installing rules that already exist the
     // device, i.e. same match key and action.
-    // FIXME: can remove this check as soon as the multi-apply-per-same-flow rule bug is fixed.
-    private boolean checkStoreBeforeUpdate = true;
+    private static final String IGNORE_SAME_ENTRY_UPDATE = "tableIgnoreSameEntryUpdate";
+    private static final boolean DEFAULT_IGNORE_SAME_ENTRY_UPDATE = false;
 
     // If true, we avoid querying the device and return what's already known by
     // the ONOS store.
-    private boolean ignoreDeviceWhenGet = true;
+    private static final String READ_FROM_MIRROR = "tableReadFromMirror";
+    private static final boolean DEFAULT_READ_FROM_MIRROR = false;
 
-    /* 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. */
+    // 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";
     // FIXME: set to true as soon as the feature is implemented in P4Runtime.
-    private boolean readAllDirectCounters = false;
+    private static final boolean DEFAULT_READ_ALL_DIRECT_COUNTERS = false;
 
     private static final int TABLE_ENTRY_LOCK_EXPIRE_TIME_IN_MIN = 10;
 
@@ -134,7 +136,7 @@
             return Collections.emptyList();
         }
 
-        if (ignoreDeviceWhenGet) {
+        if (driverBoolProperty(READ_FROM_MIRROR, DEFAULT_READ_FROM_MIRROR)) {
             return getFlowEntriesFromMirror();
         }
 
@@ -316,11 +318,13 @@
                 // Entry is first-timer.
                 p4Operation = INSERT;
             } else {
-                if (checkStoreBeforeUpdate
+                if (driverBoolProperty(IGNORE_SAME_ENTRY_UPDATE,
+                                       DEFAULT_IGNORE_SAME_ENTRY_UPDATE)
                         && piEntryToApply.action().equals(piEntryOnDevice.entry().action())) {
                     log.debug("Ignoring re-apply of existing entry: {}", piEntryToApply);
                     p4Operation = null;
-                } else if (deleteEntryBeforeUpdate) {
+                } else if (driverBoolProperty(DELETE_BEFORE_UPDATE,
+                                              DEFAULT_DELETE_BEFORE_UPDATE)) {
                     // Some devices return error when updating existing
                     // entries. If requested, remove entry before
                     // re-inserting the modified one.
@@ -391,7 +395,8 @@
             PiCounterId counterId, Collection<PiTableEntry> tableEntries) {
         Collection<PiCounterCellData> cellDatas;
         try {
-            if (readAllDirectCounters) {
+            if (driverBoolProperty(READ_ALL_DIRECT_COUNTERS,
+                                   DEFAULT_READ_ALL_DIRECT_COUNTERS)) {
                 cellDatas = client.readAllCounterCells(
                         singleton(counterId), pipeconf).get();
             } else {