LISP: Fix several control plane message issues, VPP-558
[vpp.git] / vnet / vnet / lisp-cp / control.c
index 40ce6b0..de048a4 100644 (file)
@@ -34,6 +34,17 @@ typedef struct
   u8 smr_invoked;
 } map_request_args_t;
 
+typedef struct
+{
+  u64 nonce;
+  u8 is_rloc_probe;
+  mapping_t *mappings;
+} map_records_arg_t;
+
+static int
+lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
+                       gid_address_t * remote_eid, u8 is_add);
+
 u8
 vnet_lisp_get_map_request_mode (void)
 {
@@ -360,6 +371,7 @@ get_locator_pairs (lisp_cp_main_t * lcm, mapping_t * lcl_map,
                                   &gid_address_ip (&rmt->address));
                  ip_address_copy (&pair.lcl_loc, lcl_addr);
                  pair.weight = rmt->weight;
+                 pair.priority = rmt->priority;
                  vec_add1 (locator_pairs[0], pair);
                  found = 1;
                }
@@ -1150,11 +1162,20 @@ remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid,
                              remove_mapping_if_needed, &a);
 
   vec_foreach (e, a.eids_to_be_deleted)
+  {
+    lisp_add_del_adjacency (lcm, 0, e, 0 /* is_add */ );
     vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0);
+  }
 
   vec_free (a.eids_to_be_deleted);
 }
 
+static void
+mapping_delete_timer (lisp_cp_main_t * lcm, u32 mi)
+{
+  timing_wheel_delete (&lcm->wheel, mi);
+}
+
 /**
  * Adds/removes/updates mapping. Does not program forwarding.
  *
@@ -1247,6 +1268,7 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
          m_args->action = action;
          m_args->locator_set_index = ls_index;
          m_args->is_static = is_static;
+         m_args->ttl = ttl;
          vnet_lisp_map_cache_add_del (m_args, &dst_map_index);
 
          if (res_map_index)
@@ -1274,6 +1296,10 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action,
       /* delete locator set */
       vnet_lisp_add_del_locator_set (ls_args, 0);
 
+      /* delete timer associated to the mapping if any */
+      if (old_map->timer_set)
+       mapping_delete_timer (lcm, mi);
+
       /* return old mapping index */
       if (res_map_index)
        res_map_index[0] = mi;
@@ -1334,7 +1360,7 @@ cleanup:
  * Note that adjacencies are not stored, they only result in forwarding entries
  * being created.
  */
-int
+static int
 lisp_add_del_adjacency (lisp_cp_main_t * lcm, gid_address_t * local_eid,
                        gid_address_t * remote_eid, u8 is_add)
 {
@@ -3502,13 +3528,18 @@ send_rloc_probe (lisp_cp_main_t * lcm, gid_address_t * deid,
 static int
 send_rloc_probes (lisp_cp_main_t * lcm)
 {
+  u8 lprio = 0;
   mapping_t *lm;
   fwd_entry_t *e;
+  locator_pair_t *lp;
   u32 si;
 
   /* *INDENT-OFF* */
   pool_foreach (e, lcm->fwd_entry_pool,
   {
+    if (vec_len (e->locator_pairs) == 0)
+      continue;
+
     si = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &e->leid);
     if (~0 == si)
       {
@@ -3518,16 +3549,19 @@ send_rloc_probes (lisp_cp_main_t * lcm)
       }
     lm = pool_elt_at_index (lcm->mapping_pool, si);
 
-    if (vec_len (e->locator_pairs) == 0)
-      continue;
+    /* get the best (lowest) priority */
+    lprio = e->locator_pairs[0].priority;
 
-    /* TODO send rloc-probe for each pair? for now assume there is only one
-      pair at a time */
-    locator_pair_t *lp = &e->locator_pairs[0];
+    /* send rloc-probe for pair(s) with the best remote locator priority */
+    vec_foreach (lp, e->locator_pairs)
+      {
+        if (lp->priority != lprio)
+          break;
 
-    /* get first remote locator */
-    send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
-                     &lp->rmt_loc);
+        /* get first remote locator */
+        send_rloc_probe (lcm, &e->reid, lm->locator_set_index, &lp->lcl_loc,
+                         &lp->rmt_loc);
+      }
   });
   /* *INDENT-ON* */
 
@@ -3544,6 +3578,7 @@ send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
   u64 nonce = 0;
   u32 next_index, *to_next;
   ip_address_t *ms = 0;
+  mapping_t *records, *r, *g;
 
   // TODO: support multiple map servers and do election
   if (0 == vec_len (lcm->map_servers))
@@ -3558,38 +3593,44 @@ send_map_register (lisp_cp_main_t * lcm, u8 want_map_notif)
       return -1;
     }
 
-  /* TODO build mapping records grouped by secret key and send one map-register
-     per group. Currently only one secret key per vpp is supported  */
-  mapping_t *records = build_map_register_record_list (lcm);
+  records = build_map_register_record_list (lcm);
   if (!records)
     return -1;
 
-  u8 *key = records[0].key;
-  u8 key_id = records[0].key_id;
-
-  if (!key)
-    return 0;                  /* no secret key -> map-register cannot be sent */
+  vec_foreach (r, records)
+  {
+    u8 *key = r->key;
+    u8 key_id = r->key_id;
+
+    if (!key)
+      continue;                        /* no secret key -> map-register cannot be sent */
+
+    g = 0;
+    // TODO: group mappings that share common key
+    vec_add1 (g, r[0]);
+    b = build_map_register (lcm, &sloc, ms, &nonce, want_map_notif, g,
+                           key_id, key, &bi);
+    vec_free (g);
+    if (!b)
+      continue;
 
-  b = build_map_register (lcm, &sloc, ms, &nonce, want_map_notif, records,
-                         key_id, key, &bi);
-  if (!b)
-    return -1;
-  free_map_register_records (records);
+    vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
 
-  vnet_buffer (b)->sw_if_index[VLIB_TX] = 0;
+    next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
+      ip4_lookup_node.index : ip6_lookup_node.index;
 
-  next_index = (ip_addr_version (&lcm->active_map_resolver) == IP4) ?
-    ip4_lookup_node.index : ip6_lookup_node.index;
+    f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
 
-  f = vlib_get_frame_to_node (lcm->vlib_main, next_index);
+    /* Enqueue the packet */
+    to_next = vlib_frame_vector_args (f);
+    to_next[0] = bi;
+    f->n_vectors = 1;
+    vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
 
-  /* Enqueue the packet */
-  to_next = vlib_frame_vector_args (f);
-  to_next[0] = bi;
-  f->n_vectors = 1;
-  vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
+    hash_set (lcm->map_register_messages_by_nonce, nonce, 0);
+  }
+  free_map_register_records (records);
 
-  hash_set (lcm->map_register_messages_by_nonce, nonce, 0);
   return 0;
 }
 
@@ -3614,8 +3655,6 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm,
   ip_address_t sloc;
   u32 ls_index;
 
-  ASSERT (*lcm->pending_map_request_lock);
-
   /* if there is already a pending request remember it */
 
   /* *INDENT-OFF* */
@@ -4067,67 +4106,83 @@ format_lisp_cp_input_trace (u8 * s, va_list * args)
   return s;
 }
 
+static void
+remove_expired_mapping (lisp_cp_main_t * lcm, u32 mi)
+{
+  mapping_t *m;
+
+  m = pool_elt_at_index (lcm->mapping_pool, mi);
+  lisp_add_del_adjacency (lcm, 0, &m->eid, 0 /* is_add */ );
+  vnet_lisp_add_del_mapping (&m->eid, 0, 0, 0, ~0, 0 /* is_add */ ,
+                            0 /* is_static */ , 0);
+  mapping_delete_timer (lcm, mi);
+}
+
+static void
+mapping_start_expiration_timer (lisp_cp_main_t * lcm, u32 mi,
+                               f64 expiration_time)
+{
+  mapping_t *m;
+  u64 now = clib_cpu_time_now ();
+  u64 cpu_cps = lcm->vlib_main->clib_time.clocks_per_second;
+  u64 exp_clock_time = now + expiration_time * cpu_cps;
+
+  m = pool_elt_at_index (lcm->mapping_pool, mi);
+
+  m->timer_set = 1;
+  timing_wheel_insert (&lcm->wheel, exp_clock_time, mi);
+}
+
+static void
+map_records_arg_free (map_records_arg_t * a)
+{
+  mapping_t *m;
+  vec_foreach (m, a->mappings)
+  {
+    vec_free (m->locators);
+    gid_address_free (&m->eid);
+  }
+
+  clib_mem_free (a);
+}
+
 void *
-process_map_reply (void *arg)
+process_map_reply (map_records_arg_t * a)
 {
+  mapping_t *m;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
-  vlib_buffer_t *b = arg;
-  u32 len = 0, i, ttl, dst_map_index = 0;
-  void *h;
+  u32 dst_map_index = 0;
   pending_map_request_t *pmr;
-  locator_t probed;
-  map_reply_hdr_t *mrep_hdr;
-  u64 nonce, *noncep;
-  gid_address_t deid;
+  u64 *noncep;
   uword *pmr_index;
-  u8 authoritative, action;
-  locator_t *locators = 0, *loc;
-
-  mrep_hdr = vlib_buffer_get_current (b);
 
-  lisp_pending_map_request_lock (lcm);
+  if (a->is_rloc_probe)
+    goto done;
 
   /* Check pending requests table and nonce */
-  nonce = MREP_NONCE (mrep_hdr);
-  pmr_index = hash_get (lcm->pending_map_requests_by_nonce, nonce);
+  pmr_index = hash_get (lcm->pending_map_requests_by_nonce, a->nonce);
   if (!pmr_index)
     {
-      clib_warning ("No pending map-request entry with nonce %lu!", nonce);
+      clib_warning ("No pending map-request entry with nonce %lu!", a->nonce);
       goto done;
     }
   pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
 
-  vlib_buffer_pull (b, sizeof (*mrep_hdr));
-
-  for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
-    {
-      h = vlib_buffer_get_current (b);
-      ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
-      action = MAP_REC_ACTION (h);
-      authoritative = MAP_REC_AUTH (h);
-
-      len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
-      if (len == ~0)
-       {
-         clib_warning ("Failed to parse mapping record!");
-         vec_foreach (loc, locators)
-         {
-           locator_free (loc);
-         }
-         vec_free (locators);
-         goto done;
-       }
-
-      /* insert/update mappings cache */
-      vnet_lisp_add_del_mapping (&deid, locators, action, authoritative, ttl,
-                                1, 0 /* is_static */ , &dst_map_index);
-
-      /* try to program forwarding only if mapping saved or updated */
-      if ((u32) ~ 0 != dst_map_index)
-       lisp_add_del_adjacency (lcm, &pmr->src, &deid, 1);
+  vec_foreach (m, a->mappings)
+  {
+    /* insert/update mappings cache */
+    vnet_lisp_add_del_mapping (&m->eid, m->locators, m->action,
+                              m->authoritative, m->ttl,
+                              1, 0 /* is_static */ , &dst_map_index);
 
-      vec_free (locators);
-    }
+    /* try to program forwarding only if mapping saved or updated */
+    if ((u32) ~ 0 != dst_map_index)
+      {
+       lisp_add_del_adjacency (lcm, &pmr->src, &m->eid, 1);
+       if ((u32) ~ 0 != m->ttl)
+         mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60);
+      }
+  }
 
   /* remove pending map request entry */
 
@@ -4141,7 +4196,7 @@ process_map_reply (void *arg)
   pool_put (lcm->pending_map_requests_pool, pmr);
 
 done:
-  lisp_pending_map_request_unlock (lcm);
+  map_records_arg_free (a);
   return 0;
 }
 
@@ -4179,83 +4234,151 @@ is_auth_data_valid (map_notify_hdr_t * h, u32 msg_len,
 }
 
 static void
-process_map_notify (vlib_main_t * vm, lisp_cp_main_t * lcm, vlib_buffer_t * b)
+process_map_notify (map_records_arg_t * a)
 {
-  lisp_key_type_t key_id;
-  gid_address_t deid;
-  mapping_t *m;
-  u32 i, mi, len;
-  map_notify_hdr_t *mnotif_hdr;
-  u64 nonce;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
   uword *pmr_index;
-  locator_t *locators = 0, *loc;
-  u16 auth_data_len = 0;
 
-  mnotif_hdr = vlib_buffer_get_current (b);
-  vlib_buffer_pull (b, sizeof (*mnotif_hdr));
-  memset (&deid, 0, sizeof (deid));
-
-  nonce = MNOTIFY_NONCE (mnotif_hdr);
-  key_id = clib_net_to_host_u16 (MNOTIFY_KEY_ID (mnotif_hdr));
-  auth_data_len = auth_data_len_by_key_id (key_id);
-
-  pmr_index = hash_get (lcm->map_register_messages_by_nonce, nonce);
+  pmr_index = hash_get (lcm->map_register_messages_by_nonce, a->nonce);
   if (!pmr_index)
     {
-      clib_warning ("No pending map-register entry with nonce %lu!", nonce);
+      clib_warning ("No pending map-register entry with nonce %lu!",
+                   a->nonce);
       return;
     }
 
-  /* advance buffer by authentication data */
-  vlib_buffer_pull (b, auth_data_len);
+  map_records_arg_free (a);
+  hash_unset (lcm->map_register_messages_by_nonce, a->nonce);
+}
+
+static mapping_t *
+get_mapping (lisp_cp_main_t * lcm, gid_address_t * e)
+{
+  u32 mi;
+
+  mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, e);
+  if (~0 == mi)
+    {
+      clib_warning ("eid %U not found in map-cache!", unformat_gid_address,
+                   e);
+      return 0;
+    }
+  return pool_elt_at_index (lcm->mapping_pool, mi);
+}
+
+/**
+ * When map-notify is received it is necessary that all EIDs in the record
+ * list share common key. The key is then used to verify authentication
+ * data in map-notify message.
+ */
+static int
+map_record_integrity_check (lisp_cp_main_t * lcm, mapping_t * maps,
+                           u32 key_id, u8 ** key_out)
+{
+  u32 i, len = vec_len (maps);
+  mapping_t *m;
+
+  /* get key of the first mapping */
+  m = get_mapping (lcm, &maps[0].eid);
+  if (!m || !m->key)
+    return -1;
+
+  key_out[0] = m->key;
+
+  for (i = 1; i < len; i++)
+    {
+      m = get_mapping (lcm, &maps[i].eid);
+      if (!m || !m->key)
+       return -1;
+
+      if (key_id != m->key_id || vec_cmp (m->key, key_out[0]))
+       {
+         clib_warning ("keys does not match! %v, %v", key_out[0], m->key);
+         return -1;
+       }
+    }
+  return 0;
+}
+
+static int
+parse_map_records (vlib_buffer_t * b, map_records_arg_t * a, u8 count)
+{
+  locator_t *locators = 0;
+  u32 i, len;
+  gid_address_t deid;
+  mapping_t m;
+  locator_t *loc;
 
   /* parse record eid */
-  for (i = 0; i < MNOTIFY_REC_COUNT (mnotif_hdr); i++)
+  for (i = 0; i < count; i++)
     {
       len = lisp_msg_parse_mapping_record (b, &deid, &locators, NULL);
       if (len == ~0)
        {
          clib_warning ("Failed to parse mapping record!");
-         vec_foreach (loc, locators)
-         {
-           locator_free (loc);
-         }
+         vec_foreach (loc, locators) locator_free (loc);
          vec_free (locators);
-         return;
+         return -1;
        }
 
-      vec_free (locators);
+      m.locators = locators;
+      gid_address_copy (&m.eid, &deid);
+      vec_add1 (a->mappings, m);
     }
 
-  /* lookup eid in map-cache */
-  mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &deid);
-  if (~0 == mi)
+  return 0;
+}
+
+static map_records_arg_t *
+parse_map_notify (vlib_buffer_t * b)
+{
+  int rc = 0;
+  map_notify_hdr_t *mnotif_hdr;
+  lisp_key_type_t key_id;
+  lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  u8 *key = 0;
+  gid_address_t deid;
+  u16 auth_data_len = 0;
+  u8 record_count;
+  map_records_arg_t *a = clib_mem_alloc (sizeof (*a));
+
+  memset (a, 0, sizeof (*a));
+  mnotif_hdr = vlib_buffer_get_current (b);
+  vlib_buffer_pull (b, sizeof (*mnotif_hdr));
+  memset (&deid, 0, sizeof (deid));
+
+  a->nonce = MNOTIFY_NONCE (mnotif_hdr);
+  key_id = clib_net_to_host_u16 (MNOTIFY_KEY_ID (mnotif_hdr));
+  auth_data_len = auth_data_len_by_key_id (key_id);
+
+  /* advance buffer by authentication data */
+  vlib_buffer_pull (b, auth_data_len);
+
+  record_count = MNOTIFY_REC_COUNT (mnotif_hdr);
+  rc = parse_map_records (b, a, record_count);
+  if (rc != 0)
     {
-      clib_warning ("eid %U not found in map-cache!", unformat_gid_address,
-                   &deid);
-      return;
+      map_records_arg_free (a);
+      return 0;
     }
 
-  m = pool_elt_at_index (lcm->mapping_pool, mi);
-  if (!m->key)
+  rc = map_record_integrity_check (lcm, a->mappings, key_id, &key);
+  if (rc != 0)
     {
-      clib_warning ("There is no secret key assigned to %U!",
-                   format_gid_address, &deid);
-      goto done;
+      map_records_arg_free (a);
+      return 0;
     }
 
   /* verify authentication data */
   if (!is_auth_data_valid (mnotif_hdr, vlib_buffer_get_tail (b)
-                          - (u8 *) mnotif_hdr, m->key_id, m->key))
+                          - (u8 *) mnotif_hdr, key_id, key))
     {
       clib_warning ("Map-notify auth data verification failed for nonce %lu!",
-                   nonce);
-      goto done;
+                   a->nonce);
+      map_records_arg_free (a);
+      return 0;
     }
-
-done:
-  hash_unset (lcm->map_register_messages_by_nonce, nonce);
-  gid_address_free (&deid);
+  return a;
 }
 
 static vlib_buffer_t *
@@ -4347,7 +4470,7 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
   gid_address_t src, dst;
   u64 nonce;
   u32 i, len = 0;
-  gid_address_t *itr_rlocs = 0, *rloc;
+  gid_address_t *itr_rlocs = 0;
 
   mreq_hdr = vlib_buffer_get_current (b);
 
@@ -4389,10 +4512,8 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
   if (len == ~0)
     return;
 
-  /* for now we don't do anything with the itr's rlocs */
-  len =
-    lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
-                             MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
+  len = lisp_msg_parse_itr_rlocs (b, &itr_rlocs,
+                                 MREQ_ITR_RLOC_COUNT (mreq_hdr) + 1);
   if (len == ~0)
     return;
 
@@ -4432,24 +4553,62 @@ process_map_request (vlib_main_t * vm, lisp_cp_main_t * lcm,
     }
 
 done:
-  vec_foreach (rloc, itr_rlocs)
-  {
-    gid_address_free (rloc);
-  }
+  vec_free (itr_rlocs);
 }
 
-static void
-queue_map_reply (vlib_buffer_t * b)
+static map_records_arg_t *
+parse_map_reply (vlib_buffer_t * b)
 {
-  vlib_buffer_t *a = clib_mem_alloc (sizeof (a[0]) + b->current_length);
+  locator_t probed;
+  gid_address_t deid;
+  void *h;
+  u32 i, len = 0;
+  mapping_t m;
+  map_reply_hdr_t *mrep_hdr;
+  map_records_arg_t *a = clib_mem_alloc (sizeof (*a));
+  memset (a, 0, sizeof (*a));
+  locator_t *locators;
+
+  mrep_hdr = vlib_buffer_get_current (b);
+  a->nonce = MREP_NONCE (mrep_hdr);
+  a->is_rloc_probe = MREP_RLOC_PROBE (mrep_hdr);
+  vlib_buffer_pull (b, sizeof (*mrep_hdr));
 
-  clib_memcpy (a->data, b->data + b->current_data, b->current_length);
-  a->current_length = b->current_length;
-  a->current_data = 0;
+  for (i = 0; i < MREP_REC_COUNT (mrep_hdr); i++)
+    {
+      memset (&m, 0, sizeof (m));
+      locators = 0;
+      h = vlib_buffer_get_current (b);
 
-  vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a[0])
-                              + a->current_length);
-  clib_mem_free (a);
+      m.ttl = clib_net_to_host_u32 (MAP_REC_TTL (h));
+      m.action = MAP_REC_ACTION (h);
+      m.authoritative = MAP_REC_AUTH (h);
+
+      len = lisp_msg_parse_mapping_record (b, &deid, &locators, &probed);
+      if (len == ~0)
+       {
+         clib_warning ("Failed to parse mapping record!");
+         map_records_arg_free (a);
+         return 0;
+       }
+
+      m.locators = locators;
+      gid_address_copy (&m.eid, &deid);
+      vec_add1 (a->mappings, m);
+    }
+  return a;
+}
+
+static void
+queue_map_reply_for_processing (map_records_arg_t * a)
+{
+  vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a));
+}
+
+static void
+queue_map_notify_for_processing (map_records_arg_t * a)
+{
+  vl_api_rpc_call_main_thread (process_map_notify, (u8 *) a, sizeof (a[0]));
 }
 
 static uword
@@ -4459,6 +4618,7 @@ lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
   u32 n_left_from, *from, *to_next_drop;
   lisp_msg_type_e type;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+  map_records_arg_t *a;
 
   from = vlib_frame_vector_args (from_frame);
   n_left_from = from_frame->n_vectors;
@@ -4488,13 +4648,17 @@ lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
          switch (type)
            {
            case LISP_MAP_REPLY:
-             queue_map_reply (b0);
+             a = parse_map_reply (b0);
+             if (a)
+               queue_map_reply_for_processing (a);
              break;
            case LISP_MAP_REQUEST:
              process_map_request (vm, lcm, b0);
              break;
            case LISP_MAP_NOTIFY:
-             process_map_notify (vm, lcm, b0);
+             a = parse_map_notify (b0);
+             if (a)
+               queue_map_notify_for_processing (a);
              break;
            default:
              clib_warning ("Unsupported LISP message type %d", type);
@@ -4551,10 +4715,6 @@ lisp_cp_init (vlib_main_t * vm)
   lcm->lisp_pitr = 0;
   memset (&lcm->active_map_resolver, 0, sizeof (lcm->active_map_resolver));
 
-  lcm->pending_map_request_lock =
-    clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
-
-  lcm->pending_map_request_lock[0] = 0;
   gid_dictionary_init (&lcm->mapping_index_by_gid);
   lcm->do_map_resolver_election = 1;
   lcm->map_request_mode = MR_MODE_DST_ONLY;
@@ -4568,6 +4728,8 @@ lisp_cp_init (vlib_main_t * vm)
   udp_register_dst_port (vm, UDP_DST_PORT_lisp_cp6,
                         lisp_cp_input_node.index, 0 /* is_ip4 */ );
 
+  u64 now = clib_cpu_time_now ();
+  timing_wheel_init (&lcm->wheel, now, vm->clib_time.clocks_per_second);
   return 0;
 }
 
@@ -4578,16 +4740,9 @@ send_map_request_thread_fn (void *arg)
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
 
   if (a->is_resend)
-    /* if resending, we already have the lock */
     resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
   else
-    {
-      /* get lock before sending map-request */
-      lisp_pending_map_request_lock (lcm);
-      send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
-      lisp_pending_map_request_unlock (lcm);
-    }
-
+    send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
 
   return 0;
 }
@@ -4669,8 +4824,6 @@ remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
   pending_map_request_t *pmr;
   u32 *to_be_removed = 0, *pmr_index;
 
-  ASSERT (*lcm->pending_map_request_lock);
-
   /* *INDENT-OFF* */
   pool_foreach (pmr, lcm->pending_map_requests_pool,
   ({
@@ -4734,6 +4887,7 @@ static uword
 send_map_resolver_service (vlib_main_t * vm,
                           vlib_node_runtime_t * rt, vlib_frame_t * f)
 {
+  u32 *expired = 0;
   f64 period = 2.0;
   pending_map_request_t *pmr;
   lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
@@ -4745,8 +4899,6 @@ send_map_resolver_service (vlib_main_t * vm,
       /* currently no signals are expected - just wait for clock */
       (void) vlib_process_get_events (vm, 0);
 
-      lisp_pending_map_request_lock (lcm);
-
       /* *INDENT-OFF* */
       pool_foreach (pmr, lcm->pending_map_requests_pool,
       ({
@@ -4756,10 +4908,22 @@ send_map_resolver_service (vlib_main_t * vm,
       /* *INDENT-ON* */
 
       remove_dead_pending_map_requests (lcm);
-      lisp_pending_map_request_unlock (lcm);
 
       update_map_register (lcm, period);
       update_rloc_probing (lcm, period);
+
+      u64 now = clib_cpu_time_now ();
+
+      expired = timing_wheel_advance (&lcm->wheel, now, expired, 0);
+      if (vec_len (expired) > 0)
+       {
+         u32 *mi = 0;
+         vec_foreach (mi, expired)
+         {
+           remove_expired_mapping (lcm, mi[0]);
+         }
+         _vec_len (expired) = 0;
+       }
     }
 
   /* unreachable */