aboutsummaryrefslogtreecommitdiffstats
path: root/extras
diff options
context:
space:
mode:
Diffstat (limited to 'extras')
-rw-r--r--extras/deprecated/netmap/FEATURE.yaml12
-rw-r--r--extras/deprecated/netmap/cli.c236
-rw-r--r--extras/deprecated/netmap/device.c252
-rw-r--r--extras/deprecated/netmap/dir.dox27
-rw-r--r--extras/deprecated/netmap/net_netmap.h650
-rw-r--r--extras/deprecated/netmap/netmap.api56
-rw-r--r--extras/deprecated/netmap/netmap.c315
-rw-r--r--extras/deprecated/netmap/netmap.h166
-rw-r--r--extras/deprecated/netmap/netmap_api.c137
-rw-r--r--extras/deprecated/netmap/node.c297
-rw-r--r--extras/deprecated/plugins/gbp/test_gbp.py30
-rw-r--r--extras/deprecated/vnet/lawful-intercept/lawful_intercept.c122
-rw-r--r--extras/deprecated/vnet/lawful-intercept/lawful_intercept.h54
-rw-r--r--extras/deprecated/vnet/lawful-intercept/node.c286
-rw-r--r--extras/deprecated/vnet/vxlan-gbp/vpp_vxlan_gbp_tunnel.py6
-rw-r--r--extras/hs-test/Makefile53
-rw-r--r--extras/hs-test/README.rst175
-rw-r--r--extras/hs-test/address_allocator.go16
-rw-r--r--extras/hs-test/container.go21
-rw-r--r--extras/hs-test/cpu.go29
-rw-r--r--extras/hs-test/docker/Dockerfile.vpp2
-rw-r--r--extras/hs-test/echo_test.go13
-rw-r--r--extras/hs-test/framework_test.go29
-rw-r--r--extras/hs-test/go.mod17
-rw-r--r--extras/hs-test/go.sum33
-rw-r--r--extras/hs-test/hst_suite.go145
-rw-r--r--extras/hs-test/http_test.go150
-rw-r--r--extras/hs-test/ldp_test.go31
-rw-r--r--extras/hs-test/linux_iperf_test.go24
-rw-r--r--extras/hs-test/mirroring_test.go6
-rw-r--r--extras/hs-test/proxy_test.go26
-rw-r--r--extras/hs-test/raw_session_test.go12
-rw-r--r--extras/hs-test/script/compress.sh34
-rw-r--r--extras/hs-test/suite_nginx_test.go78
-rw-r--r--extras/hs-test/suite_no_topo_test.go79
-rw-r--r--extras/hs-test/suite_ns_test.go78
-rw-r--r--extras/hs-test/suite_tap_test.go69
-rw-r--r--extras/hs-test/suite_veth_test.go81
-rwxr-xr-xextras/hs-test/test18
-rw-r--r--extras/hs-test/vcl_test.go20
-rw-r--r--extras/hs-test/vppinstance.go27
-rwxr-xr-xextras/scripts/crcchecker.py16
42 files changed, 1502 insertions, 2426 deletions
diff --git a/extras/deprecated/netmap/FEATURE.yaml b/extras/deprecated/netmap/FEATURE.yaml
deleted file mode 100644
index e23e5c243e7..00000000000
--- a/extras/deprecated/netmap/FEATURE.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
----
-name: Netmap Device
-maintainer: Damjan Marion <damarion@cisco.com>
-features:
- - L4 checksum offload
-description: "Create a netmap interface, which is a high speed user-space
- interface that allows VPP to patch into a linux namespace,
- a linux container, or a physical NIC without the use of DPDK."
-missing:
- - API dump
-state: production
-properties: [API, CLI, STATS, MULTITHREAD]
diff --git a/extras/deprecated/netmap/cli.c b/extras/deprecated/netmap/cli.c
deleted file mode 100644
index 713632947a1..00000000000
--- a/extras/deprecated/netmap/cli.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2016 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 <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <vnet/devices/netmap/net_netmap.h>
-#include <vnet/devices/netmap/netmap.h>
-
-static clib_error_t *
-netmap_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u8 *host_if_name = NULL;
- u8 hwaddr[6];
- u8 *hw_addr_ptr = 0;
- int r;
- u8 is_pipe = 0;
- u8 is_master = 0;
- u32 sw_if_index = ~0;
- clib_error_t *error = NULL;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "name %s", &host_if_name))
- ;
- else
- if (unformat
- (line_input, "hw-addr %U", unformat_ethernet_address, hwaddr))
- hw_addr_ptr = hwaddr;
- else if (unformat (line_input, "pipe"))
- is_pipe = 1;
- else if (unformat (line_input, "master"))
- is_master = 1;
- else if (unformat (line_input, "slave"))
- is_master = 0;
- else
- {
- error = clib_error_return (0, "unknown input `%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (host_if_name == NULL)
- {
- error = clib_error_return (0, "missing host interface name");
- goto done;
- }
-
- r =
- netmap_create_if (vm, host_if_name, hw_addr_ptr, is_pipe, is_master,
- &sw_if_index);
-
- if (r == VNET_API_ERROR_SYSCALL_ERROR_1)
- {
- error = clib_error_return (0, "%s (errno %d)", strerror (errno), errno);
- goto done;
- }
-
- if (r == VNET_API_ERROR_INVALID_INTERFACE)
- {
- error = clib_error_return (0, "Invalid interface name");
- goto done;
- }
-
- if (r == VNET_API_ERROR_SUBIF_ALREADY_EXISTS)
- {
- error = clib_error_return (0, "Interface already exists");
- goto done;
- }
-
- vlib_cli_output (vm, "%U\n", format_vnet_sw_if_index_name, vnet_get_main (),
- sw_if_index);
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * '<em>netmap</em>' is a framework for very fast packet I/O from userspace.
- * '<em>VALE</em>' is an equally fast in-kernel software switch using the
- * netmap API. '<em>netmap</em>' includes '<em>netmap pipes</em>', a shared
- * memory packet transport channel. Together, they provide a high speed
- * user-space interface that allows VPP to patch into a linux namespace, a
- * linux container, or a physical NIC without the use of DPDK. Netmap/VALE
- * generates the '<em>netmap.ko</em>' kernel module that needs to be loaded
- * before netmap interfaces can be created.
- * - https://github.com/luigirizzo/netmap - Netmap/VALE repo.
- * - https://github.com/vpp-dev/netmap - VPP development package for Netmap/VALE,
- * which is a snapshot of the Netmap/VALE repo with minor changes to work
- * with containers and modified kernel drivers to work with NICs.
- *
- * Create a netmap interface that will attach to a linux interface.
- * The interface must already exist. Once created, a new netmap interface
- * will exist in VPP with the name '<em>netmap-<ifname></em>', where
- * '<em><ifname></em>' takes one of two forms:
- * - <b>ifname</b> - Linux interface to bind too.
- * - <b>valeXXX:YYY</b> -
- * - Where '<em>valeXXX</em>' is an arbitrary name for a VALE
- * interface that must start with '<em>vale</em>' and is less
- * than 16 characters.
- * - Where '<em>YYY</em>' is an existing linux namespace.
- *
- * This command has the following optional parameters:
- *
- * - <b>hw-addr <mac-addr></b> - Optional ethernet address, can be in either
- * X:X:X:X:X:X unix or X.X.X cisco format.
- *
- * - <b>pipe</b> - Optional flag to indicate that a '<em>netmap pipe</em>'
- * instance should be created.
- *
- * - <b>master | slave</b> - Optional flag to indicate whether VPP should
- * be the master or slave of the '<em>netmap pipe</em>'. Only considered
- * if '<em>pipe</em>' is entered. Defaults to '<em>slave</em>' if not entered.
- *
- * @cliexpar
- * Example of how to create a netmap interface tied to the linux
- * namespace '<em>vpp1</em>':
- * @cliexstart{create netmap name vale00:vpp1 hw-addr 02:FE:3F:34:15:9B pipe master}
- * netmap-vale00:vpp1
- * @cliexend
- * Once the netmap interface is created, enable the interface using:
- * @cliexcmd{set interface state netmap-vale00:vpp1 up}
-?*/
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (netmap_create_command, static) = {
- .path = "create netmap",
- .short_help = "create netmap name <ifname>|valeXXX:YYY "
- "[hw-addr <mac-addr>] [pipe] [master|slave]",
- .function = netmap_create_command_fn,
-};
-/* *INDENT-ON* */
-
-static clib_error_t *
-netmap_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u8 *host_if_name = NULL;
- clib_error_t *error = NULL;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "name %s", &host_if_name))
- ;
- else
- {
- error = clib_error_return (0, "unknown input `%U'",
- format_unformat_error, line_input);
- goto done;
- }
- }
-
- if (host_if_name == NULL)
- {
- error = clib_error_return (0, "missing host interface name");
- goto done;
- }
-
- netmap_delete_if (vm, host_if_name);
-
-done:
- unformat_free (line_input);
-
- return error;
-}
-
-/*?
- * Delete a netmap interface. Use the '<em><ifname></em>' to identify
- * the netmap interface to be deleted. In VPP, netmap interfaces are
- * named as '<em>netmap-<ifname></em>', where '<em><ifname></em>'
- * takes one of two forms:
- * - <b>ifname</b> - Linux interface to bind too.
- * - <b>valeXXX:YYY</b> -
- * - Where '<em>valeXXX</em>' is an arbitrary name for a VALE
- * interface that must start with '<em>vale</em>' and is less
- * than 16 characters.
- * - Where '<em>YYY</em>' is an existing linux namespace.
- *
- * @cliexpar
- * Example of how to delete a netmap interface named '<em>netmap-vale00:vpp1</em>':
- * @cliexcmd{delete netmap name vale00:vpp1}
-?*/
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (netmap_delete_command, static) = {
- .path = "delete netmap",
- .short_help = "delete netmap name <ifname>|valeXXX:YYY",
- .function = netmap_delete_command_fn,
-};
-/* *INDENT-ON* */
-
-clib_error_t *
-netmap_cli_init (vlib_main_t * vm)
-{
- return 0;
-}
-
-VLIB_INIT_FUNCTION (netmap_cli_init);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/device.c b/extras/deprecated/netmap/device.c
deleted file mode 100644
index 47407aaaa26..00000000000
--- a/extras/deprecated/netmap/device.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2016 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 <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <vnet/devices/netmap/net_netmap.h>
-#include <vnet/devices/netmap/netmap.h>
-
-#define foreach_netmap_tx_func_error \
-_(NO_FREE_SLOTS, "no free tx slots") \
-_(PENDING_MSGS, "pending msgs in tx ring")
-
-typedef enum
-{
-#define _(f,s) NETMAP_TX_ERROR_##f,
- foreach_netmap_tx_func_error
-#undef _
- NETMAP_TX_N_ERROR,
-} netmap_tx_func_error_t;
-
-static char *netmap_tx_func_error_strings[] = {
-#define _(n,s) s,
- foreach_netmap_tx_func_error
-#undef _
-};
-
-
-static u8 *
-format_netmap_device_name (u8 * s, va_list * args)
-{
- u32 i = va_arg (*args, u32);
- netmap_main_t *apm = &netmap_main;
- netmap_if_t *nif = pool_elt_at_index (apm->interfaces, i);
-
- s = format (s, "netmap-%s", nif->host_if_name);
- return s;
-}
-
-static u8 *
-format_netmap_device (u8 * s, va_list * args)
-{
- u32 dev_instance = va_arg (*args, u32);
- int verbose = va_arg (*args, int);
- netmap_main_t *nm = &netmap_main;
- netmap_if_t *nif = vec_elt_at_index (nm->interfaces, dev_instance);
- u32 indent = format_get_indent (s);
-
- s = format (s, "NETMAP interface");
- if (verbose)
- {
- s = format (s, "\n%U version %d flags 0x%x"
- "\n%U region %u memsize 0x%x offset 0x%x"
- "\n%U tx_slots %u rx_slots %u tx_rings %u rx_rings %u",
- format_white_space, indent + 2,
- nif->req->nr_version,
- nif->req->nr_flags,
- format_white_space, indent + 2,
- nif->mem_region,
- nif->req->nr_memsize,
- nif->req->nr_offset,
- format_white_space, indent + 2,
- nif->req->nr_tx_slots,
- nif->req->nr_rx_slots,
- nif->req->nr_tx_rings, nif->req->nr_rx_rings);
- }
- return s;
-}
-
-static u8 *
-format_netmap_tx_trace (u8 * s, va_list * args)
-{
- s = format (s, "Unimplemented...");
- return s;
-}
-
-VNET_DEVICE_CLASS_TX_FN (netmap_device_class) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- netmap_main_t *nm = &netmap_main;
- u32 *buffers = vlib_frame_vector_args (frame);
- u32 n_left = frame->n_vectors;
- f64 const time_constant = 1e3;
- vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
- netmap_if_t *nif = pool_elt_at_index (nm->interfaces, rd->dev_instance);
- int cur_ring;
-
- clib_spinlock_lock_if_init (&nif->lockp);
-
- cur_ring = nif->first_tx_ring;
-
- while (n_left && cur_ring <= nif->last_tx_ring)
- {
- struct netmap_ring *ring = NETMAP_TXRING (nif->nifp, cur_ring);
- int n_free_slots = nm_ring_space (ring);
- uint cur = ring->cur;
-
- if (nm_tx_pending (ring))
- {
- if (ioctl (nif->fd, NIOCTXSYNC, NULL) < 0)
- clib_unix_warning ("NIOCTXSYNC");
- clib_cpu_time_wait (time_constant);
-
- if (nm_tx_pending (ring) && !n_free_slots)
- {
- cur_ring++;
- continue;
- }
- }
-
- while (n_left && n_free_slots)
- {
- vlib_buffer_t *b0 = 0;
- u32 bi = buffers[0];
- u32 len;
- u32 offset = 0;
- buffers++;
-
- struct netmap_slot *slot = &ring->slot[cur];
-
- do
- {
- b0 = vlib_get_buffer (vm, bi);
- len = b0->current_length;
- /* memcpy */
- clib_memcpy_fast ((u8 *) NETMAP_BUF (ring, slot->buf_idx) +
- offset, vlib_buffer_get_current (b0), len);
- offset += len;
- }
- while ((bi = b0->next_buffer));
-
- slot->len = offset;
- cur = (cur + 1) % ring->num_slots;
- n_free_slots--;
- n_left--;
- }
- CLIB_MEMORY_BARRIER ();
- ring->head = ring->cur = cur;
- }
-
- if (n_left < frame->n_vectors)
- ioctl (nif->fd, NIOCTXSYNC, NULL);
-
- clib_spinlock_unlock_if_init (&nif->lockp);
-
- if (n_left)
- vlib_error_count (vm, node->node_index,
- (n_left ==
- frame->n_vectors ? NETMAP_TX_ERROR_PENDING_MSGS :
- NETMAP_TX_ERROR_NO_FREE_SLOTS), n_left);
-
- vlib_buffer_free (vm, vlib_frame_vector_args (frame), frame->n_vectors);
- return frame->n_vectors;
-}
-
-static void
-netmap_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
- u32 node_index)
-{
- netmap_main_t *apm = &netmap_main;
- vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
- netmap_if_t *nif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
-
- /* Shut off redirection */
- if (node_index == ~0)
- {
- nif->per_interface_next_index = node_index;
- return;
- }
-
- nif->per_interface_next_index =
- vlib_node_add_next (vlib_get_main (), netmap_input_node.index,
- node_index);
-}
-
-static void
-netmap_clear_hw_interface_counters (u32 instance)
-{
- /* Nothing for now */
-}
-
-static clib_error_t *
-netmap_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
-{
- netmap_main_t *apm = &netmap_main;
- vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
- netmap_if_t *nif = pool_elt_at_index (apm->interfaces, hw->dev_instance);
- u32 hw_flags;
-
- nif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
-
- if (nif->is_admin_up)
- hw_flags = VNET_HW_INTERFACE_FLAG_LINK_UP;
- else
- hw_flags = 0;
-
- vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
-
- return 0;
-}
-
-static clib_error_t *
-netmap_subif_add_del_function (vnet_main_t * vnm,
- u32 hw_if_index,
- struct vnet_sw_interface_t *st, int is_add)
-{
- /* Nothing for now */
- return 0;
-}
-
-/* *INDENT-OFF* */
-VNET_DEVICE_CLASS (netmap_device_class) = {
- .name = "netmap",
- .format_device_name = format_netmap_device_name,
- .format_device = format_netmap_device,
- .format_tx_trace = format_netmap_tx_trace,
- .tx_function_n_errors = NETMAP_TX_N_ERROR,
- .tx_function_error_strings = netmap_tx_func_error_strings,
- .rx_redirect_to_node = netmap_set_interface_next_node,
- .clear_counters = netmap_clear_hw_interface_counters,
- .admin_up_down_function = netmap_interface_admin_up_down,
- .subif_add_del_function = netmap_subif_add_del_function,
-};
-/* *INDENT-ON* */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/dir.dox b/extras/deprecated/netmap/dir.dox
deleted file mode 100644
index 7ddbf947c29..00000000000
--- a/extras/deprecated/netmap/dir.dox
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2017 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.
- */
-
-/* Doxygen directory documentation */
-
-/**
-@dir
-@brief netmap Interface Implementation.
-
-This directory contains the source code for the netmap driver.
-
-*/
-/*? %%clicmd:group_label netmap %% ?*/
-/*? %%syscfg:group_label netmap %% ?*/
diff --git a/extras/deprecated/netmap/net_netmap.h b/extras/deprecated/netmap/net_netmap.h
deleted file mode 100644
index fd4253b7c0c..00000000000
--- a/extras/deprecated/netmap/net_netmap.h
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``S IS''AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * $FreeBSD: head/sys/net/netmap.h 251139 2013-05-30 14:07:14Z luigi $
- *
- * Definitions of constants and the structures used by the netmap
- * framework, for the part visible to both kernel and userspace.
- * Detailed info on netmap is available with "man netmap" or at
- *
- * http://info.iet.unipi.it/~luigi/netmap/
- *
- * This API is also used to communicate with the VALE software switch
- */
-
-#ifndef _NET_NETMAP_H_
-#define _NET_NETMAP_H_
-
-#define NETMAP_API 11 /* current API version */
-
-#define NETMAP_MIN_API 11 /* min and max versions accepted */
-#define NETMAP_MAX_API 15
-/*
- * Some fields should be cache-aligned to reduce contention.
- * The alignment is architecture and OS dependent, but rather than
- * digging into OS headers to find the exact value we use an estimate
- * that should cover most architectures.
- */
-#define NM_CACHE_ALIGN 128
-
-/*
- * --- Netmap data structures ---
- *
- * The userspace data structures used by netmap are shown below.
- * They are allocated by the kernel and mmap()ed by userspace threads.
- * Pointers are implemented as memory offsets or indexes,
- * so that they can be easily dereferenced in kernel and userspace.
-
- KERNEL (opaque, obviously)
-
- ====================================================================
- |
- USERSPACE | struct netmap_ring
- +---->+---------------+
- / | head,cur,tail |
- struct netmap_if (nifp, 1 per fd) / | buf_ofs |
- +---------------+ / | other fields |
- | ni_tx_rings | / +===============+
- | ni_rx_rings | / | buf_idx, len | slot[0]
- | | / | flags, ptr |
- | | / +---------------+
- +===============+ / | buf_idx, len | slot[1]
- | txring_ofs[0] | (rel.to nifp)--' | flags, ptr |
- | txring_ofs[1] | +---------------+
- (tx+1 entries) (num_slots entries)
- | txring_ofs[t] | | buf_idx, len | slot[n-1]
- +---------------+ | flags, ptr |
- | rxring_ofs[0] | +---------------+
- | rxring_ofs[1] |
- (rx+1 entries)
- | rxring_ofs[r] |
- +---------------+
-
- * For each "interface" (NIC, host stack, PIPE, VALE switch port) bound to
- * a file descriptor, the mmap()ed region contains a (logically readonly)
- * struct netmap_if pointing to struct netmap_ring's.
- *
- * There is one netmap_ring per physical NIC ring, plus one tx/rx ring
- * pair attached to the host stack (this pair is unused for non-NIC ports).
- *
- * All physical/host stack ports share the same memory region,
- * so that zero-copy can be implemented between them.
- * VALE switch ports instead have separate memory regions.
- *
- * The netmap_ring is the userspace-visible replica of the NIC ring.
- * Each slot has the index of a buffer (MTU-sized and residing in the
- * mmapped region), its length and some flags. An extra 64-bit pointer
- * is provided for user-supplied buffers in the tx path.
- *
- * In user space, the buffer address is computed as
- * (char *)ring + buf_ofs + index * NETMAP_BUF_SIZE
- *
- * Added in NETMAP_API 11:
- *
- * + NIOCREGIF can request the allocation of extra spare buffers from
- * the same memory pool. The desired number of buffers must be in
- * nr_arg3. The ioctl may return fewer buffers, depending on memory
- * availability. nr_arg3 will return the actual value, and, once
- * mapped, nifp->ni_bufs_head will be the index of the first buffer.
- *
- * The buffers are linked to each other using the first uint32_t
- * as the index. On close, ni_bufs_head must point to the list of
- * buffers to be released.
- *
- * + NIOCREGIF can request space for extra rings (and buffers)
- * allocated in the same memory space. The number of extra rings
- * is in nr_arg1, and is advisory. This is a no-op on NICs where
- * the size of the memory space is fixed.
- *
- * + NIOCREGIF can attach to PIPE rings sharing the same memory
- * space with a parent device. The ifname indicates the parent device,
- * which must already exist. Flags in nr_flags indicate if we want to
- * bind the master or slave side, the index (from nr_ringid)
- * is just a cookie and does not need to be sequential.
- *
- * + NIOCREGIF can also attach to 'monitor' rings that replicate
- * the content of specific rings, also from the same memory space.
- *
- * Extra flags in nr_flags support the above functions.
- * Application libraries may use the following naming scheme:
- * netmap:foo all NIC ring pairs
- * netmap:foo^ only host ring pair
- * netmap:foo+ all NIC ring + host ring pairs
- * netmap:foo-k the k-th NIC ring pair
- * netmap:foo{k PIPE ring pair k, master side
- * netmap:foo}k PIPE ring pair k, slave side
- */
-
-/*
- * struct netmap_slot is a buffer descriptor
- */
-struct netmap_slot {
- uint32_t buf_idx; /* buffer index */
- uint16_t len; /* length for this slot */
- uint16_t flags; /* buf changed, etc. */
- uint64_t ptr; /* pointer for indirect buffers */
-};
-
-/*
- * The following flags control how the slot is used
- */
-
-#define NS_BUF_CHANGED 0x0001 /* buf_idx changed */
- /*
- * must be set whenever buf_idx is changed (as it might be
- * necessary to recompute the physical address and mapping)
- *
- * It is also set by the kernel whenever the buf_idx is
- * changed internally (e.g., by pipes). Applications may
- * use this information to know when they can reuse the
- * contents of previously prepared buffers.
- */
-
-#define NS_REPORT 0x0002 /* ask the hardware to report results */
- /*
- * Request notification when slot is used by the hardware.
- * Normally transmit completions are handled lazily and
- * may be unreported. This flag lets us know when a slot
- * has been sent (e.g. to terminate the sender).
- */
-
-#define NS_FORWARD 0x0004 /* pass packet 'forward' */
- /*
- * (Only for physical ports, rx rings with NR_FORWARD set).
- * Slot released to the kernel (i.e. before ring->head) with
- * this flag set are passed to the peer ring (host/NIC),
- * thus restoring the host-NIC connection for these slots.
- * This supports efficient traffic monitoring or firewalling.
- */
-
-#define NS_NO_LEARN 0x0008 /* disable bridge learning */
- /*
- * On a VALE switch, do not 'learn' the source port for
- * this buffer.
- */
-
-#define NS_INDIRECT 0x0010 /* userspace buffer */
- /*
- * (VALE tx rings only) data is in a userspace buffer,
- * whose address is in the 'ptr' field in the slot.
- */
-
-#define NS_MOREFRAG 0x0020 /* packet has more fragments */
- /*
- * (VALE ports only)
- * Set on all but the last slot of a multi-segment packet.
- * The 'len' field refers to the individual fragment.
- */
-
-#define NS_PORT_SHIFT 8
-#define NS_PORT_MASK (0xff << NS_PORT_SHIFT)
- /*
- * The high 8 bits of the flag, if not zero, indicate the
- * destination port for the VALE switch, overriding
- * the lookup table.
- */
-
-#define NS_RFRAGS(_slot) ( ((_slot)->flags >> 8) & 0xff)
- /*
- * (VALE rx rings only) the high 8 bits
- * are the number of fragments.
- */
-
-
-/*
- * struct netmap_ring
- *
- * Netmap representation of a TX or RX ring (also known as "queue").
- * This is a queue implemented as a fixed-size circular array.
- * At the software level the important fields are: head, cur, tail.
- *
- * In TX rings:
- *
- * head first slot available for transmission.
- * cur wakeup point. select() and poll() will unblock
- * when 'tail' moves past 'cur'
- * tail (readonly) first slot reserved to the kernel
- *
- * [head .. tail-1] can be used for new packets to send;
- * 'head' and 'cur' must be incremented as slots are filled
- * with new packets to be sent;
- * 'cur' can be moved further ahead if we need more space
- * for new transmissions. XXX todo (2014-03-12)
- *
- * In RX rings:
- *
- * head first valid received packet
- * cur wakeup point. select() and poll() will unblock
- * when 'tail' moves past 'cur'
- * tail (readonly) first slot reserved to the kernel
- *
- * [head .. tail-1] contain received packets;
- * 'head' and 'cur' must be incremented as slots are consumed
- * and can be returned to the kernel;
- * 'cur' can be moved further ahead if we want to wait for
- * new packets without returning the previous ones.
- *
- * DATA OWNERSHIP/LOCKING:
- * The netmap_ring, and all slots and buffers in the range
- * [head .. tail-1] are owned by the user program;
- * the kernel only accesses them during a netmap system call
- * and in the user thread context.
- *
- * Other slots and buffers are reserved for use by the kernel
- */
-struct netmap_ring {
- /*
- * buf_ofs is meant to be used through macros.
- * It contains the offset of the buffer region from this
- * descriptor.
- */
- const int64_t buf_ofs;
- const uint32_t num_slots; /* number of slots in the ring. */
- const uint32_t nr_buf_size;
- const uint16_t ringid;
- const uint16_t dir; /* 0: tx, 1: rx */
-
- uint32_t head; /* (u) first user slot */
- uint32_t cur; /* (u) wakeup point */
- uint32_t tail; /* (k) first kernel slot */
-
- uint32_t flags;
-
- struct timeval ts; /* (k) time of last *sync() */
-
- /* opaque room for a mutex or similar object */
-#if !defined(_WIN32) || defined(__CYGWIN__)
- uint8_t __attribute__((__aligned__(NM_CACHE_ALIGN))) sem[128];
-#else
- uint8_t __declspec(align(NM_CACHE_ALIGN)) sem[128];
-#endif
-
- /* the slots follow. This struct has variable size */
- struct netmap_slot slot[0]; /* array of slots. */
-};
-
-
-/*
- * RING FLAGS
- */
-#define NR_TIMESTAMP 0x0002 /* set timestamp on *sync() */
- /*
- * updates the 'ts' field on each netmap syscall. This saves
- * saves a separate gettimeofday(), and is not much worse than
- * software timestamps generated in the interrupt handler.
- */
-
-#define NR_FORWARD 0x0004 /* enable NS_FORWARD for ring */
- /*
- * Enables the NS_FORWARD slot flag for the ring.
- */
-
-
-/*
- * Netmap representation of an interface and its queue(s).
- * This is initialized by the kernel when binding a file
- * descriptor to a port, and should be considered as readonly
- * by user programs. The kernel never uses it.
- *
- * There is one netmap_if for each file descriptor on which we want
- * to select/poll.
- * select/poll operates on one or all pairs depending on the value of
- * nmr_queueid passed on the ioctl.
- */
-struct netmap_if {
- char ni_name[IFNAMSIZ]; /* name of the interface. */
- const uint32_t ni_version; /* API version, currently unused */
- const uint32_t ni_flags; /* properties */
-#define NI_PRIV_MEM 0x1 /* private memory region */
-
- /*
- * The number of packet rings available in netmap mode.
- * Physical NICs can have different numbers of tx and rx rings.
- * Physical NICs also have a 'host' ring pair.
- * Additionally, clients can request additional ring pairs to
- * be used for internal communication.
- */
- const uint32_t ni_tx_rings; /* number of HW tx rings */
- const uint32_t ni_rx_rings; /* number of HW rx rings */
-
- uint32_t ni_bufs_head; /* head index for extra bufs */
- uint32_t ni_spare1[5];
- /*
- * The following array contains the offset of each netmap ring
- * from this structure, in the following order:
- * NIC tx rings (ni_tx_rings); host tx ring (1); extra tx rings;
- * NIC rx rings (ni_rx_rings); host tx ring (1); extra rx rings.
- *
- * The area is filled up by the kernel on NIOCREGIF,
- * and then only read by userspace code.
- */
- const ssize_t ring_ofs[0];
-};
-
-
-#ifndef NIOCREGIF
-/*
- * ioctl names and related fields
- *
- * NIOCTXSYNC, NIOCRXSYNC synchronize tx or rx queues,
- * whose identity is set in NIOCREGIF through nr_ringid.
- * These are non blocking and take no argument.
- *
- * NIOCGINFO takes a struct ifreq, the interface name is the input,
- * the outputs are number of queues and number of descriptor
- * for each queue (useful to set number of threads etc.).
- * The info returned is only advisory and may change before
- * the interface is bound to a file descriptor.
- *
- * NIOCREGIF takes an interface name within a struct nmre,
- * and activates netmap mode on the interface (if possible).
- *
- * The argument to NIOCGINFO/NIOCREGIF overlays struct ifreq so we
- * can pass it down to other NIC-related ioctls.
- *
- * The actual argument (struct nmreq) has a number of options to request
- * different functions.
- * The following are used in NIOCREGIF when nr_cmd == 0:
- *
- * nr_name (in)
- * The name of the port (em0, valeXXX:YYY, etc.)
- * limited to IFNAMSIZ for backward compatibility.
- *
- * nr_version (in/out)
- * Must match NETMAP_API as used in the kernel, error otherwise.
- * Always returns the desired value on output.
- *
- * nr_tx_slots, nr_tx_slots, nr_tx_rings, nr_rx_rings (in/out)
- * On input, non-zero values may be used to reconfigure the port
- * according to the requested values, but this is not guaranteed.
- * On output the actual values in use are reported.
- *
- * nr_ringid (in)
- * Indicates how rings should be bound to the file descriptors.
- * If nr_flags != 0, then the low bits (in NETMAP_RING_MASK)
- * are used to indicate the ring number, and nr_flags specifies
- * the actual rings to bind. NETMAP_NO_TX_POLL is unaffected.
- *
- * NOTE: THE FOLLOWING (nr_flags == 0) IS DEPRECATED:
- * If nr_flags == 0, NETMAP_HW_RING and NETMAP_SW_RING control
- * the binding as follows:
- * 0 (default) binds all physical rings
- * NETMAP_HW_RING | ring number binds a single ring pair
- * NETMAP_SW_RING binds only the host tx/rx rings
- *
- * NETMAP_NO_TX_POLL can be OR-ed to make select()/poll() push
- * packets on tx rings only if POLLOUT is set.
- * The default is to push any pending packet.
- *
- * NETMAP_DO_RX_POLL can be OR-ed to make select()/poll() release
- * packets on rx rings also when POLLIN is NOT set.
- * The default is to touch the rx ring only with POLLIN.
- * Note that this is the opposite of TX because it
- * reflects the common usage.
- *
- * NOTE: NETMAP_PRIV_MEM IS DEPRECATED, use nr_arg2 instead.
- * NETMAP_PRIV_MEM is set on return for ports that do not use
- * the global memory allocator.
- * This information is not significant and applications
- * should look at the region id in nr_arg2
- *
- * nr_flags is the recommended mode to indicate which rings should
- * be bound to a file descriptor. Values are NR_REG_*
- *
- * nr_arg1 (in) The number of extra rings to be reserved.
- * Especially when allocating a VALE port the system only
- * allocates the amount of memory needed for the port.
- * If more shared memory rings are desired (e.g. for pipes),
- * the first invocation for the same basename/allocator
- * should specify a suitable number. Memory cannot be
- * extended after the first allocation without closing
- * all ports on the same region.
- *
- * nr_arg2 (in/out) The identity of the memory region used.
- * On input, 0 means the system decides autonomously,
- * other values may try to select a specific region.
- * On return the actual value is reported.
- * Region '1' is the global allocator, normally shared
- * by all interfaces. Other values are private regions.
- * If two ports the same region zero-copy is possible.
- *
- * nr_arg3 (in/out) number of extra buffers to be allocated.
- *
- *
- *
- * nr_cmd (in) if non-zero indicates a special command:
- * NETMAP_BDG_ATTACH and nr_name = vale*:ifname
- * attaches the NIC to the switch; nr_ringid specifies
- * which rings to use. Used by vale-ctl -a ...
- * nr_arg1 = NETMAP_BDG_HOST also attaches the host port
- * as in vale-ctl -h ...
- *
- * NETMAP_BDG_DETACH and nr_name = vale*:ifname
- * disconnects a previously attached NIC.
- * Used by vale-ctl -d ...
- *
- * NETMAP_BDG_LIST
- * list the configuration of VALE switches.
- *
- * NETMAP_BDG_VNET_HDR
- * Set the virtio-net header length used by the client
- * of a VALE switch port.
- *
- * NETMAP_BDG_NEWIF
- * create a persistent VALE port with name nr_name.
- * Used by vale-ctl -n ...
- *
- * NETMAP_BDG_DELIF
- * delete a persistent VALE port. Used by vale-ctl -d ...
- *
- * nr_arg1, nr_arg2, nr_arg3 (in/out) command specific
- *
- *
- *
- */
-
-
-/*
- * struct nmreq overlays a struct ifreq (just the name)
- */
-struct nmreq {
- char nr_name[IFNAMSIZ];
- uint32_t nr_version; /* API version */
- uint32_t nr_offset; /* nifp offset in the shared region */
- uint32_t nr_memsize; /* size of the shared region */
- uint32_t nr_tx_slots; /* slots in tx rings */
- uint32_t nr_rx_slots; /* slots in rx rings */
- uint16_t nr_tx_rings; /* number of tx rings */
- uint16_t nr_rx_rings; /* number of rx rings */
-
- uint16_t nr_ringid; /* ring(s) we care about */
-#define NETMAP_HW_RING 0x4000 /* single NIC ring pair */
-#define NETMAP_SW_RING 0x2000 /* only host ring pair */
-
-#define NETMAP_RING_MASK 0x0fff /* the ring number */
-
-#define NETMAP_NO_TX_POLL 0x1000 /* no automatic txsync on poll */
-
-#define NETMAP_DO_RX_POLL 0x8000 /* DO automatic rxsync on poll */
-
- uint16_t nr_cmd;
-#define NETMAP_BDG_ATTACH 1 /* attach the NIC */
-#define NETMAP_BDG_DETACH 2 /* detach the NIC */
-#define NETMAP_BDG_REGOPS 3 /* register bridge callbacks */
-#define NETMAP_BDG_LIST 4 /* get bridge's info */
-#define NETMAP_BDG_VNET_HDR 5 /* set the port virtio-net-hdr length */
-#define NETMAP_BDG_OFFSET NETMAP_BDG_VNET_HDR /* deprecated alias */
-#define NETMAP_BDG_NEWIF 6 /* create a virtual port */
-#define NETMAP_BDG_DELIF 7 /* destroy a virtual port */
-#define NETMAP_PT_HOST_CREATE 8 /* create ptnetmap kthreads */
-#define NETMAP_PT_HOST_DELETE 9 /* delete ptnetmap kthreads */
-#define NETMAP_BDG_POLLING_ON 10 /* delete polling kthread */
-#define NETMAP_BDG_POLLING_OFF 11 /* delete polling kthread */
-#define NETMAP_VNET_HDR_GET 12 /* get the port virtio-net-hdr length */
- uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */
-#define NETMAP_BDG_HOST 1 /* attach the host stack on ATTACH */
-
- uint16_t nr_arg2;
- uint32_t nr_arg3; /* req. extra buffers in NIOCREGIF */
- uint32_t nr_flags;
- /* various modes, extends nr_ringid */
- uint32_t spare2[1];
-};
-
-#define NR_REG_MASK 0xf /* values for nr_flags */
-enum { NR_REG_DEFAULT = 0, /* backward compat, should not be used. */
- NR_REG_ALL_NIC = 1,
- NR_REG_SW = 2,
- NR_REG_NIC_SW = 3,
- NR_REG_ONE_NIC = 4,
- NR_REG_PIPE_MASTER = 5,
- NR_REG_PIPE_SLAVE = 6,
-};
-/* monitor uses the NR_REG to select the rings to monitor */
-#define NR_MONITOR_TX 0x100
-#define NR_MONITOR_RX 0x200
-#define NR_ZCOPY_MON 0x400
-/* request exclusive access to the selected rings */
-#define NR_EXCLUSIVE 0x800
-/* request ptnetmap host support */
-#define NR_PASSTHROUGH_HOST NR_PTNETMAP_HOST /* deprecated */
-#define NR_PTNETMAP_HOST 0x1000
-#define NR_RX_RINGS_ONLY 0x2000
-#define NR_TX_RINGS_ONLY 0x4000
-/* Applications set this flag if they are able to deal with virtio-net headers,
- * that is send/receive frames that start with a virtio-net header.
- * If not set, NIOCREGIF will fail with netmap ports that require applications
- * to use those headers. If the flag is set, the application can use the
- * NETMAP_VNET_HDR_GET command to figure out the header length. */
-#define NR_ACCEPT_VNET_HDR 0x8000
-
-
-/*
- * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined
- * in ws2def.h but not sure if they are in the form we need.
- * XXX so we redefine them
- * in a convenient way to use for DeviceIoControl signatures
- */
-#ifdef _WIN32
-#undef _IO // ws2def.h
-#define _WIN_NM_IOCTL_TYPE 40000
-#define _IO(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
- METHOD_BUFFERED, FILE_ANY_ACCESS )
-#define _IO_direct(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \
- METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
-
-#define _IOWR(_c, _n, _s) _IO(_c, _n)
-
-/* We havesome internal sysctl in addition to the externally visible ones */
-#define NETMAP_MMAP _IO_direct('i', 160) // note METHOD_OUT_DIRECT
-#define NETMAP_POLL _IO('i', 162)
-
-/* and also two setsockopt for sysctl emulation */
-#define NETMAP_SETSOCKOPT _IO('i', 140)
-#define NETMAP_GETSOCKOPT _IO('i', 141)
-
-
-//These linknames are for the Netmap Core Driver
-#define NETMAP_NT_DEVICE_NAME L"\\Device\\NETMAP"
-#define NETMAP_DOS_DEVICE_NAME L"\\DosDevices\\netmap"
-
-//Definition of a structure used to pass a virtual address within an IOCTL
-typedef struct _MEMORY_ENTRY {
- PVOID pUsermodeVirtualAddress;
-} MEMORY_ENTRY, *PMEMORY_ENTRY;
-
-typedef struct _POLL_REQUEST_DATA {
- int events;
- int timeout;
- int revents;
-} POLL_REQUEST_DATA;
-
-#endif /* _WIN32 */
-
-/*
- * FreeBSD uses the size value embedded in the _IOWR to determine
- * how much to copy in/out. So we need it to match the actual
- * data structure we pass. We put some spares in the structure
- * to ease compatibility with other versions
- */
-#define NIOCGINFO _IOWR('i', 145, struct nmreq) /* return IF info */
-#define NIOCREGIF _IOWR('i', 146, struct nmreq) /* interface register */
-#define NIOCTXSYNC _IO('i', 148) /* sync tx queues */
-#define NIOCRXSYNC _IO('i', 149) /* sync rx queues */
-#define NIOCCONFIG _IOWR('i',150, struct nm_ifreq) /* for ext. modules */
-#endif /* !NIOCREGIF */
-
-
-/*
- * Helper functions for kernel and userspace
- */
-
-/*
- * check if space is available in the ring.
- */
-static inline int
-nm_ring_empty(struct netmap_ring *ring)
-{
- return (ring->cur == ring->tail);
-}
-
-/*
- * Opaque structure that is passed to an external kernel
- * module via ioctl(fd, NIOCCONFIG, req) for a user-owned
- * bridge port (at this point ephemeral VALE interface).
- */
-#define NM_IFRDATA_LEN 256
-struct nm_ifreq {
- char nifr_name[IFNAMSIZ];
- char data[NM_IFRDATA_LEN];
-};
-
-/*
- * netmap kernel thread configuration
- */
-/* bhyve/vmm.ko MSIX parameters for IOCTL */
-struct ptn_vmm_ioctl_msix {
- uint64_t msg;
- uint64_t addr;
-};
-
-/* IOCTL parameters */
-struct nm_kth_ioctl {
- u_long com;
- /* TODO: use union */
- union {
- struct ptn_vmm_ioctl_msix msix;
- } data;
-};
-
-/* Configuration of a ptnetmap ring */
-struct ptnet_ring_cfg {
- uint64_t ioeventfd; /* eventfd in linux, tsleep() parameter in FreeBSD */
- uint64_t irqfd; /* eventfd in linux, ioctl fd in FreeBSD */
- struct nm_kth_ioctl ioctl; /* ioctl parameter to send irq (only used in bhyve/FreeBSD) */
-};
-#endif /* _NET_NETMAP_H_ */
diff --git a/extras/deprecated/netmap/netmap.api b/extras/deprecated/netmap/netmap.api
deleted file mode 100644
index a14753cad9c..00000000000
--- a/extras/deprecated/netmap/netmap.api
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2015-2016 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.
- */
-
-option version = "1.0.0";
-
-/** \brief Create netmap
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param netmap_if_name - interface name
- @param hw_addr - interface MAC
- @param use_random_hw_addr - use random generated MAC
- @param is_pipe - is pipe
- @param is_master - 0=slave, 1=master
-*/
-autoreply define netmap_create
-{
- u32 client_index;
- u32 context;
-
- u8 netmap_if_name[64];
- u8 hw_addr[6];
- u8 use_random_hw_addr;
- u8 is_pipe;
- u8 is_master;
-};
-
-/** \brief Delete netmap
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param netmap_if_name - interface name
-*/
-autoreply define netmap_delete
-{
- u32 client_index;
- u32 context;
-
- u8 netmap_if_name[64];
-};
-
-/*
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/netmap.c b/extras/deprecated/netmap/netmap.c
deleted file mode 100644
index 7cab6bb0289..00000000000
--- a/extras/deprecated/netmap/netmap.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2016 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 <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <vnet/devices/netmap/net_netmap.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/devices/netmap/netmap.h>
-
-netmap_main_t netmap_main;
-
-static u32
-netmap_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
- u32 flags)
-{
- /* nothing for now */
- return 0;
-}
-
-static clib_error_t *
-netmap_fd_read_ready (clib_file_t * uf)
-{
- vlib_main_t *vm = vlib_get_main ();
- netmap_main_t *nm = &netmap_main;
- u32 idx = uf->private_data;
-
- nm->pending_input_bitmap =
- clib_bitmap_set (nm->pending_input_bitmap, idx, 1);
-
- /* Schedule the rx node */
- vlib_node_set_interrupt_pending (vm, netmap_input_node.index);
-
- return 0;
-}
-
-static void
-close_netmap_if (netmap_main_t * nm, netmap_if_t * nif)
-{
- if (nif->clib_file_index != ~0)
- {
- clib_file_del (&file_main, file_main.file_pool + nif->clib_file_index);
- nif->clib_file_index = ~0;
- }
- else if (nif->fd > -1)
- close (nif->fd);
-
- if (nif->mem_region)
- {
- netmap_mem_region_t *reg = &nm->mem_regions[nif->mem_region];
- if (--reg->refcnt == 0)
- {
- munmap (reg->mem, reg->region_size);
- reg->region_size = 0;
- }
- }
-
-
- mhash_unset (&nm->if_index_by_host_if_name, nif->host_if_name,
- &nif->if_index);
- vec_free (nif->host_if_name);
- vec_free (nif->req);
-
- clib_memset (nif, 0, sizeof (*nif));
- pool_put (nm->interfaces, nif);
-}
-
-int
-netmap_worker_thread_enable ()
-{
- /* if worker threads are enabled, switch to polling mode */
- foreach_vlib_main ((
- {
- vlib_node_set_state (this_vlib_main,
- netmap_input_node.index,
- VLIB_NODE_STATE_POLLING);
- }));
-
- return 0;
-}
-
-int
-netmap_worker_thread_disable ()
-{
- foreach_vlib_main ((
- {
- vlib_node_set_state (this_vlib_main,
- netmap_input_node.index,
- VLIB_NODE_STATE_INTERRUPT);
- }));
-
- return 0;
-}
-
-int
-netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set,
- u8 is_pipe, u8 is_master, u32 * sw_if_index)
-{
- netmap_main_t *nm = &netmap_main;
- int ret = 0;
- netmap_if_t *nif = 0;
- u8 hw_addr[6];
- clib_error_t *error = 0;
- vnet_sw_interface_t *sw;
- vnet_main_t *vnm = vnet_get_main ();
- uword *p;
- struct nmreq *req = 0;
- netmap_mem_region_t *reg;
- vlib_thread_main_t *tm = vlib_get_thread_main ();
- int fd;
-
- p = mhash_get (&nm->if_index_by_host_if_name, if_name);
- if (p)
- return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
-
- fd = open ("/dev/netmap", O_RDWR);
- if (fd < 0)
- return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
-
- pool_get (nm->interfaces, nif);
- nif->if_index = nif - nm->interfaces;
- nif->fd = fd;
- nif->clib_file_index = ~0;
-
- vec_validate (req, 0);
- nif->req = req;
- req->nr_version = NETMAP_API;
- req->nr_flags = NR_REG_ALL_NIC;
-
- if (is_pipe)
- req->nr_flags = is_master ? NR_REG_PIPE_MASTER : NR_REG_PIPE_SLAVE;
- else
- req->nr_flags = NR_REG_ALL_NIC;
-
- req->nr_flags |= NR_ACCEPT_VNET_HDR;
- snprintf (req->nr_name, IFNAMSIZ, "%s", if_name);
- req->nr_name[IFNAMSIZ - 1] = 0;
-
- if (ioctl (nif->fd, NIOCREGIF, req))
- {
- ret = VNET_API_ERROR_NOT_CONNECTED;
- goto error;
- }
-
- nif->mem_region = req->nr_arg2;
- vec_validate (nm->mem_regions, nif->mem_region);
- reg = &nm->mem_regions[nif->mem_region];
- if (reg->region_size == 0)
- {
- reg->mem = mmap (NULL, req->nr_memsize, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- clib_warning ("mem %p", reg->mem);
- if (reg->mem == MAP_FAILED)
- {
- ret = VNET_API_ERROR_NOT_CONNECTED;
- goto error;
- }
- reg->region_size = req->nr_memsize;
- }
- reg->refcnt++;
-
- nif->nifp = NETMAP_IF (reg->mem, req->nr_offset);
- nif->first_rx_ring = 0;
- nif->last_rx_ring = 0;
- nif->first_tx_ring = 0;
- nif->last_tx_ring = 0;
- nif->host_if_name = if_name;
- nif->per_interface_next_index = ~0;
-
- if (tm->n_vlib_mains > 1)
- clib_spinlock_init (&nif->lockp);
-
- {
- clib_file_t template = { 0 };
- template.read_function = netmap_fd_read_ready;
- template.file_descriptor = nif->fd;
- template.private_data = nif->if_index;
- template.description = format (0, "netmap socket");
- nif->clib_file_index = clib_file_add (&file_main, &template);
- }
-
- /*use configured or generate random MAC address */
- if (hw_addr_set)
- memcpy (hw_addr, hw_addr_set, 6);
- else
- {
- f64 now = vlib_time_now (vm);
- u32 rnd;
- rnd = (u32) (now * 1e6);
- rnd = random_u32 (&rnd);
-
- memcpy (hw_addr + 2, &rnd, sizeof (rnd));
- hw_addr[0] = 2;
- hw_addr[1] = 0xfe;
- }
-
- error = ethernet_register_interface (vnm, netmap_device_class.index,
- nif->if_index, hw_addr,
- &nif->hw_if_index,
- netmap_eth_flag_change);
-
- if (error)
- {
- clib_error_report (error);
- ret = VNET_API_ERROR_SYSCALL_ERROR_1;
- goto error;
- }
-
- sw = vnet_get_hw_sw_interface (vnm, nif->hw_if_index);
- nif->sw_if_index = sw->sw_if_index;
-
- mhash_set_mem (&nm->if_index_by_host_if_name, if_name, &nif->if_index, 0);
-
- if (sw_if_index)
- *sw_if_index = nif->sw_if_index;
-
- if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 1)
- netmap_worker_thread_enable ();
-
- return 0;
-
-error:
- close_netmap_if (nm, nif);
- return ret;
-}
-
-int
-netmap_delete_if (vlib_main_t * vm, u8 * host_if_name)
-{
- vnet_main_t *vnm = vnet_get_main ();
- netmap_main_t *nm = &netmap_main;
- netmap_if_t *nif;
- uword *p;
- vlib_thread_main_t *tm = vlib_get_thread_main ();
-
- p = mhash_get (&nm->if_index_by_host_if_name, host_if_name);
- if (p == NULL)
- {
- clib_warning ("Host interface %s does not exist", host_if_name);
- return VNET_API_ERROR_SYSCALL_ERROR_1;
- }
- nif = pool_elt_at_index (nm->interfaces, p[0]);
-
- /* bring down the interface */
- vnet_hw_interface_set_flags (vnm, nif->hw_if_index, 0);
-
- ethernet_delete_interface (vnm, nif->hw_if_index);
-
- close_netmap_if (nm, nif);
-
- if (tm->n_vlib_mains > 1 && pool_elts (nm->interfaces) == 0)
- netmap_worker_thread_disable ();
-
- return 0;
-}
-
-static clib_error_t *
-netmap_init (vlib_main_t * vm)
-{
- netmap_main_t *nm = &netmap_main;
- vlib_thread_main_t *tm = vlib_get_thread_main ();
- vlib_thread_registration_t *tr;
- uword *p;
-
- clib_memset (nm, 0, sizeof (netmap_main_t));
-
- nm->input_cpu_first_index = 0;
- nm->input_cpu_count = 1;
-
- /* find out which cpus will be used for input */
- p = hash_get_mem (tm->thread_registrations_by_name, "workers");
- tr = p ? (vlib_thread_registration_t *) p[0] : 0;
-
- if (tr && tr->count > 0)
- {
- nm->input_cpu_first_index = tr->first_index;
- nm->input_cpu_count = tr->count;
- }
-
- mhash_init_vec_string (&nm->if_index_by_host_if_name, sizeof (uword));
-
- vec_validate_aligned (nm->rx_buffers, tm->n_vlib_mains - 1,
- CLIB_CACHE_LINE_BYTES);
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (netmap_init);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/netmap.h b/extras/deprecated/netmap/netmap.h
deleted file mode 100644
index 29f855fda8e..00000000000
--- a/extras/deprecated/netmap/netmap.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2016 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.
- *------------------------------------------------------------------
- */
-/*
- * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <vppinfra/lock.h>
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- clib_spinlock_t lockp;
- u8 *host_if_name;
- uword if_index;
- u32 hw_if_index;
- u32 sw_if_index;
- u32 clib_file_index;
-
- u32 per_interface_next_index;
- u8 is_admin_up;
-
- /* netmap */
- struct nmreq *req;
- u16 mem_region;
- int fd;
- struct netmap_if *nifp;
- u16 first_tx_ring;
- u16 last_tx_ring;
- u16 first_rx_ring;
- u16 last_rx_ring;
-
-} netmap_if_t;
-
-typedef struct
-{
- char *mem;
- u32 region_size;
- int refcnt;
-} netmap_mem_region_t;
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- netmap_if_t *interfaces;
-
- /* bitmap of pending rx interfaces */
- uword *pending_input_bitmap;
-
- /* rx buffer cache */
- u32 **rx_buffers;
-
- /* hash of host interface names */
- mhash_t if_index_by_host_if_name;
-
- /* vector of memory regions */
- netmap_mem_region_t *mem_regions;
-
- /* first cpu index */
- u32 input_cpu_first_index;
-
- /* total cpu count */
- u32 input_cpu_count;
-} netmap_main_t;
-
-extern netmap_main_t netmap_main;
-extern vnet_device_class_t netmap_device_class;
-extern vlib_node_registration_t netmap_input_node;
-
-int netmap_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set,
- u8 is_pipe, u8 is_master, u32 * sw_if_index);
-int netmap_delete_if (vlib_main_t * vm, u8 * host_if_name);
-
-
-/* Macros and helper functions from sys/net/netmap_user.h */
-
-#ifdef _NET_NETMAP_H_
-
-#define _NETMAP_OFFSET(type, ptr, offset) \
- ((type)(void *)((char *)(ptr) + (offset)))
-
-#define NETMAP_IF(_base, _ofs) _NETMAP_OFFSET(struct netmap_if *, _base, _ofs)
-
-#define NETMAP_TXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
- nifp, (nifp)->ring_ofs[index] )
-
-#define NETMAP_RXRING(nifp, index) _NETMAP_OFFSET(struct netmap_ring *, \
- nifp, (nifp)->ring_ofs[index + (nifp)->ni_tx_rings + 1] )
-
-#define NETMAP_BUF(ring, index) \
- ((char *)(ring) + (ring)->buf_ofs + ((index)*(ring)->nr_buf_size))
-
-#define NETMAP_BUF_IDX(ring, buf) \
- ( ((char *)(buf) - ((char *)(ring) + (ring)->buf_ofs) ) / \
- (ring)->nr_buf_size )
-
-static inline uint32_t
-nm_ring_next (struct netmap_ring *ring, uint32_t i)
-{
- return (PREDICT_FALSE (i + 1 == ring->num_slots) ? 0 : i + 1);
-}
-
-
-/*
- * Return 1 if we have pending transmissions in the tx ring.
- * When everything is complete ring->head = ring->tail + 1 (modulo ring size)
- */
-static inline int
-nm_tx_pending (struct netmap_ring *ring)
-{
- return nm_ring_next (ring, ring->tail) != ring->head;
-}
-
-static inline uint32_t
-nm_ring_space (struct netmap_ring *ring)
-{
- int ret = ring->tail - ring->cur;
- if (ret < 0)
- ret += ring->num_slots;
- return ret;
-}
-#endif
-
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/netmap_api.c b/extras/deprecated/netmap/netmap_api.c
deleted file mode 100644
index ee05ec22d25..00000000000
--- a/extras/deprecated/netmap/netmap_api.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- *------------------------------------------------------------------
- * netmap_api.c - netmap api
- *
- * Copyright (c) 2016 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 <vnet/vnet.h>
-#include <vlibmemory/api.h>
-
-#include <vnet/interface.h>
-#include <vnet/api_errno.h>
-#include <vnet/devices/netmap/netmap.h>
-
-#include <vnet/vnet_msg_enum.h>
-
-#define vl_typedefs /* define message structures */
-#include <vnet/vnet_all_api_h.h>
-#undef vl_typedefs
-
-#define vl_endianfun /* define message structures */
-#include <vnet/vnet_all_api_h.h>
-#undef vl_endianfun
-
-/* instantiate all the print functions we know about */
-#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
-#define vl_printfun
-#include <vnet/vnet_all_api_h.h>
-#undef vl_printfun
-
-#include <vlibapi/api_helper_macros.h>
-
-#define foreach_vpe_api_msg \
-_(NETMAP_CREATE, netmap_create) \
-_(NETMAP_DELETE, netmap_delete) \
-
-static void
-vl_api_netmap_create_t_handler (vl_api_netmap_create_t * mp)
-{
- vlib_main_t *vm = vlib_get_main ();
- vl_api_netmap_create_reply_t *rmp;
- int rv = 0;
- u8 *if_name = NULL;
-
- if_name = format (0, "%s", mp->netmap_if_name);
- vec_add1 (if_name, 0);
-
- rv =
- netmap_create_if (vm, if_name, mp->use_random_hw_addr ? 0 : mp->hw_addr,
- mp->is_pipe, mp->is_master, 0);
-
- vec_free (if_name);
-
- REPLY_MACRO (VL_API_NETMAP_CREATE_REPLY);
-}
-
-static void
-vl_api_netmap_delete_t_handler (vl_api_netmap_delete_t * mp)
-{
- vlib_main_t *vm = vlib_get_main ();
- vl_api_netmap_delete_reply_t *rmp;
- int rv = 0;
- u8 *if_name = NULL;
-
- if_name = format (0, "%s", mp->netmap_if_name);
- vec_add1 (if_name, 0);
-
- rv = netmap_delete_if (vm, if_name);
-
- vec_free (if_name);
-
- REPLY_MACRO (VL_API_NETMAP_DELETE_REPLY);
-}
-
-/*
- * netmap_api_hookup
- * Add vpe's API message handlers to the table.
- * vlib has already mapped shared memory and
- * added the client registration handlers.
- * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
- */
-#define vl_msg_name_crc_list
-#include <vnet/vnet_all_api_h.h>
-#undef vl_msg_name_crc_list
-
-static void
-setup_message_id_table (api_main_t * am)
-{
-#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
- foreach_vl_msg_name_crc_netmap;
-#undef _
-}
-
-static clib_error_t *
-netmap_api_hookup (vlib_main_t * vm)
-{
- api_main_t *am = vlibapi_get_main ();
-
-#define _(N,n) \
- vl_msg_api_set_handlers(VL_API_##N, #n, \
- vl_api_##n##_t_handler, \
- vl_noop_handler, \
- vl_api_##n##_t_endian, \
- vl_api_##n##_t_print, \
- sizeof(vl_api_##n##_t), 1);
- foreach_vpe_api_msg;
-#undef _
-
- /*
- * Set up the (msg_name, crc, message-id) table
- */
- setup_message_id_table (am);
-
- return 0;
-}
-
-VLIB_API_INIT_FUNCTION (netmap_api_hookup);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/netmap/node.c b/extras/deprecated/netmap/node.c
deleted file mode 100644
index b0a68824b9c..00000000000
--- a/extras/deprecated/netmap/node.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2016 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 <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/devices/devices.h>
-#include <vnet/feature/feature.h>
-
-#include <vnet/devices/netmap/net_netmap.h>
-#include <vnet/devices/netmap/netmap.h>
-
-#define foreach_netmap_input_error
-
-typedef enum
-{
-#define _(f,s) NETMAP_INPUT_ERROR_##f,
- foreach_netmap_input_error
-#undef _
- NETMAP_INPUT_N_ERROR,
-} netmap_input_error_t;
-
-static char *netmap_input_error_strings[] = {
-#define _(n,s) s,
- foreach_netmap_input_error
-#undef _
-};
-
-typedef struct
-{
- u32 next_index;
- u32 hw_if_index;
- struct netmap_slot slot;
-} netmap_input_trace_t;
-
-static u8 *
-format_netmap_input_trace (u8 * s, va_list * args)
-{
- CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
- CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
- netmap_input_trace_t *t = va_arg (*args, netmap_input_trace_t *);
- u32 indent = format_get_indent (s);
-
- s = format (s, "netmap: hw_if_index %d next-index %d",
- t->hw_if_index, t->next_index);
- s = format (s, "\n%Uslot: flags 0x%x len %u buf_idx %u",
- format_white_space, indent + 2,
- t->slot.flags, t->slot.len, t->slot.buf_idx);
- return s;
-}
-
-always_inline void
-buffer_add_to_chain (vlib_main_t * vm, u32 bi, u32 first_bi, u32 prev_bi)
-{
- vlib_buffer_t *b = vlib_get_buffer (vm, bi);
- vlib_buffer_t *first_b = vlib_get_buffer (vm, first_bi);
- vlib_buffer_t *prev_b = vlib_get_buffer (vm, prev_bi);
-
- /* update first buffer */
- first_b->total_length_not_including_first_buffer += b->current_length;
-
- /* update previous buffer */
- prev_b->next_buffer = bi;
- prev_b->flags |= VLIB_BUFFER_NEXT_PRESENT;
-
- /* update current buffer */
- b->next_buffer = 0;
-}
-
-always_inline uword
-netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame, netmap_if_t * nif)
-{
- u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
- uword n_trace = vlib_get_trace_count (vm, node);
- netmap_main_t *nm = &netmap_main;
- u32 n_rx_packets = 0;
- u32 n_rx_bytes = 0;
- u32 *to_next = 0;
- u32 n_free_bufs;
- struct netmap_ring *ring;
- int cur_ring;
- u32 thread_index = vm->thread_index;
- u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
-
- if (nif->per_interface_next_index != ~0)
- next_index = nif->per_interface_next_index;
-
- n_free_bufs = vec_len (nm->rx_buffers[thread_index]);
- if (PREDICT_FALSE (n_free_bufs < VLIB_FRAME_SIZE))
- {
- vec_validate (nm->rx_buffers[thread_index],
- VLIB_FRAME_SIZE + n_free_bufs - 1);
- n_free_bufs +=
- vlib_buffer_alloc (vm, &nm->rx_buffers[thread_index][n_free_bufs],
- VLIB_FRAME_SIZE);
- _vec_len (nm->rx_buffers[thread_index]) = n_free_bufs;
- }
-
- cur_ring = nif->first_rx_ring;
- while (cur_ring <= nif->last_rx_ring && n_free_bufs)
- {
- int r = 0;
- u32 cur_slot_index;
- ring = NETMAP_RXRING (nif->nifp, cur_ring);
- r = nm_ring_space (ring);
-
- if (!r)
- {
- cur_ring++;
- continue;
- }
-
- if (r > n_free_bufs)
- r = n_free_bufs;
-
- cur_slot_index = ring->cur;
- while (r)
- {
- u32 n_left_to_next;
- u32 next0 = next_index;
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
-
- while (r && n_left_to_next)
- {
- vlib_buffer_t *first_b0 = 0;
- u32 offset = 0;
- u32 bi0 = 0, first_bi0 = 0, prev_bi0;
- u32 next_slot_index = (cur_slot_index + 1) % ring->num_slots;
- u32 next2_slot_index = (cur_slot_index + 2) % ring->num_slots;
- struct netmap_slot *slot = &ring->slot[cur_slot_index];
- u32 data_len = slot->len;
-
- /* prefetch 2 slots in advance */
- CLIB_PREFETCH (&ring->slot[next2_slot_index],
- CLIB_CACHE_LINE_BYTES, LOAD);
- /* prefetch start of next packet */
- CLIB_PREFETCH (NETMAP_BUF
- (ring, ring->slot[next_slot_index].buf_idx),
- CLIB_CACHE_LINE_BYTES, LOAD);
-
- while (data_len && n_free_bufs)
- {
- vlib_buffer_t *b0;
- /* grab free buffer */
- u32 last_empty_buffer =
- vec_len (nm->rx_buffers[thread_index]) - 1;
- prev_bi0 = bi0;
- bi0 = nm->rx_buffers[thread_index][last_empty_buffer];
- b0 = vlib_get_buffer (vm, bi0);
- _vec_len (nm->rx_buffers[thread_index]) = last_empty_buffer;
- n_free_bufs--;
-
- /* copy data */
- u32 bytes_to_copy =
- data_len > n_buffer_bytes ? n_buffer_bytes : data_len;
- b0->current_data = 0;
- clib_memcpy_fast (vlib_buffer_get_current (b0),
- (u8 *) NETMAP_BUF (ring, slot->buf_idx) +
- offset, bytes_to_copy);
-
- /* fill buffer header */
- b0->current_length = bytes_to_copy;
-
- if (offset == 0)
- {
- b0->total_length_not_including_first_buffer = 0;
- b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
- vnet_buffer (b0)->sw_if_index[VLIB_RX] =
- nif->sw_if_index;
- vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
- first_bi0 = bi0;
- first_b0 = vlib_get_buffer (vm, first_bi0);
- }
- else
- buffer_add_to_chain (vm, bi0, first_bi0, prev_bi0);
-
- offset += bytes_to_copy;
- data_len -= bytes_to_copy;
- }
-
- /* trace */
- if (PREDICT_FALSE (n_trace > 0))
- {
- if (PREDICT_TRUE (first_b0 != 0))
- {
- netmap_input_trace_t *tr;
- vlib_trace_buffer (vm, node, next0, first_b0,
- /* follow_chain */ 0);
- vlib_set_trace_count (vm, node, --n_trace);
- tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr));
- tr->next_index = next0;
- tr->hw_if_index = nif->hw_if_index;
- memcpy (&tr->slot, slot, sizeof (struct netmap_slot));
- }
- }
-
- /* redirect if feature path enabled */
- vnet_feature_start_device_input_x1 (nif->sw_if_index, &next0,
- first_b0);
-
- /* enque and take next packet */
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
- n_left_to_next, first_bi0,
- next0);
-
- /* next packet */
- n_rx_packets++;
- n_rx_bytes += slot->len;
- to_next[0] = first_bi0;
- to_next += 1;
- n_left_to_next--;
- cur_slot_index = next_slot_index;
-
- r--;
- }
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
- ring->head = ring->cur = cur_slot_index;
- cur_ring++;
- }
-
- if (n_rx_packets)
- ioctl (nif->fd, NIOCRXSYNC, NULL);
-
- vlib_increment_combined_counter
- (vnet_get_main ()->interface_main.combined_sw_if_counters
- + VNET_INTERFACE_COUNTER_RX,
- vlib_get_thread_index (), nif->hw_if_index, n_rx_packets, n_rx_bytes);
-
- vnet_device_increment_rx_packets (thread_index, n_rx_packets);
-
- return n_rx_packets;
-}
-
-VLIB_NODE_FN (netmap_input_node) (vlib_main_t * vm,
- vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- int i;
- u32 n_rx_packets = 0;
- u32 thread_index = vm->thread_index;
- netmap_main_t *nm = &netmap_main;
- netmap_if_t *nmi;
-
- for (i = 0; i < vec_len (nm->interfaces); i++)
- {
- nmi = vec_elt_at_index (nm->interfaces, i);
- if (nmi->is_admin_up &&
- (i % nm->input_cpu_count) ==
- (thread_index - nm->input_cpu_first_index))
- n_rx_packets += netmap_device_input_fn (vm, node, frame, nmi);
- }
-
- return n_rx_packets;
-}
-
-/* *INDENT-OFF* */
-VLIB_REGISTER_NODE (netmap_input_node) = {
- .name = "netmap-input",
- .sibling_of = "device-input",
- .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
- .format_trace = format_netmap_input_trace,
- .type = VLIB_NODE_TYPE_INPUT,
- /* default state is INTERRUPT mode, switch to POLLING if worker threads are enabled */
- .state = VLIB_NODE_STATE_INTERRUPT,
- .n_errors = NETMAP_INPUT_N_ERROR,
- .error_strings = netmap_input_error_strings,
-};
-/* *INDENT-ON* */
-
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/extras/deprecated/plugins/gbp/test_gbp.py b/extras/deprecated/plugins/gbp/test_gbp.py
index 84dda76af19..6a4fe0dae42 100644
--- a/extras/deprecated/plugins/gbp/test_gbp.py
+++ b/extras/deprecated/plugins/gbp/test_gbp.py
@@ -391,9 +391,9 @@ class VppGbpEndpointGroup(VppObject):
def encode(self) -> dict:
return {
- "uplink_sw_if_index": self.uplink.sw_if_index
- if self.uplink
- else INDEX_INVALID,
+ "uplink_sw_if_index": (
+ self.uplink.sw_if_index if self.uplink else INDEX_INVALID
+ ),
"bd_id": self.bd.bd.bd_id,
"rd_id": self.rd.rd_id,
"vnid": self.vnid,
@@ -460,12 +460,12 @@ class VppGbpBridgeDomain(VppObject):
return {
"flags": self.flags,
"bvi_sw_if_index": self.bvi.sw_if_index,
- "uu_fwd_sw_if_index": self.uu_fwd.sw_if_index
- if self.uu_fwd
- else INDEX_INVALID,
- "bm_flood_sw_if_index": self.bm_flood.sw_if_index
- if self.bm_flood
- else INDEX_INVALID,
+ "uu_fwd_sw_if_index": (
+ self.uu_fwd.sw_if_index if self.uu_fwd else INDEX_INVALID
+ ),
+ "bm_flood_sw_if_index": (
+ self.bm_flood.sw_if_index if self.bm_flood else INDEX_INVALID
+ ),
"bd_id": self.bd.bd_id,
"rd_id": self.rd.rd_id,
}
@@ -510,12 +510,12 @@ class VppGbpRouteDomain(VppObject):
"scope": self.scope,
"ip4_table_id": self.t4.table_id,
"ip6_table_id": self.t6.table_id,
- "ip4_uu_sw_if_index": self.ip4_uu.sw_if_index
- if self.ip4_uu
- else INDEX_INVALID,
- "ip6_uu_sw_if_index": self.ip6_uu.sw_if_index
- if self.ip6_uu
- else INDEX_INVALID,
+ "ip4_uu_sw_if_index": (
+ self.ip4_uu.sw_if_index if self.ip4_uu else INDEX_INVALID
+ ),
+ "ip6_uu_sw_if_index": (
+ self.ip6_uu.sw_if_index if self.ip6_uu else INDEX_INVALID
+ ),
}
def add_vpp_config(self):
diff --git a/extras/deprecated/vnet/lawful-intercept/lawful_intercept.c b/extras/deprecated/vnet/lawful-intercept/lawful_intercept.c
new file mode 100644
index 00000000000..61b1a6165f4
--- /dev/null
+++ b/extras/deprecated/vnet/lawful-intercept/lawful_intercept.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015 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 <vnet/lawful-intercept/lawful_intercept.h>
+
+li_main_t li_main;
+
+static clib_error_t *
+set_li_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ li_main_t *lm = &li_main;
+ ip4_address_t collector;
+ u8 collector_set = 0;
+ ip4_address_t src;
+ u8 src_set = 0;
+ u32 tmp;
+ u16 udp_port = 0;
+ u8 is_add = 1;
+ int i;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "collector %U", unformat_ip4_address, &collector))
+ collector_set = 1;
+ if (unformat (input, "src %U", unformat_ip4_address, &src))
+ src_set = 1;
+ else if (unformat (input, "udp-port %d", &tmp))
+ udp_port = tmp;
+ else if (unformat (input, "del"))
+ is_add = 0;
+ else
+ break;
+ }
+
+ if (collector_set == 0)
+ return clib_error_return (0, "collector must be set...");
+ if (src_set == 0)
+ return clib_error_return (0, "src must be set...");
+ if (udp_port == 0)
+ return clib_error_return (0, "udp-port must be set...");
+
+ if (is_add == 1)
+ {
+ for (i = 0; i < vec_len (lm->collectors); i++)
+ {
+ if (lm->collectors[i].as_u32 == collector.as_u32)
+ {
+ if (lm->ports[i] == udp_port)
+ return clib_error_return (
+ 0, "collector %U:%d already configured", format_ip4_address,
+ &collector, udp_port);
+ else
+ return clib_error_return (
+ 0, "collector %U already configured with port %d",
+ format_ip4_address, &collector, (int) (lm->ports[i]));
+ }
+ }
+ vec_add1 (lm->collectors, collector);
+ vec_add1 (lm->ports, udp_port);
+ vec_add1 (lm->src_addrs, src);
+ return 0;
+ }
+ else
+ {
+ for (i = 0; i < vec_len (lm->collectors); i++)
+ {
+ if ((lm->collectors[i].as_u32 == collector.as_u32)
+ && lm->ports[i] == udp_port)
+ {
+ vec_delete (lm->collectors, 1, i);
+ vec_delete (lm->ports, 1, i);
+ vec_delete (lm->src_addrs, 1, i);
+ return 0;
+ }
+ }
+ return clib_error_return (0, "collector %U:%d not configured",
+ &collector, udp_port);
+ }
+ return 0;
+}
+
+VLIB_CLI_COMMAND (set_li_command, static) = {
+ .path = "set li",
+ .short_help =
+ "set li src <ip4-address> collector <ip4-address> udp-port <nnnn>",
+ .function = set_li_command_fn,
+};
+
+static clib_error_t *
+li_init (vlib_main_t * vm)
+{
+ li_main_t *lm = &li_main;
+
+ lm->vlib_main = vm;
+ lm->vnet_main = vnet_get_main ();
+ lm->hit_node_index = li_hit_node.index;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (li_init);
+
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/extras/deprecated/vnet/lawful-intercept/lawful_intercept.h b/extras/deprecated/vnet/lawful-intercept/lawful_intercept.h
new file mode 100644
index 00000000000..ba74204fb9e
--- /dev/null
+++ b/extras/deprecated/vnet/lawful-intercept/lawful_intercept.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+
+#ifndef __lawful_intercept_h__
+#define __lawful_intercept_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+
+typedef struct
+{
+ /* LI collector info */
+ ip4_address_t *src_addrs;
+ ip4_address_t *collectors;
+ u16 *ports;
+
+ /* Hit node index */
+ u32 hit_node_index;
+
+ /* convenience */
+ vlib_main_t *vlib_main;
+ vnet_main_t *vnet_main;
+} li_main_t;
+
+extern li_main_t li_main;
+
+typedef CLIB_PACKED(struct {
+ ip4_header_t ip4;
+ udp_header_t udp;
+}) ip4_udp_header_t;
+
+extern vlib_node_registration_t li_hit_node;
+
+#endif /* __lawful_intercept_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/extras/deprecated/vnet/lawful-intercept/node.c b/extras/deprecated/vnet/lawful-intercept/node.c
new file mode 100644
index 00000000000..86f135b9ea1
--- /dev/null
+++ b/extras/deprecated/vnet/lawful-intercept/node.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2015 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 <vnet/vnet.h>
+#include <vppinfra/error.h>
+
+#include <vnet/lawful-intercept/lawful_intercept.h>
+
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+extern vlib_node_registration_t li_hit_node;
+
+typedef struct
+{
+ u32 next_index;
+} li_hit_trace_t;
+
+/* packet trace format function */
+static u8 *
+format_li_hit_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ li_hit_trace_t *t = va_arg (*args, li_hit_trace_t *);
+
+ s = format (s, "LI_HIT: next index %d", t->next_index);
+
+ return s;
+}
+
+#define foreach_li_hit_error \
+_(HITS, "LI packets processed") \
+_(NO_COLLECTOR, "No collector configured") \
+_(BUFFER_ALLOCATION_FAILURE, "Buffer allocation failure")
+
+typedef enum
+{
+#define _(sym,str) LI_HIT_ERROR_##sym,
+ foreach_li_hit_error
+#undef _
+ LI_HIT_N_ERROR,
+} li_hit_error_t;
+
+static char *li_hit_error_strings[] = {
+#define _(sym,string) string,
+ foreach_li_hit_error
+#undef _
+};
+
+typedef enum
+{
+ LI_HIT_NEXT_ETHERNET,
+ LI_HIT_N_NEXT,
+} li_hit_next_t;
+
+VLIB_NODE_FN (li_hit_node) (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * frame)
+{
+ u32 n_left_from, *from, *to_next;
+ li_hit_next_t next_index;
+ vlib_frame_t *int_frame = 0;
+ u32 *to_int_next = 0;
+ li_main_t *lm = &li_main;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ next_index = node->cached_next_index;
+
+ if (PREDICT_FALSE (vec_len (lm->collectors) == 0))
+ {
+ vlib_node_increment_counter (vm, li_hit_node.index,
+ LI_HIT_ERROR_NO_COLLECTOR, n_left_from);
+ }
+ else
+ {
+ /* The intercept frame... */
+ int_frame = vlib_get_frame_to_node (vm, ip4_lookup_node.index);
+ to_int_next = vlib_frame_vector_args (int_frame);
+ }
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+#if 0
+ while (n_left_from >= 4 && n_left_to_next >= 2)
+ {
+ u32 next0 = LI_HIT_NEXT_INTERFACE_OUTPUT;
+ u32 next1 = LI_HIT_NEXT_INTERFACE_OUTPUT;
+ u32 sw_if_index0, sw_if_index1;
+ u8 tmp0[6], tmp1[6];
+ ethernet_header_t *en0, *en1;
+ u32 bi0, bi1;
+ vlib_buffer_t *b0, *b1;
+
+ /* Prefetch next iteration. */
+ {
+ vlib_buffer_t *p2, *p3;
+
+ p2 = vlib_get_buffer (vm, from[2]);
+ p3 = vlib_get_buffer (vm, from[3]);
+
+ vlib_prefetch_buffer_header (p2, LOAD);
+ vlib_prefetch_buffer_header (p3, LOAD);
+
+ clib_prefetch_store (p2->data);
+ clib_prefetch_store (p3->data);
+ }
+
+ /* speculatively enqueue b0 and b1 to the current next frame */
+ to_next[0] = bi0 = from[0];
+ to_next[1] = bi1 = from[1];
+ from += 2;
+ to_next += 2;
+ n_left_from -= 2;
+ n_left_to_next -= 2;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ b1 = vlib_get_buffer (vm, bi1);
+
+ /* $$$$$ Dual loop: process 2 x packets here $$$$$ */
+ ASSERT (b0->current_data == 0);
+ ASSERT (b1->current_data == 0);
+
+ en0 = vlib_buffer_get_current (b0);
+ en1 = vlib_buffer_get_current (b1);
+
+ sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
+ sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
+
+ /* Send pkt back out the RX interface */
+ vnet_buffer (b0)->sw_if_index[VLIB_TX] = sw_if_index0;
+ vnet_buffer (b1)->sw_if_index[VLIB_TX] = sw_if_index1;
+
+ /* $$$$$ End of processing 2 x packets $$$$$ */
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
+ {
+ if (b0->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ li_hit_trace_t *t =
+ vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->sw_if_index = sw_if_index0;
+ t->next_index = next0;
+ }
+ if (b1->flags & VLIB_BUFFER_IS_TRACED)
+ {
+ li_hit_trace_t *t =
+ vlib_add_trace (vm, node, b1, sizeof (*t));
+ t->sw_if_index = sw_if_index1;
+ t->next_index = next1;
+ }
+ }
+
+ /* verify speculative enqueues, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, bi1, next0, next1);
+ }
+#endif /* $$$ dual-loop off */
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0;
+ vlib_buffer_t *b0;
+ vlib_buffer_t *c0;
+ ip4_udp_header_t *iu0;
+ ip4_header_t *ip0;
+ udp_header_t *udp0;
+ u32 next0 = LI_HIT_NEXT_ETHERNET;
+
+ /* speculatively enqueue b0 to the current next frame */
+ bi0 = from[0];
+ to_next[0] = bi0;
+ from += 1;
+ to_next += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ b0 = vlib_get_buffer (vm, bi0);
+ if (PREDICT_TRUE (to_int_next != 0))
+ {
+ /* Make an intercept copy. This can fail. */
+ c0 = vlib_buffer_copy (vm, b0);
+
+ if (PREDICT_FALSE (c0 == 0))
+ {
+ vlib_node_increment_counter
+ (vm, node->node_index,
+ LI_HIT_ERROR_BUFFER_ALLOCATION_FAILURE, 1);
+ goto skip;
+ }
+
+ vlib_buffer_advance (c0, -sizeof (*iu0));
+
+ iu0 = vlib_buffer_get_current (c0);
+ ip0 = &iu0->ip4;
+
+ ip0->ip_version_and_header_length = 0x45;
+ ip0->ttl = 254;
+ ip0->protocol = IP_PROTOCOL_UDP;
+
+ ip0->src_address.as_u32 = lm->src_addrs[0].as_u32;
+ ip0->dst_address.as_u32 = lm->collectors[0].as_u32;
+ ip0->length = vlib_buffer_length_in_chain (vm, c0);
+ ip0->checksum = ip4_header_checksum (ip0);
+
+ udp0 = &iu0->udp;
+ udp0->src_port = udp0->dst_port =
+ clib_host_to_net_u16 (lm->ports[0]);
+ udp0->checksum = 0;
+ udp0->length =
+ clib_net_to_host_u16 (vlib_buffer_length_in_chain (vm, b0));
+
+ to_int_next[0] = vlib_get_buffer_index (vm, c0);
+ to_int_next++;
+ }
+
+ skip:
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
+ && (b0->flags & VLIB_BUFFER_IS_TRACED)))
+ {
+ li_hit_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t));
+ t->next_index = next0;
+ }
+
+ /* verify speculative enqueue, maybe switch current next frame */
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next,
+ bi0, next0);
+ }
+
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+
+ if (int_frame)
+ {
+ int_frame->n_vectors = frame->n_vectors;
+ vlib_put_frame_to_node (vm, ip4_lookup_node.index, int_frame);
+ }
+
+ vlib_node_increment_counter (vm, li_hit_node.index,
+ LI_HIT_ERROR_HITS, frame->n_vectors);
+ return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (li_hit_node) = {
+ .name = "li-hit",
+ .vector_size = sizeof (u32),
+ .format_trace = format_li_hit_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(li_hit_error_strings),
+ .error_strings = li_hit_error_strings,
+
+ .n_next_nodes = LI_HIT_N_NEXT,
+
+ /* edit / add dispositions here */
+ .next_nodes = {
+ [LI_HIT_NEXT_ETHERNET] = "ethernet-input-not-l2",
+ },
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/extras/deprecated/vnet/vxlan-gbp/vpp_vxlan_gbp_tunnel.py b/extras/deprecated/vnet/vxlan-gbp/vpp_vxlan_gbp_tunnel.py
index 1b6b4e731ca..2a373f8e56e 100644
--- a/extras/deprecated/vnet/vxlan-gbp/vpp_vxlan_gbp_tunnel.py
+++ b/extras/deprecated/vnet/vxlan-gbp/vpp_vxlan_gbp_tunnel.py
@@ -56,9 +56,9 @@ class VppVxlanGbpTunnel(VppInterface):
"dst": self.dst,
"mode": self.mode,
"vni": self.vni,
- "mcast_sw_if_index": self.mcast_itf.sw_if_index
- if self.mcast_itf
- else INDEX_INVALID,
+ "mcast_sw_if_index": (
+ self.mcast_itf.sw_if_index if self.mcast_itf else INDEX_INVALID
+ ),
"encap_table_id": self.encap_table_id,
"instance": self.instance,
}
diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile
index f0ec755afb2..6ee89bc2770 100644
--- a/extras/hs-test/Makefile
+++ b/extras/hs-test/Makefile
@@ -23,6 +23,14 @@ ifeq ($(CPUS),)
CPUS=1
endif
+ifeq ($(PARALLEL),)
+PARALLEL=1
+endif
+
+ifeq ($(REPEAT),)
+REPEAT=0
+endif
+
ifeq ($(VPPSRC),)
VPPSRC=$(shell pwd)/../..
endif
@@ -35,13 +43,14 @@ ifeq ($(ARCH),)
ARCH=$(shell dpkg --print-architecture)
endif
-list_tests = @(grep -r ') Test' *_test.go | cut -d '*' -f2 | cut -d '(' -f1 | \
- tr -d ' ' | tr ')' '/' | sed 's/Suite//')
+list_tests = @go run github.com/onsi/ginkgo/v2/ginkgo --dry-run -v --no-color --seed=2 | head -n -1 | grep 'Test' | \
+ sed 's/^/* /; s/\(Suite\) /\1\//g'
.PHONY: help
help:
@echo "Make targets:"
@echo " test - run tests"
+ @echo " test-debug - run tests (vpp debug image)"
@echo " build - build test infra"
@echo " build-debug - build test infra (vpp debug image)"
@echo " build-go - just build golang files"
@@ -60,6 +69,8 @@ help:
@echo " TEST=[test-name] - specific test to run"
@echo " CPUS=[n-cpus] - number of cpus to run with vpp"
@echo " VPPSRC=[path-to-vpp-src] - path to vpp source files (for gdb)"
+ @echo " PARALLEL=[n-cpus] - number of test processes to spawn to run in parallel"
+ @echo " REPEAT=[n] - repeat tests up to N times or until a failure occurs"
@echo
@echo "List of all tests:"
$(call list_tests)
@@ -68,30 +79,49 @@ help:
list-tests:
$(call list_tests)
+.PHONY: build-vpp-release
build-vpp-release:
@make -C ../.. build-release
+.PHONY: build-vpp-debug
build-vpp-debug:
@make -C ../.. build
+.build.ok: build
+ @touch .build.ok
+
+.build_debug.ok: build-debug
+ @touch .build.ok
+
.PHONY: test
-test: .deps.ok .build.vpp
+test: .deps.ok .build.ok
+ -bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \
+ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \
+ --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT)
+ $(call jq-summary)
+ @bash ./script/compress.sh
+
+.PHONY: test-debug
+test-debug: .deps.ok .build_debug.ok
@bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \
--unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \
- --vppsrc=$(VPPSRC)
+ --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT)
+.PHONY: build-go
build-go:
go build ./tools/http_server
+.PHONY: build
build: .deps.ok build-vpp-release build-go
- @rm -f .build.vpp
+ @rm -f .build.ok
bash ./script/build_hst.sh release
- @touch .build.vpp
+ @touch .build.ok
+.PHONY: build-debug
build-debug: .deps.ok build-vpp-debug build-go
- @rm -f .build.vpp
+ @rm -f .build.ok
bash ./script/build_hst.sh debug
- @touch .build.vpp
+ @touch .build.ok
.deps.ok:
@sudo make install-deps
@@ -101,17 +131,20 @@ install-deps:
@rm -f .deps.ok
@apt-get update \
&& apt-get install -y apt-transport-https ca-certificates curl software-properties-common \
- && apt-get install -y golang apache2-utils wrk bridge-utils
+ apache2-utils wrk bridge-utils
@if [ ! -f /usr/share/keyrings/docker-archive-keyring.gpg ] ; then \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg; \
echo "deb [arch=$(ARCH) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(UBUNTU_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ; \
apt-get update; \
fi
- @apt-get install -y docker-ce
@touch .deps.ok
.PHONY: fixstyle
fixstyle:
@gofmt -w .
@go mod tidy
+
+# splitting this into multiple lines breaks the command
+jq-summary = @jq -r '.[0] | .SpecReports[] | select(.State == "failed") | select(.Failure != null) | "TestName: \(.LeafNodeText)\nMessage:\n\(.Failure.Message)\n Full Stack Trace:\n\(.Failure.Location.FullStackTrace)\n"' summary/report.json > summary/failed-summary.log \
+ && echo "Summary generated -> failed-summary.log"
diff --git a/extras/hs-test/README.rst b/extras/hs-test/README.rst
index 6db832b7fbe..1dc1039b33f 100644
--- a/extras/hs-test/README.rst
+++ b/extras/hs-test/README.rst
@@ -9,7 +9,10 @@ End-to-end tests often want multiple VPP instances, network namespaces, differen
and to execute external tools or commands. With such requirements the existing VPP test framework is not sufficient.
For this, ``Go`` was chosen as a high level language, allowing rapid development, with ``Docker`` and ``ip`` being the tools for creating required topology.
-Go's package `testing`_ together with `go test`_ command form the base framework upon which the *hs-test* is built and run.
+`Ginkgo`_ forms the base framework upon which the *hs-test* is built and run.
+All tests are technically in a single suite because we are only using ``package main``. We simulate suite behavior by grouping tests by the topology they require.
+This allows us to run those mentioned groups in parallel, but not individual tests in parallel.
+
Anatomy of a test case
----------------------
@@ -24,15 +27,16 @@ Anatomy of a test case
**Action flow when running a test case**:
#. It starts with running ``make test``. Optional arguments are VERBOSE, PERSIST (topology configuration isn't cleaned up after test run),
- and TEST=<test-name> to run specific test.
-#. ``make list-tests`` (or ``make help``) shows all test names.
-#. ``go test`` compiles package ``main`` along with any files with names matching the file pattern ``*_test.go``
- and then runs the resulting test binaries
-#. The go test framework runs each function matching :ref:`naming convention<test-convention>`. Each of these corresponds to a `test suite`_
-#. Testify toolkit's ``suite.Run(t *testing.T, suite TestingSuite)`` function runs the suite and does the following:
-
+ TEST=<test-name> to run a specific test and PARALLEL=[n-cpus].
+#. ``make list-tests`` (or ``make help``) shows all tests. The current `list of tests`_ is at the bottom of this document.
+#. ``Ginkgo`` looks for a spec suite in the current directory and then compiles it to a .test binary
+#. The Ginkgo test framework runs each function that was registered manually using ``registerMySuiteTest(s *MySuite)``. Each of these functions correspond to a suite
+#. Ginkgo's ``RunSpecs(t, "Suite description")`` function is the entry point and does the following:
+
+ #. Ginkgo compiles the spec, builds a spec tree
+ #. ``Describe`` container nodes in suite\_\*_test.go files are run (in series by default, or in parallel with the argument PARALLEL=[n-cpus])
#. Suite is initialized. The topology is loaded and configured in this step
- #. Test suite runs all the tests attached to it
+ #. Registered tests are run in generated ``It`` subject nodes
#. Execute tear-down functions, which currently consists of stopping running containers
and clean-up of test topology
@@ -43,23 +47,25 @@ This describes adding a new test case to an existing suite.
For adding a new suite, please see `Modifying the framework`_ below.
#. To write a new test case, create a file whose name ends with ``_test.go`` or pick one that already exists
-#. Declare method whose name starts with ``Test`` and specifies its receiver as a pointer to the suite's struct (defined in ``framework_test.go``)
+#. Declare method whose name ends with ``Test`` and specifies its parameter as a pointer to the suite's struct (defined in ``suite_*_test.go``)
#. Implement test behaviour inside the test method. This typically includes the following:
- #. Retrieve a running container in which to run some action. Method ``getContainerByName``
- from ``HstSuite`` struct serves this purpose
- #. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI
- #. Run arbitrary commands inside the containers with ``exec`` method
- #. Run other external tool with one of the preexisting functions in the ``utils.go`` file.
- For example, use ``wget`` with ``startWget`` function
- #. Use ``exechelper`` or just plain ``exec`` packages to run whatever else
- #. Verify results of your tests using ``assert`` methods provided by the test suite,
- implemented by HstSuite struct
+ #. Retrieve a running container in which to run some action. Method ``getContainerByName``
+ from ``HstSuite`` struct serves this purpose
+ #. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI
+ #. Run arbitrary commands inside the containers with ``exec`` method
+ #. Run other external tool with one of the preexisting functions in the ``utils.go`` file.
+ For example, use ``wget`` with ``startWget`` function
+ #. Use ``exechelper`` or just plain ``exec`` packages to run whatever else
+ #. Verify results of your tests using ``assert`` methods provided by the test suite, implemented by HstSuite struct or use ``Gomega`` assert functions.
+
+#. Create an ``init()`` function and register the test using ``register*SuiteTests(testCaseFunction)``
+
**Example test case**
Assumed are two docker containers, each with its own VPP instance running. One VPP then pings the other.
-This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./test -run TestMySuite/TestMyCase``.
+This can be put in file ``extras/hs-test/my_test.go`` and run with command ``make test TEST=MyTest`` or ``ginkgo -v --trace --focus MyTest``.
::
@@ -69,7 +75,11 @@ This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./t
"fmt"
)
- func (s *MySuite) TestMyCase() {
+ func init(){
+ registerMySuiteTest(MyTest)
+ }
+
+ func MyTest(s *MySuite) {
clientVpp := s.getContainerByName("client-vpp").vppInstance
serverVethAddress := s.netInterfaces["server-iface"].AddressString()
@@ -86,8 +96,7 @@ Modifying the framework
.. _test-convention:
-#. Adding a new suite takes place in ``framework_test.go`` and by creating a new file for the suite.
- Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced
+#. To add a new suite, create a new file. Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced
by the actual name
#. Make a ``struct``, in the suite file, with at least ``HstSuite`` struct as its member.
@@ -99,7 +108,17 @@ Modifying the framework
HstSuite
}
-#. In suite file, implement ``SetupSuite`` method which testify runs once before starting any of the tests.
+#. Create a new slice that will contain test functions with a pointer to the suite's struct: ``var myTests = []func(s *MySuite){}``
+
+#. Then create a new function that will append test functions to that slice:
+
+ ::
+
+ func registerMySuiteTests(tests ...func(s *MySuite)) {
+ nginxTests = append(myTests, tests...)
+ }
+
+#. In suite file, implement ``SetupSuite`` method which Ginkgo runs once before starting any of the tests.
It's important here to call ``configureNetworkTopology`` method,
pass the topology name to the function in a form of file name of one of the *yaml* files in ``topo-network`` folder.
Without the extension. In this example, *myTopology* corresponds to file ``extras/hs-test/topo-network/myTopology.yaml``
@@ -111,6 +130,8 @@ Modifying the framework
::
func (s *MySuite) SetupSuite() {
+ s.HstSuite.SetupSuite()
+
// Add custom setup code here
s.configureNetworkTopology("myTopology")
@@ -123,19 +144,62 @@ Modifying the framework
::
func (s *MySuite) SetupTest() {
+ s.HstSuite.setupTest()
s.SetupVolumes()
s.SetupContainers()
}
-#. In order for ``go test`` to run this suite, we need to create a normal test function and pass our suite to ``suite.Run``.
- These functions are placed at the end of ``framework_test.go``
+#. In order for ``Ginkgo`` to run this suite, we need to create a ``Describe`` container node with setup nodes and an ``It`` subject node.
+ Place them at the end of the suite file
+
+ * Declare a suite struct variable before anything else
+ * To use ``BeforeAll()`` and ``AfterAll()``, the container has to be marked as ``Ordered``
+ * Because the container is now marked as Ordered, if a test fails, all the subsequent tests are skipped.
+ To override this behavior, decorate the container node with ``ContinueOnFailure``
::
- func TestMySuite(t *testing.T) {
- var m MySuite
- suite.Run(t, &m)
- }
+ var _ = Describe("MySuite", Ordered, ContinueOnFailure, func() {
+ var s MySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+ for _, test := range mySuiteTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+ })
+
+#. Notice the loop - it will generate multiple ``It`` nodes, each running a different test.
+ ``test := test`` is necessary, otherwise only the last test in a suite will run.
+ For a more detailed description, check Ginkgo's documentation: https://onsi.github.io/ginkgo/#dynamically-generating-specs\.
+
+#. ``funcValue.Name()`` returns the full name of a function (e.g. ``fd.io/hs-test.MyTest``), however, we only need the test name (``MyTest``).
+
+#. To run certain tests solo, create a new slice that will only contain tests that have to run solo and a new register function.
+ Add a ``Serial`` decorator to the container node and ``Label("SOLO")`` to the ``It`` subject node:
+
+ ::
+
+ var _ = Describe("MySuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ ...
+ It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ })
#. Next step is to add test cases to the suite. For that, see section `Adding a test case`_ above
@@ -186,14 +250,9 @@ Alternatively copy the executable from host system to the Docker image, similarl
**Skipping tests**
``HstSuite`` provides several methods that can be called in tests for skipping it conditionally or unconditionally such as:
-``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``.
+``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``. You can also use Ginkgo's ``Skip()``.
However the tests currently run under test suites which set up topology and containers before actual test is run. For the reason of saving
-test run time it is not advisable to use aforementioned skip methods and instead prefix test name with ``Skip``:
-
-::
-
- func (s *MySuite) SkipTest(){
-
+test run time it is not advisable to use aforementioned skip methods and instead, just don't register the test.
**Debugging a test**
@@ -201,11 +260,11 @@ It is possible to debug VPP by attaching ``gdb`` before test execution by adding
::
- $ make test TEST=TestVeths/TestLDPreloadIperfVpp DEBUG=true
+ $ make test TEST=LDPreloadIperfVppTest DEBUG=true
...
run following command in different terminal:
- docker exec -it server-vpp gdb -ex "attach $(docker exec server-vpp pidof vpp)"
- Afterwards press CTRL+C to continue
+ docker exec -it server-vpp2456109 gdb -ex "attach $(docker exec server-vpp2456109 pidof vpp)"
+ Afterwards press CTRL+\ to continue
If a test consists of more VPP instances then this is done for each of them.
@@ -223,8 +282,38 @@ Generally, these will be updated on a per-need basis, for example when a bug is
or a new version incompatibility issue occurs.
-.. _testing: https://pkg.go.dev/testing
-.. _go test: https://pkg.go.dev/cmd/go#hdr-Test_packages
-.. _test suite: https://github.com/stretchr/testify#suite-package
+.. _ginkgo: https://onsi.github.io/ginkgo/
.. _volumes: https://docs.docker.com/storage/volumes/
+**List of tests**
+
+.. _list of tests:
+
+Please update this list whenever you add a new test by pasting the output below.
+
+* NsSuite/HttpTpsTest
+* NsSuite/VppProxyHttpTcpTest
+* NsSuite/VppProxyHttpTlsTest
+* NsSuite/EnvoyProxyHttpTcpTest
+* NginxSuite/MirroringTest
+* VethsSuiteSolo TcpWithLossTest [SOLO]
+* NoTopoSuiteSolo HttpStaticPromTest [SOLO]
+* TapSuite/LinuxIperfTest
+* NoTopoSuite/NginxHttp3Test
+* NoTopoSuite/NginxAsServerTest
+* NoTopoSuite/NginxPerfCpsTest
+* NoTopoSuite/NginxPerfRpsTest
+* NoTopoSuite/NginxPerfWrkTest
+* VethsSuite/EchoBuiltinTest
+* VethsSuite/HttpCliTest
+* VethsSuite/LDPreloadIperfVppTest
+* VethsSuite/VppEchoQuicTest
+* VethsSuite/VppEchoTcpTest
+* VethsSuite/VppEchoUdpTest
+* VethsSuite/XEchoVclClientUdpTest
+* VethsSuite/XEchoVclClientTcpTest
+* VethsSuite/XEchoVclServerUdpTest
+* VethsSuite/XEchoVclServerTcpTest
+* VethsSuite/VclEchoTcpTest
+* VethsSuite/VclEchoUdpTest
+* VethsSuite/VclRetryAttachTest
diff --git a/extras/hs-test/address_allocator.go b/extras/hs-test/address_allocator.go
index 72bc298fd3f..e05ea76b9bb 100644
--- a/extras/hs-test/address_allocator.go
+++ b/extras/hs-test/address_allocator.go
@@ -12,7 +12,7 @@ import (
type AddressCounter = int
type Ip4AddressAllocator struct {
- networks map[int]AddressCounter
+ networks map[int]AddressCounter
chosenOctet int
assignedIps []string
}
@@ -47,7 +47,7 @@ func (a *Ip4AddressAllocator) NewIp4InterfaceAddress(inputNetworkNumber ...int)
// Creates a file every time an IP is assigned: used to keep track of addresses in use.
// If an address is not in use, 'counter' is then copied to 'chosenOctet' and it is used for the remaining tests.
// Also checks host IP addresses.
-func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error){
+func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) {
hostIps, _ := exechelper.CombinedOutput("ip a")
counter := 10
var address string
@@ -56,7 +56,7 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
if a.chosenOctet != 0 {
address = fmt.Sprintf("10.%v.%v.%v", a.chosenOctet, networkNumber, numberOfAddresses)
file, err := os.Create(address)
- if err != nil{
+ if err != nil {
return "", errors.New("unable to create file: " + fmt.Sprint(err))
}
file.Close()
@@ -68,14 +68,14 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
counter++
} else if os.IsNotExist(err) {
file, err := os.Create(address)
- if err != nil{
+ if err != nil {
return "", errors.New("unable to create file: " + fmt.Sprint(err))
- }
+ }
file.Close()
a.chosenOctet = counter
break
} else {
- return "", errors.New("an error occured while checking if a file exists: " + fmt.Sprint(err))
+ return "", errors.New("an error occurred while checking if a file exists: " + fmt.Sprint(err))
}
}
}
@@ -84,8 +84,8 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
return address, nil
}
-func (a *Ip4AddressAllocator) deleteIpAddresses(){
- for ip := range a.assignedIps{
+func (a *Ip4AddressAllocator) deleteIpAddresses() {
+ for ip := range a.assignedIps {
os.Remove(a.assignedIps[ip])
}
}
diff --git a/extras/hs-test/container.go b/extras/hs-test/container.go
index 87e8aa38e98..45f41d26a87 100644
--- a/extras/hs-test/container.go
+++ b/extras/hs-test/container.go
@@ -9,6 +9,7 @@ import (
"time"
"github.com/edwarnicke/exechelper"
+ . "github.com/onsi/ginkgo/v2"
)
const (
@@ -38,7 +39,7 @@ type Container struct {
vppInstance *VppInstance
}
-func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Container, error) {
+func newContainer(suite *HstSuite, yamlInput ContainerConfig) (*Container, error) {
containerName := yamlInput["name"].(string)
if len(containerName) == 0 {
err := fmt.Errorf("container name must not be blank")
@@ -48,7 +49,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont
var container = new(Container)
container.volumes = make(map[string]Volume)
container.envVars = make(map[string]string)
- container.name = containerName + pid
+ container.name = containerName
container.suite = suite
if image, ok := yamlInput["image"]; ok {
@@ -76,7 +77,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont
}
if _, ok := yamlInput["volumes"]; ok {
- workingVolumeDir := logDir + container.suite.T().Name() + pid + volumeDir
+ workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + volumeDir
workDirReplacer := strings.NewReplacer("$HST_DIR", workDir)
volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir)
for _, volu := range yamlInput["volumes"].([]interface{}) {
@@ -249,7 +250,7 @@ func (c *Container) copy(sourceFileName string, targetFileName string) error {
}
func (c *Container) createFile(destFileName string, content string) error {
- f, err := os.CreateTemp("/tmp", "hst-config" + c.suite.pid)
+ f, err := os.CreateTemp("/tmp", "hst-config"+c.suite.pid)
if err != nil {
return err
}
@@ -273,7 +274,7 @@ func (c *Container) execServer(command string, arguments ...any) {
serverCommand := fmt.Sprintf(command, arguments...)
containerExecCommand := "docker exec -d" + c.getEnvVarsAsCliOption() +
" " + c.name + " " + serverCommand
- c.suite.T().Helper()
+ GinkgoHelper()
c.suite.log(containerExecCommand)
c.suite.assertNil(exechelper.Run(containerExecCommand))
}
@@ -282,7 +283,7 @@ func (c *Container) exec(command string, arguments ...any) string {
cliCommand := fmt.Sprintf(command, arguments...)
containerExecCommand := "docker exec" + c.getEnvVarsAsCliOption() +
" " + c.name + " " + cliCommand
- c.suite.T().Helper()
+ GinkgoHelper()
c.suite.log(containerExecCommand)
byteOutput, err := exechelper.CombinedOutput(containerExecCommand)
c.suite.assertNil(err, err)
@@ -291,12 +292,12 @@ func (c *Container) exec(command string, arguments ...any) string {
func (c *Container) getLogDirPath() string {
testId := c.suite.getTestId()
- testName := c.suite.T().Name()
+ testName := CurrentSpecReport().LeafNodeText
logDirPath := logDir + testName + "/" + testId + "/"
cmd := exec.Command("mkdir", "-p", logDirPath)
if err := cmd.Run(); err != nil {
- c.suite.T().Fatalf("mkdir error: %v", err)
+ Fail("mkdir error: " + fmt.Sprint(err))
}
return logDirPath
@@ -313,12 +314,12 @@ func (c *Container) saveLogs() {
cmd = exec.Command("docker", "logs", "--details", "-t", c.name)
output, err := cmd.CombinedOutput()
if err != nil {
- c.suite.T().Fatalf("fetching logs error: %v", err)
+ Fail("fetching logs error: " + fmt.Sprint(err))
}
f, err := os.Create(testLogFilePath)
if err != nil {
- c.suite.T().Fatalf("file create error: %v", err)
+ Fail("file create error: " + fmt.Sprint(err))
}
fmt.Fprint(f, string(output))
f.Close()
diff --git a/extras/hs-test/cpu.go b/extras/hs-test/cpu.go
index e17bc11fbe0..a976f47d8a5 100644
--- a/extras/hs-test/cpu.go
+++ b/extras/hs-test/cpu.go
@@ -2,11 +2,14 @@ package main
import (
"bufio"
+ "errors"
"fmt"
"os"
+ "os/exec"
+ "strings"
)
-var CPU_PATH = "/sys/fs/cgroup/cpuset.cpus.effective"
+var CgroupPath = "/sys/fs/cgroup/"
type CpuContext struct {
cpuAllocator *CpuAllocatorT
@@ -36,9 +39,27 @@ func (c *CpuAllocatorT) Allocate(nCpus int) (*CpuContext, error) {
return &cpuCtx, nil
}
-func (c *CpuAllocatorT) readCpus(fname string) error {
+func (c *CpuAllocatorT) readCpus() error {
var first, last int
- file, err := os.Open(CPU_PATH)
+
+ // Path depends on cgroup version. We need to check which version is in use.
+ // For that following command can be used: 'stat -fc %T /sys/fs/cgroup/'
+ // In case the output states 'cgroup2fs' then cgroups v2 is used, 'tmpfs' in case cgroups v1.
+ cmd := exec.Command("stat", "-fc", "%T", "/sys/fs/cgroup/")
+ byteOutput, err := cmd.CombinedOutput()
+ if err != nil {
+ return err
+ }
+ CpuPath := CgroupPath
+ if strings.Contains(string(byteOutput), "tmpfs") {
+ CpuPath += "cpuset/cpuset.effective_cpus"
+ } else if strings.Contains(string(byteOutput), "cgroup2fs") {
+ CpuPath += "cpuset.cpus.effective"
+ } else {
+ return errors.New("cgroup unknown fs: " + string(byteOutput))
+ }
+
+ file, err := os.Open(CpuPath)
if err != nil {
return err
}
@@ -60,7 +81,7 @@ func (c *CpuAllocatorT) readCpus(fname string) error {
func CpuAllocator() (*CpuAllocatorT, error) {
if cpuAllocator == nil {
cpuAllocator = new(CpuAllocatorT)
- err := cpuAllocator.readCpus(CPU_PATH)
+ err := cpuAllocator.readCpus()
if err != nil {
return nil, err
}
diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp
index 6b057581d4b..ace83c593c6 100644
--- a/extras/hs-test/docker/Dockerfile.vpp
+++ b/extras/hs-test/docker/Dockerfile.vpp
@@ -16,6 +16,8 @@ COPY \
$DIR/unittest_plugin.so \
$DIR/quic_plugin.so \
$DIR/http_static_plugin.so \
+ $DIR/ping_plugin.so \
+ $DIR/nsim_plugin.so \
$DIR/prom_plugin.so \
$DIR/tlsopenssl_plugin.so \
/usr/lib/x86_64-linux-gnu/vpp_plugins/
diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go
index 690f6d1378e..0515b5e0411 100644
--- a/extras/hs-test/echo_test.go
+++ b/extras/hs-test/echo_test.go
@@ -1,6 +1,11 @@
package main
-func (s *VethsSuite) TestEchoBuiltin() {
+func init() {
+ registerVethTests(EchoBuiltinTest)
+ registerSoloVethTests(TcpWithLossTest)
+}
+
+func EchoBuiltinTest(s *VethsSuite) {
serverVpp := s.getContainerByName("server-vpp").vppInstance
serverVeth := s.getInterfaceByName(serverInterfaceName)
@@ -16,7 +21,7 @@ func (s *VethsSuite) TestEchoBuiltin() {
s.assertNotContains(o, "failed:")
}
-func (s *VethsSuite) TestTcpWithLoss() {
+func TcpWithLossTest(s *VethsSuite) {
serverVpp := s.getContainerByName("server-vpp").vppInstance
serverVeth := s.getInterfaceByName(serverInterfaceName)
@@ -26,14 +31,14 @@ func (s *VethsSuite) TestTcpWithLoss() {
clientVpp := s.getContainerByName("client-vpp").vppInstance
// Ensure that VPP doesn't abort itself with NSIM enabled
- // Warning: Removing this ping will make the test fail!
+ // Warning: Removing this ping will make VPP crash!
clientVpp.vppctl("ping %s", serverVeth.ip4AddressString())
// Add loss of packets with Network Delay Simulator
clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +
" packet-size 1400 packets-per-drop 1000")
- clientVpp.vppctl("nsim output-feature enable-disable " + s.getInterfaceByName(clientInterfaceName).name)
+ clientVpp.vppctl("nsim output-feature enable-disable host-" + s.getInterfaceByName(clientInterfaceName).name)
// Do echo test from client-vpp container
output := clientVpp.vppctl("test echo client uri tcp://%s/20022 verbose echo-bytes mbytes 50",
diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go
index 84aa570e681..8773fa2417d 100644
--- a/extras/hs-test/framework_test.go
+++ b/extras/hs-test/framework_test.go
@@ -3,30 +3,11 @@ package main
import (
"testing"
- "github.com/stretchr/testify/suite"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
)
-func TestTapSuite(t *testing.T) {
- var m TapSuite
- suite.Run(t, &m)
-}
-
-func TestNs(t *testing.T) {
- var m NsSuite
- suite.Run(t, &m)
-}
-
-func TestVeths(t *testing.T) {
- var m VethsSuite
- suite.Run(t, &m)
-}
-
-func TestNoTopo(t *testing.T) {
- var m NoTopoSuite
- suite.Run(t, &m)
-}
-
-func TestNginx(t *testing.T) {
- var m NginxSuite
- suite.Run(t, &m)
+func TestHst(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "HST")
}
diff --git a/extras/hs-test/go.mod b/extras/hs-test/go.mod
index 00e1213079d..0f3854d2148 100644
--- a/extras/hs-test/go.mod
+++ b/extras/hs-test/go.mod
@@ -4,19 +4,28 @@ go 1.21
require (
github.com/edwarnicke/exechelper v1.0.3
- github.com/stretchr/testify v1.8.4
- go.fd.io/govpp v0.9.0
+ go.fd.io/govpp v0.10.0
gopkg.in/yaml.v3 v3.0.1
)
require (
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/go-logr/logr v1.4.1 // indirect
+ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
+ github.com/google/go-cmp v0.6.0 // indirect
+ github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ golang.org/x/tools v0.17.0 // indirect
+)
+
+require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
+ github.com/onsi/ginkgo/v2 v2.16.0
+ github.com/onsi/gomega v1.32.0
github.com/pkg/errors v0.9.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/sys v0.16.0 // indirect
diff --git a/extras/hs-test/go.sum b/extras/hs-test/go.sum
index df596738622..479b0289814 100644
--- a/extras/hs-test/go.sum
+++ b/extras/hs-test/go.sum
@@ -1,3 +1,6 @@
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -6,10 +9,17 @@ github.com/edwarnicke/exechelper v1.0.3 h1:OY2ocGAITTqnEDvZk0dRQSeMIQvyH0SyL/4nc
github.com/edwarnicke/exechelper v1.0.3/go.mod h1:R65OUPKns4bgeHkCmfSHbmqLBU8aHZxTgLmEyUBUk4U=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
+github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
+github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -18,8 +28,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
-github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
-github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
+github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM=
+github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
+github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
+github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -28,22 +40,27 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
-go.fd.io/govpp v0.9.0 h1:EHUXhQ+dph2K2An4YMqmd/WBE3Fcqsg97KVmdLJoSoU=
-go.fd.io/govpp v0.9.0/go.mod h1:9QoqjEbvfuuXNfjHS0A7YS+7QQVVaQ9cMioOWpSM4rY=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+go.fd.io/govpp v0.10.0 h1:lL93SbqOILjON2pMvazrlHRekGYTRy0Qmj57RuAkxR0=
+go.fd.io/govpp v0.10.0/go.mod h1:5m3bZM9ck+2EGC2O3ASmSSJAaoouyOlVWtiwj5BdCv0=
+golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
+golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/extras/hs-test/hst_suite.go b/extras/hs-test/hst_suite.go
index c5c8edbb829..725fee73f24 100644
--- a/extras/hs-test/hst_suite.go
+++ b/extras/hs-test/hst_suite.go
@@ -5,14 +5,16 @@ import (
"errors"
"flag"
"fmt"
+ "io"
+ "log"
"os"
"os/exec"
"strings"
"time"
"github.com/edwarnicke/exechelper"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/suite"
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
"gopkg.in/yaml.v3"
)
@@ -28,7 +30,6 @@ var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
var vppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory")
type HstSuite struct {
- suite.Suite
containers map[string]*Container
volumes []string
netConfigs []NetConfig
@@ -38,15 +39,23 @@ type HstSuite struct {
cpuAllocator *CpuAllocatorT
cpuContexts []*CpuContext
cpuPerVpp int
- pid string
+ pid string
+ logger *log.Logger
+ logFile *os.File
}
func (s *HstSuite) SetupSuite() {
+ s.createLogger()
+ s.log("Suite Setup")
+ RegisterFailHandler(func(message string, callerSkip ...int) {
+ s.hstFail()
+ Fail(message, callerSkip...)
+ })
var err error
s.pid = fmt.Sprint(os.Getpid())
s.cpuAllocator, err = CpuAllocator()
if err != nil {
- s.FailNow("failed to init cpu allocator: %v", err)
+ Fail("failed to init cpu allocator: " + fmt.Sprint(err))
}
s.cpuPerVpp = *nConfiguredCpus
}
@@ -63,10 +72,13 @@ func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) {
}
func (s *HstSuite) TearDownSuite() {
+ defer s.logFile.Close()
+ s.log("Suite Teardown")
s.unconfigureNetworkTopology()
}
func (s *HstSuite) TearDownTest() {
+ s.log("Test Teardown")
if *isPersistent {
return
}
@@ -85,6 +97,7 @@ func (s *HstSuite) skipIfUnconfiguring() {
}
func (s *HstSuite) SetupTest() {
+ s.log("Test Setup")
s.skipIfUnconfiguring()
s.setupVolumes()
s.setupContainers()
@@ -106,15 +119,15 @@ func (s *HstSuite) setupContainers() {
}
}
-func logVppInstance(container *Container, maxLines int){
- if container.vppInstance == nil{
+func (s *HstSuite) logVppInstance(container *Container, maxLines int) {
+ if container.vppInstance == nil {
return
}
logSource := container.getHostWorkDir() + defaultLogFilePath
file, err := os.Open(logSource)
- if err != nil{
+ if err != nil {
return
}
defer file.Close()
@@ -123,7 +136,7 @@ func logVppInstance(container *Container, maxLines int){
var lines []string
var counter int
- for scanner.Scan(){
+ for scanner.Scan() {
lines = append(lines, scanner.Text())
counter++
if counter > maxLines {
@@ -132,82 +145,81 @@ func logVppInstance(container *Container, maxLines int){
}
}
- fmt.Println("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:")
- for _, line := range lines{
- fmt.Println(line)
+ s.log("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:")
+ for _, line := range lines {
+ s.log(line)
}
- fmt.Printf("^^^^^^^^^^^^^^^\n\n")
+ s.log("^^^^^^^^^^^^^^^\n\n")
}
func (s *HstSuite) hstFail() {
- fmt.Println("Containers: " + fmt.Sprint(s.containers))
- for _, container := range s.containers{
+ s.log("Containers: " + fmt.Sprint(s.containers))
+ for _, container := range s.containers {
out, err := container.log(20)
- if err != nil{
+ if err != nil {
fmt.Printf("An error occured while obtaining '%s' container logs: %s\n", container.name, fmt.Sprint(err))
- break
+ continue
}
- fmt.Printf("\nvvvvvvvvvvvvvvv " +
- container.name + ":\n" +
- out +
- "^^^^^^^^^^^^^^^\n\n")
- logVppInstance(container, 20)
+ s.log("\nvvvvvvvvvvvvvvv " +
+ container.name + ":\n" +
+ out +
+ "^^^^^^^^^^^^^^^\n\n")
+ s.logVppInstance(container, 20)
}
- s.T().FailNow()
}
func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
- if !assert.Nil(s.T(), object, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(object).To(BeNil(), msgAndArgs...)
}
func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
- if !assert.NotNil(s.T(), object, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(object).ToNot(BeNil(), msgAndArgs...)
}
func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
- if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(actual).To(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
- if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(actual).ToNot(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
- if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
- if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
- s.hstFail()
- }
+ Expect(testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
- if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
- s.hstFail()
+ Expect(object).ToNot(BeEmpty(), msgAndArgs...)
+}
+
+func (s *HstSuite) createLogger(){
+ suiteName := CurrentSpecReport().ContainerHierarchyTexts[0]
+ var err error
+ s.logFile, err = os.Create("summary/" + suiteName + ".log")
+ if err != nil {
+ Fail("Unable to create log file.")
}
+ s.logger = log.New(io.Writer(s.logFile), "", log.LstdFlags)
}
-func (s *HstSuite) log(args ...any) {
+// Logs to files by default, logs to stdout when VERBOSE=true with GinkgoWriter
+// to keep console tidy
+func (s *HstSuite) log(arg any) {
+ logs := strings.Split(fmt.Sprint(arg), "\n")
+ for _, line := range logs {
+ s.logger.Println(line)
+ }
if *isVerbose {
- s.T().Helper()
- s.T().Log(args...)
+ GinkgoWriter.Println(arg)
}
}
-func (s *HstSuite) skip(args ...any) {
- s.log(args...)
- s.T().SkipNow()
+func (s *HstSuite) skip(args string) {
+ Skip(args)
}
func (s *HstSuite) SkipIfMultiWorker(args ...any) {
@@ -249,11 +261,11 @@ func (s *HstSuite) getNetNamespaceByName(name string) string {
}
func (s *HstSuite) getInterfaceByName(name string) *NetInterface {
- return s.netInterfaces[name + s.pid]
+ return s.netInterfaces[name+s.pid]
}
func (s *HstSuite) getContainerByName(name string) *Container {
- return s.containers[name + s.pid]
+ return s.containers[name+s.pid]
}
/*
@@ -261,25 +273,25 @@ func (s *HstSuite) getContainerByName(name string) *Container {
* are not able to modify the original container and affect other tests by doing that
*/
func (s *HstSuite) getTransientContainerByName(name string) *Container {
- containerCopy := *s.containers[name + s.pid]
+ containerCopy := *s.containers[name+s.pid]
return &containerCopy
}
func (s *HstSuite) loadContainerTopology(topologyName string) {
data, err := os.ReadFile(containerTopologyDir + topologyName + ".yaml")
if err != nil {
- s.T().Fatalf("read error: %v", err)
+ Fail("read error: " + fmt.Sprint(err))
}
var yamlTopo YamlTopology
err = yaml.Unmarshal(data, &yamlTopo)
if err != nil {
- s.T().Fatalf("unmarshal error: %v", err)
+ Fail("unmarshal error: " + fmt.Sprint(err))
}
for _, elem := range yamlTopo.Volumes {
volumeMap := elem["volume"].(VolumeConfig)
hostDir := volumeMap["host-dir"].(string)
- workingVolumeDir := logDir + s.T().Name() + s.pid + volumeDir
+ workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + volumeDir
volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir)
hostDir = volDirReplacer.Replace(hostDir)
s.volumes = append(s.volumes, hostDir)
@@ -287,10 +299,11 @@ func (s *HstSuite) loadContainerTopology(topologyName string) {
s.containers = make(map[string]*Container)
for _, elem := range yamlTopo.Containers {
- newContainer, err := newContainer(s, elem, s.pid)
+ newContainer, err := newContainer(s, elem)
newContainer.suite = s
+ newContainer.name += newContainer.suite.pid
if err != nil {
- s.T().Fatalf("container config error: %v", err)
+ Fail("container config error: " + fmt.Sprint(err))
}
s.containers[newContainer.name] = newContainer
}
@@ -299,12 +312,12 @@ func (s *HstSuite) loadContainerTopology(topologyName string) {
func (s *HstSuite) loadNetworkTopology(topologyName string) {
data, err := os.ReadFile(networkTopologyDir + topologyName + ".yaml")
if err != nil {
- s.T().Fatalf("read error: %v", err)
+ Fail("read error: " + fmt.Sprint(err))
}
var yamlTopo YamlTopology
err = yaml.Unmarshal(data, &yamlTopo)
if err != nil {
- s.T().Fatalf("unmarshal error: %v", err)
+ Fail("unmarshal error: " + fmt.Sprint(err))
}
s.ip4AddrAllocator = NewIp4AddressAllocator()
@@ -316,10 +329,10 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
}
if peer, ok := elem["peer"].(NetDevConfig); ok {
- if peer["name"].(string) != ""{
+ if peer["name"].(string) != "" {
peer["name"] = peer["name"].(string) + s.pid
}
- if _, ok := peer["netns"]; ok{
+ if _, ok := peer["netns"]; ok {
peer["netns"] = peer["netns"].(string) + s.pid
}
}
@@ -341,7 +354,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
if namespace, err := newNetNamespace(elem); err == nil {
s.netConfigs = append(s.netConfigs, &namespace)
} else {
- s.T().Fatalf("network config error: %v", err)
+ Fail("network config error: " + fmt.Sprint(err))
}
}
case Veth, Tap:
@@ -350,7 +363,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
s.netConfigs = append(s.netConfigs, netIf)
s.netInterfaces[netIf.Name()] = netIf
} else {
- s.T().Fatalf("network config error: %v", err)
+ Fail("network config error: " + fmt.Sprint(err))
}
}
case Bridge:
@@ -358,7 +371,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
if bridge, err := newBridge(elem); err == nil {
s.netConfigs = append(s.netConfigs, &bridge)
} else {
- s.T().Fatalf("network config error: %v", err)
+ Fail("network config error: " + fmt.Sprint(err))
}
}
}
@@ -374,7 +387,7 @@ func (s *HstSuite) configureNetworkTopology(topologyName string) {
for _, nc := range s.netConfigs {
if err := nc.configure(); err != nil {
- s.T().Fatalf("network config error: %v", err)
+ Fail("Network config error: " + fmt.Sprint(err))
}
}
}
@@ -389,7 +402,7 @@ func (s *HstSuite) unconfigureNetworkTopology() {
}
func (s *HstSuite) getTestId() string {
- testName := s.T().Name()
+ testName := CurrentSpecReport().LeafNodeText
if s.testIds == nil {
s.testIds = map[string]string{}
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go
index 943c8a591d4..f52d2816930 100644
--- a/extras/hs-test/http_test.go
+++ b/extras/hs-test/http_test.go
@@ -2,11 +2,25 @@ package main
import (
"fmt"
+ "net/http"
"os"
"strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
)
-func (s *NsSuite) TestHttpTps() {
+func init() {
+ registerNsTests(HttpTpsTest)
+ registerVethTests(HttpCliTest, HttpCliConnectErrorTest)
+ registerNoTopoTests(NginxHttp3Test, NginxAsServerTest,
+ NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, HeaderServerTest,
+ HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest,
+ HttpCliBadRequestTest)
+ registerNoTopoSoloTests(HttpStaticPromTest)
+}
+
+func HttpTpsTest(s *NsSuite) {
iface := s.getInterfaceByName(clientInterface)
client_ip := iface.ip4AddressString()
port := "8080"
@@ -18,13 +32,16 @@ func (s *NsSuite) TestHttpTps() {
// configure vpp in the container
container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080")
- go s.startWget(finished, client_ip, port, "test_file_10M", clientNetns)
+ go func() {
+ defer GinkgoRecover()
+ s.startWget(finished, client_ip, port, "test_file_10M", clientNetns)
+ }()
// wait for client
err := <-finished
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
}
-func (s *VethsSuite) TestHttpCli() {
+func HttpCliTest(s *VethsSuite) {
serverContainer := s.getContainerByName("server-vpp")
clientContainer := s.getContainerByName("client-vpp")
@@ -35,13 +52,27 @@ func (s *VethsSuite) TestHttpCli() {
uri := "http://" + serverVeth.ip4AddressString() + "/80"
o := clientContainer.vppInstance.vppctl("http cli client" +
- " uri " + uri + " query /show/version")
+ " uri " + uri + " query /show/vlib/graph")
s.log(o)
s.assertContains(o, "<html>", "<html> not found in the result!")
}
-func (s *NoTopoSuite) TestNginxHttp3() {
+func HttpCliConnectErrorTest(s *VethsSuite) {
+ clientContainer := s.getContainerByName("client-vpp")
+
+ serverVeth := s.getInterfaceByName(serverInterfaceName)
+
+ uri := "http://" + serverVeth.ip4AddressString() + "/80"
+
+ o := clientContainer.vppInstance.vppctl("http cli client" +
+ " uri " + uri + " query /show/vlib/graph")
+
+ s.log(o)
+ s.assertContains(o, "failed to connect")
+}
+
+func NginxHttp3Test(s *NoTopoSuite) {
s.SkipUnlessExtendedTestsBuilt()
query := "index.html"
@@ -57,23 +88,102 @@ func (s *NoTopoSuite) TestNginxHttp3() {
args := fmt.Sprintf("curl --noproxy '*' --local-port 55444 --http3-only -k https://%s:8443/%s", serverAddress, query)
curlCont.extraRunningArgs = args
o, err := curlCont.combinedOutput()
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.assertContains(o, "<http>", "<http> not found in the result!")
}
-func (s *NoTopoSuite) TestHttpStaticProm() {
+func HttpStaticPromTest(s *NoTopoSuite) {
finished := make(chan error, 1)
query := "stats.prom"
vpp := s.getContainerByName("vpp").vppInstance
serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
s.log(vpp.vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
s.log(vpp.vppctl("prom enable"))
- go s.startWget(finished, serverAddress, "80", query, "")
+ time.Sleep(time.Second * 5)
+ go func() {
+ defer GinkgoRecover()
+ s.startWget(finished, serverAddress, "80", query, "")
+ }()
err := <-finished
- s.assertNil(err, err)
+ s.assertNil(err)
+}
+
+func HttpStaticMovedTest(s *NoTopoSuite) {
+ vpp := s.getContainerByName("vpp").vppInstance
+ vpp.container.exec("mkdir -p /tmp/tmp.aaa")
+ vpp.container.createFile("/tmp/tmp.aaa/index.html", "<http><body><p>Hello</p></body></http>")
+ serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
+ s.log(vpp.vppctl("http static server www-root /tmp uri tcp://" + serverAddress + "/80 debug"))
+
+ client := &http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ },
+ }
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80/tmp.aaa", nil)
+ s.assertNil(err, fmt.Sprint(err))
+ resp, err := client.Do(req)
+ s.assertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.assertEqual(301, resp.StatusCode)
+ s.assertNotEqual("", resp.Header.Get("Location"))
+}
+
+func HttpStaticNotFoundTest(s *NoTopoSuite) {
+ vpp := s.getContainerByName("vpp").vppInstance
+ serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
+ s.log(vpp.vppctl("http static server www-root /tmp uri tcp://" + serverAddress + "/80 debug"))
+
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80/notfound.html", nil)
+ s.assertNil(err, fmt.Sprint(err))
+ resp, err := http.DefaultClient.Do(req)
+ s.assertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.assertEqual(404, resp.StatusCode)
+}
+
+func HttpCliMethodNotAllowedTest(s *NoTopoSuite) {
+ vpp := s.getContainerByName("vpp").vppInstance
+ serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
+ vpp.vppctl("http cli server")
+
+ req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test", nil)
+ s.assertNil(err, fmt.Sprint(err))
+ resp, err := http.DefaultClient.Do(req)
+ s.assertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.assertEqual(405, resp.StatusCode)
+ // TODO: need to be fixed in http code
+ //s.assertNotEqual("", resp.Header.Get("Allow"))
+}
+
+func HttpCliBadRequestTest(s *NoTopoSuite) {
+ vpp := s.getContainerByName("vpp").vppInstance
+ serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
+ vpp.vppctl("http cli server")
+
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80", nil)
+ s.assertNil(err, fmt.Sprint(err))
+ resp, err := http.DefaultClient.Do(req)
+ s.assertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.assertEqual(400, resp.StatusCode)
+}
+
+func HeaderServerTest(s *NoTopoSuite) {
+ vpp := s.getContainerByName("vpp").vppInstance
+ serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
+ vpp.vppctl("http cli server")
+
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80/show/version", nil)
+ s.assertNil(err, fmt.Sprint(err))
+ resp, err := http.DefaultClient.Do(req)
+ s.assertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.assertEqual("http_cli_server", resp.Header.Get("Server"))
}
-func (s *NoTopoSuite) TestNginxAsServer() {
+func NginxAsServerTest(s *NoTopoSuite) {
query := "return_ok"
finished := make(chan error, 1)
@@ -86,7 +196,10 @@ func (s *NoTopoSuite) TestNginxAsServer() {
serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
defer func() { os.Remove(query) }()
- go s.startWget(finished, serverAddress, "80", query, "")
+ go func() {
+ defer GinkgoRecover()
+ s.startWget(finished, serverAddress, "80", query, "")
+ }()
s.assertNil(<-finished)
}
@@ -124,9 +237,11 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
args += " -r"
args += " http://" + serverAddress + ":80/64B.json"
abCont.extraRunningArgs = args
+ time.Sleep(time.Second * 10)
o, err := abCont.combinedOutput()
rps := parseString(o, "Requests per second:")
- s.log(rps, err)
+ s.log(rps)
+ s.log(err)
s.assertNil(err, "err: '%s', output: '%s'", err, o)
} else {
wrkCont := s.getContainerByName("wrk")
@@ -135,20 +250,21 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
wrkCont.extraRunningArgs = args
o, err := wrkCont.combinedOutput()
rps := parseString(o, "requests")
- s.log(rps, err)
+ s.log(rps)
+ s.log(err)
s.assertNil(err, "err: '%s', output: '%s'", err, o)
}
return nil
}
-func (s *NoTopoSuite) TestNginxPerfCps() {
+func NginxPerfCpsTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "cps", "ab"))
}
-func (s *NoTopoSuite) TestNginxPerfRps() {
+func NginxPerfRpsTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "rps", "ab"))
}
-func (s *NoTopoSuite) TestNginxPerfWrk() {
+func NginxPerfWrkTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "", "wrk"))
}
diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go
index 8d9168d3d5d..24d2de39485 100644
--- a/extras/hs-test/ldp_test.go
+++ b/extras/hs-test/ldp_test.go
@@ -3,9 +3,15 @@ package main
import (
"fmt"
"os"
+
+ . "github.com/onsi/ginkgo/v2"
)
-func (s *VethsSuite) TestLDPreloadIperfVpp() {
+func init() {
+ registerVethTests(LDPreloadIperfVppTest)
+}
+
+func LDPreloadIperfVppTest(s *VethsSuite) {
var clnVclConf, srvVclConf Stanza
serverContainer := s.getContainerByName("server-vpp")
@@ -14,10 +20,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
clientContainer := s.getContainerByName("client-vpp")
clientVclFileName := clientContainer.getHostWorkDir() + "/vcl_cln.conf"
- ldpreload := os.Getenv("HST_LDPRELOAD")
- s.assertNotEqual("", ldpreload)
-
- ldpreload = "LD_PRELOAD=" + ldpreload
+ ldpreload := "LD_PRELOAD=../../build-root/build-vpp-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so"
stopServerCh := make(chan struct{}, 1)
srvCh := make(chan error, 1)
@@ -36,7 +39,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
append("use-mq-eventfd").
append(clientAppSocketApi).close().
saveToFile(clientVclFileName)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
serverContainer.getHostWorkDir())
@@ -49,26 +52,32 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
append("use-mq-eventfd").
append(serverAppSocketApi).close().
saveToFile(serverVclFileName)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.log("attaching server to vpp")
srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+serverVclFileName)
- go s.startServerApp(srvCh, stopServerCh, srvEnv)
+ go func() {
+ defer GinkgoRecover()
+ s.startServerApp(srvCh, stopServerCh, srvEnv)
+ }()
err = <-srvCh
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.log("attaching client to vpp")
var clnRes = make(chan string, 1)
clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName)
serverVethAddress := s.getInterfaceByName(serverInterfaceName).ip4AddressString()
- go s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
+ go func() {
+ defer GinkgoRecover()
+ s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
+ }()
s.log(<-clnRes)
// wait for client's result
err = <-clnCh
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
// stop server
stopServerCh <- struct{}{}
diff --git a/extras/hs-test/linux_iperf_test.go b/extras/hs-test/linux_iperf_test.go
index 06247e45240..e323f7fb721 100644
--- a/extras/hs-test/linux_iperf_test.go
+++ b/extras/hs-test/linux_iperf_test.go
@@ -1,6 +1,16 @@
package main
-func (s *TapSuite) TestLinuxIperf() {
+import (
+ "fmt"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
+func init() {
+ registerTapTests(LinuxIperfTest)
+}
+
+func LinuxIperfTest(s *TapSuite) {
clnCh := make(chan error)
stopServerCh := make(chan struct{})
srvCh := make(chan error, 1)
@@ -9,13 +19,19 @@ func (s *TapSuite) TestLinuxIperf() {
stopServerCh <- struct{}{}
}()
- go s.startServerApp(srvCh, stopServerCh, nil)
+ go func() {
+ defer GinkgoRecover()
+ s.startServerApp(srvCh, stopServerCh, nil)
+ }()
err := <-srvCh
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.log("server running")
ipAddress := s.getInterfaceByName(tapInterfaceName).ip4AddressString()
- go s.startClientApp(ipAddress, nil, clnCh, clnRes)
+ go func() {
+ defer GinkgoRecover()
+ s.startClientApp(ipAddress, nil, clnCh, clnRes)
+ }()
s.log("client running")
s.log(<-clnRes)
err = <-clnCh
diff --git a/extras/hs-test/mirroring_test.go b/extras/hs-test/mirroring_test.go
index 91f43f45682..6c5a860b01c 100644
--- a/extras/hs-test/mirroring_test.go
+++ b/extras/hs-test/mirroring_test.go
@@ -4,7 +4,11 @@ import (
"github.com/edwarnicke/exechelper"
)
-func (s *NginxSuite) TestMirroring() {
+func init() {
+ registerNginxTests(MirroringTest)
+}
+
+func MirroringTest(s *NginxSuite) {
proxyAddress := s.getInterfaceByName(mirroringClientInterfaceName).peer.ip4AddressString()
path := "/64B.json"
diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go
index c2f9b6f2825..ac5f94c8535 100644
--- a/extras/hs-test/proxy_test.go
+++ b/extras/hs-test/proxy_test.go
@@ -5,8 +5,13 @@ import (
"os"
"github.com/edwarnicke/exechelper"
+ . "github.com/onsi/ginkgo/v2"
)
+func init() {
+ registerNsTests(VppProxyHttpTcpTest, VppProxyHttpTlsTest, EnvoyProxyHttpTcpTest)
+}
+
func testProxyHttpTcp(s *NsSuite, proto string) error {
var outputFile string = "test" + s.pid + ".data"
var srcFilePid string = "httpTestFile" + s.pid
@@ -19,12 +24,15 @@ func testProxyHttpTcp(s *NsSuite, proto string) error {
// create test file
err := exechelper.Run(fmt.Sprintf("ip netns exec %s truncate -s %s %s", serverNetns, fileSize, srcFilePid))
- s.assertNil(err, "failed to run truncate command: " + fmt.Sprint(err))
+ s.assertNil(err, "failed to run truncate command: "+fmt.Sprint(err))
defer func() { os.Remove(srcFilePid) }()
s.log("test file created...")
- go s.startHttpServer(serverRunning, stopServer, ":666", serverNetns)
+ go func() {
+ defer GinkgoRecover()
+ s.startHttpServer(serverRunning, stopServer, ":666", serverNetns)
+ }()
// TODO better error handling and recovery
<-serverRunning
@@ -64,21 +72,21 @@ func configureVppProxy(s *NsSuite, proto string) {
clientVeth.ip4AddressString(),
serverVeth.peer.ip4AddressString(),
)
- s.log("proxy configured...", output)
+ s.log("proxy configured: " + output)
}
-func (s *NsSuite) TestVppProxyHttpTcp() {
+func VppProxyHttpTcpTest(s *NsSuite) {
proto := "tcp"
configureVppProxy(s, proto)
err := testProxyHttpTcp(s, proto)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
}
-func (s *NsSuite) TestVppProxyHttpTls() {
+func VppProxyHttpTlsTest(s *NsSuite) {
proto := "tls"
configureVppProxy(s, proto)
err := testProxyHttpTcp(s, proto)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
}
func configureEnvoyProxy(s *NsSuite) {
@@ -100,8 +108,8 @@ func configureEnvoyProxy(s *NsSuite) {
s.assertNil(envoyContainer.start())
}
-func (s *NsSuite) TestEnvoyProxyHttpTcp() {
+func EnvoyProxyHttpTcpTest(s *NsSuite) {
configureEnvoyProxy(s)
err := testProxyHttpTcp(s, "tcp")
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
}
diff --git a/extras/hs-test/raw_session_test.go b/extras/hs-test/raw_session_test.go
index 670ed582522..5c66df0b1ce 100644
--- a/extras/hs-test/raw_session_test.go
+++ b/extras/hs-test/raw_session_test.go
@@ -1,15 +1,19 @@
package main
-func (s *VethsSuite) TestVppEchoQuic() {
+func init() {
+ registerVethTests(VppEchoQuicTest, VppEchoTcpTest)
+}
+
+func VppEchoQuicTest(s *VethsSuite) {
s.testVppEcho("quic")
}
-// udp echo currently broken in vpp, skipping
-func (s *VethsSuite) SkipTestVppEchoUdp() {
+// TODO: udp echo currently broken in vpp
+func VppEchoUdpTest(s *VethsSuite) {
s.testVppEcho("udp")
}
-func (s *VethsSuite) TestVppEchoTcp() {
+func VppEchoTcpTest(s *VethsSuite) {
s.testVppEcho("tcp")
}
diff --git a/extras/hs-test/script/compress.sh b/extras/hs-test/script/compress.sh
new file mode 100644
index 00000000000..92a2fbd6789
--- /dev/null
+++ b/extras/hs-test/script/compress.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+if [ "${COMPRESS_FAILED_TEST_LOGS}" == "yes" -a -s "${HS_SUMMARY}/failed-summary.log" ]
+then
+ echo -n "Copying docker logs..."
+ dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText' ${HS_SUMMARY}/report.json)
+ for dirName in $dirs; do
+ logDir=/tmp/hs-test/$dirName
+ if [ -d "$logDir" ]; then
+ mkdir -p $WORKSPACE/archives/summary
+ cp -r $logDir $WORKSPACE/archives/summary/
+ fi
+ done
+ echo "Done."
+
+ if [ -n "$WORKSPACE" ]
+ then
+ echo -n "Copying failed test logs into build log archive directory ($WORKSPACE/archives)... "
+ mkdir -p $WORKSPACE/archives/summary
+ cp -a ${HS_SUMMARY}/* $WORKSPACE/archives/summary
+ echo "Done."
+ fi
+
+ echo -n "Compressing files in $WORKSPACE/archives from test runs... "
+ cd $WORKSPACE/archives
+ find . -type f \( -name "*.json" -o -name "*.log" \) -exec gzip {} \;
+ echo "Done."
+
+else
+ echo "Not compressing files in temporary directories from test runs."
+ exit 0
+fi
+
+exit 1 \ No newline at end of file
diff --git a/extras/hs-test/suite_nginx_test.go b/extras/hs-test/suite_nginx_test.go
index 8f40590d1f2..c559496e71b 100644
--- a/extras/hs-test/suite_nginx_test.go
+++ b/extras/hs-test/suite_nginx_test.go
@@ -1,18 +1,37 @@
package main
+import (
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
// These correspond to names used in yaml config
const (
- vppProxyContainerName = "vpp-proxy"
- nginxProxyContainerName = "nginx-proxy"
- nginxServerContainerName = "nginx-server"
+ vppProxyContainerName = "vpp-proxy"
+ nginxProxyContainerName = "nginx-proxy"
+ nginxServerContainerName = "nginx-server"
mirroringClientInterfaceName = "hstcln"
mirroringServerInterfaceName = "hstsrv"
)
+var nginxTests = []func(s *NginxSuite){}
+var nginxSoloTests = []func(s *NginxSuite){}
+
type NginxSuite struct {
HstSuite
}
+func registerNginxTests(tests ...func(s *NginxSuite)) {
+ nginxTests = append(nginxTests, tests...)
+}
+func registerNginxSoloTests(tests ...func(s *NginxSuite)) {
+ nginxSoloTests = append(nginxSoloTests, tests...)
+}
+
func (s *NginxSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.loadNetworkTopology("2taps")
@@ -60,3 +79,56 @@ func (s *NginxSuite) SetupTest() {
proxyVpp.waitForApp("nginx-", 5)
}
+
+var _ = Describe("NginxSuite", Ordered, ContinueOnFailure, func() {
+ var s NginxSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+ for _, test := range nginxTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
+
+var _ = Describe("NginxSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s NginxSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range nginxSoloTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
diff --git a/extras/hs-test/suite_no_topo_test.go b/extras/hs-test/suite_no_topo_test.go
index bbf0cfda685..625dca9f3cf 100644
--- a/extras/hs-test/suite_no_topo_test.go
+++ b/extras/hs-test/suite_no_topo_test.go
@@ -1,15 +1,34 @@
package main
+import (
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
const (
- singleTopoContainerVpp = "vpp"
- singleTopoContainerNginx = "nginx"
- tapInterfaceName = "htaphost"
+ singleTopoContainerVpp = "vpp"
+ singleTopoContainerNginx = "nginx"
+ tapInterfaceName = "htaphost"
)
+var noTopoTests = []func(s *NoTopoSuite){}
+var noTopoSoloTests = []func(s *NoTopoSuite){}
+
type NoTopoSuite struct {
HstSuite
}
+func registerNoTopoTests(tests ...func(s *NoTopoSuite)) {
+ noTopoTests = append(noTopoTests, tests...)
+}
+func registerNoTopoSoloTests(tests ...func(s *NoTopoSuite)) {
+ noTopoSoloTests = append(noTopoSoloTests, tests...)
+}
+
func (s *NoTopoSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.loadNetworkTopology("tap")
@@ -35,3 +54,57 @@ func (s *NoTopoSuite) SetupTest() {
s.assertNil(vpp.createTap(tapInterface), "failed to create tap interface")
}
+
+var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() {
+ var s NoTopoSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range noTopoTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
+
+var _ = Describe("NoTopoSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s NoTopoSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range noTopoSoloTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
diff --git a/extras/hs-test/suite_ns_test.go b/extras/hs-test/suite_ns_test.go
index 46d5bef92ad..85b90911c2f 100644
--- a/extras/hs-test/suite_ns_test.go
+++ b/extras/hs-test/suite_ns_test.go
@@ -1,15 +1,35 @@
package main
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
// These correspond to names used in yaml config
const (
clientInterface = "hclnvpp"
serverInterface = "hsrvvpp"
)
+var nsTests = []func(s *NsSuite){}
+var nsSoloTests = []func(s *NsSuite){}
+
type NsSuite struct {
HstSuite
}
+func registerNsTests(tests ...func(s *NsSuite)) {
+ nsTests = append(nsTests, tests...)
+}
+func registerNsSoloTests(tests ...func(s *NsSuite)) {
+ nsSoloTests = append(nsSoloTests, tests...)
+}
+
func (s *NsSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.configureNetworkTopology("ns")
@@ -34,12 +54,66 @@ func (s *NsSuite) SetupTest() {
s.assertNil(vpp.start())
idx, err := vpp.createAfPacket(s.getInterfaceByName(serverInterface))
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
idx, err = vpp.createAfPacket(s.getInterfaceByName(clientInterface))
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
container.exec("chmod 777 -R %s", container.getContainerWorkDir())
}
+
+var _ = Describe("NsSuite", Ordered, ContinueOnFailure, func() {
+ var s NsSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range nsTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
+
+var _ = Describe("NsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s NsSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range nsSoloTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
diff --git a/extras/hs-test/suite_tap_test.go b/extras/hs-test/suite_tap_test.go
index 8b0950a797e..ebf0f9b3cbc 100644
--- a/extras/hs-test/suite_tap_test.go
+++ b/extras/hs-test/suite_tap_test.go
@@ -1,15 +1,84 @@
package main
import (
+ "reflect"
+ "runtime"
+ "strings"
"time"
+
+ . "github.com/onsi/ginkgo/v2"
)
type TapSuite struct {
HstSuite
}
+var tapTests = []func(s *TapSuite){}
+var tapSoloTests = []func(s *TapSuite){}
+
+func registerTapTests(tests ...func(s *TapSuite)) {
+ tapTests = append(tapTests, tests...)
+}
+func registerTapSoloTests(tests ...func(s *TapSuite)) {
+ tapSoloTests = append(tapSoloTests, tests...)
+}
+
func (s *TapSuite) SetupSuite() {
time.Sleep(1 * time.Second)
s.HstSuite.SetupSuite()
s.configureNetworkTopology("tap")
}
+
+var _ = Describe("TapSuite", Ordered, ContinueOnFailure, func() {
+ var s TapSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range tapTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
+
+var _ = Describe("TapSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s TapSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for _, test := range tapSoloTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
diff --git a/extras/hs-test/suite_veth_test.go b/extras/hs-test/suite_veth_test.go
index 061eee07d1f..d47bf8c52a9 100644
--- a/extras/hs-test/suite_veth_test.go
+++ b/extras/hs-test/suite_veth_test.go
@@ -1,7 +1,13 @@
package main
import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
"time"
+
+ . "github.com/onsi/ginkgo/v2"
)
// These correspond to names used in yaml config
@@ -10,10 +16,20 @@ const (
clientInterfaceName = "cln"
)
+var vethTests = []func(s *VethsSuite){}
+var vethSoloTests = []func(s *VethsSuite){}
+
type VethsSuite struct {
HstSuite
}
+func registerVethTests(tests ...func(s *VethsSuite)) {
+ vethTests = append(vethTests, tests...)
+}
+func registerSoloVethTests(tests ...func(s *VethsSuite)) {
+ vethSoloTests = append(vethSoloTests, tests...)
+}
+
func (s *VethsSuite) SetupSuite() {
time.Sleep(1 * time.Second)
s.HstSuite.SetupSuite()
@@ -36,7 +52,7 @@ func (s *VethsSuite) SetupTest() {
cpus := s.AllocateCpus()
serverVpp, err := serverContainer.newVppInstance(cpus, sessionConfig)
- s.assertNotNil(serverVpp, err)
+ s.assertNotNil(serverVpp, fmt.Sprint(err))
s.setupServerVpp()
@@ -45,7 +61,7 @@ func (s *VethsSuite) SetupTest() {
cpus = s.AllocateCpus()
clientVpp, err := clientContainer.newVppInstance(cpus, sessionConfig)
- s.assertNotNil(clientVpp, err)
+ s.assertNotNil(clientVpp, fmt.Sprint(err))
s.setupClientVpp()
}
@@ -56,7 +72,7 @@ func (s *VethsSuite) setupServerVpp() {
serverVeth := s.getInterfaceByName(serverInterfaceName)
idx, err := serverVpp.createAfPacket(serverVeth)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
}
@@ -66,6 +82,63 @@ func (s *VethsSuite) setupClientVpp() {
clientVeth := s.getInterfaceByName(clientInterfaceName)
idx, err := clientVpp.createAfPacket(clientVeth)
- s.assertNil(err, err)
+ s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
}
+
+var _ = Describe("VethsSuite", Ordered, ContinueOnFailure, func() {
+ var s VethsSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+ for _, test := range vethTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
+
+var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s VethsSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+ for _, test := range vethSoloTests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(time.Minute*5))
+ }
+})
diff --git a/extras/hs-test/test b/extras/hs-test/test
index c3b9eaef145..fd17feb2c50 100755
--- a/extras/hs-test/test
+++ b/extras/hs-test/test
@@ -8,6 +8,8 @@ persist_set=0
unconfigure_set=0
debug_set=0
vppsrc=
+ginkgo_args=
+parallel=
for i in "$@"
do
@@ -49,8 +51,18 @@ case "${i}" in
tc_name="${i#*=}"
if [ $tc_name != "all" ]; then
single_test=1
- args="$args -run $tc_name -verbose"
+ ginkgo_args="$ginkgo_args --focus $tc_name -vv"
+ args="$args -verbose"
+ else
+ ginkgo_args="$ginkgo_args -v"
fi
+ ;;
+ --parallel=*)
+ ginkgo_args="$ginkgo_args -procs=${i#*=}"
+ ;;
+ --repeat=*)
+ ginkgo_args="$ginkgo_args --repeat=${i#*=}"
+ ;;
esac
done
@@ -74,4 +86,6 @@ if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then
exit 1
fi
-sudo -E go test -timeout=20m -buildvcs=false -v $args
+mkdir -p summary
+
+sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --no-color --trace --json-report=summary/report.json $ginkgo_args -- $args
diff --git a/extras/hs-test/vcl_test.go b/extras/hs-test/vcl_test.go
index cb6aaa4adc0..fdcd60ad503 100644
--- a/extras/hs-test/vcl_test.go
+++ b/extras/hs-test/vcl_test.go
@@ -5,6 +5,11 @@ import (
"time"
)
+func init() {
+ registerVethTests(XEchoVclClientUdpTest, XEchoVclClientTcpTest, XEchoVclServerUdpTest,
+ XEchoVclServerTcpTest, VclEchoTcpTest, VclEchoUdpTest, VclRetryAttachTest)
+}
+
func getVclConfig(c *Container, ns_id_optional ...string) string {
var s Stanza
ns_id := "default"
@@ -23,11 +28,11 @@ func getVclConfig(c *Container, ns_id_optional ...string) string {
return s.close().toString()
}
-func (s *VethsSuite) TestXEchoVclClientUdp() {
+func XEchoVclClientUdpTest(s *VethsSuite) {
s.testXEchoVclClient("udp")
}
-func (s *VethsSuite) TestXEchoVclClientTcp() {
+func XEchoVclClientTcpTest(s *VethsSuite) {
s.testXEchoVclClient("tcp")
}
@@ -49,11 +54,11 @@ func (s *VethsSuite) testXEchoVclClient(proto string) {
s.assertContains(o, "CLIENT RESULTS")
}
-func (s *VethsSuite) TestXEchoVclServerUdp() {
+func XEchoVclServerUdpTest(s *VethsSuite) {
s.testXEchoVclServer("udp")
}
-func (s *VethsSuite) TestXEchoVclServerTcp() {
+func XEchoVclServerTcpTest(s *VethsSuite) {
s.testXEchoVclServer("tcp")
}
@@ -97,16 +102,15 @@ func (s *VethsSuite) testVclEcho(proto string) {
s.log(o)
}
-func (s *VethsSuite) TestVclEchoTcp() {
+func VclEchoTcpTest(s *VethsSuite) {
s.testVclEcho("tcp")
}
-func (s *VethsSuite) TestVclEchoUdp() {
+func VclEchoUdpTest(s *VethsSuite) {
s.testVclEcho("udp")
}
-// this test takes too long, for now it's being skipped
-func (s *VethsSuite) SkipTestVclRetryAttach() {
+func VclRetryAttachTest(s *VethsSuite) {
s.testRetryAttach("tcp")
}
diff --git a/extras/hs-test/vppinstance.go b/extras/hs-test/vppinstance.go
index 1a058c8e0e3..9b400cfcb77 100644
--- a/extras/hs-test/vppinstance.go
+++ b/extras/hs-test/vppinstance.go
@@ -2,6 +2,7 @@ package main
import (
"fmt"
+ "io"
"os"
"os/exec"
"os/signal"
@@ -10,7 +11,9 @@ import (
"syscall"
"time"
+ "github.com/sirupsen/logrus"
"github.com/edwarnicke/exechelper"
+ . "github.com/onsi/ginkgo/v2"
"go.fd.io/govpp"
"go.fd.io/govpp/api"
@@ -59,6 +62,8 @@ plugins {
plugin http_static_plugin.so { enable }
plugin prom_plugin.so { enable }
plugin tlsopenssl_plugin.so { enable }
+ plugin ping_plugin.so { enable }
+ plugin nsim_plugin.so { enable }
}
logging {
@@ -103,6 +108,10 @@ func (vpp *VppInstance) getEtcDir() string {
}
func (vpp *VppInstance) start() error {
+ // Replace default logger in govpp with our own
+ govppLogger := logrus.New()
+ govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().logger.Writer(), GinkgoWriter))
+ core.SetLogger(govppLogger)
// Create folders
containerWorkDir := vpp.container.getContainerWorkDir()
@@ -131,9 +140,10 @@ func (vpp *VppInstance) start() error {
vpp.container.createFile(vppcliFileName, cliContent)
vpp.container.exec("chmod 0755 " + vppcliFileName)
+ vpp.getSuite().log("starting vpp")
if *isVppDebug {
sig := make(chan os.Signal, 1)
- signal.Notify(sig, syscall.SIGINT)
+ signal.Notify(sig, syscall.SIGQUIT)
cont := make(chan bool, 1)
go func() {
<-sig
@@ -143,7 +153,7 @@ func (vpp *VppInstance) start() error {
vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
fmt.Println("run following command in different terminal:")
fmt.Println("docker exec -it " + vpp.container.name + " gdb -ex \"attach $(docker exec " + vpp.container.name + " pidof vpp)\"")
- fmt.Println("Afterwards press CTRL+C to continue")
+ fmt.Println("Afterwards press CTRL+\\ to continue")
<-cont
fmt.Println("continuing...")
} else {
@@ -151,6 +161,7 @@ func (vpp *VppInstance) start() error {
vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
}
+ vpp.getSuite().log("connecting to vpp")
// Connect to VPP and store the connection
sockAddress := vpp.container.getHostWorkDir() + defaultApiSocketFilePath
conn, connEv, err := govpp.AsyncConnect(
@@ -207,7 +218,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int {
tokens := strings.Split(strings.TrimSpace(line), " ")
val, err := strconv.Atoi(tokens[0])
if err != nil {
- vpp.getSuite().FailNow("failed to parse stat value %s", err)
+ Fail("failed to parse stat value %s" + fmt.Sprint(err))
return 0
}
return val
@@ -217,6 +228,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int {
}
func (vpp *VppInstance) waitForApp(appName string, timeout int) {
+ vpp.getSuite().log("waiting for app " + appName)
for i := 0; i < timeout; i++ {
o := vpp.vppctl("show app")
if strings.Contains(o, appName) {
@@ -240,6 +252,7 @@ func (vpp *VppInstance) createAfPacket(
}
createReply := &af_packet.AfPacketCreateV2Reply{}
+ vpp.getSuite().log("create af-packet interface " + veth.Name())
if err := vpp.apiChannel.SendRequest(createReq).ReceiveReply(createReply); err != nil {
return 0, err
}
@@ -252,6 +265,7 @@ func (vpp *VppInstance) createAfPacket(
}
upReply := &interfaces.SwInterfaceSetFlagsReply{}
+ vpp.getSuite().log("set af-packet interface " + veth.Name() + " up")
if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil {
return 0, err
}
@@ -273,6 +287,7 @@ func (vpp *VppInstance) createAfPacket(
}
addressReply := &interfaces.SwInterfaceAddDelAddressReply{}
+ vpp.getSuite().log("af-packet interface " + veth.Name() + " add address " + veth.ip4Address)
if err := vpp.apiChannel.SendRequest(addressReq).ReceiveReply(addressReply); err != nil {
return 0, err
}
@@ -292,6 +307,7 @@ func (vpp *VppInstance) addAppNamespace(
}
reply := &session.AppNamespaceAddDelV2Reply{}
+ vpp.getSuite().log("add app namespace " + namespaceId)
if err := vpp.apiChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return err
}
@@ -301,6 +317,7 @@ func (vpp *VppInstance) addAppNamespace(
}
sessionReply := &session.SessionEnableDisableReply{}
+ vpp.getSuite().log("enable app namespace " + namespaceId)
if err := vpp.apiChannel.SendRequest(sessionReq).ReceiveReply(sessionReply); err != nil {
return err
}
@@ -325,6 +342,7 @@ func (vpp *VppInstance) createTap(
}
createTapReply := &tapv2.TapCreateV2Reply{}
+ vpp.getSuite().log("create tap interface " + tap.Name())
// Create tap interface
if err := vpp.apiChannel.SendRequest(createTapReq).ReceiveReply(createTapReply); err != nil {
return err
@@ -338,6 +356,7 @@ func (vpp *VppInstance) createTap(
}
addAddressReply := &interfaces.SwInterfaceAddDelAddressReply{}
+ vpp.getSuite().log("tap interface " + tap.Name() + " add address " + tap.peer.ip4Address)
if err := vpp.apiChannel.SendRequest(addAddressReq).ReceiveReply(addAddressReply); err != nil {
return err
}
@@ -349,6 +368,7 @@ func (vpp *VppInstance) createTap(
}
upReply := &interfaces.SwInterfaceSetFlagsReply{}
+ vpp.getSuite().log("set tap interface " + tap.Name() + " up")
if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil {
return err
}
@@ -360,7 +380,6 @@ func (vpp *VppInstance) saveLogs() {
logTarget := vpp.container.getLogDirPath() + "vppinstance-" + vpp.container.name + ".log"
logSource := vpp.container.getHostWorkDir() + defaultLogFilePath
cmd := exec.Command("cp", logSource, logTarget)
- vpp.getSuite().T().Helper()
vpp.getSuite().log(cmd.String())
cmd.Run()
}
diff --git a/extras/scripts/crcchecker.py b/extras/scripts/crcchecker.py
index 01cb02523d0..7dcdb681e18 100755
--- a/extras/scripts/crcchecker.py
+++ b/extras/scripts/crcchecker.py
@@ -82,13 +82,15 @@ def filelist_from_git_ls():
def is_uncommitted_changes():
"""Returns true if there are uncommitted changes in the repo"""
- git_status = "git status --porcelain -uno"
- returncode = run(git_status.split(), stdout=PIPE, stderr=PIPE)
- if returncode.returncode != 0:
- sys.exit(returncode.returncode)
-
- if returncode.stdout:
- return True
+ # Don't run this check in the Jenkins CI
+ if os.getenv("FDIOTOOLS_IMAGE") is None:
+ git_status = "git status --porcelain -uno"
+ returncode = run(git_status.split(), stdout=PIPE, stderr=PIPE)
+ if returncode.returncode != 0:
+ sys.exit(returncode.returncode)
+
+ if returncode.stdout:
+ return True
return False