l2: add per bridge domain learn limit
Type: feature Signed-off-by: Jerome Tollet <jtollet@cisco.com> Change-Id: I57ed6699050445d9c9aec98eff3aab56735aca54 Signed-off-by: Jerome Tollet <jtollet@cisco.com>
This commit is contained in:
@@ -247,6 +247,33 @@ autoreply define bridge_domain_set_mac_age
|
||||
u8 mac_age;
|
||||
};
|
||||
|
||||
/** \brief L2 bridge domain set default learn limit
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param learn limit - maximum number of entries by default for bridge domains
|
||||
*/
|
||||
autoreply define bridge_domain_set_default_learn_limit
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 learn_limit;
|
||||
};
|
||||
|
||||
|
||||
/** \brief L2 bridge domain set learn limit
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param bd_id - the bridge domain idenntifier
|
||||
@param learn limit - maximum number of entries for this bd
|
||||
*/
|
||||
autoreply define bridge_domain_set_learn_limit
|
||||
{
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 bd_id;
|
||||
u32 learn_limit;
|
||||
};
|
||||
|
||||
/** \brief L2 bridge domain add or delete request
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
|
||||
+69
-27
@@ -50,33 +50,36 @@
|
||||
|
||||
#include <vlibapi/api_helper_macros.h>
|
||||
|
||||
#define foreach_vpe_api_msg \
|
||||
_(L2_XCONNECT_DUMP, l2_xconnect_dump) \
|
||||
_(L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \
|
||||
_(L2_FIB_TABLE_DUMP, l2_fib_table_dump) \
|
||||
_(L2FIB_FLUSH_ALL, l2fib_flush_all) \
|
||||
_(L2FIB_FLUSH_INT, l2fib_flush_int) \
|
||||
_(L2FIB_FLUSH_BD, l2fib_flush_bd) \
|
||||
_(L2FIB_ADD_DEL, l2fib_add_del) \
|
||||
_(WANT_L2_MACS_EVENTS, want_l2_macs_events) \
|
||||
_(L2_FLAGS, l2_flags) \
|
||||
_(SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \
|
||||
_(SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \
|
||||
_(L2_PATCH_ADD_DEL, l2_patch_add_del) \
|
||||
_(L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \
|
||||
_(BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del) \
|
||||
_(BD_IP_MAC_FLUSH, bd_ip_mac_flush) \
|
||||
_(BD_IP_MAC_DUMP, bd_ip_mac_dump) \
|
||||
_(BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \
|
||||
_(BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \
|
||||
_(BRIDGE_FLAGS, bridge_flags) \
|
||||
_(L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
|
||||
_(L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
|
||||
_(BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \
|
||||
_(SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \
|
||||
_(BVI_CREATE, bvi_create) \
|
||||
_(BVI_DELETE, bvi_delete) \
|
||||
_(WANT_L2_ARP_TERM_EVENTS, want_l2_arp_term_events)
|
||||
#define foreach_vpe_api_msg \
|
||||
_ (L2_XCONNECT_DUMP, l2_xconnect_dump) \
|
||||
_ (L2_FIB_CLEAR_TABLE, l2_fib_clear_table) \
|
||||
_ (L2_FIB_TABLE_DUMP, l2_fib_table_dump) \
|
||||
_ (L2FIB_FLUSH_ALL, l2fib_flush_all) \
|
||||
_ (L2FIB_FLUSH_INT, l2fib_flush_int) \
|
||||
_ (L2FIB_FLUSH_BD, l2fib_flush_bd) \
|
||||
_ (L2FIB_ADD_DEL, l2fib_add_del) \
|
||||
_ (WANT_L2_MACS_EVENTS, want_l2_macs_events) \
|
||||
_ (L2_FLAGS, l2_flags) \
|
||||
_ (SW_INTERFACE_SET_L2_XCONNECT, sw_interface_set_l2_xconnect) \
|
||||
_ (SW_INTERFACE_SET_L2_BRIDGE, sw_interface_set_l2_bridge) \
|
||||
_ (L2_PATCH_ADD_DEL, l2_patch_add_del) \
|
||||
_ (L2_INTERFACE_EFP_FILTER, l2_interface_efp_filter) \
|
||||
_ (BD_IP_MAC_ADD_DEL, bd_ip_mac_add_del) \
|
||||
_ (BD_IP_MAC_FLUSH, bd_ip_mac_flush) \
|
||||
_ (BD_IP_MAC_DUMP, bd_ip_mac_dump) \
|
||||
_ (BRIDGE_DOMAIN_ADD_DEL, bridge_domain_add_del) \
|
||||
_ (BRIDGE_DOMAIN_DUMP, bridge_domain_dump) \
|
||||
_ (BRIDGE_FLAGS, bridge_flags) \
|
||||
_ (L2_INTERFACE_VLAN_TAG_REWRITE, l2_interface_vlan_tag_rewrite) \
|
||||
_ (L2_INTERFACE_PBB_TAG_REWRITE, l2_interface_pbb_tag_rewrite) \
|
||||
_ (BRIDGE_DOMAIN_SET_MAC_AGE, bridge_domain_set_mac_age) \
|
||||
_ (SW_INTERFACE_SET_VPATH, sw_interface_set_vpath) \
|
||||
_ (BVI_CREATE, bvi_create) \
|
||||
_ (BVI_DELETE, bvi_delete) \
|
||||
_ (WANT_L2_ARP_TERM_EVENTS, want_l2_arp_term_events) \
|
||||
_ (BRIDGE_DOMAIN_SET_LEARN_LIMIT, bridge_domain_set_learn_limit) \
|
||||
_ (BRIDGE_DOMAIN_SET_DEFAULT_LEARN_LIMIT, \
|
||||
bridge_domain_set_default_learn_limit)
|
||||
|
||||
static void
|
||||
send_l2_xconnect_details (vl_api_registration_t * reg, u32 context,
|
||||
@@ -408,6 +411,45 @@ vl_api_l2_flags_t_handler (vl_api_l2_flags_t * mp)
|
||||
/* *INDENT-ON* */
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_bridge_domain_set_default_learn_limit_t_handler (
|
||||
vl_api_bridge_domain_set_default_learn_limit_t *mp)
|
||||
{
|
||||
vl_api_bridge_domain_set_default_learn_limit_reply_t *rmp;
|
||||
int rv = 0;
|
||||
|
||||
l2learn_main.bd_default_learn_limit = ntohl (mp->learn_limit);
|
||||
REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_DEFAULT_LEARN_LIMIT_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_bridge_domain_set_learn_limit_t_handler (
|
||||
vl_api_bridge_domain_set_learn_limit_t *mp)
|
||||
{
|
||||
vlib_main_t *vm = vlib_get_main ();
|
||||
bd_main_t *bdm = &bd_main;
|
||||
vl_api_bridge_domain_set_learn_limit_reply_t *rmp;
|
||||
int rv = 0;
|
||||
u32 bd_id = ntohl (mp->bd_id);
|
||||
uword *p;
|
||||
|
||||
if (bd_id == 0)
|
||||
{
|
||||
rv = VNET_API_ERROR_BD_NOT_MODIFIABLE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = hash_get (bdm->bd_index_by_bd_id, bd_id);
|
||||
if (p == 0)
|
||||
{
|
||||
rv = VNET_API_ERROR_NO_SUCH_ENTRY;
|
||||
goto out;
|
||||
}
|
||||
bd_set_learn_limit (vm, *p, ntohl (mp->learn_limit));
|
||||
out:
|
||||
REPLY_MACRO (VL_API_BRIDGE_DOMAIN_SET_LEARN_LIMIT_REPLY);
|
||||
}
|
||||
|
||||
static void
|
||||
vl_api_bridge_domain_set_mac_age_t_handler (vl_api_bridge_domain_set_mac_age_t
|
||||
* mp)
|
||||
|
||||
+118
-23
@@ -88,6 +88,9 @@ bd_add_bd_index (bd_main_t * bdm, u32 bd_id)
|
||||
|
||||
vec_validate (l2input_main.bd_configs, rv);
|
||||
l2input_main.bd_configs[rv].bd_id = bd_id;
|
||||
l2input_main.bd_configs[rv].learn_limit =
|
||||
l2learn_main.bd_default_learn_limit;
|
||||
l2input_main.bd_configs[rv].learn_count = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
@@ -124,6 +127,8 @@ bd_delete (bd_main_t * bdm, u32 bd_index)
|
||||
/* clear BD config for reuse: bd_id to -1 and clear feature_bitmap */
|
||||
bd->bd_id = ~0;
|
||||
bd->feature_bitmap = 0;
|
||||
bd->learn_limit = 0;
|
||||
bd->learn_count = ~0;
|
||||
|
||||
/* free BD tag */
|
||||
vec_free (bd->bd_tag);
|
||||
@@ -355,10 +360,21 @@ bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age)
|
||||
L2_MAC_AGE_PROCESS_EVENT_STOP, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Set learn limit for the bridge domain.
|
||||
*/
|
||||
void
|
||||
bd_set_learn_limit (vlib_main_t *vm, u32 bd_index, u32 learn_limit)
|
||||
{
|
||||
l2_bridge_domain_t *bd_config;
|
||||
vec_validate (l2input_main.bd_configs, bd_index);
|
||||
bd_config = vec_elt_at_index (l2input_main.bd_configs, bd_index);
|
||||
bd_config->learn_limit = learn_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
Set the tag for the bridge domain.
|
||||
*/
|
||||
|
||||
static void
|
||||
bd_set_bd_tag (vlib_main_t * vm, u32 bd_index, u8 * bd_tag)
|
||||
{
|
||||
@@ -446,6 +462,34 @@ VLIB_CLI_COMMAND (bd_learn_cli, static) = {
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static clib_error_t *
|
||||
bd_default_learn_limit (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
l2learn_main_t *l2m = &l2learn_main;
|
||||
clib_error_t *error = 0;
|
||||
u32 learn_limit;
|
||||
|
||||
if (!unformat (input, "%d", &learn_limit))
|
||||
{
|
||||
error = clib_error_return (
|
||||
0, "expecting per bridge-domain max entry number got`%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
|
||||
l2m->bd_default_learn_limit = learn_limit;
|
||||
|
||||
done:
|
||||
return error;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (bd_default_learn_limit_cli, static) = {
|
||||
.path = "set bridge-domain default-learn-limit",
|
||||
.short_help = "set bridge-domain default-learn-limit <maxentries>",
|
||||
.function = bd_default_learn_limit,
|
||||
};
|
||||
|
||||
/**
|
||||
Set bridge-domain forward enable/disable.
|
||||
The CLI format is:
|
||||
@@ -818,6 +862,55 @@ VLIB_CLI_COMMAND (bd_mac_age_cli, static) = {
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
static clib_error_t *
|
||||
bd_learn_limit (vlib_main_t *vm, unformat_input_t *input,
|
||||
vlib_cli_command_t *cmd)
|
||||
{
|
||||
bd_main_t *bdm = &bd_main;
|
||||
clib_error_t *error = 0;
|
||||
u32 bd_index, bd_id;
|
||||
u32 learn_limit;
|
||||
uword *p;
|
||||
|
||||
if (!unformat (input, "%d", &bd_id))
|
||||
{
|
||||
error = clib_error_return (0, "expecting bridge-domain id but got `%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (bd_id == 0)
|
||||
return clib_error_return (
|
||||
0, "No operations on the default bridge domain are supported");
|
||||
|
||||
p = hash_get (bdm->bd_index_by_bd_id, bd_id);
|
||||
|
||||
if (p == 0)
|
||||
return clib_error_return (0, "No such bridge domain %d", bd_id);
|
||||
|
||||
bd_index = p[0];
|
||||
|
||||
if (!unformat (input, "%u", &learn_limit))
|
||||
{
|
||||
error = clib_error_return (
|
||||
0, "expecting maxium number of learned entries but got `%U'",
|
||||
format_unformat_error, input);
|
||||
goto done;
|
||||
}
|
||||
|
||||
bd_set_learn_limit (vm, bd_index, learn_limit);
|
||||
|
||||
done:
|
||||
return error;
|
||||
}
|
||||
|
||||
VLIB_CLI_COMMAND (bd_learn_limit_cli, static) = {
|
||||
.path = "set bridge-domain learn-limit",
|
||||
.short_help =
|
||||
"set bridge-domain learn-limit <bridge-domain-id> <learn-limit>",
|
||||
.function = bd_learn_limit,
|
||||
};
|
||||
|
||||
/*?
|
||||
* Modify whether or not an existing bridge-domain should terminate and respond
|
||||
* to ARP Requests. ARP Termination is disabled by default.
|
||||
@@ -1121,10 +1214,11 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
{
|
||||
printed = 1;
|
||||
vlib_cli_output (vm,
|
||||
"%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s %=9s %=11s",
|
||||
"BD-ID", "Index", "BSN", "Age(min)",
|
||||
"Learning", "U-Forwrd", "UU-Flood",
|
||||
"Flooding", "ARP-Term", "arp-ufwd",
|
||||
"%=8s %=7s %=4s %=9s %=9s %=9s %=11s %=9s %=9s "
|
||||
"%=9s %=8s %=8s %=11s",
|
||||
"BD-ID", "Index", "BSN", "Age(min)", "Learning",
|
||||
"U-Forwrd", "UU-Flood", "Flooding", "ARP-Term",
|
||||
"arp-ufwd", "Learn-count", "Learn-limit",
|
||||
"BVI-Intf");
|
||||
}
|
||||
|
||||
@@ -1132,24 +1226,23 @@ bd_show (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd)
|
||||
as = format (as, "%d", bd_config->mac_age);
|
||||
else
|
||||
as = format (as, "off");
|
||||
vlib_cli_output (vm,
|
||||
"%=8d %=7d %=9v %=9s %=9s %=11U %=9s %=9s %=9s %=11U",
|
||||
bd_config->bd_id, bd_index, as,
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ?
|
||||
"on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_FWD ?
|
||||
"on" : "off",
|
||||
format_uu_cfg, bd_config,
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ?
|
||||
"on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ?
|
||||
"on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD ?
|
||||
"on" : "off",
|
||||
format_vnet_sw_if_index_name_with_NA,
|
||||
vnm, bd_config->bvi_sw_if_index);
|
||||
vlib_cli_output (vm, "%U", format_l2_input_feature_bitmap,
|
||||
bd_config->feature_bitmap);
|
||||
vlib_cli_output (
|
||||
vm,
|
||||
"%=8d %=7d %=4d %=9v %=9s %=9s %=11U %=9s %=9s %=9s %=8d %=8d "
|
||||
"%=11U",
|
||||
bd_config->bd_id, bd_index, bd_config->seq_num, as,
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_LEARN ? "on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_FWD ? "on" : "off",
|
||||
format_uu_cfg, bd_config,
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_FLOOD ? "on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_ARP_TERM ? "on" : "off",
|
||||
bd_config->feature_bitmap & L2INPUT_FEAT_ARP_UFWD ? "on" : "off",
|
||||
bd_config->learn_count, bd_config->learn_limit,
|
||||
format_vnet_sw_if_index_name_with_NA, vnm,
|
||||
bd_config->bvi_sw_if_index);
|
||||
if (detail)
|
||||
vlib_cli_output (vm, "%U", format_l2_input_feature_bitmap,
|
||||
bd_config->feature_bitmap);
|
||||
vec_reset_length (as);
|
||||
|
||||
if (detail || intf)
|
||||
@@ -1326,6 +1419,8 @@ bd_add_del (l2_bridge_domain_add_del_args_t * a)
|
||||
if (a->bd_tag)
|
||||
bd_set_bd_tag (vm, bd_index, a->bd_tag);
|
||||
|
||||
bd_set_learn_limit (vm, bd_index, l2learn_main.bd_default_learn_limit);
|
||||
vec_elt_at_index (l2input_main.bd_configs, bd_index)->learn_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -110,6 +110,12 @@ typedef struct
|
||||
/* Bridge domain tag (C string NULL terminated) */
|
||||
u8 *bd_tag;
|
||||
|
||||
/* Maximum number of learned entries */
|
||||
u32 learn_limit;
|
||||
|
||||
/* Current number of learned entries */
|
||||
u32 learn_count;
|
||||
|
||||
} l2_bridge_domain_t;
|
||||
|
||||
/* Limit Bridge Domain ID to 24 bits to match 24-bit VNI range */
|
||||
@@ -158,6 +164,7 @@ typedef enum bd_flags_t_
|
||||
u32 bd_set_flags (vlib_main_t * vm, u32 bd_index, bd_flags_t flags,
|
||||
u32 enable);
|
||||
void bd_set_mac_age (vlib_main_t * vm, u32 bd_index, u8 age);
|
||||
void bd_set_learn_limit (vlib_main_t *vm, u32 bd_index, u32 learn_limit);
|
||||
int bd_add_del (l2_bridge_domain_add_del_args_t * args);
|
||||
|
||||
/**
|
||||
|
||||
+46
-9
@@ -212,8 +212,7 @@ l2fib_show_walk_cb (BVT (clib_bihash_kv) * kvp, void *arg)
|
||||
if (ctx->add && !l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
return (BIHASH_WALK_CONTINUE); /* skip learned macs */
|
||||
|
||||
bd_config = vec_elt_at_index (l2input_main.bd_configs,
|
||||
key.fields.bd_index);
|
||||
bd_config = &vec_elt (l2input_main.bd_configs, key.fields.bd_index);
|
||||
|
||||
if (l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
s = format (s, "no");
|
||||
@@ -384,6 +383,7 @@ void
|
||||
l2fib_clear_table (void)
|
||||
{
|
||||
l2fib_main_t *mp = &l2fib_main;
|
||||
l2_bridge_domain_t *bd_config;
|
||||
|
||||
if (mp->mac_table_initialized == 0)
|
||||
return;
|
||||
@@ -394,6 +394,8 @@ l2fib_clear_table (void)
|
||||
BV (clib_bihash_free) (&mp->mac_table);
|
||||
l2fib_table_init ();
|
||||
l2learn_main.global_learn_count = 0;
|
||||
vec_foreach (bd_config, l2input_main.bd_configs)
|
||||
bd_config->learn_count = 0;
|
||||
}
|
||||
|
||||
/** Clear all entries in L2FIB.
|
||||
@@ -462,9 +464,21 @@ l2fib_add_entry (const u8 * mac, u32 bd_index,
|
||||
{
|
||||
/* decrement counter if overwriting a learned mac */
|
||||
result.raw = kv.value;
|
||||
if ((!l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
&& (lm->global_learn_count))
|
||||
lm->global_learn_count--;
|
||||
if (!l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
{
|
||||
l2_bridge_domain_t *bd_config =
|
||||
vec_elt_at_index (l2input_main.bd_configs, bd_index);
|
||||
|
||||
/* check if learn_count == 0 in case of race condition between 2
|
||||
* workers adding an entry simultaneously */
|
||||
/* learn_count variable may have little inaccuracy because they are
|
||||
* not incremented/decremented with atomic operations */
|
||||
/* l2fib_scan is call every 2sec fixing potential inaccuracy */
|
||||
if (lm->global_learn_count)
|
||||
lm->global_learn_count--;
|
||||
if (bd_config->learn_count)
|
||||
bd_config->learn_count--;
|
||||
}
|
||||
}
|
||||
|
||||
/* set up result */
|
||||
@@ -751,9 +765,15 @@ l2fib_del_entry (const u8 * mac, u32 bd_index, u32 sw_if_index)
|
||||
return 1;
|
||||
|
||||
/* decrement counter if dynamically learned mac */
|
||||
if ((!l2fib_entry_result_is_set_AGE_NOT (&result)) &&
|
||||
(l2learn_main.global_learn_count))
|
||||
l2learn_main.global_learn_count--;
|
||||
if (!l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
{
|
||||
l2_bridge_domain_t *bd_config =
|
||||
vec_elt_at_index (l2input_main.bd_configs, bd_index);
|
||||
if (l2learn_main.global_learn_count)
|
||||
l2learn_main.global_learn_count--;
|
||||
if (bd_config->learn_count)
|
||||
bd_config->learn_count--;
|
||||
}
|
||||
|
||||
/* Remove entry from hash table */
|
||||
BV (clib_bihash_add_del) (&mp->mac_table, &kv, 0 /* is_add */ );
|
||||
@@ -1051,11 +1071,16 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
|
||||
u32 cl_idx = lm->client_index;
|
||||
vl_api_l2_macs_event_t *mp = 0;
|
||||
vl_api_registration_t *reg = 0;
|
||||
u32 bd_index;
|
||||
static u32 *bd_learn_counts = 0;
|
||||
|
||||
/* Don't scan the l2 fib if it hasn't been instantiated yet */
|
||||
if (alloc_arena (h) == 0)
|
||||
return 0.0;
|
||||
|
||||
vec_reset_length (bd_learn_counts);
|
||||
vec_validate (bd_learn_counts, vec_len (l2input_main.bd_configs) - 1);
|
||||
|
||||
if (client)
|
||||
{
|
||||
mp = allocate_mac_evt_buf (client, cl_idx);
|
||||
@@ -1069,6 +1094,9 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
|
||||
if (delta_t > 20e-6)
|
||||
{
|
||||
vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
|
||||
/* in case a new bd was created while sleeping */
|
||||
vec_validate (bd_learn_counts,
|
||||
vec_len (l2input_main.bd_configs) - 1);
|
||||
last_start = vlib_time_now (vm);
|
||||
accum_t += delta_t;
|
||||
}
|
||||
@@ -1102,7 +1130,10 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
|
||||
l2fib_entry_result_t result = {.raw = v->kvp[k].value };
|
||||
|
||||
if (!l2fib_entry_result_is_set_AGE_NOT (&result))
|
||||
learn_count++;
|
||||
{
|
||||
learn_count++;
|
||||
vec_elt (bd_learn_counts, key.fields.bd_index)++;
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
@@ -1190,6 +1221,7 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
|
||||
kv.key = key.raw;
|
||||
BV (clib_bihash_add_del) (&fm->mac_table, &kv, 0);
|
||||
learn_count--;
|
||||
vec_elt (bd_learn_counts, key.fields.bd_index)--;
|
||||
/*
|
||||
* Note: we may have just freed the bucket's backing
|
||||
* storage, so check right here...
|
||||
@@ -1205,6 +1237,11 @@ l2fib_scan (vlib_main_t * vm, f64 start_time, u8 event_only)
|
||||
|
||||
/* keep learn count consistent */
|
||||
l2learn_main.global_learn_count = learn_count;
|
||||
vec_foreach_index (bd_index, l2input_main.bd_configs)
|
||||
{
|
||||
vec_elt (l2input_main.bd_configs, bd_index).learn_count =
|
||||
vec_elt (bd_learn_counts, bd_index);
|
||||
}
|
||||
|
||||
if (mp)
|
||||
{
|
||||
|
||||
+20
-1
@@ -119,6 +119,8 @@ l2learn_process (vlib_node_runtime_t * node,
|
||||
u32 * count,
|
||||
l2fib_entry_result_t * result0, u16 * next0, u8 timestamp)
|
||||
{
|
||||
l2_bridge_domain_t *bd_config =
|
||||
vec_elt_at_index (l2input_main.bd_configs, vnet_buffer (b0)->l2.bd_index);
|
||||
/* Set up the default next node (typically L2FWD) */
|
||||
*next0 = vnet_l2_feature_next (b0, msm->feat_next_node_index,
|
||||
L2INPUT_FEAT_LEARN);
|
||||
@@ -137,6 +139,8 @@ l2learn_process (vlib_node_runtime_t * node,
|
||||
return; /* Static MAC always age_not */
|
||||
if (msm->global_learn_count > msm->global_learn_limit)
|
||||
return; /* Above learn limit - do not update */
|
||||
if (bd_config->learn_count > bd_config->learn_limit)
|
||||
return; /* Above bridge domain learn limit - do not update */
|
||||
|
||||
/* Limit updates per l2-learn node call to avoid prolonged update burst
|
||||
* as dtime advance over 1 minute mark, unless more than 1 min behind
|
||||
@@ -152,7 +156,8 @@ l2learn_process (vlib_node_runtime_t * node,
|
||||
/* Entry not in L2FIB - add it */
|
||||
counter_base[L2LEARN_ERROR_MISS] += 1;
|
||||
|
||||
if (msm->global_learn_count >= msm->global_learn_limit)
|
||||
if ((msm->global_learn_count >= msm->global_learn_limit) ||
|
||||
(bd_config->learn_count >= bd_config->learn_limit))
|
||||
{
|
||||
/*
|
||||
* Global limit reached. Do not learn the mac but forward the packet.
|
||||
@@ -169,7 +174,11 @@ l2learn_process (vlib_node_runtime_t * node,
|
||||
return;
|
||||
|
||||
/* It is ok to learn */
|
||||
/* learn_count variable may have little inaccuracy because they are not
|
||||
* incremented/decremented with atomic operations */
|
||||
/* l2fib_scan is call every 2sec fixing potential inaccuracy */
|
||||
msm->global_learn_count++;
|
||||
bd_config->learn_count++;
|
||||
result0->raw = 0; /* clear all fields */
|
||||
result0->fields.sw_if_index = sw_if_index0;
|
||||
if (msm->client_pid != 0)
|
||||
@@ -208,7 +217,12 @@ l2learn_process (vlib_node_runtime_t * node,
|
||||
if (l2fib_entry_result_is_set_AGE_NOT (result0))
|
||||
{
|
||||
/* The mac was provisioned */
|
||||
/* learn_count variable may have little inaccuracy because they are
|
||||
* not incremented/decremented with atomic operations */
|
||||
/* l2fib_scan is call every 2sec fixing potential inaccuracy */
|
||||
msm->global_learn_count++;
|
||||
bd_config->learn_count++;
|
||||
|
||||
l2fib_entry_result_clear_AGE_NOT (result0);
|
||||
}
|
||||
if (msm->client_pid != 0)
|
||||
@@ -470,6 +484,11 @@ l2learn_init (vlib_main_t * vm)
|
||||
*/
|
||||
mp->global_learn_limit = L2LEARN_DEFAULT_LIMIT;
|
||||
|
||||
/*
|
||||
* Set the default number of dynamically learned macs to the number
|
||||
* of buckets.
|
||||
*/
|
||||
mp->bd_default_learn_limit = L2LEARN_DEFAULT_LIMIT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ typedef struct
|
||||
/* maximum number of dynamically learned mac entries */
|
||||
u32 global_learn_limit;
|
||||
|
||||
/* maximum number of dynamically learned mac entries per bridge domain */
|
||||
u32 bd_default_learn_limit;
|
||||
|
||||
/* client waiting for L2 MAC events for learned and aged MACs */
|
||||
u32 client_pid;
|
||||
u32 client_index;
|
||||
|
||||
@@ -17,7 +17,7 @@ class TestL2LearnLimit(VppTestCase):
|
||||
@classmethod
|
||||
def setUpClass(self):
|
||||
super(TestL2LearnLimit, self).setUpClass()
|
||||
self.create_pg_interfaces(range(2))
|
||||
self.create_pg_interfaces(range(3))
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
@@ -94,6 +94,39 @@ class TestL2LearnLimit(VppTestCase):
|
||||
# check that bd2 was not able to learn
|
||||
self.assertEqual(len(lfs2), 0)
|
||||
|
||||
def test_l2bd_learnlimit03(self):
|
||||
""" L2BD test with bridge domain limit
|
||||
"""
|
||||
self.vapi.bridge_domain_set_default_learn_limit(4)
|
||||
self.vapi.bridge_domain_add_del(bd_id=3)
|
||||
self.vapi.sw_interface_set_l2_bridge(
|
||||
self.pg_interfaces[2].sw_if_index, bd_id=3)
|
||||
|
||||
self.vapi.bridge_domain_set_learn_limit(2, 5)
|
||||
|
||||
hosts = self.create_hosts(self.pg_interfaces[1], 20, 2)
|
||||
fhosts = self.create_hosts(self.pg_interfaces[2], 20, 3)
|
||||
|
||||
# inject 20 mac addresses on bd2
|
||||
self.learn_hosts(self.pg_interfaces[1], 2, hosts)
|
||||
|
||||
# inject 20 macs address on bd3
|
||||
self.learn_hosts(self.pg_interfaces[2], 3, fhosts)
|
||||
|
||||
lfs1 = self.vapi.l2_fib_table_dump(2)
|
||||
lfs2 = self.vapi.l2_fib_table_dump(3)
|
||||
|
||||
# check that only 5 macs are learned.
|
||||
self.assertEqual(len(lfs1), 5)
|
||||
|
||||
# check that only 4 macs are learned.
|
||||
self.assertEqual(len(lfs2), 4)
|
||||
|
||||
self.vapi.sw_interface_set_l2_bridge(
|
||||
rx_sw_if_index=self.pg_interfaces[2].sw_if_index,
|
||||
bd_id=3, enable=0)
|
||||
self.vapi.bridge_domain_add_del(is_add=0, bd_id=3)
|
||||
|
||||
def setUp(self):
|
||||
super(TestL2LearnLimit, self).setUp()
|
||||
|
||||
@@ -106,13 +139,21 @@ class TestL2LearnLimit(VppTestCase):
|
||||
self.pg_interfaces[1].sw_if_index, bd_id=2)
|
||||
|
||||
def tearDown(self):
|
||||
for i in self.pg_interfaces[:2]:
|
||||
self.vapi.sw_interface_set_l2_bridge(rx_sw_if_index=i.sw_if_index,
|
||||
bd_id=1, enable=0)
|
||||
super(TestL2LearnLimit, self).tearDown()
|
||||
self.vapi.sw_interface_set_l2_bridge(
|
||||
rx_sw_if_index=self.pg_interfaces[0].sw_if_index,
|
||||
bd_id=1, enable=0)
|
||||
self.vapi.sw_interface_set_l2_bridge(
|
||||
rx_sw_if_index=self.pg_interfaces[1].sw_if_index,
|
||||
bd_id=2, enable=0)
|
||||
self.vapi.bridge_domain_add_del(bd_id=1, is_add=0)
|
||||
self.vapi.bridge_domain_add_del(bd_id=2, is_add=0)
|
||||
|
||||
super(TestL2LearnLimit, self).tearDown()
|
||||
i = 0
|
||||
while (len(self.vapi.l2_fib_table_dump(bd_id=0xffffffff)) != 0):
|
||||
time.sleep(1)
|
||||
i = i + 1
|
||||
if i == 30:
|
||||
self.assertTrue(False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user