diff options
-rw-r--r-- | src/plugins/unittest/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/unittest/test_buffer.c | 91 | ||||
-rw-r--r-- | src/vlib/buffer_funcs.h | 12 | ||||
-rw-r--r-- | test/test_buffers.py | 29 |
4 files changed, 130 insertions, 3 deletions
diff --git a/src/plugins/unittest/CMakeLists.txt b/src/plugins/unittest/CMakeLists.txt index 5b7e1f7655e..3e0e550b609 100644 --- a/src/plugins/unittest/CMakeLists.txt +++ b/src/plugins/unittest/CMakeLists.txt @@ -36,4 +36,5 @@ add_vpp_plugin(unittest svm_fifo_test.c unittest.c util_test.c + test_buffer.c ) diff --git a/src/plugins/unittest/test_buffer.c b/src/plugins/unittest/test_buffer.c new file mode 100644 index 00000000000..e5a5643099c --- /dev/null +++ b/src/plugins/unittest/test_buffer.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 Cisco and/or its affiliates. + * 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 <vlib/vlib.h> +#include <vlib/buffer_funcs.h> + +#define TEST_I(_cond, _comment, _args...) \ +({ \ + int _evald = (_cond); \ + if (!(_evald)) { \ + fformat(stderr, "FAIL:%d: " _comment "\n", \ + __LINE__, ##_args); \ + } else { \ + fformat(stderr, "PASS:%d: " _comment "\n", \ + __LINE__, ##_args); \ + } \ + _evald; \ +}) + +#define TEST(_cond, _comment, _args...) \ +{ \ + if (!TEST_I(_cond, _comment, ##_args)) { \ + return 1; \ + } \ +} + +/* test function for a specific case where current_data is negative, verify + * that there is no crash */ +static int +linearize_negative_current_data (vlib_main_t * vm) +{ + u32 bi[32]; + TEST (ARRAY_LEN (bi) == vlib_buffer_alloc (vm, bi, ARRAY_LEN (bi)), + "buff alloc"); + u32 data_size = vlib_buffer_get_default_data_size (vm); + u32 i; + for (i = 0; i < ARRAY_LEN (bi) - 1; ++i) + { + vlib_buffer_t *b = vlib_get_buffer (vm, bi[i]); + b->next_buffer = bi[i + 1]; + b->flags |= VLIB_BUFFER_NEXT_PRESENT; + b->current_data = -14; + b->current_length = 14 + data_size; + } + + vlib_buffer_chain_linearize (vm, vlib_get_buffer (vm, bi[0])); + + return 0; +} + +static clib_error_t * +test_linearize_fn (vlib_main_t * vm, unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + + if (linearize_negative_current_data (vm)) + { + return clib_error_return (0, "linearize_negative_current_data failed"); + } + + return (NULL); +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_linearize_command, static) = +{ + .path = "test chained-buffer-linearization", + .short_help = "test chained-buffer-linearization", + .function = test_linearize_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vlib/buffer_funcs.h b/src/vlib/buffer_funcs.h index 521a036812c..8091d83729c 100644 --- a/src/vlib/buffer_funcs.h +++ b/src/vlib/buffer_funcs.h @@ -1416,13 +1416,19 @@ vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * b) if (dst_left == 0) { - if (db != first) - db->current_data = 0; db->current_length = dp - (u8 *) vlib_buffer_get_current (db); ASSERT (db->flags & VLIB_BUFFER_NEXT_PRESENT); db = vlib_get_buffer (vm, db->next_buffer); dst_left = data_size; - dp = db->data; + if (db->current_data > 0) + { + db->current_data = 0; + } + else + { + dst_left += -db->current_data; + } + dp = vlib_buffer_get_current (db); } while (src_left == 0) diff --git a/test/test_buffers.py b/test/test_buffers.py new file mode 100644 index 00000000000..fe92378b484 --- /dev/null +++ b/test/test_buffers.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +from framework import VppTestCase + + +class TestBuffers(VppTestCase): + """ Buffer C Unit Tests """ + + @classmethod + def setUpClass(cls): + super(TestBuffers, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestBuffers, cls).tearDownClass() + + def setUp(self): + super(TestBuffers, self).setUp() + + def tearDown(self): + super(TestBuffers, self).tearDown() + + def test_linearize(self): + """ Chained Buffer Linearization """ + error = self.vapi.cli("test chained-buffer-linearization") + + if error: + self.logger.critical(error) + self.assertNotIn('failed', error) |