From c83c3b7f117b981b677f646a0e30f44ec70de239 Mon Sep 17 00:00:00 2001 From: Jon Loeliger Date: Thu, 23 Feb 2017 13:57:35 -0600 Subject: Implement a loopback instance allocation scheme. To support creating loopback interfaces with a specific instance number, a new CREATE_LOOPBACK_INSTANCE API call with flag is_specified and value user_instance is introduced. Presumably the existing CREATE_LOOPBACK API message will be obsoleted and revmoved. The VAT cli commands can now mention and format the new field as 'instance %d' data. If no instance number is named, the old call CREATE_LOOPBACK is used to maintain backward compatibility. However, if the instance is named, the new CREATE_LOOPBACK_INSTANCE message will be used. Both the dynamically allocated and user-requested instance number are tracked in a bitvector. If is_specified is 0, the next free instance will be used.. A request for a specific instance number will be granted if it is available. On error, the value ~0 is returned. Change-Id: I849815563a5da736dcd6bccd262ef49b963f6643 Signed-off-by: Jon Loeliger --- src/vat/api_format.c | 59 +++++++++++++++++--- src/vnet/ethernet/ethernet.h | 6 ++- src/vnet/ethernet/interface.c | 123 ++++++++++++++++++++++++++++++++++++++---- src/vpp/api/api.c | 23 +++++++- src/vpp/api/custom_dump.c | 13 +++++ src/vpp/api/test_client.c | 8 +++ src/vpp/api/vpe.api | 28 ++++++++++ 7 files changed, 241 insertions(+), 19 deletions(-) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 524369178ac..993a6e8b393 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -725,6 +725,34 @@ static void vl_api_create_loopback_reply_t_handler_json vam->result_ready = 1; } +static void vl_api_create_loopback_instance_reply_t_handler + (vl_api_create_loopback_instance_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + i32 retval = ntohl (mp->retval); + + vam->retval = retval; + vam->regenerate_interface_table = 1; + vam->sw_if_index = ntohl (mp->sw_if_index); + vam->result_ready = 1; +} + +static void vl_api_create_loopback_instance_reply_t_handler_json + (vl_api_create_loopback_instance_reply_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t node; + + vat_json_init_object (&node); + vat_json_object_add_int (&node, "retval", ntohl (mp->retval)); + vat_json_object_add_uint (&node, "sw_if_index", ntohl (mp->sw_if_index)); + + vat_json_print (vam->ofp, &node); + vat_json_free (&node); + vam->retval = ntohl (mp->retval); + vam->result_ready = 1; +} + static void vl_api_af_packet_create_reply_t_handler (vl_api_af_packet_create_reply_t * mp) { @@ -4010,6 +4038,7 @@ foreach_standard_reply_retval_handler; #define foreach_vpe_api_reply_msg \ _(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ +_(CREATE_LOOPBACK_INSTANCE_REPLY, create_loopback_instance_reply) \ _(SW_INTERFACE_DETAILS, sw_interface_details) \ _(SW_INTERFACE_SET_FLAGS_REPLY, sw_interface_set_flags_reply) \ _(CONTROL_PING_REPLY, control_ping_reply) \ @@ -4720,8 +4749,11 @@ api_create_loopback (vat_main_t * vam) { unformat_input_t *i = vam->input; vl_api_create_loopback_t *mp; + vl_api_create_loopback_instance_t *mp_lbi; u8 mac_address[6]; u8 mac_set = 0; + u8 is_specified = 0; + u32 user_instance = 0; int ret; memset (mac_address, 0, sizeof (mac_address)); @@ -4730,16 +4762,31 @@ api_create_loopback (vat_main_t * vam) { if (unformat (i, "mac %U", unformat_ethernet_address, mac_address)) mac_set = 1; + if (unformat (i, "instance %d", &user_instance)) + is_specified = 1; else break; } - /* Construct the API message */ - M (CREATE_LOOPBACK, mp); - if (mac_set) - clib_memcpy (mp->mac_address, mac_address, sizeof (mac_address)); + if (is_specified) + { + M (CREATE_LOOPBACK_INSTANCE, mp_lbi); + mp_lbi->is_specified = is_specified; + if (is_specified) + mp_lbi->user_instance = htonl (user_instance); + if (mac_set) + clib_memcpy (mp_lbi->mac_address, mac_address, sizeof (mac_address)); + S (mp_lbi); + } + else + { + /* Construct the API message */ + M (CREATE_LOOPBACK, mp); + if (mac_set) + clib_memcpy (mp->mac_address, mac_address, sizeof (mac_address)); + S (mp); + } - S (mp); W (ret); return ret; } @@ -18021,7 +18068,7 @@ echo (vat_main_t * vam) /* List of API message constructors, CLI names map to api_xxx */ #define foreach_vpe_api_msg \ -_(create_loopback,"[mac ]") \ +_(create_loopback,"[mac ] [instance ]") \ _(sw_interface_dump,"") \ _(sw_interface_set_flags, \ " | sw_if_index admin-up | admin-down link-up | link down") \ diff --git a/src/vnet/ethernet/ethernet.h b/src/vnet/ethernet/ethernet.h index 3acde421f78..ba84c69c00c 100644 --- a/src/vnet/ethernet/ethernet.h +++ b/src/vnet/ethernet/ethernet.h @@ -265,6 +265,9 @@ typedef struct /* Feature arc index */ u8 output_feature_arc_index; + + /* Allocated loopback instances */ + uword *bm_loopback_instances; } ethernet_main_t; ethernet_main_t ethernet_main; @@ -412,7 +415,8 @@ clib_error_t *next_by_ethertype_init (next_by_ethertype_t * l3_next); clib_error_t *next_by_ethertype_register (next_by_ethertype_t * l3_next, u32 ethertype, u32 next_index); -int vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address); +int vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address, + u8 is_specified, u32 user_instance); int vnet_delete_loopback_interface (u32 sw_if_index); int vnet_delete_sub_interface (u32 sw_if_index); diff --git a/src/vnet/ethernet/interface.c b/src/vnet/ethernet/interface.c index 95700309499..9894e3c887b 100644 --- a/src/vnet/ethernet/interface.c +++ b/src/vnet/ethernet/interface.c @@ -453,13 +453,87 @@ VNET_DEVICE_CLASS (ethernet_simulated_device_class) = { }; /* *INDENT-ON* */ + +/* + * Maintain a bitmap of allocated loopback instance numbers. + */ +#define LOOPBACK_MAX_INSTANCE (16 * 1024) + +static u32 +loopback_instance_alloc (u8 is_specified, u32 want) +{ + ethernet_main_t *em = ðernet_main; + + /* + * Check for dynamically allocaetd instance number. + */ + if (!is_specified) + { + u32 bit; + + bit = clib_bitmap_first_clear (em->bm_loopback_instances); + if (bit >= LOOPBACK_MAX_INSTANCE) + { + return ~0; + } + em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances, + bit, 1); + return bit; + } + + /* + * In range? + */ + if (want >= LOOPBACK_MAX_INSTANCE) + { + return ~0; + } + + /* + * Already in use? + */ + if (clib_bitmap_get (em->bm_loopback_instances, want)) + { + return ~0; + } + + /* + * Grant allocation request. + */ + em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances, + want, 1); + + return want; +} + +static int +loopback_instance_free (u32 instance) +{ + ethernet_main_t *em = ðernet_main; + + if (instance >= LOOPBACK_MAX_INSTANCE) + { + return -1; + } + + if (clib_bitmap_get (em->bm_loopback_instances, instance) == 0) + { + return -1; + } + + em->bm_loopback_instances = clib_bitmap_set (em->bm_loopback_instances, + instance, 0); + return 0; +} + int -vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address) +vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address, + u8 is_specified, u32 user_instance) { vnet_main_t *vnm = vnet_get_main (); vlib_main_t *vm = vlib_get_main (); clib_error_t *error; - static u32 instance; + u32 instance; u8 address[6]; u32 hw_if_index; vnet_hw_interface_t *hw_if; @@ -472,6 +546,16 @@ vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address) memset (address, 0, sizeof (address)); + /* + * Allocate a loopback instance. Either select on dynamically + * or try to use the desired user_instance number. + */ + instance = loopback_instance_alloc (is_specified, user_instance); + if (instance == ~0) + { + return VNET_API_ERROR_INVALID_REGISTRATION; + } + /* * Default MAC address (dead:0000:0000 + instance) is allocated * if zero mac_address is configured. Otherwise, user-configurable MAC @@ -488,7 +572,7 @@ vnet_create_loopback_interface (u32 * sw_if_indexp, u8 * mac_address) error = ethernet_register_interface (vnm, - ethernet_simulated_device_class.index, instance++, address, &hw_if_index, + ethernet_simulated_device_class.index, instance, address, &hw_if_index, /* flag change */ 0); if (error) @@ -520,6 +604,8 @@ create_simulated_ethernet_interfaces (vlib_main_t * vm, int rv; u32 sw_if_index; u8 mac_address[6]; + u8 is_specified = 0; + u32 user_instance = 0; memset (mac_address, 0, sizeof (mac_address)); @@ -527,11 +613,14 @@ create_simulated_ethernet_interfaces (vlib_main_t * vm, { if (unformat (input, "mac %U", unformat_ethernet_address, mac_address)) ; + if (unformat (input, "instance %d", &user_instance)) + is_specified = 1; else break; } - rv = vnet_create_loopback_interface (&sw_if_index, mac_address); + rv = vnet_create_loopback_interface (&sw_if_index, mac_address, + is_specified, user_instance); if (rv) return clib_error_return (0, "vnet_create_loopback_interface failed"); @@ -547,15 +636,15 @@ create_simulated_ethernet_interfaces (vlib_main_t * vm, * * @cliexpar * The following two command syntaxes are equivalent: - * @cliexcmd{loopback create-interface [mac ]} - * @cliexcmd{create loopback interface [mac ]} + * @cliexcmd{loopback create-interface [mac ] [instance ]} + * @cliexcmd{create loopback interface [mac ] [instance ]} * Example of how to create a loopback interface: * @cliexcmd{loopback create-interface} ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = { .path = "loopback create-interface", - .short_help = "loopback create-interface [mac ]", + .short_help = "loopback create-interface [mac ] [instance ]", .function = create_simulated_ethernet_interfaces, }; /* *INDENT-ON* */ @@ -566,15 +655,15 @@ VLIB_CLI_COMMAND (create_simulated_ethernet_interface_command, static) = { * * @cliexpar * The following two command syntaxes are equivalent: - * @cliexcmd{loopback create-interface [mac ]} - * @cliexcmd{create loopback interface [mac ]} + * @cliexcmd{loopback create-interface [mac ] [instance ]} + * @cliexcmd{create loopback interface [mac ] [instance ]} * Example of how to create a loopback interface: * @cliexcmd{create loopback interface} ?*/ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (create_loopback_interface_command, static) = { .path = "create loopback interface", - .short_help = "create loopback interface [mac ]", + .short_help = "create loopback interface [mac ] [instance ]", .function = create_simulated_ethernet_interfaces, }; /* *INDENT-ON* */ @@ -594,12 +683,24 @@ vnet_delete_loopback_interface (u32 sw_if_index) { vnet_main_t *vnm = vnet_get_main (); vnet_sw_interface_t *si; + u32 hw_if_index; + vnet_hw_interface_t *hw; + u32 instance; if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index)) return VNET_API_ERROR_INVALID_SW_IF_INDEX; si = vnet_get_sw_interface (vnm, sw_if_index); - ethernet_delete_interface (vnm, si->hw_if_index); + hw_if_index = si->hw_if_index; + hw = vnet_get_hw_interface (vnm, hw_if_index); + instance = hw->dev_instance; + + if (loopback_instance_free (instance) < 0) + { + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + } + + ethernet_delete_interface (vnm, hw_if_index); return 0; } diff --git a/src/vpp/api/api.c b/src/vpp/api/api.c index e028fad4a39..f06894e8783 100644 --- a/src/vpp/api/api.c +++ b/src/vpp/api/api.c @@ -116,6 +116,7 @@ _(PROXY_ARP_INTFC_ENABLE_DISABLE, proxy_arp_intfc_enable_disable) \ _(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \ _(RESET_FIB, reset_fib) \ _(CREATE_LOOPBACK, create_loopback) \ +_(CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \ _(CONTROL_PING, control_ping) \ _(CLI_REQUEST, cli_request) \ _(CLI_INBAND, cli_inband) \ @@ -1026,7 +1027,7 @@ vl_api_create_loopback_t_handler (vl_api_create_loopback_t * mp) u32 sw_if_index; int rv; - rv = vnet_create_loopback_interface (&sw_if_index, mp->mac_address); + rv = vnet_create_loopback_interface (&sw_if_index, mp->mac_address, 0, 0); /* *INDENT-OFF* */ REPLY_MACRO2(VL_API_CREATE_LOOPBACK_REPLY, @@ -1036,6 +1037,26 @@ vl_api_create_loopback_t_handler (vl_api_create_loopback_t * mp) /* *INDENT-ON* */ } +static void vl_api_create_loopback_instance_t_handler + (vl_api_create_loopback_instance_t * mp) +{ + vl_api_create_loopback_instance_reply_t *rmp; + u32 sw_if_index; + u8 is_specified = mp->is_specified; + u32 user_instance = ntohl (mp->user_instance); + int rv; + + rv = vnet_create_loopback_interface (&sw_if_index, mp->mac_address, + is_specified, user_instance); + + /* *INDENT-OFF* */ + REPLY_MACRO2(VL_API_CREATE_LOOPBACK_INSTANCE_REPLY, + ({ + rmp->sw_if_index = ntohl (sw_if_index); + })); + /* *INDENT-ON* */ +} + static void vl_api_delete_loopback_t_handler (vl_api_delete_loopback_t * mp) { diff --git a/src/vpp/api/custom_dump.c b/src/vpp/api/custom_dump.c index c61e31bb8d5..ee0c4629b50 100644 --- a/src/vpp/api/custom_dump.c +++ b/src/vpp/api/custom_dump.c @@ -72,6 +72,18 @@ static void *vl_api_create_loopback_t_print FINISH; } +static void *vl_api_create_loopback_instance_t_print + (vl_api_create_loopback_instance_t * mp, void *handle) +{ + u8 *s; + + s = format (0, "SCRIPT: create_loopback "); + s = format (s, "mac %U ", format_ethernet_address, &mp->mac_address); + s = format (s, "instance %d ", ntohl (mp->user_instance)); + + FINISH; +} + static void *vl_api_delete_loopback_t_print (vl_api_delete_loopback_t * mp, void *handle) { @@ -2821,6 +2833,7 @@ foreach_custom_print_no_arg_function #undef _ #define foreach_custom_print_function \ _(CREATE_LOOPBACK, create_loopback) \ +_(CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \ _(SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \ _(SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \ _(SW_INTERFACE_SET_TABLE, sw_interface_set_table) \ diff --git a/src/vpp/api/test_client.c b/src/vpp/api/test_client.c index ceafc35788d..8b61f4f3a05 100644 --- a/src/vpp/api/test_client.c +++ b/src/vpp/api/test_client.c @@ -534,6 +534,13 @@ static void vl_api_create_loopback_reply_t_handler ntohl (mp->retval), ntohl (mp->sw_if_index)); } +static void vl_api_create_loopback_instance_reply_t_handler + (vl_api_create_loopback_instance_reply_t * mp) +{ + fformat (stdout, "create loopback status %d, sw_if_index %d\n", + ntohl (mp->retval), ntohl (mp->sw_if_index)); +} + static void vl_api_sr_tunnel_add_del_reply_t_handler (vl_api_sr_tunnel_add_del_reply_t * mp) @@ -598,6 +605,7 @@ _(SW_INTERFACE_IP6ND_RA_PREFIX_REPLY, sw_interface_ip6nd_ra_prefix_reply) \ _(SW_INTERFACE_IP6_ENABLE_DISABLE_REPLY, sw_interface_ip6_enable_disable_reply) \ _(SW_INTERFACE_IP6_SET_LINK_LOCAL_ADDRESS_REPLY, sw_interface_ip6_set_link_local_address_reply) \ _(CREATE_LOOPBACK_REPLY, create_loopback_reply) \ + _(CREATE_LOOPBACK_INSTANCE_REPLY, create_loopback_instance_reply) \ _(L2_PATCH_ADD_DEL_REPLY, l2_patch_add_del_reply) \ _(SR_TUNNEL_ADD_DEL_REPLY,sr_tunnel_add_del_reply) \ _(SW_INTERFACE_SET_L2_XCONNECT_REPLY, sw_interface_set_l2_xconnect_reply) \ diff --git a/src/vpp/api/vpe.api b/src/vpp/api/vpe.api index 7f9c203807c..a4ba180dfb2 100644 --- a/src/vpp/api/vpe.api +++ b/src/vpp/api/vpe.api @@ -425,6 +425,34 @@ define create_loopback_reply u32 sw_if_index; }; +/** \brief Create loopback interface instance request + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param mac_address - mac addr to assign to the interface if none-zero + @param is_specified - if non-0, a specific user_instance is being requested + @param user_instance - requested instance, ~0 => dynamically allocate +*/ +define create_loopback_instance +{ + u32 client_index; + u32 context; + u8 mac_address[6]; + u8 is_specified; + u32 user_instance; +}; + +/** \brief Create loopback interface instance response + @param context - sender context, to match reply w/ request + @param sw_if_index - sw index of the interface that was created + @param retval - return code for the request +*/ +define create_loopback_instance_reply +{ + u32 context; + i32 retval; + u32 sw_if_index; +}; + /** \brief Delete loopback interface request @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request -- cgit 1.2.3-korg