/* * Copyright (c) 2021 EMnify. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include enum { type_simple = 0, type_combined, }; enum { test_expand = 0, }; /* * Return the stats segment epoch value. */ static uint64_t get_stats_epoch () { vlib_stats_segment_t *sm = vlib_stats_get_segment (); return sm->shared_header->epoch; } /* number of times to repeat the counter expand tests */ #define EXPAND_TEST_ROUNDS 3 /* * Let a simple counter vector grow and verify that * the stats epoch is increased only when the vector * is expanded. */ static clib_error_t * test_simple_counter_expand (vlib_main_t *vm) { vlib_simple_counter_main_t counter = { .name = "test-simple-counter-expand", .stat_segment_name = "/vlib/test-simple-counter-expand", }; int i, index; uint64_t epoch, new_epoch; // Create one counter to allocate the vector. vlib_validate_simple_counter (&counter, 0); epoch = get_stats_epoch (); for (i = 0; i < EXPAND_TEST_ROUNDS; i++) { // Check how many elements fit into the counter vector without expanding // that. The next validate calls should not increase the stats segment // epoch. int mem_size = vec_max_len (counter.counters[0]); for (index = 1; index <= mem_size - 1; index++) { vlib_validate_simple_counter (&counter, index); new_epoch = get_stats_epoch (); if (new_epoch != epoch) return clib_error_return ( 0, "Stats segment epoch should not increase"); } // The next counter index does not fit and it will extend the vector. // The stats segment epoch should increase. vlib_validate_simple_counter (&counter, index + 1); new_epoch = get_stats_epoch (); if (new_epoch == epoch) return clib_error_return (0, "Stats segment epoch should have increased"); epoch = new_epoch; } vlib_free_simple_counter (&counter); vlib_validate_simple_counter (&counter, 0); return 0; } /* * Let a combined counter vector grow and verify that * the stats epoch is increased only when the vector * is expanded. */ static clib_error_t * test_combined_counter_expand (vlib_main_t *vm) { vlib_combined_counter_main_t counter = { .name = "test-combined-counter-expand", .stat_segment_name = "/vlib/test-combined-counter-expand", }; int i, index; uint64_t epoch, new_epoch; // Create one counter to allocate the vector. vlib_validate_combined_counter (&counter, 0); epoch = get_stats_epoch (); for (i = 0; i < EXPAND_TEST_ROUNDS; i++) { // Check how many elements fit into the counter vector without expanding // that. The next validate calls should not increase the stats segment // epoch. int mem_size = vec_max_len (counter.counters[0]); for (index = 1; index <= mem_size - 1; index++) { vlib_validate_combined_counter (&counter, index); new_epoch = get_stats_epoch (); if (new_epoch != epoch) return clib_error_return ( 0, "Stats segment epoch should not increase"); } // The next counter index does not fit and it will extend the vector. // The stats segment epoch should increase. vlib_validate_combined_counter (&counter, index + 1); new_epoch = get_stats_epoch (); if (new_epoch == epoch) return clib_error_return (0, "Stats segment epoch should have increased"); epoch = new_epoch; } vlib_free_combined_counter (&counter); vlib_validate_combined_counter (&counter, 0); return 0; } static clib_error_t * test_simple_counter (vlib_main_t *vm, int test_case) { clib_error_t *error; switch (test_case) { case test_expand: error = test_simple_counter_expand (vm); break; default: return clib_error_return (0, "no such test"); } return error; } static clib_error_t * test_combined_counter (vlib_main_t *vm, int test_case) { clib_error_t *error; switch (test_case) { case test_expand: error = test_combined_counter_expand (vm); break; default: return clib_error_return (0, "no such test"); } return error; } static clib_error_t * test_counter_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { clib_error_t *error; int counter_type = -1; int test_case = -1; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { if (unformat (input, "simple")) counter_type = type_simple; else if (unformat (input, "combined")) counter_type = type_combined; else if (unformat (input, "expand")) test_case = test_expand; else return clib_error_return (0, "unknown input '%U'", format_unformat_error, input); } if (test_case == -1) return clib_error_return (0, "no such test"); switch (counter_type) { case type_simple: error = test_simple_counter (vm, test_case); break; case type_combined: error = test_combined_counter (vm, test_case); break; default: return clib_error_return (0, "no such test"); } return error; } VLIB_CLI_COMMAND (test_counter_command, static) = { .path = "test counter", .short_help = "test counter [simple | combined] expand", .function = test_counter_command_fn, }; static clib_error_t * test_counter_init (vlib_main_t *vm) { return (0); } VLIB_INIT_FUNCTION (test_counter_init); /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */