aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vat/api_format.c59
-rw-r--r--src/vnet/ethernet/ethernet.h6
-rw-r--r--src/vnet/ethernet/interface.c123
-rw-r--r--src/vpp/api/api.c23
-rw-r--r--src/vpp/api/custom_dump.c13
-rw-r--r--src/vpp/api/test_client.c8
-rw-r--r--src/vpp/api/vpe.api28
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 <mac-addr>]") \
+_(create_loopback,"[mac <mac-addr>] [instance <instance>]") \
_(sw_interface_dump,"") \
_(sw_interface_set_flags, \
"<intfc> | sw_if_index <id> 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 = &ethernet_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 = &ethernet_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;
@@ -473,6 +547,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
* address is programmed on the loopback interface.
@@ -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 <mac-addr>]}
- * @cliexcmd{create loopback interface [mac <mac-addr>]}
+ * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
+ * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <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 <mac-addr>]",
+ .short_help = "loopback create-interface [mac <mac-addr>] [instance <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 <mac-addr>]}
- * @cliexcmd{create loopback interface [mac <mac-addr>]}
+ * @cliexcmd{loopback create-interface [mac <mac-addr>] [instance <instance>]}
+ * @cliexcmd{create loopback interface [mac <mac-addr>] [instance <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 <mac-addr>]",
+ .short_help = "create loopback interface [mac <mac-addr>] [instance <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