ONOS-7810 calculate cookie field when pipeconf registered

Change-Id: Iea29fc447b34c49d4e8fcc831812385459c1ccbb
(cherry picked from commit ec1a420030d2ecab77909056a34aee50f808f72f)
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
index 7d9dd28..cff8248 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/DefaultPiPipeconf.java
@@ -17,11 +17,15 @@
 package org.onosproject.net.pi.model;
 
 import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.IOUtils;
 import org.onosproject.net.driver.Behaviour;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
@@ -37,14 +41,16 @@
 
     private final PiPipeconfId id;
     private final PiPipelineModel pipelineModel;
+    private final long fingerprint;
     private final Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours;
     private final Map<ExtensionType, URL> extensions;
 
-    private DefaultPiPipeconf(PiPipeconfId id, PiPipelineModel pipelineModel,
+    private DefaultPiPipeconf(PiPipeconfId id, PiPipelineModel pipelineModel, long fingerprint,
                               Map<Class<? extends Behaviour>, Class<? extends Behaviour>> behaviours,
                               Map<ExtensionType, URL> extensions) {
         this.id = id;
         this.pipelineModel = pipelineModel;
+        this.fingerprint = fingerprint;
         this.behaviours = behaviours;
         this.extensions = extensions;
     }
@@ -60,6 +66,11 @@
     }
 
     @Override
+    public long fingerprint() {
+        return fingerprint;
+    }
+
+    @Override
     public Collection<Class<? extends Behaviour>> behaviours() {
         return behaviours.keySet();
     }
@@ -175,8 +186,23 @@
         public PiPipeconf build() {
             checkNotNull(id);
             checkNotNull(pipelineModel);
-            return new DefaultPiPipeconf(id, pipelineModel, behaviourMapBuilder.build(), extensionMapBuilder.build());
+
+            Map<ExtensionType, URL> extensions = extensionMapBuilder.build();
+            return new DefaultPiPipeconf(id, pipelineModel, generateFingerprint(extensions),
+                                         behaviourMapBuilder.build(), extensions);
         }
 
+        private long generateFingerprint(Map<ExtensionType, URL> extensions) {
+            Collection<Integer> hashArray = new ArrayList<>();
+            for (Map.Entry<ExtensionType, URL> pair : extensions.entrySet()) {
+                try {
+                    hashArray.add(Arrays.hashCode(ByteBuffer.wrap(IOUtils.toByteArray(
+                            pair.getValue().openStream())).array()));
+                } catch (IOException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+            return Arrays.hashCode(hashArray.toArray());
+        }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
index 5fedaf7..e3664e1 100644
--- a/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
+++ b/core/api/src/main/java/org/onosproject/net/pi/model/PiPipeconf.java
@@ -45,6 +45,13 @@
     PiPipelineModel pipelineModel();
 
     /**
+     * Returns the fingerprint of pipeconf.
+     *
+     * @return a fingerprint
+     */
+    long fingerprint();
+
+    /**
      * Returns all pipeline-specific behaviour interfaces defined by this configuration.
      *
      * @return a collection of behaviours
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 bbc7b69..fa85056 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,7 +80,6 @@
 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;
@@ -411,7 +410,7 @@
 
         ForwardingPipelineConfig.Cookie pipeconfCookie = ForwardingPipelineConfig.Cookie
                 .newBuilder()
-                .setCookie(generateCookie(p4Info, deviceData))
+                .setCookie(pipeconf.fingerprint())
                 .build();
 
         // FIXME: This is specific to PI P4Runtime implementation.
@@ -454,10 +453,6 @@
             }
             return false;
         }
-
-        long expectedConfigCookie = generateCookie(
-                PipeconfHelper.getP4Info(pipeconf), deviceData);
-
         if (!resp.getConfig().hasCookie()) {
             log.warn("{} returned GetForwardingPipelineConfigResponse " +
                              "with 'cookie' field unset",
@@ -465,7 +460,7 @@
             return false;
         }
 
-        return resp.getConfig().getCookie().getCookie() == expectedConfigCookie;
+        return resp.getConfig().getCookie().getCookie() == pipeconf.fingerprint();
     }
 
     private boolean doSetPipelineConfig(PiPipeconf pipeconf, ByteBuffer deviceData) {
@@ -1304,15 +1299,6 @@
                 .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)