LISP - fix bug in ip_prefix_normalize_ip6
[vpp.git] / vnet / vnet / lisp-cp / lisp_types.c
index 1608e09..753b229 100644 (file)
@@ -146,8 +146,20 @@ 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
@@ -192,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;
 }
 
@@ -462,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)
 {
@@ -515,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)
   {
@@ -782,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)