Secure LLDP-based Topology Detection

Current LLDP/BDDP-based Topology Detection is vulnerable to the
creation of fake links via forged, modified, or replayed LLDP packets.
This patch fixes this vulnerability by authenticating LLDP/BDDP packets
using a Message Authentication Code and adding a timestamp to prevent
replay. We use HMAC with SHA-256 has our Messge Authentication Code and
derive the key from the config/cluster.json file via the
ClusterMetadata class.

Change-Id: I01dd6edc5cffd6dfe274bcdb97189f2661a6c4f1
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataDiff.java b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataDiff.java
index acad25f..e9f73b4 100644
--- a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataDiff.java
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataDiff.java
@@ -37,6 +37,7 @@
     private final ClusterMetadata newValue;
     private final Set<ControllerNode> nodesAdded;
     private final Set<NodeId> nodesRemoved;
+    private final boolean secretChanged;
 
      public ClusterMetadataDiff(ClusterMetadata oldValue, ClusterMetadata newValue) {
          this.oldValue = oldValue;
@@ -51,6 +52,20 @@
                             .stream()
                             .map(ControllerNode::id)
                             .collect(Collectors.toSet());
+
+         boolean haveOldSecret = (oldValue != null && oldValue.getClusterSecret() != null);
+         boolean haveNewSecret = (newValue != null && newValue.getClusterSecret() != null);
+
+         if (!haveOldSecret && haveNewSecret) {
+             secretChanged = true;
+         } else if (haveOldSecret && haveNewSecret &&
+                 !oldValue.getClusterSecret().equals(newValue.getClusterSecret())) {
+             secretChanged = true;
+         } else if (haveOldSecret && !haveNewSecret) {
+             secretChanged = true;
+         } else {
+             secretChanged = false;
+         }
      }
 
     /**
@@ -70,6 +85,14 @@
     }
 
     /**
+     * Returns whether the cluster-wide shared secret changed.
+     * @return  whether the cluster secret changed
+     */
+    public boolean clusterSecretChanged() {
+        return secretChanged;
+    }
+
+    /**
      * Returns a mapping of all partition diffs.
      * @return partition diffs.
      */