diff options
author | Jon Loeliger <jdl@netgate.com> | 2017-02-23 13:57:35 -0600 |
---|---|---|
committer | John Lo <loj@cisco.com> | 2017-03-03 23:19:21 +0000 |
commit | c83c3b7f117b981b677f646a0e30f44ec70de239 (patch) | |
tree | 323266bab831bcbfb14f089e803b7cbc13b857e1 /src/vnet/ethernet | |
parent | a084d62a6e47d3505b3ed314230598704314f7bc (diff) |
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 <jdl@netgate.com>
Diffstat (limited to 'src/vnet/ethernet')
-rw-r--r-- | src/vnet/ethernet/ethernet.h | 6 | ||||
-rw-r--r-- | src/vnet/ethernet/interface.c | 123 |
2 files changed, 117 insertions, 12 deletions
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; @@ -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; } |