LISP - fix bug in ip_prefix_normalize_ip6
[vpp.git] / vnet / vnet / lisp-cp / lisp_types.c
index 9e1cb1f..753b229 100644 (file)
@@ -15,6 +15,9 @@
 
 #include <vnet/lisp-cp/lisp_types.h>
 
+static u16 gid_address_put_no_vni (u8 * b, gid_address_t * gid);
+static u16 gid_address_size_to_put_no_vni (gid_address_t * gid);
+
 typedef u16 (*size_to_write_fct)(void *);
 typedef void * (*cast_fct)(gid_address_t *);
 typedef u16 (*serdes_fct)(u8 *, void *);
@@ -143,8 +146,36 @@ uword
 unformat_ip_prefix (unformat_input_t * input, va_list * args)
 {
   ip_prefix_t * a = va_arg(*args, ip_prefix_t *);
-  return unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a),
-                   &ip_prefix_len(a));
+  if (unformat (input, "%U/%d", unformat_ip_address, &ip_prefix_addr(a),
+                   &ip_prefix_len(a)))
+    {
+      if ((ip_prefix_version(a) == IP4 && 32 < ip_prefix_len(a)) ||
+          (ip_prefix_version(a) == IP6 && 128 < ip_prefix_length(a)))
+        {
+          clib_warning("Prefix length to big: %d!", ip_prefix_len(a));
+          return 0;
+        }
+      ip_prefix_normalize(a);
+    }
+  else
+      return 0;
+  return 1;
+}
+
+uword
+unformat_mac_address (unformat_input_t * input, va_list * args)
+{
+  u8 * a = va_arg(*args, u8 *);
+  return unformat (input, "%x:%x:%x:%x:%x:%x", &a[0], &a[1], &a[2], &a[3],
+                   &a[4], &a[5]);
+}
+
+u8 *
+format_mac_address (u8 * s, va_list * args)
+{
+  u8 * a = va_arg (*args, u8 *);
+  return format (s, "%02x:%02x:%02x:%02x:%02x:%02x",
+                 a[0], a[1], a[2], a[3], a[4], a[5]);
 }
 
 u8 *
@@ -155,7 +186,15 @@ format_gid_address (u8 * s, va_list * args)
   switch (type)
     {
     case GID_ADDR_IP_PREFIX:
-      return format (s, "%U", format_ip_prefix, &gid_address_ippref(a));
+      return format (s, "[%d] %U", gid_address_vni(a), format_ip_prefix,
+                     &gid_address_ippref(a));
+    case GID_ADDR_SRC_DST:
+      return format (s, "[%d] %U|%U", gid_address_vni(a),
+                     format_ip_prefix, &gid_address_sd_source_pref(a),
+                     format_ip_prefix, &gid_address_sd_dest_pref(a));
+    case GID_ADDR_MAC:
+      return format (s, "[%d] %U", gid_address_vni(a), format_mac_address,
+                     &gid_address_mac(a));
     default:
       clib_warning("Can't format gid type %d", type);
       return 0;
@@ -165,11 +204,60 @@ format_gid_address (u8 * s, va_list * args)
 uword
 unformat_gid_address (unformat_input_t * input, va_list * args)
 {
+  u32 vni;
   gid_address_t * a = va_arg(*args, gid_address_t *);
-  if (unformat (input, "%U", unformat_ip_prefix, &gid_address_ippref(a)))
-    gid_address_type(a) = GID_ADDR_IP_PREFIX;
+  u8 mac[6] = {0};
+  ip_prefix_t ippref;
+
+  memset (&ippref, 0, sizeof (ippref));
+  memset(a, 0, sizeof(a[0]));
+
+  if (unformat (input, "%U", unformat_ip_prefix, &ippref))
+    {
+      clib_memcpy (&gid_address_ippref(a), &ippref, sizeof(ippref));
+      gid_address_type(a) = GID_ADDR_IP_PREFIX;
+    }
+  else if (unformat (input, "%U", unformat_mac_address, mac))
+    {
+      clib_memcpy (gid_address_mac(a), mac, sizeof(mac));
+      gid_address_type(a) = GID_ADDR_MAC;
+    }
+  else if (unformat (input, "[%d]", &vni))
+    gid_address_vni(a) = vni;
   else
     return 0;
+
+  return 1;
+}
+
+uword
+unformat_negative_mapping_action (unformat_input_t * input, va_list * args)
+{
+  u32 * action = va_arg(*args, u32 *);
+  u8 * s = 0;
+
+  if (unformat (input, "%s", &s))
+    {
+      int len = vec_len(s);
+      clib_warning ("len = %d", len);
+      if (!strcmp ((char *) s, "no-action"))
+        action[0] = ACTION_NONE;
+      if (!strcmp ((char *) s, "natively-forward"))
+        action[0] = ACTION_NATIVELY_FORWARDED;
+      if (!strcmp ((char *) s, "send-map-request"))
+        action[0] = ACTION_SEND_MAP_REQUEST;
+      else if (!strcmp ((char *) s, "drop"))
+        action[0] = ACTION_DROP;
+      else
+        {
+          clib_warning("invalid action: '%s'", s);
+          action[0] = ACTION_DROP;
+          return 0;
+        }
+    }
+  else
+    return 0;
+
   return 1;
 }
 
@@ -335,16 +423,17 @@ lcaf_hdr_parse (void * offset, lcaf_t * lcaf)
 u16
 vni_parse (u8 * p, void * a)
 {
-  vni_t * v = a;
+  lcaf_t * lcaf = a;
+  gid_address_t * g = a;
   u16 size = 0;
-  vni_vni (v) = clib_net_to_host_u32 ( *(u32 *) p);
-  size += sizeof (u32);
 
-  vni_gid (v) = clib_mem_alloc (sizeof (gid_address_t));
-  gid_address_t * gid = vni_gid (v);
-  memset (gid, 0, sizeof (gid[0]));
+  gid_address_vni (g) = clib_net_to_host_u32 ( *(u32 *) p);
+  size += sizeof (u32);
+  gid_address_vni_mask (g) = lcaf_vni_len (lcaf);
 
-  size += gid_address_parse (p + size, gid);
+  /* nested LCAFs are not supported - it is expected that nested AFI type is
+     IP address */
+  size += gid_address_parse (p + size, g);
   return size;
 }
 
@@ -434,6 +523,79 @@ ip_address_set(ip_address_t * dst, void * src, u8 version)
   ip_addr_version(dst) = version;
 }
 
+static void
+ip_prefix_normalize_ip4 (ip4_address_t * ip4, u8 preflen)
+{
+  u32 mask = ~0;
+
+  ASSERT (ip4);
+
+  if (32 <= preflen)
+   {
+     return;
+   }
+
+  mask = pow2_mask (preflen) << (32 - preflen);
+  mask = clib_host_to_net_u32 (mask);
+  ip4->data_u32 &= mask;
+}
+
+static void
+ip_prefix_normalize_ip6 (ip6_address_t * ip6, u8 preflen)
+{
+  u8 mask_6[16];
+  u32 * m;
+  u8 j ,i0, i1;
+
+  ASSERT (ip6);
+
+  memset (mask_6, 0, sizeof (mask_6));
+
+  if (128 <= preflen)
+   {
+     return;
+   }
+
+  i1 = preflen % 32;
+  i0 = preflen / 32;
+  m = (u32 * ) &mask_6[0];
+
+  for (j = 0; j < i0; j++)
+    {
+      m[j] = ~0;
+    }
+
+  if (i1)
+   {
+     m[i0] = clib_host_to_net_u32 (pow2_mask(i1) << (32 - i1));
+   }
+
+  for (j = 0; j < sizeof(mask_6); j++)
+    {
+      ip6->as_u8[j] &= mask_6[j];
+    }
+}
+
+void
+ip_prefix_normalize(ip_prefix_t * a)
+{
+  u8 preflen = ip_prefix_len(a);
+
+  switch (ip_prefix_version (a))
+  {
+    case IP4:
+      ip_prefix_normalize_ip4(&ip_prefix_v4(a), preflen);
+      break;
+
+    case IP6:
+      ip_prefix_normalize_ip6(&ip_prefix_v6(a), preflen);
+      break;
+
+    default:
+      ASSERT(0);
+  }
+}
+
 void *
 ip_prefix_cast (gid_address_t * a)
 {
@@ -448,9 +610,11 @@ ip_prefix_size_to_write (void * pref)
 }
 
 u16
-ip_prefix_write (u8 * p, void * pref)
+ip_prefix_write (u8 * p, void * gid)
 {
-  ip_prefix_t *a = (ip_prefix_t *) pref;
+  gid_address_t * g = gid;
+  ip_prefix_t *a = &gid_address_ippref (g);
+
   switch (ip_prefix_version (a))
   {
     case IP4:
@@ -485,6 +649,10 @@ int
 ip_prefix_cmp(ip_prefix_t * p1, ip_prefix_t * p2)
 {
   int cmp = 0;
+
+  ip_prefix_normalize (p1);
+  ip_prefix_normalize (p2);
+
   cmp = ip_address_cmp (&ip_prefix_addr(p1), &ip_prefix_addr(p2));
   if (cmp == 0)
   {
@@ -581,9 +749,6 @@ lcaf_write (u8 * p, void * a)
   u16 lcaf_len = (*lcaf_body_length_fcts[type])(lcaf);
   LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len);
 
-  if (LCAF_INSTANCE_ID == type)
-    LCAF_RES2 (h) = lcaf_vni_len(lcaf);
-
   clib_memcpy (p + size, h, sizeof (h[0]));
   size += sizeof (h[0]);
   len = (*lcaf_write_fcts[type])(p + size, lcaf);
@@ -605,12 +770,30 @@ mac_write (u8 * p, void * a)
 u16
 vni_write (u8 * p, void * a)
 {
-  vni_t * v = a;
+  lcaf_hdr_t _h, *h = &_h;
+  gid_address_t * g = a;
   u16 size = 0, len;
 
-  *(u32 *)p = clib_host_to_net_u32 (vni_vni (v));
+  /* put lcaf header */
+  *(u16 *) p = clib_host_to_net_u16 (LISP_AFI_LCAF);
+  size += sizeof (u16);
+  memset (h, 0, sizeof (h[0]));
+  LCAF_TYPE (h) = LCAF_INSTANCE_ID;
+  u16 lcaf_len = sizeof (u32) /* Instance ID size */
+    + gid_address_size_to_put_no_vni (g);
+  LCAF_LENGTH (h) = clib_host_to_net_u16 (lcaf_len);
+  LCAF_RES2 (h) = gid_address_vni_mask (g);
+
+  /* put vni header */
+  clib_memcpy (p + size, h, sizeof (h[0]));
+  size += sizeof (h[0]);
+
+  u32 * afip = (u32 *)(p + size);
+  afip[0] = clib_host_to_net_u32 (gid_address_vni (g));
   size += sizeof (u32);
-  len = gid_address_put (p + size, vni_gid (v));
+
+  /* write the actual address */
+  len = gid_address_put_no_vni (p + size, g);
 
   if ((u16)~0 == len)
     return ~0;
@@ -634,12 +817,11 @@ no_addr_size_to_write (void * a)
 u16
 vni_size_to_write (void * a)
 {
-  vni_t * v =  a;
-  u16 size = sizeof (vni_vni (v));
-
-  gid_address_t * gid = vni_gid (v);
-  return (size + sizeof (lcaf_hdr_t)
-    + gid_address_size_to_put (gid));
+  gid_address_t * g =  a;
+  return (sizeof (u32) /* vni size */
+          + sizeof (u16) /* LCAF AFI field size */
+          + sizeof (lcaf_hdr_t)
+    + gid_address_size_to_put_no_vni (g));
 }
 
 u16
@@ -671,20 +853,38 @@ gid_address_len (gid_address_t *a)
   return (*addr_len_fcts[type])((*cast_fcts[type])(a));
 }
 
-u16
-gid_address_put (u8 * b, gid_address_t * gid)
+static u16
+gid_address_put_no_vni (u8 * b, gid_address_t * gid)
 {
   gid_address_type_t type = gid_address_type (gid);
   return (*write_fcts[type])(b, (*cast_fcts[type])(gid));
 }
 
 u16
-gid_address_size_to_put (gid_address_t * gid)
+gid_address_put (u8 * b, gid_address_t * gid)
+{
+  if (0 != gid_address_vni (gid))
+    return vni_write (b, gid);
+
+  return gid_address_put_no_vni (b, gid);
+}
+
+static u16
+gid_address_size_to_put_no_vni (gid_address_t * gid)
 {
   gid_address_type_t type = gid_address_type (gid);
   return (*size_to_write_fcts[type])((*cast_fcts[type])(gid));
 }
 
+u16
+gid_address_size_to_put (gid_address_t * gid)
+{
+  if (0 != gid_address_vni (gid))
+    return vni_size_to_write (gid);
+
+  return gid_address_size_to_put_no_vni (gid);
+}
+
 void *
 gid_address_cast (gid_address_t * gid, gid_address_type_t type)
 {
@@ -697,6 +897,8 @@ gid_address_copy(gid_address_t * dst, gid_address_t * src)
   gid_address_type_t type = gid_address_type(src);
   (*copy_fcts[type])((*cast_fcts[type])(dst), (*cast_fcts[type])(src));
   gid_address_type(dst) = type;
+  gid_address_vni(dst) = gid_address_vni(src);
+  gid_address_vni_mask(dst) = gid_address_vni_mask(src);
 }
 
 u32
@@ -718,6 +920,8 @@ gid_address_parse (u8 * offset, gid_address_t *a)
   if (!a)
     return 0;
 
+  /* NOTE: since gid_adress_parse may be called by vni_parse, we can't 0
+   * the gid address here */
   afi = clib_net_to_host_u16 (*((u16 *) offset));
 
   switch (afi)
@@ -739,8 +943,8 @@ gid_address_parse (u8 * offset, gid_address_t *a)
       gid_address_ippref_len(a) = 128;
       break;
     case LISP_AFI_LCAF:
-      len = lcaf_parse (offset, a);
       gid_address_type(a) = GID_ADDR_LCAF;
+      len = lcaf_parse (offset, a);
       break;
     case LISP_AFI_MAC:
       len = mac_parse (offset, a);
@@ -788,6 +992,10 @@ gid_address_cmp (gid_address_t * a1, gid_address_t * a2)
     return -1;
   if (gid_address_type(a1) != gid_address_type(a2))
     return -1;
+  if (gid_address_vni(a1) != gid_address_vni(a2))
+    return -1;
+  if (gid_address_vni_mask(a1) != gid_address_vni_mask(a2))
+    return -1;
 
   switch (gid_address_type(a1))
     {