+ vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
+
+ if (duplicate_pmr)
+ /* if there is a pending request already update it */
+ {
+ if (clib_fifo_elts (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
+ {
+ /* remove the oldest nonce */
+ u64 CLIB_UNUSED (tmp), *nonce_del;
+ nonce_del = clib_fifo_head (duplicate_pmr->nonces);
+ hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
+ clib_fifo_sub1 (duplicate_pmr->nonces, tmp);
+ }
+
+ clib_fifo_add1 (duplicate_pmr->nonces, nonce);
+ hash_set (lcm->pending_map_requests_by_nonce, nonce,
+ duplicate_pmr - lcm->pending_map_requests_pool);
+ }
+ else
+ {
+ /* add map-request to pending requests table */
+ pool_get (lcm->pending_map_requests_pool, pmr);
+ memset (pmr, 0, sizeof (*pmr));
+ gid_address_copy (&pmr->src, seid);
+ gid_address_copy (&pmr->dst, deid);
+ clib_fifo_add1 (pmr->nonces, nonce);
+ pmr->is_smr_invoked = is_smr_invoked;
+ reset_pending_mr_counters (pmr);
+ hash_set (lcm->pending_map_requests_by_nonce, nonce,
+ pmr - lcm->pending_map_requests_pool);
+ }
+
+ return 0;
+}
+
+static void
+get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t * dst)
+{
+ ip4_header_t *ip4 = hdr;
+ ip6_header_t *ip6;
+
+ if ((ip4->ip_version_and_header_length & 0xF0) == 0x40)
+ {
+ ip_address_set (src, &ip4->src_address, IP4);
+ ip_address_set (dst, &ip4->dst_address, IP4);
+ }
+ else
+ {
+ ip6 = hdr;
+ ip_address_set (src, &ip6->src_address, IP6);
+ ip_address_set (dst, &ip6->dst_address, IP6);
+ }
+}
+
+static u32
+lisp_get_vni_from_buffer_ip (lisp_cp_main_t * lcm, vlib_buffer_t * b,
+ u8 version)
+{
+ uword *vnip;
+ u32 vni = ~0, table_id = ~0;
+
+ table_id = fib_table_get_table_id_for_sw_if_index ((version ==
+ IP4 ? FIB_PROTOCOL_IP4 :
+ FIB_PROTOCOL_IP6),
+ vnet_buffer
+ (b)->sw_if_index
+ [VLIB_RX]);
+
+ vnip = hash_get (lcm->vni_by_table_id, table_id);
+ if (vnip)
+ vni = vnip[0];
+ else
+ clib_warning ("vrf %d is not mapped to any vni!", table_id);
+
+ return vni;
+}
+
+always_inline u32
+lisp_get_vni_from_buffer_eth (lisp_cp_main_t * lcm, vlib_buffer_t * b)
+{
+ uword *vnip;
+ u32 vni = ~0;
+ u32 sw_if_index0;
+
+ l2input_main_t *l2im = &l2input_main;
+ l2_input_config_t *config;
+ l2_bridge_domain_t *bd_config;
+
+ sw_if_index0 = vnet_buffer (b)->sw_if_index[VLIB_RX];
+ config = vec_elt_at_index (l2im->configs, sw_if_index0);
+ bd_config = vec_elt_at_index (l2im->bd_configs, config->bd_index);
+
+ vnip = hash_get (lcm->vni_by_bd_id, bd_config->bd_id);
+ if (vnip)
+ vni = vnip[0];
+ else
+ clib_warning ("bridge domain %d is not mapped to any vni!",
+ config->bd_index);
+
+ return vni;
+}
+
+always_inline void
+get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b,
+ gid_address_t * src, gid_address_t * dst)
+{
+ u32 vni = 0;
+ u16 type;
+
+ memset (src, 0, sizeof (*src));
+ memset (dst, 0, sizeof (*dst));
+ type = vnet_buffer (b)->lisp.overlay_afi;
+
+ if (LISP_AFI_IP == type || LISP_AFI_IP6 == type)
+ {
+ ip4_header_t *ip;
+ u8 version, preflen;
+
+ gid_address_type (src) = GID_ADDR_IP_PREFIX;
+ gid_address_type (dst) = GID_ADDR_IP_PREFIX;
+
+ ip = vlib_buffer_get_current (b);
+ get_src_and_dst_ip (ip, &gid_address_ip (src), &gid_address_ip (dst));
+
+ version = gid_address_ip_version (src);
+ preflen = ip_address_max_len (version);
+ gid_address_ippref_len (src) = preflen;
+ gid_address_ippref_len (dst) = preflen;
+
+ vni = lisp_get_vni_from_buffer_ip (lcm, b, version);
+ gid_address_vni (dst) = vni;
+ gid_address_vni (src) = vni;
+ }
+ else if (LISP_AFI_MAC == type)
+ {
+ ethernet_header_t *eh;
+
+ eh = vlib_buffer_get_current (b);
+
+ gid_address_type (src) = GID_ADDR_MAC;
+ gid_address_type (dst) = GID_ADDR_MAC;
+ mac_copy (&gid_address_mac (src), eh->src_address);
+ mac_copy (&gid_address_mac (dst), eh->dst_address);
+
+ /* get vni */
+ vni = lisp_get_vni_from_buffer_eth (lcm, b);
+
+ gid_address_vni (dst) = vni;
+ gid_address_vni (src) = vni;
+ }
+}
+
+static uword
+lisp_cp_lookup_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame, int overlay)
+{
+ u32 *from, *to_next_drop, di, si;
+ lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+ u32 pkts_mapped = 0;
+ uword n_left_from, n_left_to_next_drop;
+
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ while (n_left_from > 0)
+ {
+ vlib_get_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
+ to_next_drop, n_left_to_next_drop);
+
+ while (n_left_from > 0 && n_left_to_next_drop > 0)
+ {
+ u32 pi0;
+ vlib_buffer_t *b0;
+ gid_address_t src, dst;
+
+ pi0 = from[0];
+ from += 1;
+ n_left_from -= 1;
+ to_next_drop[0] = pi0;
+ to_next_drop += 1;
+ n_left_to_next_drop -= 1;
+
+ b0 = vlib_get_buffer (vm, pi0);
+ b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
+ vnet_buffer (b0)->lisp.overlay_afi = overlay;
+
+ /* src/dst eid pair */
+ get_src_and_dst_eids_from_buffer (lcm, b0, &src, &dst);
+
+ /* if we have remote mapping for destination already in map-chache
+ add forwarding tunnel directly. If not send a map-request */
+ di = gid_dictionary_sd_lookup (&lcm->mapping_index_by_gid, &dst,
+ &src);
+ if (~0 != di)
+ {
+ mapping_t *m = vec_elt_at_index (lcm->mapping_pool, di);
+ /* send a map-request also in case of negative mapping entry
+ with corresponding action */
+ if (m->action == LISP_SEND_MAP_REQUEST)
+ {
+ /* send map-request */
+ queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
+ 0 /* is_resend */ );
+ pkts_mapped++;
+ }
+ else
+ {
+ si = gid_dictionary_lookup (&lcm->mapping_index_by_gid,
+ &src);
+ if (~0 != si)
+ {
+ dp_add_fwd_entry (lcm, si, di);
+ }
+ }
+ }
+ else
+ {
+ /* send map-request */
+ queue_map_request (&src, &dst, 0 /* smr_invoked */ ,
+ 0 /* is_resend */ );
+ pkts_mapped++;
+ }
+
+ if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
+ sizeof (*tr));
+
+ memset (tr, 0, sizeof (*tr));
+ gid_address_copy (&tr->dst_eid, &dst);
+ ip_address_copy (&tr->map_resolver_ip,
+ &lcm->active_map_resolver);
+ }
+ gid_address_free (&dst);
+ gid_address_free (&src);
+ }
+
+ vlib_put_next_frame (vm, node, LISP_CP_LOOKUP_NEXT_DROP,
+ n_left_to_next_drop);
+ }
+ vlib_node_increment_counter (vm, node->node_index,
+ LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT,
+ pkts_mapped);
+ return from_frame->n_vectors;
+}
+
+static uword
+lisp_cp_lookup_ip4 (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP));
+}
+
+static uword
+lisp_cp_lookup_ip6 (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_IP6));
+}
+
+static uword
+lisp_cp_lookup_l2 (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ return (lisp_cp_lookup_inline (vm, node, from_frame, LISP_AFI_MAC));
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = {
+ .function = lisp_cp_lookup_ip4,
+ .name = "lisp-cp-lookup-ip4",
+ .vector_size = sizeof (u32),
+ .format_trace = format_lisp_cp_lookup_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = LISP_CP_LOOKUP_N_ERROR,
+ .error_strings = lisp_cp_lookup_error_strings,
+
+ .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
+
+ .next_nodes = {
+ [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
+ },
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = {
+ .function = lisp_cp_lookup_ip6,
+ .name = "lisp-cp-lookup-ip6",
+ .vector_size = sizeof (u32),
+ .format_trace = format_lisp_cp_lookup_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = LISP_CP_LOOKUP_N_ERROR,
+ .error_strings = lisp_cp_lookup_error_strings,
+
+ .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
+
+ .next_nodes = {
+ [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
+ },
+};
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = {
+ .function = lisp_cp_lookup_l2,
+ .name = "lisp-cp-lookup-l2",
+ .vector_size = sizeof (u32),
+ .format_trace = format_lisp_cp_lookup_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = LISP_CP_LOOKUP_N_ERROR,
+ .error_strings = lisp_cp_lookup_error_strings,
+
+ .n_next_nodes = LISP_CP_LOOKUP_N_NEXT,
+
+ .next_nodes = {
+ [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop",
+ },
+};
+/* *INDENT-ON* */
+
+/* lisp_cp_input statistics */
+#define foreach_lisp_cp_input_error \
+_(DROP, "drop") \
+_(MAP_REPLIES_RECEIVED, "map-replies received")
+
+static char *lisp_cp_input_error_strings[] = {
+#define _(sym,string) string,
+ foreach_lisp_cp_input_error
+#undef _
+};
+
+typedef enum
+{
+#define _(sym,str) LISP_CP_INPUT_ERROR_##sym,
+ foreach_lisp_cp_input_error
+#undef _
+ LISP_CP_INPUT_N_ERROR,
+} lisp_cp_input_error_t;
+
+typedef enum
+{
+ LISP_CP_INPUT_NEXT_DROP,
+ LISP_CP_INPUT_N_NEXT,
+} lisp_cp_input_next_t;
+
+typedef struct
+{
+ gid_address_t dst_eid;
+ ip4_address_t map_resolver_ip;
+} lisp_cp_input_trace_t;
+
+u8 *
+format_lisp_cp_input_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ CLIB_UNUSED (lisp_cp_input_trace_t * t) =
+ va_arg (*args, lisp_cp_input_trace_t *);
+
+ s = format (s, "LISP-CP-INPUT: TODO");
+ 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 (map_records_arg_t * a)
+{
+ mapping_t *m;
+ lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+ u32 dst_map_index = 0;
+ pending_map_request_t *pmr;
+ u64 *noncep;
+ uword *pmr_index;
+
+ if (a->is_rloc_probe)
+ goto done;
+
+ /* Check pending requests table and 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!", a->nonce);
+ goto done;
+ }
+ pmr = pool_elt_at_index (lcm->pending_map_requests_pool, pmr_index[0]);
+
+ 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);
+
+ /* 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 */
+
+ /* *INDENT-OFF* */
+ clib_fifo_foreach (noncep, pmr->nonces, ({
+ hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
+ }));
+ /* *INDENT-ON* */
+
+ clib_fifo_free (pmr->nonces);
+ pool_put (lcm->pending_map_requests_pool, pmr);
+
+done:
+ map_records_arg_free (a);
+ return 0;
+}
+
+static int
+is_auth_data_valid (map_notify_hdr_t * h, u32 msg_len,
+ lisp_key_type_t key_id, u8 * key)
+{
+ u8 *auth_data = 0;
+ u16 auth_data_len;
+ int result;
+
+ auth_data_len = auth_data_len_by_key_id (key_id);
+ if ((u16) ~ 0 == auth_data_len)
+ {
+ clib_warning ("invalid length for key_id %d!", key_id);
+ return 0;
+ }
+
+ /* save auth data */
+ vec_validate (auth_data, auth_data_len - 1);
+ clib_memcpy (auth_data, MNOTIFY_DATA (h), auth_data_len);
+
+ /* clear auth data */
+ memset (MNOTIFY_DATA (h), 0, auth_data_len);
+
+ /* get hash of the message */
+ unsigned char *code = HMAC (get_encrypt_fcn (key_id), key, vec_len (key),
+ (unsigned char *) h, msg_len, NULL, NULL);
+
+ result = memcmp (code, auth_data, auth_data_len);
+
+ vec_free (auth_data);
+
+ return !result;
+}
+
+static void
+process_map_notify (map_records_arg_t * a)
+{
+ lisp_cp_main_t *lcm = vnet_lisp_cp_get_main ();
+ uword *pmr_index;
+
+ 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!",
+ a->nonce);
+ return;
+ }