X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvnet%2Flisp-cp%2Fcontrol.c;h=fab2a9cba7bc36dba530002f3d8042692a5ea8a2;hb=5908e18faaa613e2f43619da3425a0a859705051;hp=59a45ed8910f72b0aceda35168cbf8adee1118ff;hpb=bae851fcabb9f90a70d00cab5ce55d597cc20166;p=vpp.git diff --git a/src/vnet/lisp-cp/control.c b/src/vnet/lisp-cp/control.c index 59a45ed8910..fab2a9cba7b 100644 --- a/src/vnet/lisp-cp/control.c +++ b/src/vnet/lisp-cp/control.c @@ -30,9 +30,14 @@ #define MAX_VALUE_U24 0xffffff +/* mapping timer control constants (in seconds) */ +#define TIME_UNTIL_REFETCH_OR_DELETE 20 +#define MAPPING_TIMEOUT (((m->ttl) * 60) - TIME_UNTIL_REFETCH_OR_DELETE) + lisp_cp_main_t lisp_control_main; u8 *format_lisp_cp_input_trace (u8 * s, va_list * args); +static void *send_map_request_thread_fn (void *arg); typedef enum { @@ -260,7 +265,7 @@ dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add) } static void -dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) +dp_del_fwd_entry (lisp_cp_main_t * lcm, u32 dst_map_index) { vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a; fwd_entry_t *fe = 0; @@ -433,8 +438,8 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a; gid_address_t *rmt_eid, *lcl_eid; mapping_t *lcl_map, *rmt_map; - u32 sw_if_index; - uword *feip = 0, *dpid; + u32 sw_if_index, **rmts, rmts_idx; + uword *feip = 0, *dpid, *rmts_stored_idxp = 0; fwd_entry_t *fe; u8 type, is_src_dst = 0; int rv; @@ -444,7 +449,7 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) /* remove entry if it already exists */ feip = hash_get (lcm->fwd_entry_by_mapping_index, dst_map_index); if (feip) - dp_del_fwd_entry (lcm, src_map_index, dst_map_index); + dp_del_fwd_entry (lcm, dst_map_index); /* * Determine local mapping and eid @@ -552,6 +557,23 @@ dp_add_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) fe->is_src_dst = is_src_dst; hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index, fe - lcm->fwd_entry_pool); + + /* Add rmt mapping to the vector of adjacent mappings to lcl mapping */ + rmts_stored_idxp = + hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, src_map_index); + if (!rmts_stored_idxp) + { + pool_get (lcm->lcl_to_rmt_adjacencies, rmts); + memset (rmts, 0, sizeof (*rmts)); + rmts_idx = rmts - lcm->lcl_to_rmt_adjacencies; + hash_set (lcm->lcl_to_rmt_adjs_by_lcl_idx, src_map_index, rmts_idx); + } + else + { + rmts_idx = (u32) (*rmts_stored_idxp); + rmts = pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idx); + } + vec_add1 (rmts[0], dst_map_index); } typedef struct @@ -702,6 +724,8 @@ vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a, { lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 mi, *map_indexp, map_index, i; + u32 **rmts = 0, *remote_idxp, rmts_itr, remote_idx; + uword *rmts_idxp; mapping_t *m, *old_map; u32 **eid_indexes; @@ -789,6 +813,21 @@ vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a, m = pool_elt_at_index (lcm->mapping_pool, mi); if (m->local) { + /* Remove adjacencies associated with the local mapping */ + rmts_idxp = hash_get (lcm->lcl_to_rmt_adjs_by_lcl_idx, mi); + if (rmts_idxp) + { + rmts = + pool_elt_at_index (lcm->lcl_to_rmt_adjacencies, rmts_idxp[0]); + vec_foreach (remote_idxp, rmts[0]) + { + dp_del_fwd_entry (lcm, remote_idxp[0]); + } + vec_free (rmts[0]); + pool_put (lcm->lcl_to_rmt_adjacencies, rmts); + hash_unset (lcm->lcl_to_rmt_adjs_by_lcl_idx, mi); + } + u32 k, *lm_indexp; for (k = 0; k < vec_len (lcm->local_mappings_indexes); k++) { @@ -798,6 +837,26 @@ vnet_lisp_map_cache_add_del (vnet_lisp_add_del_mapping_args_t * a, } vec_del1 (lcm->local_mappings_indexes, k); } + else + { + /* Remove remote (if present) from the vectors of lcl-to-rmts + * TODO: Address this in a more efficient way. + */ + /* *INDENT-OFF* */ + pool_foreach (rmts, lcm->lcl_to_rmt_adjacencies, + ({ + vec_foreach_index (rmts_itr, rmts[0]) + { + remote_idx = vec_elt (rmts[0], rmts_itr); + if (mi == remote_idx) + { + vec_del1 (rmts[0], rmts_itr); + break; + } + } + })); + /* *INDENT-ON* */ + } /* remove mapping from dictionary */ gid_dictionary_add_del (&lcm->mapping_index_by_gid, &a->eid, 0, 0); @@ -849,7 +908,11 @@ static void add_l2_arp_bd (BVT (clib_bihash_kv) * kvp, void *arg) { u32 **ht = arg; - u32 bd = (u32) kvp->key[0]; + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); hash_set (ht[0], bd, 0); } @@ -859,8 +922,31 @@ vnet_lisp_l2_arp_bds_get (void) lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 *bds = 0; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_bd, &bds); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_bd, &bds); + return bds; +} + +static void +add_ndp_bd (BVT (clib_bihash_kv) * kvp, void *arg) +{ + u32 **ht = arg; + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + hash_set (ht[0], bd, 0); +} + +u32 * +vnet_lisp_ndp_bds_get (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + u32 *bds = 0; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_bd, &bds); return bds; } @@ -868,15 +954,21 @@ typedef struct { void *vector; u32 bd; -} lisp_add_l2_arp_args_t; +} lisp_add_l2_arp_ndp_args_t; static void add_l2_arp_entry (BVT (clib_bihash_kv) * kvp, void *arg) { - lisp_add_l2_arp_args_t *a = arg; + lisp_add_l2_arp_ndp_args_t *a = arg; lisp_api_l2_arp_entry_t **vector = a->vector, e; - if ((u32) kvp->key[0] == a->bd) + u32 version = (u32) kvp->key[0]; + if (IP6 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) { mac_copy (e.mac, (void *) &kvp->value); e.ip4 = (u32) kvp->key[1]; @@ -889,18 +981,53 @@ vnet_lisp_l2_arp_entries_get_by_bd (u32 bd) { lisp_api_l2_arp_entry_t *entries = 0; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - lisp_add_l2_arp_args_t a; + lisp_add_l2_arp_ndp_args_t a; a.vector = &entries; a.bd = bd; - gid_dict_foreach_l2_arp_entry (&lcm->mapping_index_by_gid, - add_l2_arp_entry, &a); + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_l2_arp_entry, &a); + return entries; +} + +static void +add_ndp_entry (BVT (clib_bihash_kv) * kvp, void *arg) +{ + lisp_add_l2_arp_ndp_args_t *a = arg; + lisp_api_ndp_entry_t **vector = a->vector, e; + + u32 version = (u32) kvp->key[0]; + if (IP4 == version) + return; + + u32 bd = (u32) (kvp->key[0] >> 32); + + if (bd == a->bd) + { + mac_copy (e.mac, (void *) &kvp->value); + clib_memcpy (e.ip6, &kvp->key[1], 16); + vec_add1 (vector[0], e); + } +} + +lisp_api_ndp_entry_t * +vnet_lisp_ndp_entries_get_by_bd (u32 bd) +{ + lisp_api_ndp_entry_t *entries = 0; + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + lisp_add_l2_arp_ndp_args_t a; + + a.vector = &entries; + a.bd = bd; + + gid_dict_foreach_l2_arp_ndp_entry (&lcm->mapping_index_by_gid, + add_ndp_entry, &a); return entries; } int -vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add) +vnet_lisp_add_del_l2_arp_ndp_entry (gid_address_t * key, u8 * mac, u8 is_add) { if (vnet_lisp_enable_disable_status () == 0) { @@ -927,7 +1054,7 @@ vnet_lisp_add_del_l2_arp_entry (gid_address_t * key, u8 * mac, u8 is_add) { if (res == GID_LOOKUP_MISS_L2) { - clib_warning ("ONE ARP entry %U not found - cannot delete!", + clib_warning ("ONE entry %U not found - cannot delete!", format_gid_address, key); return -1; } @@ -1102,7 +1229,7 @@ remove_overlapping_sub_prefixes (lisp_cp_main_t * lcm, gid_address_t * eid, if (vnet_lisp_add_del_adjacency (adj_args)) clib_warning ("failed to del adjacency!"); - vnet_lisp_add_del_mapping (e, 0, 0, 0, 0, 0 /* is add */ , 0, 0); + vnet_lisp_del_mapping (e, NULL); } vec_free (a.eids_to_be_deleted); @@ -1129,24 +1256,19 @@ is_local_ip (lisp_cp_main_t * lcm, ip_address_t * addr) } /** - * Adds/removes/updates mapping. Does not program forwarding. + * Adds/updates mapping. Does not program forwarding. * - * @param eid end-host identifier + * @param a parameters of the new mapping * @param rlocs vector of remote locators - * @param action action for negative map-reply - * @param is_add add mapping if non-zero, delete otherwise - * @param res_map_index the map-index that was created/updated/removed. It is - * set to ~0 if no action is taken. - * @param is_static used for distinguishing between statically learned - remote mappings and mappings obtained from MR + * @param res_map_index index of the newly created mapping + * @param locators_changed indicator if locators were updated in the mapping * @return return code */ int -vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action, - u8 authoritative, u32 ttl, u8 is_add, u8 is_static, - u32 * res_map_index) +vnet_lisp_add_mapping (vnet_lisp_add_del_mapping_args_t * a, + locator_t * rlocs, + u32 * res_map_index, u8 * is_updated) { - vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); u32 mi, ls_index = 0, dst_map_index; @@ -1161,115 +1283,139 @@ vnet_lisp_add_del_mapping (gid_address_t * eid, locator_t * rlocs, u8 action, if (res_map_index) res_map_index[0] = ~0; + if (is_updated) + is_updated[0] = 0; - memset (m_args, 0, sizeof (m_args[0])); memset (ls_args, 0, sizeof (ls_args[0])); ls_args->locators = rlocs; - - mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid); + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &a->eid); old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; - if (is_add) - { - /* check if none of the locators match localy configured address */ - vec_foreach (loc, rlocs) + /* check if none of the locators match localy configured address */ + vec_foreach (loc, rlocs) + { + ip_prefix_t *p = &gid_address_ippref (&loc->address); + if (is_local_ip (lcm, &ip_prefix_addr (p))) { - ip_prefix_t *p = &gid_address_ippref (&loc->address); - if (is_local_ip (lcm, &ip_prefix_addr (p))) - { - clib_warning ("RLOC %U matches a local address!", - format_gid_address, &loc->address); - return VNET_API_ERROR_LISP_RLOC_LOCAL; - } + clib_warning ("RLOC %U matches a local address!", + format_gid_address, &loc->address); + return VNET_API_ERROR_LISP_RLOC_LOCAL; } + } - /* overwrite: if mapping already exists, decide if locators should be - * updated and be done */ - if (old_map && gid_address_cmp (&old_map->eid, eid) == 0) + /* overwrite: if mapping already exists, decide if locators should be + * updated and be done */ + if (old_map && gid_address_cmp (&old_map->eid, &a->eid) == 0) + { + if (!a->is_static && (old_map->is_static || old_map->local)) { - if (!is_static && (old_map->is_static || old_map->local)) - { - /* 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); - return 0; - } - - locator_set_t *old_ls; - - /* update mapping attributes */ - old_map->action = action; - old_map->authoritative = authoritative; - old_map->ttl = ttl; - - old_ls = pool_elt_at_index (lcm->locator_set_pool, - old_map->locator_set_index); - if (compare_locators (lcm, old_ls->locator_indices, - ls_args->locators)) - { - /* set locator-set index to overwrite */ - ls_args->is_add = 1; - ls_args->index = old_map->locator_set_index; - vnet_lisp_add_del_locator_set (ls_args, 0); - if (res_map_index) - res_map_index[0] = mi; - } + /* 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, + &a->eid); + return 0; } - /* new mapping */ - else - { - remove_overlapping_sub_prefixes (lcm, eid, 0 == ls_args->locators); - ls_args->is_add = 1; - ls_args->index = ~0; + locator_set_t *old_ls; - vnet_lisp_add_del_locator_set (ls_args, &ls_index); + /* update mapping attributes */ + old_map->action = a->action; + if (old_map->action != a->action && NULL != is_updated) + is_updated[0] = 1; - /* add mapping */ - gid_address_copy (&m_args->eid, eid); - m_args->is_add = 1; - 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); + old_map->authoritative = a->authoritative; + old_map->ttl = a->ttl; - if (res_map_index) - res_map_index[0] = dst_map_index; + old_ls = pool_elt_at_index (lcm->locator_set_pool, + old_map->locator_set_index); + if (compare_locators (lcm, old_ls->locator_indices, ls_args->locators)) + { + /* set locator-set index to overwrite */ + ls_args->is_add = 1; + ls_args->index = old_map->locator_set_index; + vnet_lisp_add_del_locator_set (ls_args, 0); + if (is_updated) + is_updated[0] = 1; } + if (res_map_index) + res_map_index[0] = mi; } + /* new mapping */ else { - if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0) - { - clib_warning ("cannot delete mapping for eid %U", - format_gid_address, eid); - return -1; - } - - m_args->is_add = 0; - gid_address_copy (&m_args->eid, eid); - m_args->locator_set_index = old_map->locator_set_index; + remove_overlapping_sub_prefixes (lcm, &a->eid, 0 == ls_args->locators); - /* delete mapping associated from map-cache */ - vnet_lisp_map_cache_add_del (m_args, 0); + ls_args->is_add = 1; + ls_args->index = ~0; - ls_args->is_add = 0; - ls_args->index = old_map->locator_set_index; - /* delete locator set */ - vnet_lisp_add_del_locator_set (ls_args, 0); + vnet_lisp_add_del_locator_set (ls_args, &ls_index); - /* delete timer associated to the mapping if any */ - if (old_map->timer_set) - mapping_delete_timer (lcm, mi); + /* add mapping */ + a->is_add = 1; + a->locator_set_index = ls_index; + vnet_lisp_map_cache_add_del (a, &dst_map_index); - /* return old mapping index */ if (res_map_index) - res_map_index[0] = mi; + res_map_index[0] = dst_map_index; + } + + /* success */ + return 0; +} + +/** + * Removes a mapping. Does not program forwarding. + * + * @param eid end-host indetifier + * @param res_map_index index of the removed mapping + * @return return code + */ +int +vnet_lisp_del_mapping (gid_address_t * eid, u32 * res_map_index) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + vnet_lisp_add_del_locator_set_args_t _ls_args, *ls_args = &_ls_args; + mapping_t *old_map; + u32 mi; + + memset (ls_args, 0, sizeof (ls_args[0])); + memset (m_args, 0, sizeof (m_args[0])); + if (res_map_index) + res_map_index[0] = ~0; + + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, eid); + old_map = ((u32) ~ 0 != mi) ? pool_elt_at_index (lcm->mapping_pool, mi) : 0; + + if (old_map == 0 || gid_address_cmp (&old_map->eid, eid) != 0) + { + clib_warning ("cannot delete mapping for eid %U", + format_gid_address, eid); + return -1; } + m_args->is_add = 0; + gid_address_copy (&m_args->eid, eid); + m_args->locator_set_index = old_map->locator_set_index; + + /* delete mapping associated from map-cache */ + vnet_lisp_map_cache_add_del (m_args, 0); + + ls_args->is_add = 0; + ls_args->index = old_map->locator_set_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; + /* success */ return 0; } @@ -1295,7 +1441,7 @@ vnet_lisp_clear_all_remote_adjacencies (void) mapping_t *map = pool_elt_at_index (lcm->mapping_pool, map_indexp[0]); if (!map->local) { - dp_del_fwd_entry (lcm, 0, map_indexp[0]); + dp_del_fwd_entry (lcm, map_indexp[0]); dm_args->is_add = 0; gid_address_copy (&dm_args->eid, &map->eid); @@ -1381,7 +1527,7 @@ vnet_lisp_add_del_adjacency (vnet_lisp_add_del_adjacency_args_t * a) dp_add_fwd_entry (lcm, local_mi, remote_mi); } else - dp_del_fwd_entry (lcm, 0, remote_mi); + dp_del_fwd_entry (lcm, remote_mi); return 0; } @@ -1639,6 +1785,7 @@ get_locator_set_index (vnet_lisp_add_del_locator_set_args_t * a, uword * p) /* find locator-set */ if (a->local) { + ASSERT (a->name); p = hash_get_mem (lcm->locator_set_index_by_name, a->name); } else @@ -2006,7 +2153,7 @@ vnet_lisp_map_register_enable_disable (u8 is_enable) clib_error_t * vnet_lisp_enable_disable (u8 is_enable) { - u32 vni, dp_table; + u32 vni, dp_table, **rmts; clib_error_t *error = 0; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a; @@ -2037,6 +2184,15 @@ vnet_lisp_enable_disable (u8 is_enable) /* clear interface table */ hash_free (lcm->fwd_entry_by_mapping_index); pool_free (lcm->fwd_entry_pool); + /* Clear state tracking rmt-lcl fwd entries */ + /* *INDENT-OFF* */ + pool_foreach(rmts, lcm->lcl_to_rmt_adjacencies, + { + vec_free(rmts[0]); + }); + /* *INDENT-ON* */ + hash_free (lcm->lcl_to_rmt_adjs_by_lcl_idx); + pool_free (lcm->lcl_to_rmt_adjacencies); } /* update global flag */ @@ -2150,7 +2306,9 @@ vnet_lisp_add_del_mreq_itr_rlocs (vnet_lisp_add_del_mreq_itr_rloc_args_t * a) #define foreach_lisp_cp_lookup_error \ _(DROP, "drop") \ _(MAP_REQUESTS_SENT, "map-request sent") \ -_(ARP_REPLY_TX, "ARP replies sent") +_(ARP_REPLY_TX, "ARP replies sent") \ +_(NDP_NEIGHBOR_ADVERTISEMENT_TX, \ + "neighbor advertisement sent") static char *lisp_cp_lookup_error_strings[] = { #define _(sym,string) string, @@ -2169,7 +2327,7 @@ typedef enum typedef enum { LISP_CP_LOOKUP_NEXT_DROP, - LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX, + LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX, LISP_CP_LOOKUP_N_NEXT, } lisp_cp_lookup_next_t; @@ -2544,6 +2702,7 @@ foreach_msmr /* CP output statistics */ #define foreach_lisp_cp_output_error \ _(MAP_REGISTERS_SENT, "map-registers sent") \ +_(MAP_REQUESTS_SENT, "map-requests sent") \ _(RLOC_PROBES_SENT, "rloc-probes sent") static char *lisp_cp_output_error_strings[] = { #define _(sym,string) string, @@ -2869,6 +3028,9 @@ _send_encapsulated_map_request (lisp_cp_main_t * lcm, f->n_vectors = 1; vlib_put_frame_to_node (lcm->vlib_main, next_index, f); + vlib_node_increment_counter (vlib_get_main (), lisp_cp_output_node.index, + LISP_CP_OUTPUT_ERROR_MAP_REQUESTS_SENT, 1); + if (duplicate_pmr) /* if there is a pending request already update it */ { @@ -2983,6 +3145,7 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, { ethernet_header_t *eh; u32 vni = 0; + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; memset (src, 0, sizeof (*src)); memset (dst, 0, sizeof (*dst)); @@ -3030,6 +3193,33 @@ get_src_and_dst_eids_from_buffer (lisp_cp_main_t * lcm, vlib_buffer_t * b, } else { + if (clib_net_to_host_u16 (eh->type) == ETHERNET_TYPE_IP6) + { + ip6_header_t *ip; + ip = (ip6_header_t *) (eh + 1); + + if (IP_PROTOCOL_ICMP6 == ip->protocol) + { + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ndh = ip6_next_header (ip); + if (ndh->icmp.type == ICMP6_neighbor_solicitation) + { + opt = (void *) (ndh + 1); + if ((opt->header.type != + ICMP6_NEIGHBOR_DISCOVERY_OPTION_source_link_layer_address) + || (opt->header.n_data_u64s != 1)) + return; /* source link layer address option not present */ + + gid_address_type (dst) = GID_ADDR_NDP; + gid_address_ndp_bd (dst) = + lisp_get_bd_from_buffer_eth (b); + ip_address_set (&gid_address_arp_ndp_ip (dst), + &ndh->target_address, IP6); + return; + } + } + } + gid_address_type (src) = GID_ADDR_MAC; gid_address_type (dst) = GID_ADDR_MAC; mac_copy (&gid_address_mac (src), eh->src_address); @@ -3065,9 +3255,10 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * from_frame, int overlay) { + icmp6_neighbor_discovery_ethernet_link_layer_address_option_t *opt; u32 *from, *to_next, di, si; lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); - u32 pkts_mapped = 0, next_index; + u32 next_index; uword n_left_from, n_left_to_next; vnet_main_t *vnm = vnet_get_main (); @@ -3088,6 +3279,9 @@ lisp_cp_lookup_inline (vlib_main_t * vm, ethernet_arp_header_t *arp0; ethernet_header_t *eth0; vnet_hw_interface_t *hw_if0; + ethernet_header_t *eh0; + icmp6_neighbor_solicitation_or_advertisement_header_t *ndh; + ip6_header_t *ip0; pi0 = from[0]; from += 1; @@ -3104,41 +3298,70 @@ lisp_cp_lookup_inline (vlib_main_t * vm, if (gid_address_type (&dst) == GID_ADDR_ARP) { mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); - if (GID_LOOKUP_MISS_L2 != mac0) - { - /* send ARP reply */ - - sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; - - hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); - - eth0 = vlib_buffer_get_current (b0); - arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) - + sizeof (*eth0)); - arp0->opcode = - clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); - arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; - clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, - (u8 *) & mac0, 6); - clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, - &gid_address_arp_ip4 (&dst), 4); - - /* Hardware must be ethernet-like. */ - ASSERT (vec_len (hw_if0->hw_address) == 6); - - clib_memcpy (eth0->dst_address, eth0->src_address, 6); - clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); - - b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; - next0 = LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX; - vlib_validate_buffer_enqueue_x1 (vm, node, next_index, - to_next, - n_left_to_next, pi0, - next0); - continue; - } - goto done; + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + /* send ARP reply */ + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + hw_if0 = vnet_get_sup_hw_interface (vnm, sw_if_index0); + + eth0 = vlib_buffer_get_current (b0); + arp0 = (ethernet_arp_header_t *) (((u8 *) eth0) + + sizeof (*eth0)); + arp0->opcode = clib_host_to_net_u16 (ETHERNET_ARP_OPCODE_reply); + arp0->ip4_over_ethernet[1] = arp0->ip4_over_ethernet[0]; + clib_memcpy (arp0->ip4_over_ethernet[0].ethernet, + (u8 *) & mac0, 6); + clib_memcpy (&arp0->ip4_over_ethernet[0].ip4, + &gid_address_arp_ip4 (&dst), 4); + + /* Hardware must be ethernet-like. */ + ASSERT (vec_len (hw_if0->hw_address) == 6); + + clib_memcpy (eth0->dst_address, eth0->src_address, 6); + clib_memcpy (eth0->src_address, hw_if0->hw_address, 6); + + b0->error = node->errors[LISP_CP_LOOKUP_ERROR_ARP_REPLY_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; + } + else if (gid_address_type (&dst) == GID_ADDR_NDP) + { + mac0 = gid_dictionary_lookup (&lcm->mapping_index_by_gid, &dst); + if (GID_LOOKUP_MISS_L2 == mac0) + goto drop; + + sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0; + + eh0 = vlib_buffer_get_current (b0); + ip0 = (ip6_header_t *) (eh0 + 1); + ndh = ip6_next_header (ip0); + int bogus_length; + ip0->dst_address = ip0->src_address; + ip0->src_address = ndh->target_address; + ip0->hop_limit = 255; + opt = (void *) (ndh + 1); + opt->header.type = + ICMP6_NEIGHBOR_DISCOVERY_OPTION_target_link_layer_address; + clib_memcpy (opt->ethernet_address, (u8 *) & mac0, 6); + ndh->icmp.type = ICMP6_neighbor_advertisement; + ndh->advertisement_flags = clib_host_to_net_u32 + (ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED | + ICMP6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERRIDE); + ndh->icmp.checksum = 0; + ndh->icmp.checksum = + ip6_tcp_udp_icmp_compute_checksum (vm, b0, ip0, + &bogus_length); + clib_memcpy (eh0->dst_address, eh0->src_address, 6); + clib_memcpy (eh0->src_address, (u8 *) & mac0, 6); + b0->error = + node->errors + [LISP_CP_LOOKUP_ERROR_NDP_NEIGHBOR_ADVERTISEMENT_TX]; + next0 = LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX; + goto enqueue; } /* if we have remote mapping for destination already in map-chache @@ -3155,7 +3378,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm, /* send map-request */ queue_map_request (&src, &dst, 0 /* smr_invoked */ , 0 /* is_resend */ ); - pkts_mapped++; } else { @@ -3178,11 +3400,12 @@ lisp_cp_lookup_inline (vlib_main_t * vm, /* send map-request */ queue_map_request (&src, &dst, 0 /* smr_invoked */ , 0 /* is_resend */ ); - pkts_mapped++; } - done: + drop: b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP]; + next0 = LISP_CP_LOOKUP_NEXT_DROP; + enqueue: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) { lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0, @@ -3195,7 +3418,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm, } gid_address_free (&dst); gid_address_free (&src); - next0 = LISP_CP_LOOKUP_NEXT_DROP; vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, pi0, next0); @@ -3203,9 +3425,6 @@ lisp_cp_lookup_inline (vlib_main_t * vm, vlib_put_next_frame (vm, node, next_index, n_left_to_next); } - vlib_node_increment_counter (vm, node->node_index, - LISP_CP_LOOKUP_ERROR_MAP_REQUESTS_SENT, - pkts_mapped); return from_frame->n_vectors; } @@ -3253,7 +3472,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip4_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3273,7 +3492,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_ip6_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3293,7 +3512,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_l2_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3313,7 +3532,7 @@ VLIB_REGISTER_NODE (lisp_cp_lookup_nsh_node) = { .next_nodes = { [LISP_CP_LOOKUP_NEXT_DROP] = "error-drop", - [LISP_CP_LOOKUP_NEXT_ARP_REPLY_TX] = "interface-output", + [LISP_CP_LOOKUP_NEXT_ARP_NDP_REPLY_TX] = "interface-output", }, }; /* *INDENT-ON* */ @@ -3372,8 +3591,7 @@ remove_expired_mapping (lisp_cp_main_t * lcm, u32 mi) if (vnet_lisp_add_del_adjacency (adj_args)) clib_warning ("failed to del adjacency!"); - vnet_lisp_add_del_mapping (&m->eid, 0, 0, 0, ~0, 0 /* is_add */ , - 0 /* is_static */ , 0); + vnet_lisp_del_mapping (&m->eid, NULL); mapping_delete_timer (lcm, mi); } @@ -3392,6 +3610,73 @@ mapping_start_expiration_timer (lisp_cp_main_t * lcm, u32 mi, timing_wheel_insert (&lcm->wheel, exp_clock_time, mi); } +static void +process_expired_mapping (lisp_cp_main_t * lcm, u32 mi) +{ + int rv; + vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a; + mapping_t *m = pool_elt_at_index (lcm->mapping_pool, mi); + uword *fei; + fwd_entry_t *fe; + vlib_counter_t c; + u8 have_stats = 0; + + if (m->delete_after_expiration) + { + remove_expired_mapping (lcm, mi); + return; + } + + fei = hash_get (lcm->fwd_entry_by_mapping_index, mi); + if (!fei) + return; + + fe = pool_elt_at_index (lcm->fwd_entry_pool, fei[0]); + + memset (a, 0, sizeof (*a)); + a->rmt_eid = fe->reid; + if (fe->is_src_dst) + a->lcl_eid = fe->leid; + a->vni = gid_address_vni (&fe->reid); + + rv = vnet_lisp_gpe_get_fwd_stats (a, &c); + if (0 == rv) + have_stats = 1; + + if (m->almost_expired) + { + m->almost_expired = 0; /* reset flag */ + if (have_stats) + { + if (m->packets != c.packets) + { + /* mapping is in use, re-fetch */ + map_request_args_t mr_args; + memset (&mr_args, 0, sizeof (mr_args)); + mr_args.seid = fe->leid; + mr_args.deid = fe->reid; + + send_map_request_thread_fn (&mr_args); + } + else + remove_expired_mapping (lcm, mi); + } + else + remove_expired_mapping (lcm, mi); + } + else + { + m->almost_expired = 1; + mapping_start_expiration_timer (lcm, mi, TIME_UNTIL_REFETCH_OR_DELETE); + + if (have_stats) + /* save counter */ + m->packets = c.packets; + else + m->delete_after_expiration = 1; + } +} + static void map_records_arg_free (map_records_arg_t * a) { @@ -3414,6 +3699,7 @@ process_map_reply (map_records_arg_t * a) pending_map_request_t *pmr; u64 *noncep; uword *pmr_index; + u8 is_changed = 0; if (a->is_rloc_probe) goto done; @@ -3429,26 +3715,36 @@ process_map_reply (map_records_arg_t * a) vec_foreach (m, a->mappings) { + vnet_lisp_add_del_mapping_args_t _m_args, *m_args = &_m_args; + memset (m_args, 0, sizeof (m_args[0])); + gid_address_copy (&m_args->eid, &m->eid); + m_args->action = m->action; + m_args->authoritative = m->authoritative; + m_args->ttl = m->ttl; + m_args->is_static = 0; + /* 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); + vnet_lisp_add_mapping (m_args, m->locators, &dst_map_index, &is_changed); if (dst_map_index == (u32) ~ 0) continue; - /* try to program forwarding only if mapping saved or updated */ - vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args; - memset (adj_args, 0, sizeof (adj_args[0])); + if (is_changed) + { + /* try to program forwarding only if mapping saved or updated */ + vnet_lisp_add_del_adjacency_args_t _adj_args, *adj_args = &_adj_args; + memset (adj_args, 0, sizeof (adj_args[0])); - gid_address_copy (&adj_args->leid, &pmr->src); - gid_address_copy (&adj_args->reid, &m->eid); - adj_args->is_add = 1; - if (vnet_lisp_add_del_adjacency (adj_args)) - clib_warning ("failed to add adjacency!"); + gid_address_copy (&adj_args->leid, &pmr->src); + gid_address_copy (&adj_args->reid, &m->eid); + adj_args->is_add = 1; + + if (vnet_lisp_add_del_adjacency (adj_args)) + clib_warning ("failed to add adjacency!"); + } if ((u32) ~ 0 != m->ttl) - mapping_start_expiration_timer (lcm, dst_map_index, m->ttl * 60); + mapping_start_expiration_timer (lcm, dst_map_index, MAPPING_TIMEOUT); } /* remove pending map request entry */ @@ -4056,6 +4352,7 @@ lisp_cp_init (vlib_main_t * vm) lcm->map_register_ttl = MAP_REGISTER_DEFAULT_TTL; lcm->max_expired_map_registers = MAX_EXPIRED_MAP_REGISTERS_DEFAULT; lcm->expired_map_registers = 0; + lcm->transport_protocol = LISP_TRANSPORT_PROTOCOL_UDP; return 0; } @@ -4379,7 +4676,7 @@ send_map_resolver_service (vlib_main_t * vm, u32 *mi = 0; vec_foreach (mi, expired) { - remove_expired_mapping (lcm, mi[0]); + process_expired_mapping (lcm, mi[0]); } _vec_len (expired) = 0; } @@ -4425,6 +4722,26 @@ VLIB_REGISTER_NODE (lisp_retry_service_node,static) = { }; /* *INDENT-ON* */ +u32 +vnet_lisp_set_transport_protocol (u8 protocol) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + + if (protocol < LISP_TRANSPORT_PROTOCOL_UDP || + protocol > LISP_TRANSPORT_PROTOCOL_API) + return VNET_API_ERROR_INVALID_ARGUMENT; + + lcm->transport_protocol = protocol; + return 0; +} + +lisp_transport_protocol_t +vnet_lisp_get_transport_protocol (void) +{ + lisp_cp_main_t *lcm = vnet_lisp_cp_get_main (); + return lcm->transport_protocol; +} + VLIB_INIT_FUNCTION (lisp_cp_init); /*