classify: use 32 bits hash

classify hash used to be stored as u64 in buffer metadata, use 32 bits
instead:
 - on almost all our supported arch (x86 and arm64) we use crc32c
   intrinsics to compute the final hash: we really get a 32-bits hash
 - the hash itself is used to compute a 32-bits bucket index by masking
   upper bits: we always discard the higher 32-bits
 - this allows to increase the l2 classify buffer metadata padding such
   as it does not overlap with the ip fib_index metadata anymore. This
   overlap is an issue when using the 'set metadata' action in the ip
   ACL node which updates both fields

Type: fix

Change-Id: I5d35bdae97b96c3cae534e859b63950fb500ff50
Signed-off-by: Benoît Ganne <bganne@cisco.com>
diff --git a/src/vnet/buffer.h b/src/vnet/buffer.h
index 2f25245..144f62a 100644
--- a/src/vnet/buffer.h
+++ b/src/vnet/buffer.h
@@ -320,13 +320,13 @@
     /* L2 classify */
     struct
     {
-      struct opaque_l2 pad;
+      u32 pad[4]; /* do not overlay w/ ip.fib_index nor l2 */
       union
       {
 	u32 table_index;
 	u32 opaque_index;
       };
-      u64 hash;
+      u32 hash;
     } l2_classify;
 
     /* vnet policer */
diff --git a/src/vnet/classify/flow_classify_node.c b/src/vnet/classify/flow_classify_node.c
index 4989bf0..c0a2999 100644
--- a/src/vnet/classify/flow_classify_node.c
+++ b/src/vnet/classify/flow_classify_node.c
@@ -184,7 +184,7 @@
 	  u32 table_index0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
-	  u64 hash0;
+	  u32 hash0;
 	  u8 *h0;
 
 	  /* Stride 3 seems to work best */
@@ -193,7 +193,7 @@
 	      vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
 	      vnet_classify_table_t *tp1;
 	      u32 table_index1;
-	      u64 phash1;
+	      u32 phash1;
 
 	      table_index1 = vnet_buffer (p1)->l2_classify.table_index;
 
diff --git a/src/vnet/classify/ip_classify.c b/src/vnet/classify/ip_classify.c
index a5c0445..9454ae9 100644
--- a/src/vnet/classify/ip_classify.c
+++ b/src/vnet/classify/ip_classify.c
@@ -190,7 +190,7 @@
 	  u32 table_index0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
-	  u64 hash0;
+	  u32 hash0;
 	  u8 *h0;
 
 	  /* Stride 3 seems to work best */
@@ -199,7 +199,7 @@
 	      vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
 	      vnet_classify_table_t *tp1;
 	      u32 table_index1;
-	      u64 phash1;
+	      u32 phash1;
 
 	      table_index1 = vnet_buffer (p1)->l2_classify.table_index;
 
diff --git a/src/vnet/classify/vnet_classify.c b/src/vnet/classify/vnet_classify.c
index 479d302..8281be5 100644
--- a/src/vnet/classify/vnet_classify.c
+++ b/src/vnet/classify/vnet_classify.c
@@ -424,7 +424,7 @@
   u32 value_index;
   int rv = 0;
   int i;
-  u64 hash, new_hash;
+  u32 hash, new_hash;
   u32 limit;
   u32 old_log2_pages, new_log2_pages;
   u32 thread_index = vlib_get_thread_index ();
@@ -647,15 +647,15 @@
 }) classify_data_or_mask_t;
 /* *INDENT-ON* */
 
-u64
-vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h)
+u32
+vnet_classify_hash_packet (const vnet_classify_table_t *t, u8 *h)
 {
   return vnet_classify_hash_packet_inline (t, h);
 }
 
 vnet_classify_entry_t *
-vnet_classify_find_entry (vnet_classify_table_t * t,
-			  u8 * h, u64 hash, f64 now)
+vnet_classify_find_entry (const vnet_classify_table_t *t, u8 *h, u32 hash,
+			  f64 now)
 {
   return vnet_classify_find_entry_inline (t, h, hash, now);
 }
@@ -3235,7 +3235,7 @@
   for (i = 0; i < tm->sessions; i++)
     {
       u8 *key_minus_skip;
-      u64 hash;
+      u32 hash;
       vnet_classify_entry_t *e;
 
       ep = tm->entries + i;
diff --git a/src/vnet/classify/vnet_classify.h b/src/vnet/classify/vnet_classify.h
index c61ec8f..143833d 100644
--- a/src/vnet/classify/vnet_classify.h
+++ b/src/vnet/classify/vnet_classify.h
@@ -243,7 +243,7 @@
 u8 *format_classify_table (u8 * s, va_list * args);
 u8 *format_vnet_classify_table (u8 *s, va_list *args);
 
-u64 vnet_classify_hash_packet (vnet_classify_table_t * t, u8 * h);
+u32 vnet_classify_hash_packet (const vnet_classify_table_t *t, u8 *h);
 
 static_always_inline vnet_classify_table_t *
 vnet_classify_table_get (u32 table_index)
@@ -253,8 +253,8 @@
   return (pool_elt_at_index (vcm->tables, table_index));
 }
 
-static inline u64
-vnet_classify_hash_packet_inline (vnet_classify_table_t *t, const u8 *h)
+static inline u32
+vnet_classify_hash_packet_inline (const vnet_classify_table_t *t, const u8 *h)
 {
   u64 xor_sum;
   ASSERT (t);
@@ -361,7 +361,7 @@
 }
 
 static inline vnet_classify_entry_t *
-vnet_classify_get_entry (vnet_classify_table_t * t, uword offset)
+vnet_classify_get_entry (const vnet_classify_table_t *t, uword offset)
 {
   u8 *hp = clib_mem_get_heap_base (t->mheap);
   u8 *vp = hp + offset;
@@ -383,8 +383,8 @@
 }
 
 static inline vnet_classify_entry_t *
-vnet_classify_entry_at_index (vnet_classify_table_t * t,
-			      vnet_classify_entry_t * e, u32 index)
+vnet_classify_entry_at_index (const vnet_classify_table_t *t,
+			      vnet_classify_entry_t *e, u32 index)
 {
   u8 *eu8;
 
@@ -421,8 +421,9 @@
   clib_prefetch_load (e);
 }
 
-vnet_classify_entry_t *vnet_classify_find_entry (vnet_classify_table_t * t,
-						 u8 * h, u64 hash, f64 now);
+vnet_classify_entry_t *
+vnet_classify_find_entry (const vnet_classify_table_t *t, u8 *h, u32 hash,
+			  f64 now);
 
 static_always_inline int
 vnet_classify_entry_is_equal (vnet_classify_entry_t *v, const u8 *d, u8 *m,
@@ -529,8 +530,8 @@
 }
 
 static inline vnet_classify_entry_t *
-vnet_classify_find_entry_inline (vnet_classify_table_t *t, const u8 *h,
-				 u64 hash, f64 now)
+vnet_classify_find_entry_inline (const vnet_classify_table_t *t, const u8 *h,
+				 u32 hash, f64 now)
 {
   vnet_classify_entry_t *v;
   vnet_classify_bucket_t *b;
diff --git a/src/vnet/interface_format.c b/src/vnet/interface_format.c
index 304fbb8..0c051dd 100644
--- a/src/vnet/interface_format.c
+++ b/src/vnet/interface_format.c
@@ -602,9 +602,9 @@
 
   s = format (s,
 	      "l2_classify.table_index: %d, l2_classify.opaque_index: %d, "
-	      "l2_classify.hash: 0x%llx",
-	      o->l2_classify.table_index,
-	      o->l2_classify.opaque_index, o->l2_classify.hash);
+	      "l2_classify.hash: 0x%lx",
+	      o->l2_classify.table_index, o->l2_classify.opaque_index,
+	      o->l2_classify.hash);
   vec_add1 (s, '\n');
 
   s = format (s, "policer.index: %d", o->policer.index);
diff --git a/src/vnet/ip/ip_in_out_acl.c b/src/vnet/ip/ip_in_out_acl.c
index 9fc0717..d8d6d76 100644
--- a/src/vnet/ip/ip_in_out_acl.c
+++ b/src/vnet/ip/ip_in_out_acl.c
@@ -130,7 +130,7 @@
   u32 sw_if_index[4];
   u32 table_index[4];
   vnet_classify_table_t *t[4] = { 0, 0 };
-  u64 hash[4];
+  u32 hash[4];
 
   /* calculate hashes for b[0] & b[1] */
   if (n_left >= 2)
@@ -162,16 +162,16 @@
       if (is_output)
 	{
 	  /* Save the rewrite length, since we are using the l2_classify struct */
-	  vnet_buffer (b[0])->l2_classify.pad.l2_len =
+	  vnet_buffer (b[0])->l2.l2_len =
 	    vnet_buffer (b[0])->ip.save_rewrite_length;
 	  /* advance the match pointer so the matching happens on IP header */
-	  h[2] += vnet_buffer (b[0])->l2_classify.pad.l2_len;
+	  h[2] += vnet_buffer (b[0])->l2.l2_len;
 
 	  /* Save the rewrite length, since we are using the l2_classify struct */
-	  vnet_buffer (b[1])->l2_classify.pad.l2_len =
+	  vnet_buffer (b[1])->l2.l2_len =
 	    vnet_buffer (b[1])->ip.save_rewrite_length;
 	  /* advance the match pointer so the matching happens on IP header */
-	  h[3] += vnet_buffer (b[1])->l2_classify.pad.l2_len;
+	  h[3] += vnet_buffer (b[1])->l2.l2_len;
 	}
 
       hash[2] = vnet_classify_hash_packet_inline (t[2], (u8 *) h[2]);
@@ -252,16 +252,16 @@
 	  if (is_output)
 	    {
 	      /* Save the rewrite length, since we are using the l2_classify struct */
-	      vnet_buffer (b[2])->l2_classify.pad.l2_len =
+	      vnet_buffer (b[2])->l2.l2_len =
 		vnet_buffer (b[2])->ip.save_rewrite_length;
 	      /* advance the match pointer so the matching happens on IP header */
-	      h[2] += vnet_buffer (b[2])->l2_classify.pad.l2_len;
+	      h[2] += vnet_buffer (b[2])->l2.l2_len;
 
 	      /* Save the rewrite length, since we are using the l2_classify struct */
-	      vnet_buffer (b[3])->l2_classify.pad.l2_len =
+	      vnet_buffer (b[3])->l2.l2_len =
 		vnet_buffer (b[3])->ip.save_rewrite_length;
 	      /* advance the match pointer so the matching happens on IP header */
-	      h[3] += vnet_buffer (b[3])->l2_classify.pad.l2_len;
+	      h[3] += vnet_buffer (b[3])->l2.l2_len;
 	    }
 
 	  hash[2] = vnet_classify_hash_packet_inline (t[2], (u8 *) h[2]);
@@ -351,7 +351,7 @@
 
 		  /* advance the match pointer so the matching happens on IP header */
 		  if (is_output)
-		    h[0] += vnet_buffer (b[0])->l2_classify.pad.l2_len;
+		    h[0] += vnet_buffer (b[0])->l2.l2_len;
 
 		  hash[0] =
 		    vnet_classify_hash_packet_inline (t[0], (u8 *) h[0]);
@@ -458,7 +458,7 @@
 
 		  /* advance the match pointer so the matching happens on IP header */
 		  if (is_output)
-		    h[1] += vnet_buffer (b[1])->l2_classify.pad.l2_len;
+		    h[1] += vnet_buffer (b[1])->l2.l2_len;
 
 		  hash[1] =
 		    vnet_classify_hash_packet_inline (t[1], (u8 *) h[1]);
@@ -557,7 +557,7 @@
       vnet_classify_table_t *t0 = 0;
       vnet_classify_entry_t *e0 = 0;
       u32 next0 = ACL_NEXT_INDEX_DENY;
-      u64 hash0;
+      u32 hash0;
 
       sw_if_index0 = ~0 == way ? 0 : vnet_buffer (b[0])->sw_if_index[way];
       table_index0 = table_index_by_sw_if_index[sw_if_index0];
@@ -573,10 +573,10 @@
       if (is_output)
 	{
 	  /* Save the rewrite length, since we are using the l2_classify struct */
-	  vnet_buffer (b[0])->l2_classify.pad.l2_len =
+	  vnet_buffer (b[0])->l2.l2_len =
 	    vnet_buffer (b[0])->ip.save_rewrite_length;
 	  /* advance the match pointer so the matching happens on IP header */
-	  h0 += vnet_buffer (b[0])->l2_classify.pad.l2_len;
+	  h0 += vnet_buffer (b[0])->l2.l2_len;
 	}
 
       vnet_buffer (b[0])->l2_classify.hash =
@@ -602,7 +602,7 @@
 
 	  /* advance the match pointer so the matching happens on IP header */
 	  if (is_output)
-	    h0 += vnet_buffer (b[0])->l2_classify.pad.l2_len;
+	    h0 += vnet_buffer (b[0])->l2.l2_len;
 
 	  e0 = vnet_classify_find_entry_inline (t0, (u8 *) h0, hash0, now);
 	  if (e0)
@@ -660,7 +660,7 @@
 
 		  /* advance the match pointer so the matching happens on IP header */
 		  if (is_output)
-		    h0 += vnet_buffer (b[0])->l2_classify.pad.l2_len;
+		    h0 += vnet_buffer (b[0])->l2.l2_len;
 
 		  hash0 = vnet_classify_hash_packet_inline (t0, (u8 *) h0);
 		  e0 = vnet_classify_find_entry_inline
diff --git a/src/vnet/l2/l2_in_out_acl.c b/src/vnet/l2/l2_in_out_acl.c
index f8293c1..7307a68 100644
--- a/src/vnet/l2/l2_in_out_acl.c
+++ b/src/vnet/l2/l2_in_out_acl.c
@@ -278,7 +278,7 @@
 	  u32 table_index0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
-	  u64 hash0;
+	  u32 hash0;
 	  u8 *h0;
 	  u8 error0;
 
@@ -288,7 +288,7 @@
 	      vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
 	      vnet_classify_table_t *tp1;
 	      u32 table_index1;
-	      u64 phash1;
+	      u32 phash1;
 
 	      table_index1 = vnet_buffer (p1)->l2_classify.table_index;
 
diff --git a/src/vnet/l2/l2_input_classify.c b/src/vnet/l2/l2_input_classify.c
index 53d4639..d33a081 100644
--- a/src/vnet/l2/l2_input_classify.c
+++ b/src/vnet/l2/l2_input_classify.c
@@ -179,8 +179,7 @@
       int type_index0, type_index1;
       vnet_classify_table_t *t0, *t1;
       u32 table_index0, table_index1;
-      u64 hash0, hash1;
-
+      u32 hash0, hash1;
 
       /* prefetch next iteration */
       {
@@ -265,7 +264,7 @@
       u32 type_index0;
       vnet_classify_table_t *t0;
       u32 table_index0;
-      u64 hash0;
+      u32 hash0;
 
       bi0 = from[0];
       b0 = vlib_get_buffer (vm, bi0);
@@ -316,14 +315,14 @@
 	  u32 next0 = ~0;	/* next l2 input feature, please... */
 	  ethernet_header_t *h0;
 	  u32 table_index0;
-	  u64 hash0;
+	  u32 hash0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
 
 	  if (PREDICT_TRUE (n_left_from > 2))
 	    {
 	      vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]);
-	      u64 phash2;
+	      u32 phash2;
 	      u32 table_index2;
 	      vnet_classify_table_t *tp2;
 
diff --git a/src/vnet/l2/l2_output_classify.c b/src/vnet/l2/l2_output_classify.c
index 96d0b14..97beb37 100644
--- a/src/vnet/l2/l2_output_classify.c
+++ b/src/vnet/l2/l2_output_classify.c
@@ -172,8 +172,7 @@
       int type_index0, type_index1;
       vnet_classify_table_t *t0, *t1;
       u32 table_index0, table_index1;
-      u64 hash0, hash1;
-
+      u32 hash0, hash1;
 
       /* prefetch next iteration */
       {
@@ -257,7 +256,7 @@
       u32 type_index0;
       vnet_classify_table_t *t0;
       u32 table_index0;
-      u64 hash0;
+      u32 hash0;
 
       bi0 = from[0];
       b0 = vlib_get_buffer (vm, bi0);
@@ -308,14 +307,14 @@
 	  u32 next0 = ~0;
 	  ethernet_header_t *h0;
 	  u32 table_index0;
-	  u64 hash0;
+	  u32 hash0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
 
 	  if (PREDICT_TRUE (n_left_from > 2))
 	    {
 	      vlib_buffer_t *p2 = vlib_get_buffer (vm, from[2]);
-	      u64 phash2;
+	      u32 phash2;
 	      u32 table_index2;
 	      vnet_classify_table_t *tp2;
 
diff --git a/src/vnet/policer/node_funcs.c b/src/vnet/policer/node_funcs.c
index 5fa0c85..efa2f83 100644
--- a/src/vnet/policer/node_funcs.c
+++ b/src/vnet/policer/node_funcs.c
@@ -527,7 +527,7 @@
 	  u32 table_index0;
 	  vnet_classify_table_t *t0;
 	  vnet_classify_entry_t *e0;
-	  u64 hash0;
+	  u32 hash0;
 	  u8 *h0;
 	  u8 act0;
 
@@ -537,7 +537,7 @@
 	      vlib_buffer_t *p1 = vlib_get_buffer (vm, from[3]);
 	      vnet_classify_table_t *tp1;
 	      u32 table_index1;
-	      u64 phash1;
+	      u32 phash1;
 
 	      table_index1 = vnet_buffer (p1)->l2_classify.table_index;