map: BR rule lookup update

Update to the MAP rule lookup (in IPv6) based on the rule's source
prefix instead of DMR

Type: improvement

Per RFC, the DMR is allowed to serve multiple MAP Basic Mapping Rules, but this
capability was prevented by the above logic.

Updates to the code include populating a new hash table based on the MAP rule
ip6 prefix and length, changing several functions to reference this new table,
and slight alterations to a few functions regarding pre-lookup bitmasking.

All changes are commented with [dgeist] and are in need of peer review,
especially the bitmask alterations.

An attempt was made at generating an additonal MAP rule in the test_map_br test
harness, but the coding appears very much oriented towards testing just one
rule. I would appreciate suggestions on how to test multi-rule cases.

Issue: VPP-2111
Change-Id: Id1fea280eba625e23cd893575d9b63aac7f48405
Signed-off-by: Dan Geist <dan@polter.net>
diff --git a/src/plugins/map/ip6_map_t.c b/src/plugins/map/ip6_map_t.c
index 6bfc8e0..51853d6 100644
--- a/src/plugins/map/ip6_map_t.c
+++ b/src/plugins/map/ip6_map_t.c
@@ -529,7 +529,10 @@
 	  ip60 = vlib_buffer_get_current (p0);
 
 	  d0 =
-	    ip6_map_get_domain (&ip60->dst_address,
+	    /* Originally using the IPv6 dest for rule lookup, now source
+	     * [dgeist] ip6_map_get_domain (&ip60->dst_address,
+	     */
+	    ip6_map_get_domain (&ip60->src_address,
 				&vnet_buffer (p0)->map_t.map_domain_index,
 				&error0);
 	  if (!d0)
diff --git a/src/plugins/map/lpm.c b/src/plugins/map/lpm.c
index c0e5bad..a2fc333 100644
--- a/src/plugins/map/lpm.c
+++ b/src/plugins/map/lpm.c
@@ -28,7 +28,13 @@
 static uint64_t
 masked_address64 (uint64_t addr, uint8_t len)
 {
-  return len == 64 ? addr : addr & ~(~0ull >> len);
+  /* This was originally causing non-64-bit masks to not match due to LSB vs
+   * MSB masking (0s at the head of the value) Probably needs some corner case
+   * checking in case my masking logic was off [dgeist]
+   *
+   * return len == 64 ? addr : addr & ~(~0ull >> len);
+   */
+  return len == 64 ? addr : addr & ((1ull << (len)) - 1);
 }
 
 static void
@@ -126,13 +132,25 @@
   BVT(clib_bihash_kv) kv;
   ip6_address_t *addr = addr_v;
 
-  kv.key[0] = masked_address64(addr->as_u64[0], pfxlen > 64 ? 64 : pfxlen);
+  /* This is a quick hack. It works for pfxlen < 64 but needs validation for
+   * other [dgeist]
+   *
+   * kv.key[0] = masked_address64(addr->as_u64[0], pfxlen > 64 ? 64 : pfxlen);
+   */
+  kv.key[0] = masked_address64 (addr->as_u64[0], pfxlen > 64 ? 64 : 64);
   kv.key[1] = masked_address64(addr->as_u64[1], pfxlen > 64 ? pfxlen - 64 : 0);
   kv.key[2] = pfxlen;
   kv.value = value;
   BV(clib_bihash_add_del)(&lpm->bihash, &kv, 1);
   lpm->prefix_length_refcount[pfxlen]++;
-  lpm->prefix_lengths_bitmap = clib_bitmap_set (lpm->prefix_lengths_bitmap, 128 - pfxlen, 1);
+  /* Populating the lengths bitmap table with prefix of 48 instead of 80
+   * (128 - 48) [dgeist]
+   *
+   * lpm->prefix_lengths_bitmap = clib_bitmap_set (
+   *   lpm->prefix_lengths_bitmap, 128 - pfxlen, 1);
+   */
+  lpm->prefix_lengths_bitmap = clib_bitmap_set (
+    lpm->prefix_lengths_bitmap, pfxlen > 64 ? 128 - pfxlen : pfxlen, 1);
 }
 
 static void
@@ -148,8 +166,8 @@
   /* refcount accounting */
   ASSERT (lpm->prefix_length_refcount[pfxlen] > 0);
   if (--lpm->prefix_length_refcount[pfxlen] == 0) {
-    lpm->prefix_lengths_bitmap = clib_bitmap_set (lpm->prefix_lengths_bitmap, 
-						  128 - pfxlen, 0);
+      lpm->prefix_lengths_bitmap =
+	clib_bitmap_set (lpm->prefix_lengths_bitmap, 128 - pfxlen, 0);
   }
 }
 
diff --git a/src/plugins/map/map.c b/src/plugins/map/map.c
index 6c9668d..3cffadd 100644
--- a/src/plugins/map/map.c
+++ b/src/plugins/map/map.c
@@ -176,6 +176,10 @@
   mm->ip6_src_prefix_tbl->add (mm->ip6_src_prefix_tbl, &d->ip6_src,
 			       d->ip6_src_len, *map_domain_index);
 
+  /* Let's build a table with the MAP rule ip6 prefixes as well [dgeist] */
+  mm->ip6_prefix_tbl->add (mm->ip6_prefix_tbl, &d->ip6_prefix,
+			   d->ip6_prefix_len, *map_domain_index);
+
   /* Validate packet/byte counters */
   map_domain_counter_lock (mm);
   int i;
@@ -218,6 +222,9 @@
 			      d->ip4_prefix_len);
   mm->ip6_src_prefix_tbl->delete (mm->ip6_src_prefix_tbl, &d->ip6_src,
 				  d->ip6_src_len);
+  /* Addition to remove the new table [dgeist] */
+  mm->ip6_prefix_tbl->delete (mm->ip6_prefix_tbl, &d->ip6_prefix,
+			      d->ip6_prefix_len);
 
   /* Release user-assigned MAP domain name. */
   map_free_extras (map_domain_index);
diff --git a/src/plugins/map/map.h b/src/plugins/map/map.h
index d874aa4..86b8ec2 100644
--- a/src/plugins/map/map.h
+++ b/src/plugins/map/map.h
@@ -335,7 +335,11 @@
 {
   map_main_t *mm = &map_main;
   u32 mdi =
-    mm->ip6_src_prefix_tbl->lookup (mm->ip6_src_prefix_tbl, addr, 128);
+    /* This is the old src (ip6 destination) hash lookup [dgeist]
+     *
+     * mm->ip6_src_prefix_tbl->lookup (mm->ip6_src_prefix_tbl, addr, 128);
+     */
+    mm->ip6_prefix_tbl->lookup (mm->ip6_prefix_tbl, addr, 128);
   if (mdi == ~0)
     {
       *error = MAP_ERROR_NO_DOMAIN;