}
static u32
-lookup_or_create_hash_index (u8 * name, u32 next_vector_index)
+lookup_hash_index (u8 * name)
{
stat_segment_main_t *sm = &stat_segment_main;
- u32 index;
+ u32 index = STAT_SEGMENT_INDEX_INVALID;
hash_pair_t *hp;
/* Must be called in the context of the main heap */
ASSERT (clib_mem_get_heap () != sm->heap);
hp = hash_get_pair (sm->directory_vector_by_name, name);
- if (!hp)
- {
- /* we allocate our private copy of 'name' */
- hash_set (sm->directory_vector_by_name, format (0, "%s%c", name, 0),
- next_vector_index);
- index = next_vector_index;
- }
- else
+ if (hp)
{
index = hp->value[0];
}
return index;
}
+static void
+create_hash_index (u8 * name, u32 index)
+{
+ stat_segment_main_t *sm = &stat_segment_main;
+
+ /* Must be called in the context of the main heap */
+ ASSERT (clib_mem_get_heap () != sm->heap);
+
+ hash_set (sm->directory_vector_by_name, format (0, "%s%c", name, 0), index);
+}
+
+static u32
+vlib_stats_get_next_vector_index ()
+{
+ stat_segment_main_t *sm = &stat_segment_main;
+ u32 next_vector_index = vec_len (sm->directory_vector);
+
+ ssize_t i;
+ vec_foreach_index_backwards (i, sm->directory_vector)
+ {
+ if (sm->directory_vector[i].type == STAT_DIR_TYPE_EMPTY)
+ {
+ next_vector_index = i;
+ break;
+ }
+ }
+
+ return next_vector_index;
+}
+
+static u32
+vlib_stats_create_counter (stat_segment_directory_entry_t * e, void *oldheap)
+{
+ stat_segment_main_t *sm = &stat_segment_main;
+
+ ASSERT (clib_mem_get_heap () == sm->heap);
+
+ u32 index = vlib_stats_get_next_vector_index ();
+
+ clib_mem_set_heap (oldheap);
+ create_hash_index ((u8 *) e->name, index);
+ clib_mem_set_heap (sm->heap);
+
+ vec_validate (sm->directory_vector, index);
+ sm->directory_vector[index] = *e;
+
+ return index;
+}
+
+static void
+vlib_stats_delete_counter (u32 index, void *oldheap)
+{
+ stat_segment_main_t *sm = &stat_segment_main;
+ stat_segment_directory_entry_t *e;
+
+ ASSERT (clib_mem_get_heap () == sm->heap);
+
+ if (index > vec_len (sm->directory_vector))
+ return;
+
+ e = &sm->directory_vector[index];
+
+ clib_mem_set_heap (oldheap);
+ hash_unset (sm->directory_vector_by_name, &e->name);
+ clib_mem_set_heap (sm->heap);
+
+ memset (e, 0, sizeof (*e));
+ e->type = STAT_DIR_TYPE_EMPTY;
+}
+
void
vlib_stats_pop_heap (void *cm_arg, void *oldheap, u32 cindex,
stat_directory_type_t type)
/* Lookup hash-table is on the main heap */
stat_segment_name =
cm->stat_segment_name ? cm->stat_segment_name : cm->name;
- u32 next_vector_index = vec_len (sm->directory_vector);
clib_mem_set_heap (oldheap); /* Exit stats segment */
- u32 vector_index = lookup_or_create_hash_index ((u8 *) stat_segment_name,
- next_vector_index);
+ u32 vector_index = lookup_hash_index ((u8 *) stat_segment_name);
/* Back to stats segment */
clib_mem_set_heap (sm->heap); /* Re-enter stat segment */
/* Update the vector */
- if (vector_index == next_vector_index)
+ if (vector_index == STAT_SEGMENT_INDEX_INVALID)
{ /* New */
strncpy (e.name, stat_segment_name, 128 - 1);
e.type = type;
- vec_add1 (sm->directory_vector, e);
+ vector_index = vlib_stats_create_counter (&e, oldheap);
}
stat_segment_directory_entry_t *ep = &sm->directory_vector[vector_index];
ASSERT (shared_header);
vlib_stat_segment_lock ();
- u32 next_vector_index = vec_len (sm->directory_vector);
clib_mem_set_heap (oldheap); /* Exit stats segment */
-
- u32 vector_index = lookup_or_create_hash_index (name,
- next_vector_index);
-
+ u32 vector_index = lookup_hash_index (name);
/* Back to stats segment */
clib_mem_set_heap (sm->heap); /* Re-enter stat segment */
- if (next_vector_index == vector_index)
+ if (vector_index == STAT_SEGMENT_INDEX_INVALID)
{
memcpy (e.name, name, vec_len (name));
e.name[vec_len (name)] = '\0';
e.type = STAT_DIR_TYPE_ERROR_INDEX;
e.offset = index;
e.offset_vector = 0;
- vec_add1 (sm->directory_vector, e);
+ vector_index = vlib_stats_create_counter (&e, oldheap);
/* Warn clients to refresh any pointers they might be holding */
shared_header->directory_offset =
type_name = "NameVector";
break;
+ case STAT_DIR_TYPE_EMPTY:
+ type_name = "empty";
+ break;
+
default:
type_name = "illegal!";
break;
for (i = 0; i < vec_len (show_data); i++)
{
+ stat_segment_directory_entry_t *ep = vec_elt_at_index (show_data, i);
+
+ if (ep->type == STAT_DIR_TYPE_EMPTY)
+ continue;
+
vlib_cli_output (vm, "%-100U", format_stat_dir_entry,
vec_elt_at_index (show_data, i));
}
ASSERT (shared_header);
- u32 next_vector_index = vec_len (sm->directory_vector);
- u32 vector_index = lookup_or_create_hash_index (name,
- next_vector_index);
-
- if (vector_index < next_vector_index) /* Already registered */
- return clib_error_return (0, "%v is alreadty registered", name);
+ u32 vector_index = lookup_hash_index (name);
- oldheap = vlib_stats_push_heap (NULL);
- vlib_stat_segment_lock ();
+ if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
+ return clib_error_return (0, "%v is already registered", name);
memset (&e, 0, sizeof (e));
e.type = STAT_DIR_TYPE_SCALAR_INDEX;
-
memcpy (e.name, name, vec_len (name));
- vec_add1 (sm->directory_vector, e);
+
+ oldheap = vlib_stats_push_heap (NULL);
+ vlib_stat_segment_lock ();
+ vector_index = vlib_stats_create_counter (&e, oldheap);
shared_header->directory_offset =
stat_segment_offset (shared_header, sm->directory_vector);
pool_get (sm->gauges, gauge);
gauge->fn = update_fn;
gauge->caller_index = caller_index;
- gauge->directory_index = next_vector_index;
+ gauge->directory_index = vector_index;
return NULL;
}
ASSERT (shared_header);
ASSERT (vlib_get_thread_index () == 0);
- u32 next_vector_index = vec_len (sm->directory_vector);
- u32 vector_index = lookup_or_create_hash_index (name,
- next_vector_index);
+ u32 vector_index = lookup_hash_index (name);
- if (vector_index < next_vector_index) /* Already registered */
+ if (vector_index != STAT_SEGMENT_INDEX_INVALID) /* Already registered */
return clib_error_return (0, "%v is already registered", name);
- oldheap = vlib_stats_push_heap (NULL);
- vlib_stat_segment_lock ();
-
memset (&e, 0, sizeof (e));
e.type = STAT_DIR_TYPE_SCALAR_INDEX;
-
memcpy (e.name, name, vec_len (name));
- vec_add1 (sm->directory_vector, e);
+
+ oldheap = vlib_stats_push_heap (NULL);
+ vlib_stat_segment_lock ();
+
+ vector_index = vlib_stats_create_counter (&e, oldheap);
shared_header->directory_offset =
stat_segment_offset (shared_header, sm->directory_vector);
vlib_stat_segment_unlock ();
clib_mem_set_heap (oldheap);
- *index = next_vector_index;
+ *index = vector_index;
return 0;
}
stat_segment_main_t *sm = &stat_segment_main;
stat_segment_shared_header_t *shared_header = sm->shared_header;
stat_segment_directory_entry_t *e;
+ void *oldheap;
ASSERT (shared_header);
if (e->type != STAT_DIR_TYPE_SCALAR_INDEX)
return clib_error_return (0, "%u index cannot be deleted", index);
- hash_unset (sm->directory_vector_by_name, &e->name);
- vec_del1 (sm->directory_vector, index);
+ oldheap = vlib_stats_push_heap (NULL);
+ vlib_stat_segment_lock ();
+
+ vlib_stats_delete_counter (index, oldheap);
+
+ vlib_stat_segment_unlock ();
+ clib_mem_set_heap (oldheap);
+
return 0;
}
def test_bond_enslave(self):
""" Bond enslave/detach slave test """
- # create interface (BondEthernet0)
+ # create interface (BondEthernet0) and set bond mode to LACP
self.logger.info("create bond")
- bond0 = VppBondInterface(self, mode=3)
+ bond0 = VppBondInterface(self, mode=5)
bond0.add_vpp_config()
bond0.admin_up()
- # verify pg0 and pg1 not in BondEthernet0
- if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
- self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
- self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
-
- # enslave pg0 and pg1 to BondEthernet0
- self.logger.info("bond enslave interface pg0 to BondEthernet0")
- bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
- is_passive=0,
- is_long_timeout=0)
-
- self.logger.info("bond enslave interface pg1 to BondEthernet0")
- bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
- is_passive=0,
- is_long_timeout=0)
-
- # verify both slaves in BondEthernet0
- if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
- self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
- self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
-
- # detach interface pg0
- self.logger.info("detach interface pg0")
- bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
-
- # verify pg0 is not in BondEthernet0, but pg1 is
- if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
- self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
- self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
-
- # detach interface pg1
- self.logger.info("detach interface pg1")
- bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
-
- # verify pg0 and pg1 not in BondEthernet0
- if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
- self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
- self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
+ # verify that interfaces can be enslaved and detached two times
+ for i in range(2):
+ # verify pg0 and pg1 not in BondEthernet0
+ if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
+ self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
+ self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
+
+ # enslave pg0 and pg1 to BondEthernet0
+ self.logger.info("bond enslave interface pg0 to BondEthernet0")
+ bond0.enslave_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index,
+ is_passive=0,
+ is_long_timeout=0)
+
+ self.logger.info("bond enslave interface pg1 to BondEthernet0")
+ bond0.enslave_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index,
+ is_passive=0,
+ is_long_timeout=0)
+ # verify both slaves in BondEthernet0
+ if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
+ self.assertTrue(self.pg0.is_interface_config_in_dump(if_dump))
+ self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
+
+ # detach interface pg0
+ self.logger.info("detach interface pg0")
+ bond0.detach_vpp_bond_interface(sw_if_index=self.pg0.sw_if_index)
+
+ # verify pg0 is not in BondEthernet0, but pg1 is
+ if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
+ self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
+ self.assertTrue(self.pg1.is_interface_config_in_dump(if_dump))
+
+ # detach interface pg1
+ self.logger.info("detach interface pg1")
+ bond0.detach_vpp_bond_interface(sw_if_index=self.pg1.sw_if_index)
+
+ # verify pg0 and pg1 not in BondEthernet0
+ if_dump = self.vapi.sw_interface_slave_dump(bond0.sw_if_index)
+ self.assertFalse(self.pg0.is_interface_config_in_dump(if_dump))
+ self.assertFalse(self.pg1.is_interface_config_in_dump(if_dump))
bond0.remove_vpp_config()