From 195bceec5685cb367519e37f22b36f5f99819827 Mon Sep 17 00:00:00 2001 From: Filip Tehlar Date: Fri, 13 May 2016 17:37:35 +0200 Subject: ONE-13: Add CLI/API for LISP static remote mappings Change-Id: Ic4c717af9629541bac0a0e6c65d0157619c8f578 Signed-off-by: Filip Tehlar --- vnet/vnet/lisp-cp/control.c | 245 ++++++++++++++++++++++++++++++++++++++++- vnet/vnet/lisp-cp/control.h | 4 + vnet/vnet/lisp-cp/lisp_types.h | 3 + vnet/vnet/lisp-gpe/lisp_gpe.c | 1 + vpp-api-test/vat/api_format.c | 129 ++++++++++++++++++++++ vpp/api/api.c | 64 +++++++++++ vpp/api/vpe.api | 37 +++++++ 7 files changed, 482 insertions(+), 1 deletion(-) diff --git a/vnet/vnet/lisp-cp/control.c b/vnet/vnet/lisp-cp/control.c index 3e50d92a07b..2d3c2d7471b 100644 --- a/vnet/vnet/lisp-cp/control.c +++ b/vnet/vnet/lisp-cp/control.c @@ -21,6 +21,13 @@ static void add_fwd_entry (lisp_cp_main_t* lcm, u32 src_map_index, u32 dst_map_index); +static void +del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index); + +static u8 +compare_locators (lisp_cp_main_t *lcm, u32 * old_ls_indexes, + locator_t * new_locators); + /* Stores mapping in map-cache. It does NOT program data plane forwarding for * remote/learned mappings. */ int @@ -252,6 +259,242 @@ VLIB_CLI_COMMAND (lisp_add_del_local_eid_command) = { .function = lisp_add_del_local_eid_command_fn, }; +/** + * Adds/removes/updates static remote mapping. + * + * This function also modifies forwarding entries if needed. + * + * @param deid destination EID + * @param seid source EID + * @param rlocs vector of remote locators + * @param action action for negative map-reply + * @param is_add add mapping if non-zero, delete otherwise + * @return return code + */ +int +vnet_lisp_add_del_remote_mapping (gid_address_t * deid, gid_address_t * seid, + ip_address_t * rlocs, u8 action, u8 is_add) +{ + vnet_lisp_add_del_mapping_args_t _dm_args, * dm_args = &_dm_args; + vnet_lisp_add_del_mapping_args_t _sm_args, * sm_args = &_sm_args; + vnet_lisp_add_del_locator_set_args_t _ls, * ls = &_ls; + lisp_cp_main_t * lcm = vnet_lisp_cp_get_main (); + u32 mi, ls_index = 0, dst_map_index, src_map_index; + locator_t loc; + ip_address_t * dl; + int rc = -1; + + memset (sm_args, 0, sizeof (sm_args[0])); + memset (dm_args, 0, sizeof (dm_args[0])); + memset (ls, 0, sizeof (ls[0])); + + /* prepare remote locator set */ + vec_foreach (dl, rlocs) + { + memset (&loc, 0, sizeof (loc)); + gid_address_ip (&loc.address) = dl[0]; + vec_add1 (ls->locators, loc); + } + src_map_index = gid_dictionary_lookup (&lcm->mapping_index_by_gid, seid); + + mi = gid_dictionary_lookup (&lcm->mapping_index_by_gid, deid); + /* new mapping */ + if ((u32)~0 == mi) + { + if ((u32)~0 == src_map_index) + { + clib_warning ("seid %U not found!", format_gid_address, seid); + goto done; + } + + if (!is_add) + { + clib_warning ("deid %U marked for removal but not " + "found!", format_gid_address, deid); + goto done; + } + + ls->is_add = 1; + ls->index = ~0; + vnet_lisp_add_del_locator_set (ls, &ls_index); + + /* add mapping */ + gid_address_copy (&dm_args->deid, deid); + dm_args->is_add = 1; + dm_args->action = action; + dm_args->locator_set_index = ls_index; + vnet_lisp_add_del_mapping (dm_args, &dst_map_index); + + /* add fwd tunnel */ + add_fwd_entry (lcm, src_map_index, dst_map_index); + } + else + { + /* delete mapping */ + if (!is_add) + { + /* delete forwarding entry */ + del_fwd_entry (lcm, 0, mi); + dm_args->is_add = 0; + gid_address_copy (&dm_args->deid, deid); + mapping_t * map = pool_elt_at_index (lcm->mapping_pool, mi); + dm_args->locator_set_index = map->locator_set_index; + + /* delete mapping associated to fwd entry */ + vnet_lisp_add_del_mapping (dm_args, 0); + + ls->is_add = 0; + ls->index = map->locator_set_index; + /* delete locator set */ + vnet_lisp_add_del_locator_set (ls, 0); + } + /* update existing locator set */ + else + { + if ((u32)~0 == src_map_index) + { + clib_warning ("seid %U not found!", format_gid_address, seid); + goto done; + } + + mapping_t * old_map; + locator_set_t * old_ls; + old_map = pool_elt_at_index (lcm->mapping_pool, mi); + + /* update mapping attributes */ + old_map->action = action; + + old_ls = pool_elt_at_index(lcm->locator_set_pool, + old_map->locator_set_index); + if (compare_locators (lcm, old_ls->locator_indices, + ls->locators)) + { + /* set locator-set index to overwrite */ + ls->is_add = 1; + ls->index = old_map->locator_set_index; + vnet_lisp_add_del_locator_set (ls, 0); + add_fwd_entry (lcm, src_map_index, mi); + } + } + } + /* success */ + rc = 0; +done: + vec_free (ls->locators); + return rc; +} + +/** + * Handler for add/del remote mapping CLI. + * + * @param vm vlib context + * @param input input from user + * @param cmd cmd + * @return pointer to clib error structure + */ +static clib_error_t * +lisp_add_del_remote_mapping_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + clib_error_t * error = 0; + unformat_input_t _line_input, * line_input = &_line_input; + u8 is_add = 1; + ip_address_t rloc, * rlocs = 0; + ip_prefix_t * deid_ippref, * seid_ippref; + gid_address_t seid, deid; + u8 deid_set = 0, seid_set = 0; + u32 vni, action = ~0; + + /* Get a line of input. */ + if (! unformat_user (input, unformat_line_input, line_input)) + return 0; + + memset (&deid, 0, sizeof (deid)); + memset (&seid, 0, sizeof (seid)); + + seid_ippref = &gid_address_ippref(&seid); + deid_ippref = &gid_address_ippref(&deid); + + gid_address_type (&deid) = GID_ADDR_IP_PREFIX; + gid_address_type (&seid) = GID_ADDR_IP_PREFIX; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "del")) + is_add = 0; + if (unformat (line_input, "add")) + ; + else if (unformat (line_input, "deid %U", + unformat_ip_prefix, deid_ippref)) + { + deid_set = 1; + } + else if (unformat (line_input, "vni %u", &vni)) + { + gid_address_set_vni (&seid, vni); + gid_address_set_vni (&deid, vni); + } + else if (unformat (line_input, "seid %U", + unformat_ip_prefix, seid_ippref)) + seid_set = 1; + else if (unformat (line_input, "rloc %U", unformat_ip_address, &rloc)) + vec_add1 (rlocs, rloc); + else if (unformat (line_input, "action %d", &action)) + ; + else + { + clib_warning ("parse error"); + goto done; + } + } + + if (is_add && (!deid_set || !seid_set)) + { + clib_warning ("missing paramete(s)!"); + goto done; + } + + if (!is_add && !deid_set) + { + clib_warning ("missing deid!"); + goto done; + } + + 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; + } + + if (is_add && (~0 == action) + && 0 == vec_len (rlocs)) + { + clib_warning ("no action set for negative map-reply!"); + goto done; + } + + int rv = vnet_lisp_add_del_remote_mapping (&deid, &seid, rlocs, + action, is_add); + if (rv) + clib_warning ("failed to %s remote mapping!", + is_add ? "add" : "delete"); + +done: + unformat_free (line_input); + return error; +} + +VLIB_CLI_COMMAND (lisp_add_del_remote_mapping_command) = { + .path = "lisp remote-mapping", + .short_help = "lisp remote-mapping add|del vni deid " + "seid rloc [rloc ... ]", + .function = lisp_add_del_remote_mapping_command_fn, +}; + static clib_error_t * lisp_show_local_eid_table_command_fn (vlib_main_t * vm, unformat_input_t * input, @@ -1467,7 +1710,7 @@ ip_interface_get_first_ip_addres (ip_lookup_main_t *lm, u32 sw_if_index, return ip_interface_address_get_address (lm, ia); } -void +static void del_fwd_entry (lisp_cp_main_t * lcm, u32 src_map_index, u32 dst_map_index) { diff --git a/vnet/vnet/lisp-cp/control.h b/vnet/vnet/lisp-cp/control.h index fad90e6ec68..ecab1dba091 100644 --- a/vnet/vnet/lisp-cp/control.h +++ b/vnet/vnet/lisp-cp/control.h @@ -175,4 +175,8 @@ vnet_lisp_cp_get_main() { clib_error_t * vnet_lisp_enable_disable (u8 is_enabled); u8 vnet_lisp_enable_disable_status (void); +int +vnet_lisp_add_del_remote_mapping (gid_address_t * deid, gid_address_t * seid, + ip_address_t * dlocs, u8 action, u8 is_add); + #endif /* VNET_CONTROL_H_ */ diff --git a/vnet/vnet/lisp-cp/lisp_types.h b/vnet/vnet/lisp-cp/lisp_types.h index 8db3cfe7338..21e24fb3aee 100644 --- a/vnet/vnet/lisp-cp/lisp_types.h +++ b/vnet/vnet/lisp-cp/lisp_types.h @@ -165,6 +165,9 @@ u32 gid_address_parse (u8 * offset, gid_address_t *a); #define gid_address_lcaf(_a) (_a)->lcaf #define gid_address_vni(_a) ( (GID_ADDR_LCAF == gid_address_type(_a)) ? \ lcaf_vni(&gid_address_lcaf(_a)) : 0) +/* setter for vni */ +#define gid_address_set_vni(_a, _val) \ + (lcaf_vni(&gid_address_lcaf(_a)) = (_val)) /* 'sub'address functions */ u16 ip_prefix_size_to_write (void * pref); diff --git a/vnet/vnet/lisp-gpe/lisp_gpe.c b/vnet/vnet/lisp-gpe/lisp_gpe.c index c09b322b090..c00a9cf43b6 100644 --- a/vnet/vnet/lisp-gpe/lisp_gpe.c +++ b/vnet/vnet/lisp-gpe/lisp_gpe.c @@ -350,6 +350,7 @@ lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm, done: vec_free(eids); vec_free(slocators); + vec_free(dlocators); return error; } diff --git a/vpp-api-test/vat/api_format.c b/vpp-api-test/vat/api_format.c index 496b2d60d76..bf1a3931b0b 100644 --- a/vpp-api-test/vat/api_format.c +++ b/vpp-api-test/vat/api_format.c @@ -9810,6 +9810,132 @@ api_lisp_enable_disable (vat_main_t * vam) return 0; } +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u8 is_ip4; /**< is locator an IPv4 address? */ + u8 addr[16]; /**< IPv4/IPv6 address */ +}) rloc_t; + +/** + * Add/del remote mapping from LISP control plane and updates + * forwarding entries in data-plane accordingly. + * + * @param vam vpp API test context + * @return return code + */ +static int +api_lisp_add_del_remote_mapping (vat_main_t * vam) +{ + unformat_input_t * input = vam->input; + vl_api_lisp_add_del_remote_mapping_t *mp; + f64 timeout = ~0; + u32 vni = 0; + u8 seid_set = 0, deid_set = 0; + ip4_address_t seid4, deid4, rloc4; + ip6_address_t seid6, deid6, rloc6; + u32 seid_len = 0, deid_len = 0, len; + u8 deid_is_ip4 = 0, seid_is_ip4 = 0; + u8 is_add = 1; + u32 action = ~0; + rloc_t * rlocs = 0, rloc; + + /* Parse args required to build the message */ + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { + if (unformat(input, "del")) { + is_add = 0; + } else if (unformat(input, "add")) { + is_add = 1; + } else if (unformat(input, "deid %U/%d", unformat_ip4_address, + &deid4, &len)) { + deid_set = 1; + deid_is_ip4 = 1; + deid_len = len; + } else if (unformat(input, "deid %U/%d", unformat_ip6_address, + &deid6, &len)) { + deid_set = 1; + deid_is_ip4 = 0; + deid_len = len; + } else if (unformat(input, "seid %U/%d", unformat_ip4_address, + &seid4, &len)) { + seid_set = 1; + seid_is_ip4 = 1; + seid_len = len; + } else if (unformat(input, "seid %U/%d", unformat_ip6_address, + &seid6, &len)) { + seid_set = 1; + seid_is_ip4 = 0; + seid_len = len; + } else if (unformat(input, "vni %d", &vni)) { + ; + } else if (unformat(input, "rloc %U", unformat_ip4_address, &rloc4)) { + rloc.is_ip4 = 1; + clib_memcpy (&rloc.addr, &rloc4, sizeof (rloc4)); + vec_add1 (rlocs, rloc); + } else if (unformat(input, "rloc %U", unformat_ip6_address, &rloc6)) { + rloc.is_ip4 = 0; + clib_memcpy (&rloc.addr, &rloc6, sizeof (rloc6)); + vec_add1 (rlocs, rloc); + } else if (unformat(input, "action %d", &action)) { + ; + } else { + clib_warning ("parse error '%U'", format_unformat_error, input); + return -99; + } + } + + if (!seid_set || !deid_set) { + errmsg ("missing params!"); + return -99; + } + + if (seid_is_ip4 != deid_is_ip4) { + errmsg ("source and destination EIDs are not in " "same IP family!"); + return -99; + } + + if (is_add && (~0 == action) + && 0 == vec_len (rlocs)) { + errmsg ("no action set for negative map-reply!"); + return -99; + } + + M(LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping); + mp->is_add = is_add; + mp->vni = htonl (vni); + mp->seid_len = seid_len; + mp->action = (u8) action; + mp->deid_len = deid_len; + if (seid_is_ip4) { + mp->eid_is_ip4 = 1; + clib_memcpy (mp->seid, &seid4, sizeof (seid4)); + } else { + mp->eid_is_ip4 = 0; + clib_memcpy (mp->seid, &seid6, sizeof (seid6)); + } + + if (deid_is_ip4) { + mp->eid_is_ip4 = 1; + clib_memcpy (mp->deid, &deid4, sizeof (deid4)); + } else { + mp->eid_is_ip4 = 0; + clib_memcpy (mp->deid, &deid6, sizeof (deid6)); + } + + mp->rloc_num = vec_len (rlocs); + clib_memcpy (mp->rlocs, rlocs, (sizeof (rloc_t) * vec_len (rlocs))); + vec_free (rlocs); + + /* send it... */ + S; + + /* Wait for a reply... */ + W; + + /* NOTREACHED */ + return 0; +} + static int api_lisp_gpe_add_del_iface(vat_main_t * vam) { @@ -10556,6 +10682,9 @@ _(lisp_add_del_map_resolver, " [del]") \ _(lisp_gpe_enable_disable, "enable|disable") \ _(lisp_enable_disable, "enable|disable") \ _(lisp_gpe_add_del_iface, "up|down") \ +_(lisp_add_del_remote_mapping, "add|del vni deid seid" \ + " rloc " \ + "[rloc ... ]") \ _(lisp_locator_set_dump, "") \ _(lisp_local_eid_table_dump, "") \ _(lisp_gpe_tunnel_dump, "") \ diff --git a/vpp/api/api.c b/vpp/api/api.c index 24f7d9c0e19..0d5f224118e 100644 --- a/vpp/api/api.c +++ b/vpp/api/api.c @@ -326,6 +326,7 @@ _(LISP_ADD_DEL_MAP_RESOLVER, lisp_add_del_map_resolver) \ _(LISP_GPE_ENABLE_DISABLE, lisp_gpe_enable_disable) \ _(LISP_ENABLE_DISABLE, lisp_enable_disable) \ _(LISP_GPE_ADD_DEL_IFACE, lisp_gpe_add_del_iface) \ +_(LISP_ADD_DEL_REMOTE_MAPPING, lisp_add_del_remote_mapping) \ _(LISP_LOCATOR_SET_DUMP, lisp_locator_set_dump) \ _(LISP_LOCAL_EID_TABLE_DUMP, lisp_local_eid_table_dump) \ _(LISP_GPE_TUNNEL_DUMP, lisp_gpe_tunnel_dump) \ @@ -4823,6 +4824,13 @@ vl_api_lisp_gpe_add_del_iface_t_handler( REPLY_MACRO(VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY); } +/** Used for transferring locators via VPP API */ +typedef CLIB_PACKED(struct +{ + u8 is_ip4; /**< is locator an IPv4 address */ + u8 addr[16]; /**< IPv4/IPv6 address */ +}) rloc_t; + static void send_lisp_locator_set_details_set_address (vl_api_lisp_locator_set_details_t *rmp, @@ -4840,6 +4848,62 @@ send_lisp_locator_set_details_set_address ip_address_copy_addr(rmp->ip_address, &ip_prefix_addr(ip_addr)); } +static void +vl_api_lisp_add_del_remote_mapping_t_handler ( + vl_api_lisp_add_del_remote_mapping_t *mp) +{ + u32 i; + ip_address_t rloc, * rlocs = 0; + vl_api_lisp_add_del_remote_mapping_reply_t * rmp; + int rv = 0; + gid_address_t _seid, * seid = &_seid; + gid_address_t _deid, * deid = &_deid; + ip_prefix_t * seid_pref = &gid_address_ippref(seid); + ip_prefix_t * deid_pref = &gid_address_ippref(deid); + + gid_address_type(seid) = GID_ADDR_IP_PREFIX; + gid_address_type(deid) = GID_ADDR_IP_PREFIX; + ip_address_t * seid_addr = &ip_prefix_addr(seid_pref); + ip_address_t * deid_addr = &ip_prefix_addr(deid_pref); + ip_prefix_len(seid_pref) = mp->seid_len; + ip_prefix_len(deid_pref) = mp->deid_len; + gid_address_set_vni (seid, ntohl (mp->vni)); + gid_address_set_vni (deid, ntohl (mp->vni)); + + if (mp->eid_is_ip4) { + ip_prefix_version(seid_pref) = IP4; + ip_prefix_version(deid_pref) = IP4; + clib_memcpy (&ip_addr_v4(seid_addr), + mp->seid, sizeof (ip_addr_v4(seid_addr))); + clib_memcpy (&ip_addr_v4(deid_addr), + mp->deid, sizeof (ip_addr_v4(deid_addr))); + } else { + ip_prefix_version(seid_pref) = IP6; + ip_prefix_version(deid_pref) = IP6; + clib_memcpy (&ip_addr_v6(seid_addr), + mp->seid, sizeof (ip_addr_v6(seid_addr))); + clib_memcpy (&ip_addr_v6(deid_addr), + mp->deid, sizeof (ip_addr_v6(deid_addr))); + } + + for (i = 0; i < mp->rloc_num; i++) { + rloc_t * r = &((rloc_t *) mp->rlocs)[i]; + if (r->is_ip4) { + clib_memcpy (&ip_addr_v4(&rloc), &r->addr, sizeof (rloc_t)); + ip_addr_version (&rloc) = IP4; + } else { + clib_memcpy (&ip_addr_v6(&rloc), &r->addr, sizeof (rloc_t)); + ip_addr_version (&rloc) = IP6; + } + vec_add1 (rlocs, rloc); + } + + rv = vnet_lisp_add_del_remote_mapping (deid, seid, rlocs, + mp->action, mp->is_add); + vec_free (rlocs); + REPLY_MACRO(VL_API_LISP_GPE_ADD_DEL_IFACE_REPLY); +} + static void send_lisp_locator_set_details (lisp_cp_main_t *lcm, locator_set_t *lsit, diff --git a/vpp/api/vpe.api b/vpp/api/vpe.api index fadecfb1966..df3b2af0e3c 100644 --- a/vpp/api/vpe.api +++ b/vpp/api/vpe.api @@ -2377,6 +2377,43 @@ define lisp_gpe_add_del_iface_reply { i32 retval; }; +/** \brief add or delete remote static mapping + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param is_add - add address if non-zero, else delete + @param vni - virtual network instance + @param action - negative map-reply action + @param eid_is_ip4 - ipv4/6 of source and destination EIDs + @param deid - destination EID + @param seid - source EID + @param rloc_num - number of remote locators + @param rlocs - remote locator data +*/ +define lisp_add_del_remote_mapping { + u32 client_index; + u32 context; + u8 is_add; + u32 vni; + u8 action; + u8 eid_is_ip4; + u8 deid[16]; + u8 seid[16]; + u8 deid_len; + u8 seid_len; + u32 rloc_num; + u8 rlocs[0]; +}; + +/** \brief Reply for lisp_add_del_remote_mapping + @param context - returned sender context, to match reply w/ request + @param retval - return code +*/ + +define lisp_add_del_remote_mapping_reply { + u32 context; + i32 retval; +}; + /** \brief LISP locator_set status @param locator_set_name - name of the locator_set @param sw_if_index - sw_if_index of the locator -- cgit 1.2.3-korg