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)
{
&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;
}
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.
*
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)
/* 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;
* 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)
{
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)
{
}
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* */
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))
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;
}
ip_address_t sloc;
u32 ls_index;
- ASSERT (*lcm->pending_map_request_lock);
-
/* if there is already a pending request remember it */
/* *INDENT-OFF* */
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 */
pool_put (lcm->pending_map_requests_pool, pmr);
done:
- lisp_pending_map_request_unlock (lcm);
+ map_records_arg_free (a);
return 0;
}
}
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 *
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);
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;
}
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
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;
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);
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;
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;
}
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;
}
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,
({
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 ();
/* 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,
({
/* *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 */