* limitations under the License.
*/
+#include <vlibmemory/api.h>
#include <vnet/lisp-cp/control.h>
#include <vnet/lisp-cp/packets.h>
#include <vnet/lisp-cp/lisp_msg_serdes.h>
#include <vnet/lisp-gpe/lisp_gpe.h>
+typedef struct
+{
+ u8 is_resend;
+ gid_address_t seid;
+ gid_address_t deid;
+ u8 smr_invoked;
+} map_request_args_t;
+
+static int
+queue_map_request (gid_address_t * seid, gid_address_t * deid,
+ u8 smr_invoked, u8 is_resend);
+
ip_interface_address_t *
ip_interface_get_first_interface_address (ip_lookup_main_t *lm, u32 sw_if_index,
u8 loop)
}
static int
-dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_add)
+dp_add_del_iface (lisp_cp_main_t * lcm, u32 vni, u8 is_l2, u8 is_add)
{
- uword * table_id, * intf;
+ uword * dp_table, * intf;
vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
- table_id = hash_get(lcm->table_id_by_vni, vni);
+ if (!is_l2)
+ {
+ dp_table = hash_get(lcm->table_id_by_vni, vni);
- if (!table_id)
+ if (!dp_table)
+ {
+ clib_warning("vni %d not associated to a vrf!", vni);
+ return VNET_API_ERROR_INVALID_VALUE;
+ }
+ }
+ else
{
- clib_warning ("vni %d not associated to a vrf!", vni);
- return VNET_API_ERROR_INVALID_VALUE;
+ dp_table = hash_get(lcm->bd_id_by_vni, vni);
+ if (!dp_table)
+ {
+ clib_warning("vni %d not associated to a bridge domain!", vni);
+ return VNET_API_ERROR_INVALID_VALUE;
+ }
}
- intf = hash_get(lcm->dp_intf_by_vni, vni);
+ intf = hash_get(is_l2 ? lcm->l2_dp_intf_by_vni :lcm->dp_intf_by_vni, vni);
/* enable/disable data-plane interface */
if (is_add)
{
ai->is_add = 1;
ai->vni = vni;
- ai->table_id = table_id[0];
+ ai->is_l2 = is_l2;
+ ai->dp_table = dp_table[0];
+
vnet_lisp_gpe_add_del_iface (ai, 0);
/* keep track of vnis for which interfaces have been created */
ai->is_add = 0;
ai->vni = vni;
- ai->table_id = table_id[0];
+ ai->dp_table = dp_table[0];
vnet_lisp_gpe_add_del_iface (ai, 0);
hash_unset(lcm->dp_intf_by_vni, vni);
}
/* delete dp fwd entry */
u32 sw_if_index;
a->is_add = 0;
- a->dlocator = fe->dst_loc;
- a->slocator = fe->src_loc;
- a->vni = gid_address_vni(&a->deid);
- gid_address_copy(&a->deid, &fe->deid);
+ a->locator_pairs = fe->locator_pairs;
+ a->vni = gid_address_vni(&a->rmt_eid);
+ gid_address_copy(&a->rmt_eid, &fe->deid);
vnet_lisp_gpe_add_del_fwd_entry (a, &sw_if_index);
/* delete entry in fwd table */
hash_unset(lcm->fwd_entry_by_mapping_index, dst_map_index);
+ vec_free(fe->locator_pairs);
pool_put(lcm->fwd_entry_pool, fe);
}
*
*/
static u32
-get_locator_pair (lisp_cp_main_t* lcm, mapping_t * lcl_map, mapping_t * rmt_map,
- ip_address_t * lcl_loc, ip_address_t * rmt_loc)
+get_locator_pairs (lisp_cp_main_t* lcm, mapping_t * lcl_map,
+ mapping_t * rmt_map, locator_pair_t ** locator_pairs)
{
- u32 i, minp = ~0, limitp = 0, li, check_index = 0, done = 0, esi;
+ u32 i, limitp = 0, li, found = 0, esi;
locator_set_t * rmt_ls, * lcl_ls;
- ip_address_t _lcl, * lcl = &_lcl;
- locator_t * l, * rmt = 0;
+ ip_address_t _lcl_addr, * lcl_addr = &_lcl_addr;
+ locator_t * lp, * rmt = 0;
uword * checked = 0;
+ locator_pair_t pair;
rmt_ls = pool_elt_at_index(lcm->locator_set_pool, rmt_map->locator_set_index);
lcl_ls = pool_elt_at_index(lcm->locator_set_pool, lcl_map->locator_set_index);
if (!rmt_ls || vec_len(rmt_ls->locator_indices) == 0)
return 0;
- while (!done)
+ while (1)
{
rmt = 0;
continue;
li = vec_elt(rmt_ls->locator_indices, i);
- l = pool_elt_at_index(lcm->locator_pool, li);
+ lp = pool_elt_at_index(lcm->locator_pool, li);
/* we don't support non-IP locators for now */
- if (gid_address_type(&l->address) != GID_ADDR_IP_PREFIX)
+ if (gid_address_type(&lp->address) != GID_ADDR_IP_PREFIX)
continue;
- if (l->priority < minp && l->priority >= limitp)
+ if ((found && lp->priority == limitp)
+ || (!found && lp->priority >= limitp))
{
- minp = l->priority;
- rmt = l;
- check_index = i;
+ rmt = lp;
+
+ /* don't search for locators with lower priority and don't
+ * check this locator again*/
+ limitp = lp->priority;
+ hash_set(checked, i, 1);
+ break;
}
}
/* check if a local locator with a route to remote locator exists */
if (rmt != 0)
{
+ /* find egress sw_if_index for rmt locator */
esi = ip_fib_get_egress_iface_for_dst (
lcm, &gid_address_ip(&rmt->address));
if ((u32) ~0 == esi)
li = vec_elt (lcl_ls->locator_indices, i);
locator_t * sl = pool_elt_at_index (lcm->locator_pool, li);
- /* found local locator */
+ /* found local locator with the needed sw_if_index*/
if (sl->sw_if_index == esi)
{
+ /* and it has an address */
if (0 == ip_interface_get_first_ip_address (lcm,
sl->sw_if_index,
- gid_address_ip_version(&rmt->address), lcl))
+ gid_address_ip_version(&rmt->address), lcl_addr))
continue;
- ip_address_copy(rmt_loc, &gid_address_ip(&rmt->address));
- ip_address_copy(lcl_loc, lcl);
- done = 2;
+ memset(&pair, 0, sizeof(pair));
+ ip_address_copy (&pair.rmt_loc,
+ &gid_address_ip(&rmt->address));
+ ip_address_copy(&pair.lcl_loc, lcl_addr);
+ pair.weight = rmt->weight;
+ vec_add1(locator_pairs[0], pair);
+ found = 1;
}
}
-
- /* skip this remote locator in next searches */
- limitp = minp;
- hash_set(checked, check_index, 1);
}
else
- done = 1;
+ break;
}
+
hash_free(checked);
- return (done == 2) ? 1 : 0;
+ return found;
}
static void
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;
mapping_t * src_map, * dst_map;
u32 sw_if_index;
- uword * feip = 0, * tidp;
+ uword * feip = 0, * dpid;
fwd_entry_t* fe;
- vnet_lisp_gpe_add_del_fwd_entry_args_t _a, * a = &_a;
+ u8 type;
memset (a, 0, sizeof(*a));
src_map = pool_elt_at_index (lcm->mapping_pool, src_map_index);
dst_map = pool_elt_at_index (lcm->mapping_pool, dst_map_index);
- gid_address_copy (&a->deid, &dst_map->eid);
- a->vni = gid_address_vni(&a->deid);
+ /* insert data plane forwarding entry */
+ a->is_add = 1;
+
+ gid_address_copy (&a->rmt_eid, &dst_map->eid);
+ a->vni = gid_address_vni(&a->rmt_eid);
- tidp = hash_get(lcm->table_id_by_vni, a->vni);
- if (!tidp)
+ /* get vrf or bd_index associated to vni */
+ type = gid_address_type(&dst_map->eid);
+ if (GID_ADDR_IP_PREFIX == type)
{
- clib_warning("vni %d not associated to a vrf!", a->vni);
- return;
+ dpid = hash_get(lcm->table_id_by_vni, a->vni);
+ if (!dpid)
+ {
+ clib_warning("vni %d not associated to a vrf!", a->vni);
+ return;
+ }
+ a->table_id = dpid[0];
+ }
+ else if (GID_ADDR_MAC == type)
+ {
+ dpid = hash_get(lcm->bd_id_by_vni, a->vni);
+ if (!dpid)
+ {
+ clib_warning("vni %d not associated to a bridge domain !", a->vni);
+ return;
+ }
+ a->bd_id = dpid[0];
}
- a->table_id = tidp[0];
-
- /* insert data plane forwarding entry */
- a->is_add = 1;
/* find best locator pair that 1) verifies LISP policy 2) are connected */
- if (0 == get_locator_pair (lcm, src_map, dst_map, &a->slocator, &a->dlocator))
+ if (0 == get_locator_pairs (lcm, src_map, dst_map, &a->locator_pairs))
{
/* negative entry */
a->is_negative = 1;
}
/* TODO remove */
- u8 ipver = ip_prefix_version(&gid_address_ippref(&a->deid));
+ u8 ipver = ip_prefix_version(&gid_address_ippref(&a->rmt_eid));
a->decap_next_index = (ipver == IP4) ?
LISP_GPE_INPUT_NEXT_IP4_INPUT : LISP_GPE_INPUT_NEXT_IP6_INPUT;
/* add tunnel to fwd entry table XXX check return value from DP insertion */
pool_get (lcm->fwd_entry_pool, fe);
- fe->dst_loc = a->dlocator;
- fe->src_loc = a->slocator;
- gid_address_copy (&fe->deid, &a->deid);
+ fe->locator_pairs = a->locator_pairs;
+ gid_address_copy (&fe->deid, &a->rmt_eid);
hash_set (lcm->fwd_entry_by_mapping_index, dst_map_index,
fe - lcm->fwd_entry_pool);
}
vnet_lisp_add_del_local_mapping (vnet_lisp_add_del_mapping_args_t * a,
u32 * map_index_result)
{
- uword * table_id;
+ uword * dp_table = 0;
u32 vni;
+ u8 type;
lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
}
vni = gid_address_vni(&a->eid);
- table_id = hash_get(lcm->table_id_by_vni, vni);
+ type = gid_address_type(&a->eid);
+ if (GID_ADDR_IP_PREFIX == type)
+ dp_table = hash_get(lcm->table_id_by_vni, vni);
+ else if (GID_ADDR_MAC == type)
+ dp_table = hash_get(lcm->bd_id_by_vni, vni);
- if (!table_id)
+ if (!dp_table)
{
- clib_warning ("vni %d not associated to a vrf!", vni);
+ clib_warning("vni %d not associated to a %s!", vni,
+ GID_ADDR_IP_PREFIX == type ? "vrf" : "bd");
return VNET_API_ERROR_INVALID_VALUE;
}
unformat_input_t _line_input, * line_input = &_line_input;
u8 is_add = 1;
gid_address_t eid;
- ip_prefix_t * prefp = &gid_address_ippref(&eid);
- u8 * mac = gid_address_mac(&eid);
gid_address_t * eids = 0;
clib_error_t * error = 0;
u8 * locator_set_name = 0;
u32 vni = 0;
memset (&eid, 0, sizeof (eid));
+ memset (a, 0, sizeof (*a));
+
/* Get a line of input. */
if (! unformat_user (input, unformat_line_input, line_input))
return 0;
is_add = 1;
else if (unformat (line_input, "del"))
is_add = 0;
+ else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
+ ;
else if (unformat (line_input, "vni %d", &vni))
gid_address_vni (&eid) = vni;
- else if (unformat (line_input, "eid %U", unformat_ip_prefix, prefp))
- {
- gid_address_type (&eid) = GID_ADDR_IP_PREFIX;
- vec_add1(eids, eid);
- }
- else if (unformat (line_input, "eid %U", unformat_mac_address, mac))
- {
- gid_address_type (&eid) = GID_ADDR_MAC;
- vec_add1(eids, eid);
- }
else if (unformat (line_input, "locator-set %_%v%_", &locator_set_name))
{
p = hash_get_mem(lcm->locator_set_index_by_name, locator_set_name);
}
/* XXX treat batch configuration */
- a->eid = eid;
+ if (GID_ADDR_SRC_DST == gid_address_type(&eid))
+ {
+ error = clib_error_return(0, "src/dst is not supported for local EIDs!");
+ goto done;
+ }
+
+ gid_address_copy(&a->eid, &eid);
a->is_add = is_add;
a->locator_set_index = locator_set_index;
a->local = 1;
};
int
-vnet_lisp_eid_table_map (u32 vni, u32 vrf, u8 is_add)
+vnet_lisp_eid_table_map (u32 vni, u32 dp_id, u8 is_l2, u8 is_add)
{
lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
- uword * table_id, * vnip;
+ uword * dp_idp, * vnip, ** dp_table_by_vni, ** vni_by_dp_table;
if (vnet_lisp_enable_disable_status () == 0)
{
return -1;
}
- if (vni == 0 || vrf == 0)
+ dp_table_by_vni = is_l2 ? &lcm->bd_id_by_vni : &lcm->table_id_by_vni;
+ vni_by_dp_table = is_l2 ? &lcm->vni_by_bd_id : &lcm->vni_by_table_id;
+
+ if (!is_l2 && (vni == 0 || dp_id == 0))
{
clib_warning ("can't add/del default vni-vrf mapping!");
return -1;
}
- table_id = hash_get (lcm->table_id_by_vni, vni);
- vnip = hash_get (lcm->vni_by_table_id, vrf);
+ dp_idp = hash_get (dp_table_by_vni[0], vni);
+ vnip = hash_get (vni_by_dp_table[0], dp_id);
if (is_add)
{
- if (table_id || vnip)
+ if (dp_idp || vnip)
{
- clib_warning ("vni %d or vrf %d already used in any vrf/vni "
- "mapping!", vni, vrf);
+ clib_warning ("vni %d or vrf %d already used in vrf/vni "
+ "mapping!", vni, dp_id);
return -1;
}
- hash_set (lcm->table_id_by_vni, vni, vrf);
- hash_set (lcm->vni_by_table_id, vrf, vni);
+ hash_set (dp_table_by_vni[0], vni, dp_id);
+ hash_set (vni_by_dp_table[0], dp_id, vni);
/* create dp iface */
- dp_add_del_iface (lcm, vni, 1);
+ dp_add_del_iface (lcm, vni, is_l2, 1);
}
else
{
- if (!table_id || !vnip)
+ if (!dp_idp || !vnip)
{
clib_warning ("vni %d or vrf %d not used in any vrf/vni! "
- "mapping!", vni, vrf);
+ "mapping!", vni, dp_id);
return -1;
}
- hash_unset (lcm->table_id_by_vni, vni);
- hash_unset (lcm->vni_by_table_id, vrf);
+ hash_unset (dp_table_by_vni[0], vni);
+ hash_unset (vni_by_dp_table[0], dp_id);
/* remove dp iface */
- dp_add_del_iface (lcm, vni, 0);
+ dp_add_del_iface (lcm, vni, is_l2, 0);
}
return 0;
+
}
static clib_error_t *
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
- u8 is_add = 1;
- u32 vni = 0, vrf = 0;
+ u8 is_add = 1, is_l2 = 0;
+ u32 vni = 0, dp_id = 0;
unformat_input_t _line_input, * line_input = &_line_input;
/* Get a line of input. */
is_add = 0;
else if (unformat (line_input, "vni %d", &vni))
;
- else if (unformat (line_input, "vrf %d", &vrf))
+ else if (unformat (line_input, "vrf %d", &dp_id))
;
+ else if (unformat (line_input, "bd %d", &dp_id))
+ is_l2 = 1;
else
{
return unformat_parse_error (line_input);
}
}
- vnet_lisp_eid_table_map (vni, vrf, is_add);
+ vnet_lisp_eid_table_map (vni, dp_id, is_l2, is_add);
return 0;
}
VLIB_CLI_COMMAND (lisp_eid_table_map_command) = {
.path = "lisp eid-table map",
- .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf>",
+ .short_help = "lisp eid-table map [del] vni <vni> vrf <vrf> | bd <bdi>",
.function = lisp_eid_table_map_command_fn,
};
vnet_lisp_add_del_locator_set (ls_args, 0);
/* return old mapping index */
- res_map_index[0] = mi;
+ if (res_map_index)
+ res_map_index[0] = mi;
}
/* success */
unformat_input_t _line_input, * line_input = &_line_input;
u8 is_add = 1, del_all = 0;
locator_t rloc, * rlocs = 0, * curr_rloc = 0;
- ip_prefix_t * deid_ippref, * seid_ippref;
- gid_address_t seid, deid;
- u8 * dmac = gid_address_mac (&deid);
- u8 * smac = gid_address_mac (&seid);
- u8 deid_set = 0, seid_set = 0;
- u8 * s = 0;
+ gid_address_t eid;
+ u8 eid_set = 0;
u32 vni, action = ~0, p, w;
int rv;
if (! unformat_user (input, unformat_line_input, line_input))
return 0;
- memset(&deid, 0, sizeof(deid));
- memset(&seid, 0, sizeof(seid));
+ memset(&eid, 0, sizeof(eid));
memset(&rloc, 0, sizeof(rloc));
- seid_ippref = &gid_address_ippref(&seid);
- deid_ippref = &gid_address_ippref(&deid);
-
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "del-all"))
is_add = 0;
else if (unformat (line_input, "add"))
;
- else if (unformat (line_input, "deid %U",
- unformat_ip_prefix, deid_ippref))
- {
- gid_address_type (&deid) = GID_ADDR_IP_PREFIX;
- deid_set = 1;
- }
- else if (unformat (line_input, "deid %U",
- unformat_mac_address, dmac))
- {
- gid_address_type (&deid) = GID_ADDR_MAC;
- deid_set = 1;
- }
+ else if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
+ eid_set = 1;
else if (unformat (line_input, "vni %u", &vni))
{
- gid_address_vni (&seid) = vni;
- gid_address_vni (&deid) = vni;
- }
- else if (unformat (line_input, "seid %U",
- unformat_ip_prefix, seid_ippref))
- {
- gid_address_type (&seid) = GID_ADDR_IP_PREFIX;
- seid_set = 1;
- }
- else if (unformat (line_input, "seid %U",
- unformat_mac_address, smac))
- {
- gid_address_type (&seid) = GID_ADDR_MAC;
- seid_set = 1;
+ gid_address_vni (&eid) = vni;
}
else if (unformat (line_input, "p %d w %d", &p, &w))
{
curr_rloc->weight = w;
}
else if (unformat (line_input, "rloc %U", unformat_ip_address,
- &rloc.address))
+ &gid_address_ip(&rloc.address)))
{
vec_add1 (rlocs, rloc);
curr_rloc = &rlocs[vec_len (rlocs) - 1];
}
- else if (unformat (line_input, "action %s", &s))
- {
- if (!strcmp ((char *)s, "no-action"))
- action = ACTION_NONE;
- if (!strcmp ((char *)s, "natively-forward"))
- action = ACTION_NATIVELY_FORWARDED;
- if (!strcmp ((char *)s, "send-map-request"))
- action = ACTION_SEND_MAP_REQUEST;
- else if (!strcmp ((char *)s, "drop"))
- action = ACTION_DROP;
- else
- {
- clib_warning ("invalid action: '%s'", s);
- goto done;
- }
- }
+ else if (unformat (line_input, "action %U",
+ unformat_negative_mapping_action, &action))
+ ;
else
{
clib_warning ("parse error");
}
}
- if (!del_all)
+ if (!eid_set)
{
- if (!deid_set)
- {
- clib_warning ("missing deid!");
- goto done;
- }
-
- if (GID_ADDR_IP_PREFIX == gid_address_type (&deid))
- {
- /* if seid not set, make sure the ip version is the same as that
- * of the deid. This ensures the seid to be configured will be
- * either 0/0 or ::/0 */
- if (!seid_set)
- ip_prefix_version(seid_ippref) = ip_prefix_version(deid_ippref);
-
- if (is_add &&
- (ip_prefix_version (deid_ippref)
- != ip_prefix_version(seid_ippref)))
- {
- clib_warning ("source and destination EIDs are not"
- " in the same IP family!");
- goto done;
- }
- }
+ clib_warning ("missing eid!");
+ goto done;
+ }
+ if (!del_all)
+ {
if (is_add && (~0 == action)
&& 0 == vec_len (rlocs))
{
if (!is_add)
{
lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
- rv = lisp_add_del_adjacency (lcm, 0, &deid, /* is_add */ 0);
- }
- else
- {
- /* add as static remote mapping, i.e., not authoritative and infinite
- * ttl */
- rv = vnet_lisp_add_del_mapping (&deid, rlocs, action, 0, ~0, is_add, 0);
+ rv = lisp_add_del_adjacency (lcm, 0, &eid, /* is_add */ 0);
+ if (rv)
+ {
+ goto done;
+ }
}
+ /* add as static remote mapping, i.e., not authoritative and infinite
+ * ttl */
+ rv = vnet_lisp_add_del_mapping (&eid, rlocs, action, 0, ~0, is_add, 0);
+
if (rv)
clib_warning("failed to %s remote mapping!", is_add ? "add" : "delete");
done:
vec_free (rlocs);
unformat_free (line_input);
- if (s)
- vec_free (s);
return error;
}
VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = {
.path = "lisp remote-mapping",
- .short_help = "lisp remote-mapping add|del [del-all] vni <vni>"
- "deid <dest-eid> seid <src-eid> [action <no-action|natively-forward|"
- "send-map-request|drop>] rloc <dst-locator> [rloc <dst-locator> ... ]",
+ .short_help = "lisp remote-mapping add|del [del-all] vni <vni> "
+ "eid <est-eid> [action <no-action|natively-forward|"
+ "send-map-request|drop>] rloc <dst-locator> p <prio> w <weight> "
+ "[rloc <dst-locator> ... ]",
.function = lisp_add_del_remote_mapping_command_fn,
};
unformat_input_t * input,
vlib_cli_command_t * cmd)
{
- ip_address_t * addr;
+ map_resolver_t * mr;
lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
- vec_foreach (addr, lcm->map_resolvers)
+ vec_foreach (mr, lcm->map_resolvers)
{
- vlib_cli_output (vm, "%U", format_ip_address, addr);
+ vlib_cli_output (vm, "%U", format_ip_address, &mr->address);
}
return 0;
}
.function = lisp_pitr_set_locator_set_command_fn,
};
+static clib_error_t *
+lisp_show_pitr_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+ mapping_t * m;
+ locator_set_t * ls;
+ u8 * tmp_str = 0;
+
+ vlib_cli_output (vm, "%=20s%=16s",
+ "pitr", lcm->lisp_pitr ? "locator-set" : "");
+
+ if (!lcm->lisp_pitr) {
+ vlib_cli_output (vm, "%=20s", "disable");
+ return 0;
+ }
+
+ if (~0 == lcm->pitr_map_index) {
+ tmp_str = format(0, "N/A");
+ } else {
+ m = pool_elt_at_index (lcm->mapping_pool, lcm->pitr_map_index);
+ if (~0 != m->locator_set_index) {
+ ls = pool_elt_at_index (lcm->locator_set_pool, m->locator_set_index);
+ tmp_str = format(0, "%s", ls->name);
+ } else {
+ tmp_str = format(0, "N/A");
+ }
+ }
+ vec_add1(tmp_str, 0);
+
+ vlib_cli_output (vm, "%=20s%=16s",
+ "enable", tmp_str);
+
+ vec_free(tmp_str);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (lisp_show_pitr_command) = {
+ .path = "show lisp pitr",
+ .short_help = "Show pitr",
+ .function = lisp_show_pitr_command_fn,
+};
static u8 *
format_eid_entry (u8 * s, va_list * args)
{
vnet_main_t * vnm = va_arg (*args, vnet_main_t *);
lisp_cp_main_t * lcm = va_arg (*args, lisp_cp_main_t *);
- gid_address_t * gid = va_arg (*args, gid_address_t *);
+ mapping_t * mapit = va_arg (*args, mapping_t *);
locator_set_t * ls = va_arg (*args, locator_set_t *);
+ gid_address_t * gid = &mapit->eid;
+ u32 ttl = mapit->ttl;
+ u8 aut = mapit->authoritative;
u32 * loc_index;
u8 first_line = 1;
u8 * loc;
if (vec_len (ls->locator_indices) == 0)
{
- s = format (s, "%-35U%-20s", format_gid_address, gid, type);
+ s = format (s, "%-35U%-30s%-20u%-u", format_gid_address, gid,
+ type, ttl, aut);
}
else
{
if (first_line)
{
- s = format (s, "%-35U%-20s%-v\n", format_gid_address,
- gid, type, loc);
+ s = format (s, "%-35U%-20s%-30v%-20u%-u\n", format_gid_address,
+ gid, type, loc, ttl, aut);
first_line = 0;
}
else
u32 mi;
gid_address_t eid;
u8 print_all = 1;
+ u8 filter = 0;
memset (&eid, 0, sizeof(eid));
{
if (unformat (line_input, "eid %U", unformat_gid_address, &eid))
print_all = 0;
+ else if (unformat (line_input, "local"))
+ filter = 1;
+ else if (unformat(line_input, "remote"))
+ filter = 2;
else
return clib_error_return (0, "parse error: '%U'",
format_unformat_error, line_input);
}
- vlib_cli_output (vm, "%-35s%-20s%-s", "EID", "type", "locators");
+ vlib_cli_output (vm, "%-35s%-20s%-30s%-20s%-s",
+ "EID", "type", "locators", "ttl", "autoritative");
if (print_all)
{
({
locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
mapit->locator_set_index);
+ if (filter && !((1 == filter && ls->local) ||
+ (2 == filter && !ls->local)))
+ {
+ continue;
+ }
vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
- lcm, &mapit->eid, ls);
+ lcm, mapit, ls);
}));
}
else
mapit = pool_elt_at_index (lcm->mapping_pool, mi);
locator_set_t * ls = pool_elt_at_index (lcm->locator_set_pool,
mapit->locator_set_index);
- vlib_cli_output (vm, "%U", format_eid_entry, lcm->vnet_main,
- lcm, &mapit->eid, ls);
+
+ if (filter && !((1 == filter && ls->local) ||
+ (2 == filter && !ls->local)))
+ {
+ return 0;
+ }
+
+ vlib_cli_output (vm, "%U,", format_eid_entry, lcm->vnet_main,
+ lcm, mapit, ls);
}
return 0;
vec_foreach(locit, ls->locator_indices)
{
itloc = pool_elt_at_index(lcm->locator_pool, locit[0]);
- if (itloc->sw_if_index == loc->sw_if_index ||
- !gid_address_cmp(&itloc->address, &loc->address))
+ if ((ls->local && itloc->sw_if_index == loc->sw_if_index) ||
+ (!ls->local && !gid_address_cmp(&itloc->address, &loc->address)))
{
clib_warning("Duplicate locator");
return VNET_API_ERROR_VALUE_EXIST;
clib_error_t *
vnet_lisp_enable_disable (u8 is_enable)
{
- u32 vni, table_id;
+ u32 vni, dp_table;
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;
if (is_enable)
{
- /* enable all ifaces */
- hash_foreach(vni, table_id, lcm->table_id_by_vni, ({
- dp_add_del_iface(lcm, vni, 1);
+ /* enable all l2 and l3 ifaces */
+ hash_foreach(vni, dp_table, lcm->table_id_by_vni, ({
+ dp_add_del_iface(lcm, vni, 0, 1);
+ }));
+
+ hash_foreach(vni, dp_table, lcm->bd_id_by_vni, ({
+ dp_add_del_iface(lcm, vni, /* is_l2 */ 1, 1);
}));
}
else
({
u8 * msg = 0;
int next_line = 0;
- msg = format (msg, "%=16v", lsit->name);
+ if (lsit->local)
+ {
+ msg = format (msg, "%=16v", lsit->name);
+ }
+ else
+ {
+ msg = format (msg, "%=16s", "remote");
+ }
vec_foreach (locit, lsit->locator_indices)
{
if (next_line)
.function = lisp_cp_show_locator_sets_command_fn,
};
+static map_resolver_t *
+get_map_resolver (ip_address_t * a)
+{
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+ map_resolver_t * mr;
+
+ vec_foreach (mr, lcm->map_resolvers)
+ {
+ if (!ip_address_cmp (&mr->address, a))
+ {
+ return mr;
+ }
+ }
+ return 0;
+}
+
int
vnet_lisp_add_del_map_resolver (vnet_lisp_add_del_map_resolver_args_t * a)
{
lisp_cp_main_t * lcm = vnet_lisp_cp_get_main();
- ip_address_t * addr;
u32 i;
+ map_resolver_t _mr, * mr = &_mr;
if (vnet_lisp_enable_disable_status () == 0)
{
if (a->is_add)
{
- vec_foreach(addr, lcm->map_resolvers)
+
+ if (get_map_resolver (&a->address))
{
- if (!ip_address_cmp (addr, &a->address))
- {
- clib_warning("map-resolver %U already exists!", format_ip_address,
- &a->address);
- return -1;
- }
+ clib_warning("map-resolver %U already exists!", format_ip_address,
+ &a->address);
+ return -1;
}
- vec_add1(lcm->map_resolvers, a->address);
+
+ memset (mr, 0, sizeof (*mr));
+ ip_address_copy(&mr->address, &a->address);
+ vec_add1(lcm->map_resolvers, *mr);
+
+ if (vec_len (lcm->map_resolvers) == 1)
+ lcm->do_map_resolver_election = 1;
}
else
{
for (i = 0; i < vec_len(lcm->map_resolvers); i++)
{
- addr = vec_elt_at_index(lcm->map_resolvers, i);
- if (!ip_address_cmp (addr, &a->address))
+ mr = vec_elt_at_index(lcm->map_resolvers, i);
+ if (!ip_address_cmp (&mr->address, &a->address))
{
- vec_delete(lcm->map_resolvers, 1, i);
+ if (!ip_address_cmp (&mr->address, &lcm->active_map_resolver))
+ lcm->do_map_resolver_election = 1;
+
+ vec_del1 (lcm->map_resolvers, i);
break;
}
}
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, * line_input = &_line_input;
- u8 is_add = 1;
+ u8 is_add = 1, addr_set = 0;
ip_address_t ip_addr;
clib_error_t * error = 0;
int rv = 0;
else if (unformat (line_input, "del"))
is_add = 0;
else if (unformat (line_input, "%U", unformat_ip_address, &ip_addr))
- ;
+ addr_set = 1;
else
{
error = unformat_parse_error(line_input);
goto done;
}
}
+
+ if (!addr_set)
+ {
+ error = clib_error_return(0, "Map-resolver address must be set!");
+ goto done;
+ }
+
a->is_add = is_add;
a->address = ip_addr;
rv = vnet_lisp_add_del_map_resolver (a);
get_mr_and_local_iface_ip (lisp_cp_main_t * lcm, ip_address_t * mr_ip,
ip_address_t * sloc)
{
- ip_address_t * mrit;
+ map_resolver_t * mrit;
+ ip_address_t * a;
if (vec_len(lcm->map_resolvers) == 0)
{
* iface that has a route to it */
vec_foreach(mrit, lcm->map_resolvers)
{
- if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, mrit, sloc)) {
- ip_address_copy(mr_ip, mrit);
+ a = &mrit->address;
+ if (0 != ip_fib_get_first_egress_ip_for_dst (lcm, a, sloc))
+ {
+ ip_address_copy(mr_ip, a);
+
+ /* also update globals */
return 1;
- }
+ }
}
clib_warning("Can't find map-resolver and local interface ip!");
addr = ip_interface_address_get_address (&lcm->im4->lookup_main, ia);
ip_address_set (rloc, addr, IP4);
ip_prefix_len (ippref) = 32;
+ ip_prefix_normalize (ippref);
vec_add1 (rlocs, gid[0]);
}));
addr = ip_interface_address_get_address (&lcm->im6->lookup_main, ia);
ip_address_set (rloc, addr, IP6);
ip_prefix_len (ippref) = 128;
+ ip_prefix_normalize (ippref);
vec_add1 (rlocs, gid[0]);
}));
}
}
static vlib_buffer_t *
-build_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
+build_encapsulated_map_request (lisp_cp_main_t *lcm,
gid_address_t * seid, gid_address_t * deid,
locator_set_t * loc_set, ip_address_t * mr_ip,
ip_address_t * sloc, u8 is_smr_invoked,
vlib_buffer_t * b;
u32 bi;
gid_address_t * rlocs = 0;
+ vlib_main_t * vm = lcm->vlib_main;
if (vlib_buffer_alloc (vm, &bi, 1) != 1)
{
}
static void
-send_encapsulated_map_request (vlib_main_t * vm, lisp_cp_main_t *lcm,
- gid_address_t * seid, gid_address_t * deid,
- u8 is_smr_invoked)
+reset_pending_mr_counters (pending_map_request_t * r)
+{
+ r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
+ r->retries_num = 0;
+}
+
+static int
+elect_map_resolver (lisp_cp_main_t * lcm)
{
+ map_resolver_t * mr;
+
+ vec_foreach (mr, lcm->map_resolvers)
+ {
+ if (!mr->is_down)
+ {
+ ip_address_copy (&lcm->active_map_resolver, &mr->address);
+ lcm->do_map_resolver_election = 0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#define send_encapsulated_map_request(lcm, seid, deid, smr) \
+ _send_encapsulated_map_request(lcm, seid, deid, smr, 0)
+
+#define resend_encapsulated_map_request(lcm, seid, deid, smr) \
+ _send_encapsulated_map_request(lcm, seid, deid, smr, 1)
+
+static int
+_send_encapsulated_map_request (lisp_cp_main_t *lcm,
+ gid_address_t * seid, gid_address_t * deid,
+ u8 is_smr_invoked, u8 is_resend)
+{
+ map_resolver_t * mr;
u32 next_index, bi = 0, * to_next, map_index;
vlib_buffer_t * b;
vlib_frame_t * f;
u64 nonce = 0;
locator_set_t * loc_set;
mapping_t * map;
- pending_map_request_t * pmr;
- ip_address_t mr_ip, sloc;
+ pending_map_request_t * pmr, * duplicate_pmr = 0;
+ ip_address_t sloc;
u32 ls_index;
+ ASSERT (*lcm->pending_map_request_lock);
+
+ /* if there is already a pending request remember it */
+ pool_foreach(pmr, lcm->pending_map_requests_pool,
+ ({
+ if (!gid_address_cmp (&pmr->src, seid)
+ && !gid_address_cmp (&pmr->dst, deid))
+ {
+ duplicate_pmr = pmr;
+ break;
+ }
+ }));
+
+ if (!is_resend && duplicate_pmr)
+ {
+ /* don't send the request if there is a pending map request already */
+ return 0;
+ }
+
/* get locator-set for seid */
if (!lcm->lisp_pitr)
{
{
clib_warning("No local mapping found in eid-table for %U!",
format_gid_address, seid);
- return;
+ return -1;
}
map = pool_elt_at_index (lcm->mapping_pool, map_index);
{
clib_warning("Mapping found for src eid %U is not marked as local!",
format_gid_address, seid);
- return;
+ return -1;
}
ls_index = map->locator_set_index;
}
loc_set = pool_elt_at_index (lcm->locator_set_pool, ls_index);
- /* get local iface ip to use in map-request */
- if (0 == get_mr_and_local_iface_ip (lcm, &mr_ip, &sloc))
- return;
+ while (lcm->do_map_resolver_election
+ | (0 == ip_fib_get_first_egress_ip_for_dst (lcm,
+ &lcm->active_map_resolver,
+ &sloc)))
+ {
+ if (0 == elect_map_resolver (lcm))
+ /* all Mrs are down */
+ {
+ if (duplicate_pmr)
+ duplicate_pmr->to_be_removed = 1;
+
+ /* restart MR checking by marking all of them up */
+ vec_foreach (mr, lcm->map_resolvers)
+ mr->is_down = 0;
+
+ return -1;
+ }
+ }
/* build the encapsulated map request */
- b = build_encapsulated_map_request (vm, lcm, seid, deid, loc_set, &mr_ip,
+ b = build_encapsulated_map_request (lcm, seid, deid, loc_set,
+ &lcm->active_map_resolver,
&sloc, is_smr_invoked, &nonce, &bi);
if (!b)
- return;
+ return -1;
/* set fib index to default and lookup node */
vnet_buffer(b)->sw_if_index[VLIB_TX] = 0;
- next_index = (ip_addr_version(&mr_ip) == IP4) ?
+ next_index = (ip_addr_version(&lcm->active_map_resolver) == IP4) ?
ip4_lookup_node.index : ip6_lookup_node.index;
- f = vlib_get_frame_to_node (vm, 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 (vm, next_index, f);
+ vlib_put_frame_to_node (lcm->vlib_main, next_index, f);
- /* add map-request to pending requests table */
- pool_get(lcm->pending_map_requests_pool, pmr);
- gid_address_copy (&pmr->src, seid);
- gid_address_copy (&pmr->dst, deid);
- hash_set(lcm->pending_map_requests_by_nonce, nonce,
- pmr - lcm->pending_map_requests_pool);
+ if (duplicate_pmr)
+ /* if there is a pending request already update it */
+ {
+ if (vec_len (duplicate_pmr->nonces) >= PENDING_MREQ_QUEUE_LEN)
+ {
+ /* remove the oldest nonce */
+ u64 * nonce_del = vec_elt_at_index (duplicate_pmr->nonces, 0);
+ hash_unset (lcm->pending_map_requests_by_nonce, nonce_del[0]);
+ vec_del1 (duplicate_pmr->nonces, 0);
+ }
+
+ vec_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);
+ vec_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 (void *hdr, ip_address_t * src, ip_address_t *dst)
+get_src_and_dst_ip (void *hdr, ip_address_t * src, ip_address_t *dst)
{
ip4_header_t * ip4 = hdr;
ip6_header_t * ip6;
}
static u32
-lisp_get_vni_from_buffer (vlib_buffer_t * b, u8 version)
+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, fib_index;
- lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
if (version == IP4)
{
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 (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
while (n_left_from > 0 && n_left_to_next_drop > 0)
{
- u32 pi0, vni;
- vlib_buffer_t * p0;
- ip4_header_t * ip0;
+ u32 pi0;
+ vlib_buffer_t * b0;
gid_address_t src, dst;
- ip_prefix_t * spref, * dpref;
-
- gid_address_type (&src) = GID_ADDR_IP_PREFIX;
- spref = &gid_address_ippref(&src);
- gid_address_type (&dst) = GID_ADDR_IP_PREFIX;
- dpref = &gid_address_ippref(&dst);
pi0 = from[0];
from += 1;
to_next_drop += 1;
n_left_to_next_drop -= 1;
- p0 = vlib_get_buffer (vm, pi0);
- p0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
+ b0 = vlib_get_buffer (vm, pi0);
+ b0->error = node->errors[LISP_CP_LOOKUP_ERROR_DROP];
/* src/dst eid pair */
- ip0 = vlib_buffer_get_current (p0);
- get_src_and_dst (ip0, &ip_prefix_addr(spref), &ip_prefix_addr(dpref));
- ip_prefix_len(spref) = ip_address_max_len (ip_prefix_version(spref));
- ip_prefix_len(dpref) = ip_address_max_len (ip_prefix_version(dpref));
-
- vni = lisp_get_vni_from_buffer (p0, ip_prefix_version (spref));
- gid_address_vni (&dst) = vni;
- gid_address_vni (&src) = vni;
+ 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 */
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 == ACTION_SEND_MAP_REQUEST)
+ if (m->action == LISP_SEND_MAP_REQUEST)
{
/* send map-request */
- send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
+ queue_map_request (&src, &dst, 0 /* smr_invoked */,
+ 0 /* is_resend */);
pkts_mapped++;
}
else
else
{
/* send map-request */
- send_encapsulated_map_request (vm, lcm, &src, &dst, 0);
+ queue_map_request (&src, &dst, 0 /* smr_invoked */,
+ 0 /* is_resend */);
pkts_mapped++;
}
- if (PREDICT_FALSE(p0->flags & VLIB_BUFFER_IS_TRACED))
+ if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
{
- lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, p0,
+ lisp_cp_lookup_trace_t *tr = vlib_add_trace (vm, node, b0,
sizeof(*tr));
memset(tr, 0, sizeof(*tr));
return s;
}
-void
-process_map_reply (lisp_cp_main_t * lcm, vlib_buffer_t * b)
+void *
+process_map_reply (void * arg)
{
+ 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;
pending_map_request_t * pmr;
locator_t probed;
map_reply_hdr_t * mrep_hdr;
- u64 nonce;
+ u64 nonce, * noncep;
gid_address_t deid;
uword * pmr_index;
u8 authoritative, action;
mrep_hdr = vlib_buffer_get_current (b);
+ lisp_pending_map_request_lock (lcm);
+
/* Check pending requests table and nonce */
nonce = MREP_NONCE(mrep_hdr);
pmr_index = hash_get(lcm->pending_map_requests_by_nonce, nonce);
if (!pmr_index)
{
clib_warning("No pending map-request entry with nonce %lu!", nonce);
- return;
+ goto done;
}
pmr = pool_elt_at_index(lcm->pending_map_requests_pool, pmr_index[0]);
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);
locator_free (loc);
}
vec_free(locators);
- return;
+ goto done;
}
/* insert/update mappings cache */
}
/* remove pending map request entry */
- hash_unset(lcm->pending_map_requests_by_nonce, nonce);
+ vec_foreach (noncep, pmr->nonces)
+ hash_unset(lcm->pending_map_requests_by_nonce, noncep[0]);
+ vec_free(pmr->nonces);
pool_put(lcm->pending_map_requests_pool, pmr);
+
+done:
+ lisp_pending_map_request_unlock (lcm);
+ return 0;
}
void
return;
}
/* send SMR-invoked map-requests */
- send_encapsulated_map_request (vm, lcm, &dst, &src, /* invoked */ 1);
+ queue_map_request (&dst, &src, 1 /* invoked */, 0 /* resend */);
}
}
+static void
+queue_map_reply (vlib_buffer_t * b)
+{
+ vlib_buffer_t * a = clib_mem_alloc (sizeof (a[0]) + b->current_length);
+
+ clib_memcpy (a->data, b->data + b->current_data,
+ b->current_length);
+ a->current_length = b->current_length;
+ a->current_data = 0;
+
+ vl_api_rpc_call_main_thread (process_map_reply, (u8 *) a, sizeof (a[0])
+ + a->current_length);
+ clib_mem_free (a);
+}
+
static uword
lisp_cp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
switch (type)
{
case LISP_MAP_REPLY:
- process_map_reply (lcm, b0);
+ queue_map_reply (b0);
break;
case LISP_MAP_REQUEST:
process_map_request(vm, lcm, b0);
lcm->mreq_itr_rlocs = ~0;
lcm->lisp_pitr = 0;
+ 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;
/* default vrf mapped to vni 0 */
hash_set(lcm->table_id_by_vni, 0, 0);
return 0;
}
+static void *
+send_map_request_thread_fn (void * arg)
+{
+ map_request_args_t * a = arg;
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+ lisp_pending_map_request_lock (lcm);
+
+ if (a->is_resend)
+ resend_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
+ else
+ send_encapsulated_map_request (lcm, &a->seid, &a->deid, a->smr_invoked);
+
+ lisp_pending_map_request_unlock (lcm);
+
+ return 0;
+}
+
+static int
+queue_map_request (gid_address_t * seid, gid_address_t * deid,
+ u8 smr_invoked, u8 is_resend)
+{
+ map_request_args_t a;
+
+ a.is_resend = is_resend;
+ gid_address_copy (&a.seid, seid);
+ gid_address_copy (&a.deid, deid);
+ a.smr_invoked = smr_invoked;
+
+ vl_api_rpc_call_main_thread (send_map_request_thread_fn,
+ (u8 *) &a, sizeof (a));
+ return 0;
+}
+
+/**
+ * Take an action with a pending map request depending on expiration time
+ * and re-try counters.
+ */
+static void
+update_pending_request (pending_map_request_t * r, f64 dt)
+{
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+ map_resolver_t * mr;
+
+ if (r->time_to_expire - dt < 0)
+ /* it's time to decide what to do with this pending request */
+ {
+ if (r->retries_num >= NUMBER_OF_RETRIES)
+ /* too many retries -> assume current map resolver is not available */
+ {
+ mr = get_map_resolver (&lcm->active_map_resolver);
+ if (!mr)
+ {
+ clib_warning ("Map resolver %U not found - probably deleted "
+ "by the user recently.", format_ip_address,
+ &lcm->active_map_resolver);
+ }
+ else
+ {
+ clib_warning ("map resolver %U is unreachable, ignoring",
+ format_ip_address, &lcm->active_map_resolver);
+
+ /* mark current map resolver unavailable so it won't be
+ * selected next time */
+ mr->is_down = 1;
+ mr->last_update = vlib_time_now (lcm->vlib_main);
+ }
+
+ reset_pending_mr_counters (r);
+ elect_map_resolver (lcm);
+
+ /* try to find a next eligible map resolver and re-send */
+ queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
+ 1 /* resend */);
+ }
+ else
+ {
+ /* try again */
+ queue_map_request (&r->src, &r->dst, r->is_smr_invoked,
+ 1 /* resend */);
+ r->retries_num++;
+ r->time_to_expire = PENDING_MREQ_EXPIRATION_TIME;
+ }
+ }
+ else
+ r->time_to_expire -= dt;
+}
+
+static void
+remove_dead_pending_map_requests (lisp_cp_main_t * lcm)
+{
+ u64 * nonce;
+ pending_map_request_t * pmr;
+ u32 * to_be_removed = 0, * pmr_index;
+
+ ASSERT (*lcm->pending_map_request_lock);
+
+ pool_foreach (pmr, lcm->pending_map_requests_pool,
+ ({
+ if (pmr->to_be_removed)
+ {
+ vec_foreach (nonce, pmr->nonces)
+ hash_unset (lcm->pending_map_requests_by_nonce, nonce[0]);
+
+ vec_add1 (to_be_removed, pmr - lcm->pending_map_requests_pool);
+ }
+ }));
+
+ vec_foreach (pmr_index, to_be_removed)
+ pool_put_index (lcm->pending_map_requests_by_nonce, pmr_index[0]);
+
+ vec_free (to_be_removed);
+}
+
+static uword
+send_map_resolver_service (vlib_main_t * vm,
+ vlib_node_runtime_t * rt,
+ vlib_frame_t * f)
+{
+ f64 period = 2.0;
+ pending_map_request_t * pmr;
+ lisp_cp_main_t * lcm = vnet_lisp_cp_get_main ();
+
+ while (1)
+ {
+ vlib_process_wait_for_event_or_clock (vm, period);
+
+ /* currently no signals are expected - just wait for clock */
+ (void) vlib_process_get_events (vm, 0);
+
+ lisp_pending_map_request_lock (lcm);
+ pool_foreach (pmr, lcm->pending_map_requests_pool,
+ ({
+ if (!pmr->to_be_removed)
+ update_pending_request (pmr, period);
+ }));
+
+ remove_dead_pending_map_requests (lcm);
+
+ lisp_pending_map_request_unlock (lcm);
+ }
+
+ /* unreachable */
+ return 0;
+}
+
+VLIB_REGISTER_NODE (lisp_retry_service_node,static) = {
+ .function = send_map_resolver_service,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "lisp-retry-service",
+ .process_log2_n_stack_bytes = 16,
+};
+
VLIB_INIT_FUNCTION(lisp_cp_init);