Fix LISP src/dst based policy 93/3493/5
authorFilip Tehlar <ftehlar@cisco.com>
Mon, 17 Oct 2016 14:20:18 +0000 (16:20 +0200)
committerFlorin Coras <florin.coras@gmail.com>
Tue, 25 Oct 2016 09:07:10 +0000 (09:07 +0000)
Change-Id: Ibcc58ad50e33cd26367fd28f60334e29f45a094c
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
vnet/vnet/lisp-cp/control.c
vnet/vnet/lisp-cp/gid_dictionary.c
vnet/vnet/lisp-cp/gid_dictionary.h
vnet/vnet/lisp-gpe/lisp_gpe_fwd_entry.c

index 8dc4207..3b843a0 100644 (file)
@@ -230,6 +230,8 @@ dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   a->locator_pairs = fe->locator_pairs;
   a->vni = gid_address_vni (&fe->reid);
   gid_address_copy (&a->rmt_eid, &fe->reid);
+  if (fe->is_src_dst)
+    gid_address_copy (&a->lcl_eid, &fe->leid);
 
   vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
 
@@ -386,12 +388,20 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index)
   /* insert data plane forwarding entry */
   a->is_add = 1;
 
-  if (GID_ADDR_SRC_DST == gid_address_type (&dst_map->eid))
+  if (MR_MODE_SRC_DST == lcm->map_request_mode)
     {
-      gid_address_sd_to_flat (&a->rmt_eid, &dst_map->eid,
-                             &gid_address_sd_dst (&dst_map->eid));
-      gid_address_sd_to_flat (&a->lcl_eid, &dst_map->eid,
-                             &gid_address_sd_src (&dst_map->eid));
+      if (GID_ADDR_SRC_DST == gid_address_type (&dst_map->eid))
+       {
+         gid_address_sd_to_flat (&a->rmt_eid, &dst_map->eid,
+                                 &gid_address_sd_dst (&dst_map->eid));
+         gid_address_sd_to_flat (&a->lcl_eid, &dst_map->eid,
+                                 &gid_address_sd_src (&dst_map->eid));
+       }
+      else
+       {
+         gid_address_copy (&a->rmt_eid, &dst_map->eid);
+         gid_address_copy (&a->lcl_eid, &src_map->eid);
+       }
       is_src_dst = 1;
     }
   else
@@ -873,6 +883,85 @@ compare_locators (lisp_cp_main_t * lcm, u32 * old_ls_indexes,
   return 0;
 }
 
+typedef struct
+{
+  u8 is_negative;
+  void *lcm;
+  gid_address_t *eids_to_be_deleted;
+} remove_mapping_args_t;
+
+/**
+ * Callback invoked when a sub-prefix is found
+ */
+static void
+remove_mapping_if_needed (u32 mi, void *arg)
+{
+  u8 delete = 0;
+  remove_mapping_args_t *a = arg;
+  lisp_cp_main_t *lcm = a->lcm;
+  mapping_t *m;
+  locator_set_t *ls;
+
+  m = pool_elt_at_index (lcm->mapping_pool, mi);
+  if (!m)
+    return;
+
+  ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
+
+  if (a->is_negative)
+    {
+      if (0 != vec_len (ls->locator_indices))
+       delete = 1;
+    }
+  else
+    {
+      if (0 == vec_len (ls->locator_indices))
+       delete = 1;
+    }
+
+  if (delete)
+    vec_add1 (a->eids_to_be_deleted, m->eid);
+}
+
+/**
+ * This function searches map cache and looks for IP prefixes that are subset
+ * of the provided one. If such prefix is found depending on 'is_negative'
+ * it does follows:
+ *
+ * 1) if is_negative is true and found prefix points to positive mapping,
+ *    then the mapping is removed
+ * 2) if is_negative is false and found prefix points to negative mapping,
+ *    then the mapping is removed
+ */
+static void
+remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid,
+                                u8 is_negative)
+{
+  gid_address_t *e;
+  remove_mapping_args_t a;
+  memset (&a, 0, sizeof (a));
+
+  /* do this only in src/dst mode ... */
+  if (MR_MODE_SRC_DST != lcm->map_request_mode)
+    return;
+
+  /* ... and  only for IP prefix */
+  if (GID_ADDR_SRC_DST != gid_address_type (eid)
+      || (FID_ADDR_IP_PREF != gid_address_sd_dst_type (eid)))
+    return;
+
+  a.is_negative = is_negative;
+  a.lcm = lcm;
+
+  gid_dict_foreach_subprefix (&lcm->mapping_index_by_gid, eid,
+                             remove_mapping_if_needed, &a);
+
+  vec_foreach (e, a.eids_to_be_deleted)
+    vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0);
+
+  vec_free (a.eids_to_be_deleted);
+}
+
 /**
  * Adds/removes/updates mapping. Does not program forwarding.
  *
@@ -925,7 +1014,7 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
              /* do not overwrite local or static remote mappings */
              clib_warning ("mapping %U rejected due to collision with local "
                            "or static remote mapping!", format_gid_address,
-                           &eid);
+                           eid);
              return 0;
            }
 
@@ -952,6 +1041,8 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
       /* new mapping */
       else
        {
+         remove_overlapping_sub_prefixes (lcm, eid, 0 == ls_args->locators);
+
          ls_args->is_add = 1;
          ls_args->index = ~0;
 
@@ -2843,7 +2934,8 @@ build_encapsulated_map_request (lisp_cp_main_t * lcm,
   /* get rlocs */
   rlocs = build_itr_rloc_list (lcm, loc_set);
 
-  if (MR_MODE_SRC_DST == lcm->map_request_mode)
+  if (MR_MODE_SRC_DST == lcm->map_request_mode
+      && GID_ADDR_SRC_DST != gid_address_type (deid))
     {
       gid_address_t sd;
       memset (&sd, 0, sizeof (sd));
index 2fd9096..0632ef0 100644 (file)
 
 #include <vnet/lisp-cp/gid_dictionary.h>
 
+typedef struct
+{
+  void *arg;
+  ip_prefix_t src;
+  foreach_subprefix_match_cb_t cb;
+  union
+  {
+    gid_ip4_table_t *ip4_table;
+    gid_ip6_table_t *ip6_table;
+  };
+} sfib_entry_arg_t;
+
+static u32 ip4_lookup (gid_ip4_table_t * db, u32 vni, ip_prefix_t * key);
+
+static u32 ip6_lookup (gid_ip6_table_t * db, u32 vni, ip_prefix_t * key);
+
+static void
+foreach_sfib4_subprefix (BVT (clib_bihash_kv) * kvp, void *arg)
+{
+  sfib_entry_arg_t *a = arg;
+  u32 ip = (u32) kvp->key[0];
+  ip4_address_t *mask;
+  u8 plen = ip_prefix_len (&a->src);
+
+  ASSERT (plen >= 0 && plen <= 32);
+  mask = &a->ip4_table->ip4_fib_masks[plen];
+
+  u32 src_ip = clib_host_to_net_u32 (ip_prefix_v4 (&a->src).as_u32);
+  src_ip &= mask->as_u32;
+  if (src_ip == ip)
+    {
+      /* found sub-prefix of src prefix */
+      (a->cb) (kvp->value, a->arg);
+    }
+}
+
+static void
+gid_dict_foreach_ip4_subprefix (gid_dictionary_t * db, u32 vni,
+                               ip_prefix_t * src, ip_prefix_t * dst,
+                               foreach_subprefix_match_cb_t cb, void *arg)
+{
+  u32 sfi;
+  gid_ip4_table_t *sfib4;
+  sfib_entry_arg_t a;
+
+  sfi = ip4_lookup (&db->dst_ip4_table, vni, dst);
+  if (GID_LOOKUP_MISS == sfi)
+    return;
+
+  sfib4 = pool_elt_at_index (db->src_ip4_table_pool, sfi);
+
+  a.arg = arg;
+  a.cb = cb;
+  a.src = src[0];
+  a.ip4_table = sfib4;
+
+  BV (clib_bihash_foreach_key_value_pair) (&sfib4->ip4_lookup_table,
+                                          foreach_sfib4_subprefix, &a);
+}
+
+static void
+foreach_sfib6_subprefix (BVT (clib_bihash_kv) * kvp, void *arg)
+{
+  sfib_entry_arg_t *a = arg;
+  ip6_address_t ip;
+  ip6_address_t *mask;
+  u8 plen = ip_prefix_len (&a->src);
+
+  mask = &a->ip6_table->ip6_fib_masks[plen];
+  ip.as_u64[0] = kvp->key[0];
+  ip.as_u64[1] = kvp->key[1];
+
+  if (ip6_address_is_equal_masked (&ip_prefix_v6 (&a->src), &ip, mask))
+    {
+      /* found sub-prefix of src prefix */
+      (a->cb) (kvp->value, a->arg);
+    }
+}
+
+static void
+gid_dict_foreach_ip6_subprefix (gid_dictionary_t * db, u32 vni,
+                               ip_prefix_t * src, ip_prefix_t * dst,
+                               foreach_subprefix_match_cb_t cb, void *arg)
+{
+  u32 sfi;
+  gid_ip6_table_t *sfib6;
+  sfib_entry_arg_t a;
+
+  sfi = ip6_lookup (&db->dst_ip6_table, vni, dst);
+  if (GID_LOOKUP_MISS == sfi)
+    return;
+
+  sfib6 = pool_elt_at_index (db->src_ip6_table_pool, sfi);
+
+  a.arg = arg;
+  a.cb = cb;
+  a.src = src[0];
+  a.ip6_table = sfib6;
+
+  BV (clib_bihash_foreach_key_value_pair) (&sfib6->ip6_lookup_table,
+                                          foreach_sfib6_subprefix, &a);
+}
+
+void
+gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid,
+                           foreach_subprefix_match_cb_t cb, void *arg)
+{
+  ip_prefix_t *ippref = &gid_address_sd_dst_ippref (eid);
+
+  if (IP4 == ip_prefix_version (ippref))
+    gid_dict_foreach_ip4_subprefix (db, gid_address_vni (eid),
+                                   &gid_address_sd_src_ippref (eid),
+                                   &gid_address_sd_dst_ippref (eid), cb,
+                                   arg);
+  else
+    gid_dict_foreach_ip6_subprefix (db, gid_address_vni (eid),
+                                   &gid_address_sd_src_ippref (eid),
+                                   &gid_address_sd_dst_ippref (eid), cb,
+                                   arg);
+}
+
 static void
 make_mac_sd_key (BVT (clib_bihash_kv) * kv, u32 vni, u8 src_mac[6],
                 u8 dst_mac[6])
@@ -255,6 +376,24 @@ gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst,
     case GID_ADDR_MAC:
       return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (dst),
                            gid_address_mac (dst), gid_address_mac (src));
+    case GID_ADDR_SRC_DST:
+      switch (gid_address_sd_dst_type (dst))
+       {
+       case FID_ADDR_IP_PREF:
+         return ip_sd_lookup (db, gid_address_vni (dst),
+                              &gid_address_sd_dst_ippref (dst),
+                              &gid_address_sd_src_ippref (dst));
+         break;
+       case FID_ADDR_MAC:
+         return mac_sd_lookup (&db->sd_mac_table, gid_address_vni (dst),
+                               gid_address_sd_dst_mac (dst),
+                               gid_address_sd_src_mac (dst));
+         break;
+       default:
+         clib_warning ("Source/Dest address type %d not supported!",
+                       gid_address_sd_dst_type (dst));
+         break;
+       }
     default:
       clib_warning ("address type %d not supported!", gid_address_type (dst));
       break;
index 6544cca..c5aaf8c 100644 (file)
@@ -35,6 +35,8 @@
 #define MAC_LOOKUP_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
 #define MAC_LOOKUP_DEFAULT_HASH_MEMORY_SIZE (32<<20)
 
+typedef void (*foreach_subprefix_match_cb_t) (u32, void *);
+
 typedef struct
 {
   BVT (clib_bihash) ip4_lookup_table;
@@ -103,6 +105,10 @@ u32 gid_dictionary_sd_lookup (gid_dictionary_t * db, gid_address_t * dst,
 
 void gid_dictionary_init (gid_dictionary_t * db);
 
+void
+gid_dict_foreach_subprefix (gid_dictionary_t * db, gid_address_t * eid,
+                           foreach_subprefix_match_cb_t cb, void *arg);
+
 #endif /* VNET_LISP_GPE_GID_DICTIONARY_H_ */
 
 /*
index 75db97d..018fad4 100644 (file)
@@ -69,7 +69,17 @@ ip_dst_fib_add_route (u32 dst_fib_index, const ip_prefix_t * dst_prefix)
                                   "LISP-src for [%d,%U]",
                                   dst_fib_index,
                                   format_fib_prefix, &dst_fib_prefix);
-
+      /*
+       * add src fib default route
+       */
+      fib_prefix_t prefix = {
+       .fp_proto = dst_fib_prefix.fp_proto,
+      };
+      fib_table_entry_special_dpo_add (src_fib_index, &prefix,
+                                      FIB_SOURCE_LISP,
+                                      FIB_ENTRY_FLAG_EXCLUSIVE,
+                                      lisp_cp_dpo_get (fib_proto_to_dpo
+                                                       (dst_fib_prefix.fp_proto)));
       /*
        * create a data-path object to perform the source address lookup
        * in the SRC FIB
@@ -363,11 +373,9 @@ static void
 lisp_gpe_fwd_entry_mk_paths (lisp_gpe_fwd_entry_t * lfe,
                             vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
 {
-  const lisp_gpe_tenant_t *lt;
   lisp_fwd_path_t *path;
   u32 index;
 
-  lt = lisp_gpe_tenant_get (lfe->tenant);
   vec_validate (lfe->paths, vec_len (a->locator_pairs) - 1);
 
   vec_foreach_index (index, a->locator_pairs)
@@ -380,8 +388,7 @@ lisp_gpe_fwd_entry_mk_paths (lisp_gpe_fwd_entry_t * lfe,
     path->lisp_adj =
       lisp_gpe_adjacency_find_or_create_and_lock (&a->locator_pairs
                                                  [index],
-                                                 lt->lt_table_id,
-                                                 lfe->key->vni);
+                                                 a->dp_table, lfe->key->vni);
   }
   vec_sort_with_function (lfe->paths, lisp_gpe_fwd_entry_path_sort);
 }
@@ -529,6 +536,8 @@ lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
       if (rv == 0)
        return value.value;
     }
+  else
+    return value.value;
 
   return lisp_gpe_main.l2_lb_cp_lkup.dpoi_index;
 }
@@ -886,7 +895,7 @@ format_lisp_fwd_path (u8 * s, va_list ap)
 {
   lisp_fwd_path_t *lfp = va_arg (ap, lisp_fwd_path_t *);
 
-  s = format (s, "pirority:%d weight:%d ", lfp->priority, lfp->weight);
+  s = format (s, "priority:%d weight:%d ", lfp->priority, lfp->weight);
   s = format (s, "adj:[%U]\n",
              format_lisp_gpe_adjacency,
              lisp_gpe_adjacency_get (lfp->lisp_adj),