ONOS-7810 use cookie field when checking the pipeline in P4Runtime

Change-Id: I777af9536889eb525f78493e2cbf43ff637b1a1f
diff --git a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
index c291db4..bbc7b69 100644
--- a/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
+++ b/protocols/p4runtime/ctl/src/main/java/org/onosproject/p4runtime/ctl/P4RuntimeClientImpl.java
@@ -80,6 +80,7 @@
 import java.math.BigInteger;
 import java.net.ConnectException;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -408,6 +409,11 @@
             return null;
         }
 
+        ForwardingPipelineConfig.Cookie pipeconfCookie = ForwardingPipelineConfig.Cookie
+                .newBuilder()
+                .setCookie(generateCookie(p4Info, deviceData))
+                .build();
+
         // FIXME: This is specific to PI P4Runtime implementation.
         P4Config.P4DeviceConfig p4DeviceConfigMsg = P4Config.P4DeviceConfig
                 .newBuilder()
@@ -420,6 +426,7 @@
                 .newBuilder()
                 .setP4Info(p4Info)
                 .setP4DeviceConfig(p4DeviceConfigMsg.toByteString())
+                .setCookie(pipeconfCookie)
                 .build();
     }
 
@@ -428,6 +435,8 @@
         GetForwardingPipelineConfigRequest request = GetForwardingPipelineConfigRequest
                 .newBuilder()
                 .setDeviceId(p4DeviceId)
+                .setResponseType(GetForwardingPipelineConfigRequest
+                                         .ResponseType.COOKIE_ONLY)
                 .build();
 
         GetForwardingPipelineConfigResponse resp;
@@ -446,32 +455,17 @@
             return false;
         }
 
-        ForwardingPipelineConfig expectedConfig = getPipelineConfig(
-                pipeconf, deviceData);
+        long expectedConfigCookie = generateCookie(
+                PipeconfHelper.getP4Info(pipeconf), deviceData);
 
-        if (expectedConfig == null) {
-            return false;
-        }
-        if (!resp.hasConfig()) {
+        if (!resp.getConfig().hasCookie()) {
             log.warn("{} returned GetForwardingPipelineConfigResponse " +
-                             "with 'config' field unset",
+                             "with 'cookie' field unset",
                      deviceId);
             return false;
         }
-        if (resp.getConfig().getP4DeviceConfig().isEmpty()
-                && !expectedConfig.getP4DeviceConfig().isEmpty()) {
-            // Don't bother with a warn or error since we don't really allow
-            // updating the pipeline to a different one. So the P4Info should be
-            // enough for us.
-            log.debug("{} returned GetForwardingPipelineConfigResponse " +
-                              "with empty 'p4_device_config' field, " +
-                              "equality will be based only on P4Info",
-                      deviceId);
-            return resp.getConfig().getP4Info().equals(
-                    expectedConfig.getP4Info());
-        } else {
-            return resp.getConfig().equals(expectedConfig);
-        }
+
+        return resp.getConfig().getCookie().getCookie() == expectedConfigCookie;
     }
 
     private boolean doSetPipelineConfig(PiPipeconf pipeconf, ByteBuffer deviceData) {
@@ -1310,6 +1304,15 @@
                 .build();
     }
 
+    /**
+     * A function to generate cookie based on P4Info and target-specific binary
+     * data.
+     * Moreover, the method to generate cookie can be replaced.
+     */
+    private long generateCookie(P4Info p4Info, ByteBuffer deviceData) {
+        return Objects.hash(p4Info, Arrays.hashCode(deviceData.array()));
+    }
+
     private BigInteger uint128ToBigInteger(Uint128 value) {
         return new BigInteger(
                 ByteBuffer.allocate(Long.BYTES * 2)