MAP: Add RFC6052 mapping to MAP-T

Change-Id: I2e311f8b7f50133678b9172e8d071826af491609
Signed-off-by: Ole Troan <ot@cisco.com>
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
diff --git a/src/vnet/map/ip6_map_t.c b/src/vnet/map/ip6_map_t.c
index 03cbfc1..a6314c6 100644
--- a/src/vnet/map/ip6_map_t.c
+++ b/src/vnet/map/ip6_map_t.c
@@ -59,7 +59,8 @@
 {
   u32 *ignore = NULL;
   map_ip4_reass_lock ();
-  map_ip4_reass_t *r = map_ip4_reass_get (map_get_ip4 (&ip6->src_address),
+  map_ip4_reass_t *r = map_ip4_reass_get (map_get_ip4 (&ip6->src_address,
+						       d->flags),
 					  ip6_map_t_embedded_address (d,
 								      &ip6->
 								      dst_address),
@@ -82,7 +83,8 @@
 {
   u32 *ignore = NULL;
   map_ip4_reass_lock ();
-  map_ip4_reass_t *r = map_ip4_reass_get (map_get_ip4 (&ip6->src_address),
+  map_ip4_reass_t *r = map_ip4_reass_get (map_get_ip4 (&ip6->src_address,
+						       d->flags),
 					  ip6_map_t_embedded_address (d,
 								      &ip6->
 								      dst_address),
@@ -110,7 +112,7 @@
 
   //Security check
   //Note that this prevents an intermediate IPv6 router from answering the request
-  ip4_sadr = map_get_ip4 (&ip6->src_address);
+  ip4_sadr = map_get_ip4 (&ip6->src_address, ctx->d->flags);
   if (ip6->src_address.as_u64[0] !=
       map_get_pfx_net (ctx->d, ip4_sadr, ctx->sender_port)
       || ip6->src_address.as_u64[1] != map_get_sfx_net (ctx->d, ip4_sadr,
@@ -132,7 +134,7 @@
   u32 inner_ip4_dadr;
 
   //Security check of inner packet
-  inner_ip4_dadr = map_get_ip4 (&ip6->dst_address);
+  inner_ip4_dadr = map_get_ip4 (&ip6->dst_address, ctx->d->flags);
   if (ip6->dst_address.as_u64[0] !=
       map_get_pfx_net (ctx->d, inner_ip4_dadr, ctx->sender_port)
       || ip6->dst_address.as_u64[1] != map_get_sfx_net (ctx->d,
@@ -612,8 +614,10 @@
 	  ip60 = vlib_buffer_get_current (p0);
 	  ip61 = vlib_buffer_get_current (p1);
 
-	  saddr0 = map_get_ip4 (&ip60->src_address);
-	  saddr1 = map_get_ip4 (&ip61->src_address);
+	  saddr0 = 0;		/* TODO */
+	  saddr1 = 0;		/* TODO */
+	  /* NOTE: ip6_map_get_domain currently doesn't utilize second argument */
+
 	  d0 = ip6_map_get_domain (vnet_buffer (p0)->ip.adj_index[VLIB_TX],
 				   (ip4_address_t *) & saddr0,
 				   &vnet_buffer (p0)->map_t.map_domain_index,
@@ -624,6 +628,9 @@
 				&vnet_buffer (p1)->map_t.map_domain_index,
 				&error1);
 
+	  saddr0 = map_get_ip4 (&ip60->src_address, d0->flags);
+	  saddr1 = map_get_ip4 (&ip61->src_address, d1->flags);
+
 	  vnet_buffer (p0)->map_t.v6.saddr = saddr0;
 	  vnet_buffer (p1)->map_t.v6.saddr = saddr1;
 	  vnet_buffer (p0)->map_t.v6.daddr =
@@ -790,13 +797,18 @@
 
 	  p0 = vlib_get_buffer (vm, pi0);
 	  ip60 = vlib_buffer_get_current (p0);
+
 	  //Save saddr in a different variable to not overwrite ip.adj_index
-	  saddr = map_get_ip4 (&ip60->src_address);
+	  saddr = 0;		/* TODO */
+	  /* NOTE: ip6_map_get_domain currently doesn't utilize second argument */
+
 	  d0 = ip6_map_get_domain (vnet_buffer (p0)->ip.adj_index[VLIB_TX],
 				   (ip4_address_t *) & saddr,
 				   &vnet_buffer (p0)->map_t.map_domain_index,
 				   &error0);
 
+	  saddr = map_get_ip4 (&ip60->src_address, d0->flags);
+
 	  //FIXME: What if d0 is null
 	  vnet_buffer (p0)->map_t.v6.saddr = saddr;
 	  vnet_buffer (p0)->map_t.v6.daddr =
diff --git a/src/vnet/map/map.api b/src/vnet/map/map.api
index 14f10e7..a63703a 100644
--- a/src/vnet/map/map.api
+++ b/src/vnet/map/map.api
@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-vl_api_version 1.0.0
+vl_api_version 1.1.0
 
 /** \brief Add MAP domains
     @param client_index - opaque cookie to identify the sender
@@ -27,6 +27,7 @@
     @param psid_offset - Port Set Identifider (PSID) offset
     @param psid_length - PSID length
     @param is_translation - MAP-E / MAP-T
+    @param is_rfc6052 - rfc6052 translation
     @param mtu - MTU
 */
 define map_add_domain
@@ -43,6 +44,7 @@
   u8 psid_offset;
   u8 psid_length;
   u8 is_translation;
+  u8 is_rfc6052;
   u16 mtu;
 };
 
diff --git a/src/vnet/map/map.c b/src/vnet/map/map.c
index e3886d7..b2eefee 100644
--- a/src/vnet/map/map.c
+++ b/src/vnet/map/map.c
@@ -85,6 +85,12 @@
 	  clib_warning ("MAP-T only supports ip6_src_len = 96 for now.");
 	  return -1;
 	}
+      if ((flags & MAP_DOMAIN_RFC6052) && ip6_prefix_len != 96)
+	{
+	  clib_warning ("RFC6052 translation only supports ip6_prefix_len = "
+			"96 for now");
+	  return -1;
+	}
     }
   else
     {
@@ -586,6 +592,8 @@
 	num_m_args++;
       else if (unformat (line_input, "map-t"))
 	flags |= MAP_DOMAIN_TRANSLATION;
+      else if (unformat (line_input, "rfc6052"))
+	flags |= (MAP_DOMAIN_TRANSLATION | MAP_DOMAIN_RFC6052);
       else
 	{
 	  error = clib_error_return (0, "unknown input `%U'",
@@ -919,6 +927,18 @@
   return error;
 }
 
+static char *
+map_flags_to_string (u32 flags)
+{
+  if (flags & MAP_DOMAIN_RFC6052)
+    return "rfc6052";
+  if (flags & MAP_DOMAIN_PREFIX)
+    return "prefix";
+  if (flags & MAP_DOMAIN_TRANSLATION)
+    return "map-t";
+  return "";
+}
+
 static u8 *
 format_map_domain (u8 * s, va_list * args)
 {
@@ -933,13 +953,14 @@
     ip6_prefix = d->ip6_prefix;
 
   s = format (s,
-	      "[%d] ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d ea_bits_len %d psid-offset %d psid-len %d mtu %d %s",
+	      "[%d] ip4-pfx %U/%d ip6-pfx %U/%d ip6-src %U/%d ea_bits_len %d "
+	      "psid-offset %d psid-len %d mtu %d %s",
 	      d - mm->domains,
 	      format_ip4_address, &d->ip4_prefix, d->ip4_prefix_len,
 	      format_ip6_address, &ip6_prefix, d->ip6_prefix_len,
 	      format_ip6_address, &d->ip6_src, d->ip6_src_len,
 	      d->ea_bits_len, d->psid_offset, d->psid_length, d->mtu,
-	      (d->flags & MAP_DOMAIN_TRANSLATION) ? "map-t" : "");
+	      map_flags_to_string (d->flags));
 
   if (counters)
     {
diff --git a/src/vnet/map/map.h b/src/vnet/map/map.h
index b9b3353..8bae222 100644
--- a/src/vnet/map/map.h
+++ b/src/vnet/map/map.h
@@ -35,10 +35,12 @@
 		      u8 is_add);
 u8 *format_map_trace (u8 * s, va_list * args);
 
-typedef enum __attribute__ ((__packed__))
+typedef enum
 {
-  MAP_DOMAIN_PREFIX = 1 << 0, MAP_DOMAIN_TRANSLATION = 1 << 1,	// The domain uses MAP-T
-} map_domain_flags_e;
+  MAP_DOMAIN_PREFIX = 1 << 0,
+  MAP_DOMAIN_TRANSLATION = 1 << 1,	// The domain uses MAP-T
+  MAP_DOMAIN_RFC6052 = 1 << 2,
+} __attribute__ ((__packed__)) map_domain_flags_e;
 
 /**
  * IP4 reassembly logic:
@@ -382,6 +384,9 @@
   if (d->ip6_prefix_len == 128)
     return clib_net_to_host_u64(d->ip6_prefix.as_u64[1]);
 
+  if (d->flags & MAP_DOMAIN_RFC6052)
+    return (clib_net_to_host_u64(d->ip6_prefix.as_u64[1]) | addr);
+
   /* IPv4 prefix */
   if (d->flags & MAP_DOMAIN_PREFIX)
     return (u64) (addr & (0xFFFFFFFF << d->suffix_shift)) << 16;
@@ -398,9 +403,12 @@
 }
 
 static_always_inline u32
-map_get_ip4 (ip6_address_t *addr)
+map_get_ip4 (ip6_address_t *addr, map_domain_flags_e flags)
 {
-  return clib_host_to_net_u32(clib_net_to_host_u64(addr->as_u64[1]) >> 16);
+  if (flags & MAP_DOMAIN_RFC6052)
+    return clib_host_to_net_u32(clib_net_to_host_u64(addr->as_u64[1]));
+  else
+    return clib_host_to_net_u32(clib_net_to_host_u64(addr->as_u64[1]) >> 16);
 }
 
 /*
@@ -427,16 +435,19 @@
 {
   map_main_t *mm = &map_main;
 
+#ifdef TODO
   /*
    * Disable direct MAP domain lookup on decap, until the security check is updated to verify IPv4 SA.
    * (That's done implicitly when MAP domain is looked up in the IPv4 FIB)
    */
-#ifdef MAP_NONSHARED_DOMAIN_ENABLED
-#error "How can you be sure this domain is not shared?"
-  *map_domain_index = mdi;
-  return pool_elt_at_index(mm->domains, mdi);
+  //#ifdef MAP_NONSHARED_DOMAIN_ENABLED
+  //#error "How can you be sure this domain is not shared?"
 #endif
 
+  *map_domain_index = mdi;
+  return pool_elt_at_index(mm->domains, mdi);
+
+#ifdef TODO
   u32 lbi = ip4_fib_forwarding_lookup(0, addr);
   const dpo_id_t *dpo = load_balance_get_bucket(lbi, 0);
   if (PREDICT_TRUE(dpo->dpoi_type == map_dpo_type ||
@@ -447,6 +458,7 @@
     }
   *error = MAP_ERROR_NO_DOMAIN;
   return NULL;
+#endif
 }
 
 map_ip4_reass_t *
diff --git a/src/vnet/map/map_api.c b/src/vnet/map/map_api.c
index 994a64d..35b82d4 100644
--- a/src/vnet/map/map_api.c
+++ b/src/vnet/map/map_api.c
@@ -56,7 +56,14 @@
   vl_api_map_add_domain_reply_t *rmp;
   int rv = 0;
   u32 index;
-  u8 flags = mp->is_translation ? MAP_DOMAIN_TRANSLATION : 0;
+  u8 flags = 0;
+
+  if (mp->is_translation)
+    flags |= MAP_DOMAIN_TRANSLATION;
+
+  if (mp->is_rfc6052)
+    flags |= MAP_DOMAIN_RFC6052;
+
   rv =
     map_create_domain ((ip4_address_t *) & mp->ip4_prefix, mp->ip4_prefix_len,
 		       (ip6_address_t *) & mp->ip6_prefix, mp->ip6_prefix_len,