diff --git a/.gitignore b/.gitignore index 5b20e10799..963a9da9bf 100644 --- a/.gitignore +++ b/.gitignore @@ -137,15 +137,25 @@ compile_commands.json **/test-run-*-*-* # host stack test framework -/extras/hs-test/vpp-data -/extras/hs-test/hs-test -/extras/hs-test/http_server -/extras/hs-test/.build.ok -/extras/hs-test/.build.cov.ok -/extras/hs-test/.last_hst_ppid -/extras/hs-test/.goimports.ok -/extras/hs-test/summary/ -/extras/hs-test/.last_state_hash +/test-c/hs-test/vpp-data +/test-c/hs-test/hs-test +/test-c/hs-test/http_server +/test-c/hs-test/.build.ok +/test-c/hs-test/.build.cov.ok +/test-c/hs-test/.last_hst_ppid +/test-c/hs-test/summary/ +/test-c/hs-test/.last_state_hash +/test-c/hs-test/.go_cache/ + +# kube-test +/test-c/kube-test/vpp-data +/test-c/kube-test/.build.ok +/test-c/kube-test/.last_ppid +/test-c/kube-test/summary/ +/test-c/kube-test/.last_state_hash +/test-c/kube-test/.kube_deps.ok +/test-c/kube-test/kubernetes/calico-config.yaml +/test-c/kube-test/kubernetes/.vars # ./configure /CMakeFiles diff --git a/.gitreview b/.gitreview index 1db08df202..7066c3c32f 100644 --- a/.gitreview +++ b/.gitreview @@ -2,3 +2,4 @@ host=gerrit.fd.io port=29418 project=vpp +defaultbranch=stable/2510 diff --git a/MAINTAINERS b/MAINTAINERS index 01fc7b1bff..b00762ba2b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -890,7 +890,13 @@ I: hs-test M: Florin Coras M: Matus Fabian M: Adrian Villin -F: extras/hs-test +F: test-c/hs-test + +Kube test framework +I: kube-test +M: Florin Coras +M: Adrian Villin +F: test-c/kube-test THE REST I: misc diff --git a/Makefile b/Makefile index d7fce89a16..593ea4e98b 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,10 @@ MACHINE=$(shell uname -m) SUDO?=sudo -E DPDK_CONFIG?=no-pci +ifeq ($(shell test -d /opt/vpp/optional/${MACHINE}/lib64 && echo yes),yes) +VPP_OPT_DEPS_LIBRARY_PATH?=/opt/vpp/optional/${MACHINE}/lib64 +endif + # we prefer clang by default ifeq ($(CC),cc) CC=clang @@ -61,7 +65,11 @@ GDB_ARGS= -ex "handle SIGUSR1 noprint nostop" # We allow Darwin (MacOS) for docs generation; VPP build will still fail. ifneq ($(shell uname),Darwin) OS_ID = $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') +ifeq ($(OS_ID),rhel) +OS_VERSION_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g' | sed -e 's/\..*//') +else OS_VERSION_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') +endif OS_CODENAME = $(shell grep '^VERSION_CODENAME=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') endif @@ -202,6 +210,20 @@ else ifeq ($(OS_ID)-$(OS_VERSION_ID),centos-8) RPM_DEPENDS += infiniband-diags libibumad RPM_DEPENDS += libpcap-devel llvm-toolset RPM_DEPENDS_GROUPS = 'Development Tools' +else ifeq ($(OS_ID)-$(OS_VERSION_ID),rhel-8) + RPM_DEPENDS += yum-utils + RPM_DEPENDS += openssl-devel + RPM_DEPENDS += python3-ply # for vppapigen + RPM_DEPENDS += python36-devel + RPM_DEPENDS += python3-pip + RPM_DEPENDS += python3-virtualenv + RPM_DEPENDS += python3-jsonschema + RPM_DEPENDS += gcc-toolset-9 + RPM_DEPENDS += gcc-toolset-9-libasan-devel + RPM_DEPENDS += cmake + RPM_DEPENDS += llvm-toolset + RPM_DEPENDS += infiniband-diags + RPM_DEPENDS += autoconf automake bison byacc libtool else ifeq ($(OS_ID)-$(OS_VERSION_ID),anolis-8) RPM_DEPENDS += yum-utils RPM_DEPENDS += compat-openssl10 openssl-devel @@ -382,7 +404,7 @@ ifeq ($(filter ubuntu debian linuxmint,$(OS_ID)),$(OS_ID)) exit 0 else ifneq ("$(wildcard /etc/redhat-release)","") @for i in $(RPM_DEPENDS) ; do \ - RPM=$$(basename -s .rpm "$${i##*/}" | cut -d- -f1,2,3,4) ; \ + RPM=$$(basename -s .rpm "$${i##*/}") ; \ MISSING+=$$(rpm -q $$RPM | grep "^package") ; \ done ; \ if [ -n "$$MISSING" ] ; then \ @@ -404,7 +426,11 @@ ifeq ($(filter ubuntu debian linuxmint,$(OS_ID)),$(OS_ID)) @sudo -E apt-get update @sudo -E apt-get $(APT_ARGS) $(CONFIRM) $(FORCE) install $(DEB_DEPENDS) else ifneq ("$(wildcard /etc/redhat-release)","") -ifeq ($(OS_ID),rhel) +ifeq ($(OS_ID)-$(OS_VERSION_ID),rhel-8) + @sudo -E dnf install $(CONFIRM) https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm + @sudo -E dnf install $(CONFIRM) $(RPM_DEPENDS) + @sudo -E debuginfo-install $(CONFIRM) glibc openssl-libs zlib +else ifeq ($(OS_ID)-$(OS_VERSION_ID),rhel-7) @sudo -E yum-config-manager --enable rhel-server-rhscl-7-rpms @sudo -E yum groupinstall $(CONFIRM) $(RPM_DEPENDS_GROUPS) @sudo -E yum install $(CONFIRM) $(RPM_DEPENDS) @@ -554,7 +580,7 @@ test-cov: .PHONY: test-cov-hs test-cov-hs: build-gcov - @$(MAKE) CC=$(CC) -C extras/hs-test test-cov \ + @$(MAKE) CC=$(CC) -C test-c/hs-test test-cov \ VPP_BUILD_DIR=$(BR)/build-vpp_gcov-native/vpp .PHONY: test-cov-post-standalone @@ -592,6 +618,7 @@ cov-merge: -a $(BR)/test-coverage-merged/coverage-filtered1.info -o $(BR)/test-coverage-merged/coverage-merged.info @genhtml $(BR)/test-coverage-merged/coverage-merged.info \ --output-directory $(BR)/test-coverage-merged/html + -@rm -f $(BR)/test-coverage-merged/html/cmd_line @echo "Code coverage report is in $(BR)/test-coverage-merged/html/index.html" .PHONY: test-all @@ -671,7 +698,7 @@ test-wipe-all: .PHONY: test-checkstyle test-checkstyle: @$(MAKE) -C test checkstyle-python-all - @$(MAKE) -C extras/hs-test checkstyle-go + @$(MAKE) -C test-c/hs-test checkstyle-go # Note: All python venv consolidated in test/Makefile, test/requirements*.txt .PHONY: test-checkstyle-diff @@ -714,12 +741,12 @@ define run @echo "WARNING: STARTUP_CONF not defined or file doesn't exist." @echo " Running with minimal startup config: $(MINIMAL_STARTUP_CONF)\n" @cd $(STARTUP_DIR) && \ - $(SUDO) $(2) $(1)/vpp/bin/vpp $(MINIMAL_STARTUP_CONF) + $(SUDO) LD_LIBRARY_PATH=$(VPP_OPT_DEPS_LIBRARY_PATH) $(2) $(1)/vpp/bin/vpp $(MINIMAL_STARTUP_CONF) endef else define run @cd $(STARTUP_DIR) && \ - $(SUDO) $(2) $(1)/vpp/bin/vpp $(shell cat $(STARTUP_CONF) | sed -e 's/#.*//') + $(SUDO) LD_LIBRARY_PATH=$(VPP_OPT_DEPS_LIBRARY_PATH) $(2) $(1)/vpp/bin/vpp $(shell cat $(STARTUP_CONF) | sed -e 's/#.*//') endef endif @@ -812,7 +839,11 @@ go-api-files: json-api-files .PHONY: cleanup-hst cleanup-hst: - $(MAKE) -C extras/hs-test cleanup-hst + $(MAKE) -C test-c/hs-test cleanup-hst + +.PHONY: cleanup-perf +cleanup-perf: + $(MAKE) -C test-c/kube-test cleanup-perf .PHONY: ctags ctags: ctags.files @@ -858,11 +889,13 @@ checkstyle-python: .PHONY: checkstyle-go checkstyle-go: - @$(MAKE) -C extras/hs-test checkstyle-go + @$(MAKE) -C test-c/hs-test checkstyle-go + @$(MAKE) -C test-c/kube-test checkstyle-go .PHONY: fixstyle-go fixstyle-go: - @$(MAKE) -C extras/hs-test fixstyle-go + @$(MAKE) -C test-c/hs-test fixstyle-go + @$(MAKE) -C test-c/kube-test fixstyle-go .PHONY: checkstyle-all checkstyle-all: checkstyle-commit checkstyle checkstyle-python docs-spell checkstyle-go diff --git a/build/external/Makefile b/build/external/Makefile index 5394eccc3c..51064ce8f0 100644 --- a/build/external/Makefile +++ b/build/external/Makefile @@ -16,6 +16,7 @@ PKG_SUFFIX ?= $(shell git log --oneline v$(PKG_VERSION)-rc0.. . | wc -l) include ../build_common.mk include ../packages_common.mk +include packages/daq.mk include packages/ipsec-mb.mk include packages/quicly.mk ifneq ($(shell uname), FreeBSD) @@ -31,16 +32,16 @@ clean: .PHONY: install ifeq ($(shell uname), FreeBSD) -install: $(if $(ARCH_X86_64), ipsec-mb-install) dpdk-install quicly-install +install: $(if $(ARCH_X86_64), ipsec-mb-install) daq-install dpdk-install quicly-install else -install: $(if $(ARCH_X86_64), ipsec-mb-install) dpdk-install rdma-core-install quicly-install xdp-tools-install $(if $(AARCH64), octeon-roc-install) +install: $(if $(ARCH_X86_64), ipsec-mb-install) daq-install dpdk-install rdma-core-install quicly-install xdp-tools-install $(if $(AARCH64), octeon-roc-install) endif # FreeBSD .PHONY: config ifeq ($(shell uname), FreeBSD) -config: $(if $(ARCH_X86_64), ipsec-mb-config) dpdk-config quicly-build +config: daq-config $(if $(ARCH_X86_64), ipsec-mb-config) dpdk-config quicly-build else -config: $(if $(ARCH_X86_64), ipsec-mb-config) dpdk-config rdma-core-config quicly-build +config: daq-config $(if $(ARCH_X86_64), ipsec-mb-config) dpdk-config rdma-core-config quicly-build endif # FreeBSD ############################################################################## diff --git a/build/external/mlx_rdma_dpdk_matrix.txt b/build/external/mlx_rdma_dpdk_matrix.txt index 184a2bede1..6c193e1702 100644 --- a/build/external/mlx_rdma_dpdk_matrix.txt +++ b/build/external/mlx_rdma_dpdk_matrix.txt @@ -2,3 +2,4 @@ rdma=49.0 dpdk=23.11 rdma=51.0 dpdk=24.03 rdma=55.0 dpdk=24.07 rdma=55.0 dpdk=24.11.1 +rdma=58.0 dpdk=25.07 diff --git a/build/external/packages/daq.mk b/build/external/packages/daq.mk new file mode 100644 index 0000000000..f1f5a827ab --- /dev/null +++ b/build/external/packages/daq.mk @@ -0,0 +1,40 @@ +# Copyright (c) 2025 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. + +daq_version := 3.0.21 +daq_tarball := daq-$(daq_version).tar.gz +daq_tarball_sha256sum_3.0.21 := 60ad9405c1c6b75955e0784511b173570a601491ccdb6399da53ca811c446a96 +daq_tarball_sha256sum := $(daq_tarball_sha256sum_$(daq_version)) +daq_tarball_strip_dirs := 1 +daq_url := https://github.com/snort3/libdaq/archive/refs/tags/v$(daq_version).tar.gz + +define daq_config_cmds + @rm -f $(daq_config_log) + @cd ${daq_src_dir} && ./bootstrap > $(daq_config_log) 2>&1 + @cd ${daq_src_dir} && ./configure --prefix='$(daq_install_dir)' --enable-shared --enable-static \ + --disable-bundled-modules \ + CFLAGS='' \ + >> $(daq_config_log) 2>&1 +endef + +define daq_build_cmds + @cd ${daq_src_dir} && $(MAKE) V=1 > $(daq_build_log) +endef + +define daq_install_cmds + @rm -f $(daq_install_log) + @cd ${daq_src_dir} && \ + $(MAKE) install V=1 PREFIX='$(daq_install_dir)' >> $(daq_install_log) +endef + +$(eval $(call package,daq)) diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index da6802e480..9a908c1e1d 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -21,11 +21,11 @@ DPDK_MLX_IBV_LINK ?= static # On most of the systems, default value for max lcores is 128 DPDK_MAX_LCORES ?= -dpdk_version ?= 24.11.1 +dpdk_version ?= 25.07 dpdk_base_url ?= http://fast.dpdk.org/rel dpdk_tarball := dpdk-$(dpdk_version).tar.xz -dpdk_tarball_sha256sum_24.11.1 := bcae7d42c449fc456dfb279feabcbe0599a29bebb2fe2905761e187339d96b8e +dpdk_tarball_sha256sum_25.07 := 6886cbedc350bb8cbef347d10367d6259e36435627fbb27d578adbdc0d3b410d dpdk_tarball_sha256sum := $(dpdk_tarball_sha256sum_$(dpdk_version)) dpdk_url := $(dpdk_base_url)/$(dpdk_tarball) diff --git a/build/external/packages/octeon-roc.mk b/build/external/packages/octeon-roc.mk index 92368390eb..42c917b665 100644 --- a/build/external/packages/octeon-roc.mk +++ b/build/external/packages/octeon-roc.mk @@ -2,9 +2,9 @@ # SPDX-License-Identifier: Apache-2.0 # https://spdx.org/licenses/Apache-2.0.html -octeon-roc_version := 25.05 +octeon-roc_version := 25.09 octeon-roc_tarball := v$(octeon-roc_version).tar.gz -octeon-roc_tarball_sha256sum := fc7c8583e49f76b70fb1da242482fe324e6456c04f17d1a0e8726c28266220c6 +octeon-roc_tarball_sha256sum := 39caf74eded46a01286dfbc6a90f8ddbf76d59764f89a574206afbf51b9d5613 octeon-roc_tarball_strip_dirs := 1 octeon-roc_url := https://github.com/MarvellEmbeddedProcessors/marvell-octeon-roc/archive/refs/tags/$(octeon-roc_tarball) diff --git a/build/external/packages/rdma-core.mk b/build/external/packages/rdma-core.mk index 6107ec815b..1afe56dae7 100644 --- a/build/external/packages/rdma-core.mk +++ b/build/external/packages/rdma-core.mk @@ -23,9 +23,9 @@ RDMA_CORE_DEBUG?=n # 2. Verify that the file build/external/dpdk_mlx_default.sh was generated # and contains 'DPDK_MLX_DEFAULT=y' # -rdma-core_version := 55.0 +rdma-core_version := 58.0 rdma-core_tarball := rdma-core-$(rdma-core_version).tar.gz -rdma-core_tarball_sha256sum_55.0 := 6f8b97267807cdae54845f542ee3d75de80fdc24fe2632f5db1573ecef132d0f +rdma-core_tarball_sha256sum_58.0 := 88d67897b793f42d2004eec2629ab8464e425e058f22afabd29faac0a2f54ce4 rdma-core_tarball_sha256sum := $(rdma-core_tarball_sha256sum_$(rdma-core_version)) rdma-core_tarball_strip_dirs := 1 rdma-core_url := http://github.com/linux-rdma/rdma-core/releases/download/v$(rdma-core_version)/$(rdma-core_tarball) diff --git a/build/external/packages/xdp-tools.mk b/build/external/packages/xdp-tools.mk index 57f5e0ae83..f33c220e5b 100644 --- a/build/external/packages/xdp-tools.mk +++ b/build/external/packages/xdp-tools.mk @@ -12,9 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -xdp-tools_version := 1.2.9 +xdp-tools_version := 1.5.5 xdp-tools_tarball := xdp-tools-$(xdp-tools_version).tar.gz -xdp-tools_tarball_sha256sum_1.2.9 := 3f8d30bd2e00c522103d224014f59a95400144aba1f3b322c6ad473541a0f99e +xdp-tools_tarball_sha256sum_1.5.5 := 9a4339ffc40df178c4ddf919cb2b23585a75b3023517c75e82c4dfb0899249c7 xdp-tools_tarball_sha256sum := $(xdp-tools_tarball_sha256sum_$(xdp-tools_version)) xdp-tools_tarball_strip_dirs := 1 diff --git a/build/external/patches/xdp-tools_1.5.5/0001-libxdp-add-fPIC-with-static-lib-build.patch b/build/external/patches/xdp-tools_1.5.5/0001-libxdp-add-fPIC-with-static-lib-build.patch new file mode 100644 index 0000000000..e0e6050de7 --- /dev/null +++ b/build/external/patches/xdp-tools_1.5.5/0001-libxdp-add-fPIC-with-static-lib-build.patch @@ -0,0 +1,26 @@ +From e83f80443a2f23a68037bf4c7ba16b3723d193a4 Mon Sep 17 00:00:00 2001 +From: Yulong +Date: Tue, 3 Jan 2023 14:16:17 +0000 +Subject: [PATCH] libxdp: add fPIC with static lib build + +Signed-off-by: Yulong +--- + lib/libxdp/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/libxdp/Makefile b/lib/libxdp/Makefile +index 4716fb0..403c2d9 100644 +--- a/lib/libxdp/Makefile ++++ b/lib/libxdp/Makefile +@@ -87,7 +87,7 @@ $(SHARED_OBJDIR): + $(Q)mkdir -p $(SHARED_OBJDIR) + + $(STATIC_OBJDIR)/%.o: %.c $(EXTRA_LIB_DEPS) | $(STATIC_OBJDIR) +- $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(STATIC_CFLAGS) -Wall -I../../headers -c $< -o $@ ++ $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(STATIC_CFLAGS) -fPIC -Wall -I../../headers -c $< -o $@ + + $(SHARED_OBJDIR)/%.o: %.c $(EXTRA_LIB_DEPS) | $(SHARED_OBJDIR) + $(QUIET_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(SHARED_CFLAGS) -Wall -I../../headers -c $< -o $@ +-- +2.25.1 + diff --git a/build/external/patches/xdp-tools_1.5.5/0003-libxdp-fix-maybe-uninitialized-compiler-warning.patch b/build/external/patches/xdp-tools_1.5.5/0003-libxdp-fix-maybe-uninitialized-compiler-warning.patch new file mode 100644 index 0000000000..3927c534f4 --- /dev/null +++ b/build/external/patches/xdp-tools_1.5.5/0003-libxdp-fix-maybe-uninitialized-compiler-warning.patch @@ -0,0 +1,26 @@ +From 3033b9bdbcdb270f15373b27933d554f847e01d4 Mon Sep 17 00:00:00 2001 +From: Yulong +Date: Fri, 6 Jan 2023 14:31:24 +0000 +Subject: [PATCH 3/3] libxdp: fix maybe-uninitialized compiler warning + +Signed-off-by: Yulong +--- + lib/common.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/common.mk b/lib/common.mk +index ce24c48..e964bd8 100644 +--- a/lib/common.mk ++++ b/lib/common.mk +@@ -104,7 +104,7 @@ $(LIB_OBJS): %.o: %.c %.h $(LIB_H) + + ALL_EXEC_TARGETS=$(USER_TARGETS) $(TEST_TARGETS) + $(ALL_EXEC_TARGETS): %: %.c $(OBJECT_LIBBPF) $(OBJECT_LIBXDP) $(LIBMK) $(LIB_OBJS) $(KERN_USER_H) $(EXTRA_DEPS) $(EXTRA_USER_DEPS) $(BPF_SKEL_H) $(USER_EXTRA_C) +- $(QUIET_CC)$(CC) -Wall $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(LIB_OBJS) \ ++ $(QUIET_CC)$(CC) -Wall -Wno-maybe-uninitialized $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(LIB_OBJS) \ + $< $(USER_EXTRA_C) $(LDLIBS) + + $(XDP_OBJ): %.o: %.c $(KERN_USER_H) $(EXTRA_DEPS) $(BPF_HEADERS) $(LIBMK) +-- +2.25.1 + diff --git a/build/optional/packages/openssl.mk b/build/optional/packages/openssl.mk index 1288ab12f6..26a696c707 100644 --- a/build/optional/packages/openssl.mk +++ b/build/optional/packages/openssl.mk @@ -11,9 +11,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -openssl_version := 3.5.0 +openssl_version := 3.5.1 openssl_tarball := openssl-$(openssl_version).tar.gz -openssl_tarball_sha256sum := 344d0a79f1a9b08029b0744e2cc401a43f9c90acd1044d09a530b4885a8e9fc0 +openssl_tarball_sha256sum := 529043b15cffa5f36077a4d0af83f3de399807181d607441d734196d889b641f openssl_tarball_strip_dirs := 1 openssl_url := https://github.com/openssl/openssl/releases/download/openssl-$(openssl_version)/$(openssl_tarball) diff --git a/configure b/configure index 444ed3c063..b28b3b1009 100755 --- a/configure +++ b/configure @@ -34,6 +34,7 @@ OPTIONS: --native-only, -n Only compile for Native CPU (no multiarch) --option, -o Enable specific VPP options (fib8, fib16) --platform, -p Specify target platform + --plugins, -P Specify list of plugins to be built --prefix, -r Specify prefix path (default: $prefix_path) --sanitize, -s Enable sanitizer (mem) --verbose, -v Verbose output of this script @@ -92,6 +93,15 @@ while (( "$#" )); do exit 1 fi ;; + -P|--plugins) + if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then + plugins=$2 + shift 2 + else + echo "Error: Argument for $1 is missing" >&2 + exit 1 + fi + ;; -r|--prefix) if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then prefix_path=$2 @@ -169,6 +179,8 @@ $native_only && args+=("-DVPP_BUILD_NATIVE_ONLY:BOOL=ON") $wipe && git clean -fdx --exclude=startup.\* +[[ -v plugins ]] && args+=("-DVPP_PLUGINS=${plugins}") + ( $verbose && set -o xtrace cmake ${args[@]} -G Ninja -S ${src_dir}/src -B ${build_dir} diff --git a/docs/aboutvpp/releasenotes/index.rst b/docs/aboutvpp/releasenotes/index.rst index 1c3097288b..8f2f16dd86 100644 --- a/docs/aboutvpp/releasenotes/index.rst +++ b/docs/aboutvpp/releasenotes/index.rst @@ -6,6 +6,8 @@ Release notes .. toctree:: :maxdepth: 2 + v25.10 + v25.06 v25.02 v24.10 v24.06 diff --git a/docs/aboutvpp/releasenotes/v25.06.rst b/docs/aboutvpp/releasenotes/v25.06.rst new file mode 100644 index 0000000000..23a7b7d91c --- /dev/null +++ b/docs/aboutvpp/releasenotes/v25.06.rst @@ -0,0 +1,540 @@ +Release notes for VPP 25.06 +=========================== + +More than 260 commits since the previous release, including 92 fixes. + +Features +-------- + +- Build System + + - Update VPP-opt-deps to openssl 3.5.0 (`8a5a8de71 `_) + +- Host stack test framework + + - Added basic performance testing infra (`7cd37a9d8 `_) + +- Plugins + + - HTTP + + - Hpack primitive types (`5985e8683 `_) + - Hpack headers decoding (`58b6c4e6b `_) + - Hpack headers encoding (`a013224b9 `_) + - Http2 frames (`86abfc3e0 `_) + - Http/2 core skeleton (`492d2c15d `_) + - Http/2 stream state machine (`24668f2a3 `_) + - Http/2 starting tcp connection (`b43c7090f `_) + - Http/2 flow control (`ad5159837 `_) + - Http/2 multiplexing (`2d6b545f2 `_) + + - Host Stack Applications + + - Http client parallel sessions (`c8174f366 `_) + + - Marvell Octeon device driver + + - Set cpt descriptor count to 16k (`803eac3ef `_) + - Flush CQ buffers on stop (`c8d431ea2 `_) + - Update roc version (`2eb3240d1 `_) + - Configure max npa pools using driver arg (`06df0ac7a `_) + + - QUIC protocol + + - Quic engine api (`a94fab2fb `_) + + - Http\_static + + - Support multiple listeners (`0a897eb8d `_) + +- VNET + + - Crypto Infra + + - Make configurable crypto engines (`f479eeb76 `_) + - Add support for aes-cbc with hmac (`fba37eea8 `_) + - Add new handlers for cbc/ctr+hmac (`659b78d46 `_) + + - IPSec + + - Add support for bypass and discard policies for ipv6 (`9ab79f54d `_) + - Enable support for ipv6 udp ipsec encapsulation in policy mode (`0b04d71ce `_) + + - New Device Drivers Infra + + - Add support to configure driver arguments (`0e811a0d4 `_) + + - Session Layer + + - Add session eventing infra for apps (`9ed4013fd `_) + + - TLS and TLS engine plugins + + - Add ALPN support (`0b039ae97 `_) + +- Vector Library + + - Add new node type - SCHED nodes (`8a5add5c0 `_) + - Add 'relative' keyword for cpu configuration (`9b2015150 `_) + + +Known issues +------------ + +For the full list of issues please refer to fd.io `JIRA `_. + +Fixed issues +------------ + +For the full list of fixed issues please refer to: +- fd.io `JIRA `_ +- git `commit log `_ + + +API changes +----------- + +Description of results: + +- *Definition changed*: indicates that the API file was modified between releases. +- *Only in image*: indicates the API is new for this release. +- *Only in file*: indicates the API has been removed in this release. + +============================================================= ================== +Message Name Result +============================================================= ================== +feature_is_enabled only in image +feature_is_enabled_reply only in image +http_static_enable_v2 only in file +http_static_enable_v2_reply only in file +http_static_enable_v3 only in file +http_static_enable_v3_reply only in file +http_static_enable_v4 only in image +http_static_enable_v4_reply only in image +http_static_enable_v5 only in image +http_static_enable_v5_reply only in image +ip_session_redirect_details only in image +ip_session_redirect_dump only in image +pnat_flow_lookup only in image +pnat_flow_lookup_reply only in image +============================================================= ================== + +Found 14 api message signature differences + + +Newly deprecated API messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These messages are still there in the API, but can and probably +will disappear in the next release. + +- http_static_enable_v4 +- http_static_enable_v4_reply + +In-progress API messages +~~~~~~~~~~~~~~~~~~~~~~~~ + +These messages are provided for testing and experimentation only. +They are *not* subject to any compatibility process, +and therefore can arbitrarily change or disappear at *any* moment. +Also they may have less than satisfactory testing, making +them unsuitable for other use than the technology preview. +If you are intending to use these messages in production projects, +please collaborate with the feature maintainer on their productization. + +- abf_itf_attach_add_del +- abf_itf_attach_add_del_reply +- abf_itf_attach_details +- abf_itf_attach_dump +- abf_plugin_get_version +- abf_plugin_get_version_reply +- abf_policy_add_del +- abf_policy_add_del_reply +- abf_policy_details +- abf_policy_dump +- acl_plugin_use_hash_lookup_get +- acl_plugin_use_hash_lookup_get_reply +- acl_plugin_use_hash_lookup_set +- acl_plugin_use_hash_lookup_set_reply +- bpf_trace_filter_set +- bpf_trace_filter_set_reply +- bpf_trace_filter_set_v2 +- bpf_trace_filter_set_v2_reply +- cnat_get_snat_addresses +- cnat_get_snat_addresses_reply +- cnat_session_details +- cnat_session_dump +- cnat_session_purge +- cnat_session_purge_reply +- cnat_set_snat_addresses +- cnat_set_snat_addresses_reply +- cnat_set_snat_policy +- cnat_set_snat_policy_reply +- cnat_snat_policy_add_del_exclude_pfx +- cnat_snat_policy_add_del_exclude_pfx_reply +- cnat_snat_policy_add_del_if +- cnat_snat_policy_add_del_if_reply +- cnat_translation_del +- cnat_translation_del_reply +- cnat_translation_details +- cnat_translation_dump +- cnat_translation_update +- cnat_translation_update_reply +- det44_get_timeouts_reply +- det44_set_timeouts +- det44_set_timeouts_reply +- dev_attach +- dev_attach_reply +- dev_create_port_if +- dev_create_port_if_reply +- dev_detach +- dev_detach_reply +- dev_remove_port_if +- dev_remove_port_if_reply +- flowprobe_get_params +- flowprobe_get_params_reply +- flowprobe_interface_add_del +- flowprobe_interface_add_del_reply +- flowprobe_interface_details +- flowprobe_interface_dump +- flowprobe_set_params +- flowprobe_set_params_reply +- gbp_bridge_domain_add +- gbp_bridge_domain_add_reply +- gbp_bridge_domain_del +- gbp_bridge_domain_del_reply +- gbp_bridge_domain_details +- gbp_bridge_domain_dump +- gbp_bridge_domain_dump_reply +- gbp_contract_add_del +- gbp_contract_add_del_reply +- gbp_contract_details +- gbp_contract_dump +- gbp_endpoint_add +- gbp_endpoint_add_reply +- gbp_endpoint_del +- gbp_endpoint_del_reply +- gbp_endpoint_details +- gbp_endpoint_dump +- gbp_endpoint_group_add +- gbp_endpoint_group_add_reply +- gbp_endpoint_group_del +- gbp_endpoint_group_del_reply +- gbp_endpoint_group_details +- gbp_endpoint_group_dump +- gbp_ext_itf_add_del +- gbp_ext_itf_add_del_reply +- gbp_ext_itf_details +- gbp_ext_itf_dump +- gbp_recirc_add_del +- gbp_recirc_add_del_reply +- gbp_recirc_details +- gbp_recirc_dump +- gbp_route_domain_add +- gbp_route_domain_add_reply +- gbp_route_domain_del +- gbp_route_domain_del_reply +- gbp_route_domain_details +- gbp_route_domain_dump +- gbp_route_domain_dump_reply +- gbp_subnet_add_del +- gbp_subnet_add_del_reply +- gbp_subnet_details +- gbp_subnet_dump +- gbp_vxlan_tunnel_add +- gbp_vxlan_tunnel_add_reply +- gbp_vxlan_tunnel_del +- gbp_vxlan_tunnel_del_reply +- gbp_vxlan_tunnel_details +- gbp_vxlan_tunnel_dump +- gtpu_add_del_forward +- gtpu_add_del_forward_reply +- gtpu_add_del_tunnel_v2 +- gtpu_add_del_tunnel_v2_reply +- gtpu_get_transfer_counts +- gtpu_get_transfer_counts_reply +- gtpu_tunnel_v2_details +- gtpu_tunnel_v2_dump +- ikev2_child_sa_v2_details +- ikev2_child_sa_v2_dump +- ikev2_initiate_del_child_sa +- ikev2_initiate_del_child_sa_reply +- ikev2_initiate_del_ike_sa +- ikev2_initiate_del_ike_sa_reply +- ikev2_initiate_rekey_child_sa +- ikev2_initiate_rekey_child_sa_reply +- ikev2_initiate_sa_init +- ikev2_initiate_sa_init_reply +- ikev2_nonce_get +- ikev2_nonce_get_reply +- ikev2_profile_add_del +- ikev2_profile_add_del_reply +- ikev2_profile_details +- ikev2_profile_disable_natt +- ikev2_profile_disable_natt_reply +- ikev2_profile_dump +- ikev2_profile_set_auth +- ikev2_profile_set_auth_reply +- ikev2_profile_set_id +- ikev2_profile_set_id_reply +- ikev2_profile_set_ipsec_udp_port +- ikev2_profile_set_ipsec_udp_port_reply +- ikev2_profile_set_liveness +- ikev2_profile_set_liveness_reply +- ikev2_profile_set_ts +- ikev2_profile_set_ts_reply +- ikev2_profile_set_udp_encap +- ikev2_profile_set_udp_encap_reply +- ikev2_sa_v3_details +- ikev2_sa_v3_dump +- ikev2_set_esp_transforms +- ikev2_set_esp_transforms_reply +- ikev2_set_ike_transforms +- ikev2_set_ike_transforms_reply +- ikev2_set_local_key +- ikev2_set_local_key_reply +- ikev2_set_responder +- ikev2_set_responder_hostname +- ikev2_set_responder_hostname_reply +- ikev2_set_responder_reply +- ikev2_set_sa_lifetime +- ikev2_set_sa_lifetime_reply +- ikev2_set_tunnel_interface +- ikev2_set_tunnel_interface_reply +- ikev2_traffic_selector_details +- ikev2_traffic_selector_dump +- ip_neighbor_config_get +- ip_neighbor_config_get_reply +- ip_route_add_del_v2 +- ip_route_add_del_v2_reply +- ip_route_lookup_v2 +- ip_route_lookup_v2_reply +- ip_route_v2_details +- ip_route_v2_dump +- ip_session_redirect_add +- ip_session_redirect_add_reply +- ip_session_redirect_add_v2 +- ip_session_redirect_add_v2_reply +- ip_session_redirect_del +- ip_session_redirect_del_reply +- ip_session_redirect_details +- ip_session_redirect_dump +- l2_emulation +- l2_emulation_reply +- lcp_default_ns_get_reply +- lcp_default_ns_set +- lcp_default_ns_set_reply +- lcp_itf_pair_add_del_v2 +- lcp_itf_pair_add_del_v2_reply +- lcp_itf_pair_add_del_v3 +- lcp_itf_pair_add_del_v3_reply +- lcp_itf_pair_details +- lldp_details +- mdata_enable_disable +- mdata_enable_disable_reply +- nat44_ed_vrf_tables_v2_details +- nat44_ed_vrf_tables_v2_dump +- nat44_ei_add_del_address_range +- nat44_ei_add_del_address_range_reply +- nat44_ei_add_del_static_mapping +- nat44_ei_add_del_static_mapping_reply +- nat44_ei_address_details +- nat44_ei_address_dump +- nat44_ei_del_session +- nat44_ei_del_session_reply +- nat44_ei_del_user +- nat44_ei_del_user_reply +- nat44_ei_forwarding_enable_disable +- nat44_ei_forwarding_enable_disable_reply +- nat44_ei_ha_flush +- nat44_ei_ha_flush_reply +- nat44_ei_ha_resync +- nat44_ei_ha_resync_completed_event +- nat44_ei_ha_resync_reply +- nat44_ei_ha_set_failover +- nat44_ei_ha_set_failover_reply +- nat44_ei_ha_set_listener +- nat44_ei_ha_set_listener_reply +- nat44_ei_interface_add_del_feature +- nat44_ei_interface_add_del_feature_reply +- nat44_ei_interface_details +- nat44_ei_interface_dump +- nat44_ei_ipfix_enable_disable +- nat44_ei_ipfix_enable_disable_reply +- nat44_ei_plugin_enable_disable +- nat44_ei_plugin_enable_disable_reply +- nat44_ei_set_addr_and_port_alloc_alg +- nat44_ei_set_addr_and_port_alloc_alg_reply +- nat44_ei_set_fq_options +- nat44_ei_set_fq_options_reply +- nat44_ei_set_mss_clamping +- nat44_ei_set_mss_clamping_reply +- nat44_ei_set_timeouts +- nat44_ei_set_timeouts_reply +- nat44_ei_set_workers +- nat44_ei_set_workers_reply +- nat44_ei_show_fq_options +- nat44_ei_show_fq_options_reply +- nat44_ei_show_running_config +- nat44_ei_show_running_config_reply +- nat44_ei_static_mapping_details +- nat44_ei_static_mapping_dump +- nat44_ei_user_details +- nat44_ei_user_dump +- nat44_ei_user_session_details +- nat44_ei_user_session_dump +- nat44_ei_user_session_v2_details +- nat44_ei_user_session_v2_dump +- nat44_ei_worker_details +- nat44_ei_worker_dump +- nat64_plugin_enable_disable +- nat64_plugin_enable_disable_reply +- npt66_binding_add_del +- npt66_binding_add_del_reply +- oddbuf_enable_disable +- oddbuf_enable_disable_reply +- pg_interface_enable_disable_coalesce +- pg_interface_enable_disable_coalesce_reply +- ping_finished_event +- pnat_binding_add +- pnat_binding_add_reply +- pnat_binding_add_v2 +- pnat_binding_add_v2_reply +- pnat_binding_attach +- pnat_binding_attach_reply +- pnat_binding_del +- pnat_binding_del_reply +- pnat_binding_detach +- pnat_binding_detach_reply +- pnat_bindings_details +- pnat_bindings_get +- pnat_bindings_get_reply +- pnat_flow_lookup +- pnat_flow_lookup_reply +- pnat_interfaces_details +- pnat_interfaces_get +- pnat_interfaces_get_reply +- pvti_interface_create +- pvti_interface_create_reply +- pvti_interface_delete +- pvti_interface_delete_reply +- pvti_interface_details +- pvti_interface_dump +- sample_macswap_enable_disable +- sample_macswap_enable_disable_reply +- set_ip_flow_hash_v3 +- set_ip_flow_hash_v3_reply +- sflow_enable_disable +- sflow_enable_disable_reply +- sflow_header_bytes_get +- sflow_header_bytes_get_reply +- sflow_header_bytes_set +- sflow_header_bytes_set_reply +- sflow_interface_details +- sflow_interface_dump +- sflow_polling_interval_get +- sflow_polling_interval_get_reply +- sflow_polling_interval_set +- sflow_polling_interval_set_reply +- sflow_sampling_rate_get +- sflow_sampling_rate_get_reply +- sflow_sampling_rate_set +- sflow_sampling_rate_set_reply +- sr_localsids_with_packet_stats_details +- sr_localsids_with_packet_stats_dump +- sr_mobile_localsid_add_del +- sr_mobile_localsid_add_del_reply +- sr_mobile_policy_add +- sr_mobile_policy_add_reply +- sr_policies_with_sl_index_details +- sr_policies_with_sl_index_dump +- sr_policy_add_v2 +- sr_policy_add_v2_reply +- sr_policy_mod_v2 +- sr_policy_mod_v2_reply +- sw_interface_ip6nd_ra_details +- sw_interface_ip6nd_ra_dump +- sw_interface_set_vxlan_gbp_bypass +- sw_interface_set_vxlan_gbp_bypass_reply +- test_addresses +- test_addresses2 +- test_addresses2_reply +- test_addresses3 +- test_addresses3_reply +- test_addresses_reply +- test_empty +- test_empty_reply +- test_enum +- test_enum_reply +- test_interface +- test_interface_reply +- test_prefix +- test_prefix_reply +- test_string +- test_string2 +- test_string2_reply +- test_string_reply +- test_vla +- test_vla2 +- test_vla2_reply +- test_vla3 +- test_vla3_reply +- test_vla4 +- test_vla4_reply +- test_vla5 +- test_vla5_reply +- test_vla_reply +- trace_capture_packets +- trace_capture_packets_reply +- trace_clear_cache +- trace_clear_cache_reply +- trace_clear_capture +- trace_clear_capture_reply +- trace_details +- trace_dump +- trace_dump_reply +- trace_filter_function_details +- trace_filter_function_dump +- trace_set_filter_function +- trace_set_filter_function_reply +- trace_set_filters +- trace_set_filters_reply +- trace_v2_details +- trace_v2_dump +- tracenode_enable_disable +- tracenode_enable_disable_reply +- vxlan_gbp_tunnel_add_del +- vxlan_gbp_tunnel_add_del_reply +- vxlan_gbp_tunnel_details +- vxlan_gbp_tunnel_dump +- want_ping_finished_events +- want_ping_finished_events_reply + +Patches that changed API definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +``src/vnet/feature/feature.api`` + +* `6022e9566 `_ vnet: add vapi interface feature enablement check function + +``src/plugins/linux-cp/lcp.api`` + +* `9543e2970 `_ linux-cp: Add support for LACP packets + +``src/plugins/nat/pnat/pnat.api`` + +* `406232920 `_ pnat: expose binding_index over API + +``src/plugins/vxlan-gpe/vxlan_gpe.api`` + +* `bb4858cdf `_ vxlan: move vxlan-gpe to a plugin + +``src/plugins/http_static/http_static.api`` + +* `c3bbeb93b `_ http_static: url handler buffer large POST body +* `5e94895df `_ http_static: introduce max-body-size parameter + +``src/plugins/ip_session_redirect/ip_session_redirect.api`` + +* `eca860c85 `_ ip_session_redirect: add dump api for session redirects diff --git a/docs/aboutvpp/releasenotes/v25.10.rst b/docs/aboutvpp/releasenotes/v25.10.rst new file mode 100644 index 0000000000..0e72ff7452 --- /dev/null +++ b/docs/aboutvpp/releasenotes/v25.10.rst @@ -0,0 +1,527 @@ +Release notes for VPP 25.10 +=========================== + +More than 322 commits since the previous release, including 129 fixes. + +Features +-------- + +- Build System + + - Update octeon-roc version (`fe4ff09ad `_) + +- Plugins + + - AF\_XDP driver + + - Bump xdp-tools to 1.5.5 (`d21309c22 `_) + + - DPDK + + - Bump to DPDK 25.07 and rdma-core 58.0 (`6a038c3aa `_) + + - HTTP + + - Http/2 connect method (`4d9e8e6b3 `_) + - Implement HTTP PUT method (`897615764 `_) + - Http/2 extended connect method (`2eb0e479b `_) + - Tunneling UDP over HTTP/2 (`f72488b32 `_) + - Http2 client side (`b6cc662e4 `_) + + - Marvell Octeon device driver + + - Add L4 checksum flags (`273d20cd7 `_) + + - Snort plugin + + - Plugin rework (`e070068b7 `_) + +- VNET + + - GRE + + - Add support for GRE keys in the GRE plugin (`74cf96576 `_) + + - Native Virtio Drivers + + - Add option to set interface name (`84f09f471 `_) + + - Session Layer + + - Set maximum memory for fifos (`7a08d9200 `_) + - Session\_cb\_vft add proxy\_write\_early\_data (`73354a241 `_) + - Add support for configurable trusted cas (`3012d1b8a `_) + + - TAP Drivers + + - Add option to specify interface name (`f2223b6fc `_) + + - UDP + + - Add input nolookup node (`32a2287ba `_) + + +Known issues +------------ + +For the full list of issues please refer to fd.io `GitHub mirror `_. + +Fixed issues +------------ + +For the full list of fixed issues please refer to: +- git `commit log `_ + + +API changes +----------- + +Description of results: + +- *Definition changed*: indicates that the API file was modified between releases. +- *Only in image*: indicates the API is new for this release. +- *Only in file*: indicates the API has been removed in this release. + +============================================================= ================== +Message Name Result +============================================================= ================== +bfd_udp_get_tos only in image +bfd_udp_get_tos_reply only in image +bfd_udp_set_tos only in image +bfd_udp_set_tos_reply only in image +gre_tunnel_add_del_v2 only in image +gre_tunnel_add_del_v2_reply only in image +gre_tunnel_details_v2 only in image +gre_tunnel_dump_reply only in image +gre_tunnel_dump_v2 only in image +gre_tunnel_dump_v2_reply only in image +pg_create_interface_v3 only in image +pg_create_interface_v3_reply only in image +sflow_direction_get only in image +sflow_direction_get_reply only in image +sflow_direction_set only in image +sflow_direction_set_reply only in image +sflow_drop_monitoring_get only in image +sflow_drop_monitoring_get_reply only in image +sflow_drop_monitoring_set only in image +sflow_drop_monitoring_set_reply only in image +============================================================= ================== + +Found 20 api message signature differences + + +Newly deprecated API messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These messages are still there in the API, but can and probably +will disappear in the next release. + +- pg_create_interface_v2 +- pg_create_interface_v2_reply + +In-progress API messages +~~~~~~~~~~~~~~~~~~~~~~~~ + +These messages are provided for testing and experimentation only. +They are *not* subject to any compatibility process, +and therefore can arbitrarily change or disappear at *any* moment. +Also they may have less than satisfactory testing, making +them unsuitable for other use than the technology preview. +If you are intending to use these messages in production projects, +please collaborate with the feature maintainer on their productization. + +- abf_itf_attach_add_del +- abf_itf_attach_add_del_reply +- abf_itf_attach_details +- abf_itf_attach_dump +- abf_plugin_get_version +- abf_plugin_get_version_reply +- abf_policy_add_del +- abf_policy_add_del_reply +- abf_policy_details +- abf_policy_dump +- acl_plugin_use_hash_lookup_get +- acl_plugin_use_hash_lookup_get_reply +- acl_plugin_use_hash_lookup_set +- acl_plugin_use_hash_lookup_set_reply +- bpf_trace_filter_set +- bpf_trace_filter_set_reply +- bpf_trace_filter_set_v2 +- bpf_trace_filter_set_v2_reply +- cnat_get_snat_addresses +- cnat_get_snat_addresses_reply +- cnat_session_details +- cnat_session_dump +- cnat_session_purge +- cnat_session_purge_reply +- cnat_set_snat_addresses +- cnat_set_snat_addresses_reply +- cnat_set_snat_policy +- cnat_set_snat_policy_reply +- cnat_snat_policy_add_del_exclude_pfx +- cnat_snat_policy_add_del_exclude_pfx_reply +- cnat_snat_policy_add_del_if +- cnat_snat_policy_add_del_if_reply +- cnat_translation_del +- cnat_translation_del_reply +- cnat_translation_details +- cnat_translation_dump +- cnat_translation_update +- cnat_translation_update_reply +- det44_get_timeouts_reply +- det44_set_timeouts +- det44_set_timeouts_reply +- dev_attach +- dev_attach_reply +- dev_create_port_if +- dev_create_port_if_reply +- dev_detach +- dev_detach_reply +- dev_remove_port_if +- dev_remove_port_if_reply +- flowprobe_get_params +- flowprobe_get_params_reply +- flowprobe_interface_add_del +- flowprobe_interface_add_del_reply +- flowprobe_interface_details +- flowprobe_interface_dump +- flowprobe_set_params +- flowprobe_set_params_reply +- gbp_bridge_domain_add +- gbp_bridge_domain_add_reply +- gbp_bridge_domain_del +- gbp_bridge_domain_del_reply +- gbp_bridge_domain_details +- gbp_bridge_domain_dump +- gbp_bridge_domain_dump_reply +- gbp_contract_add_del +- gbp_contract_add_del_reply +- gbp_contract_details +- gbp_contract_dump +- gbp_endpoint_add +- gbp_endpoint_add_reply +- gbp_endpoint_del +- gbp_endpoint_del_reply +- gbp_endpoint_details +- gbp_endpoint_dump +- gbp_endpoint_group_add +- gbp_endpoint_group_add_reply +- gbp_endpoint_group_del +- gbp_endpoint_group_del_reply +- gbp_endpoint_group_details +- gbp_endpoint_group_dump +- gbp_ext_itf_add_del +- gbp_ext_itf_add_del_reply +- gbp_ext_itf_details +- gbp_ext_itf_dump +- gbp_recirc_add_del +- gbp_recirc_add_del_reply +- gbp_recirc_details +- gbp_recirc_dump +- gbp_route_domain_add +- gbp_route_domain_add_reply +- gbp_route_domain_del +- gbp_route_domain_del_reply +- gbp_route_domain_details +- gbp_route_domain_dump +- gbp_route_domain_dump_reply +- gbp_subnet_add_del +- gbp_subnet_add_del_reply +- gbp_subnet_details +- gbp_subnet_dump +- gbp_vxlan_tunnel_add +- gbp_vxlan_tunnel_add_reply +- gbp_vxlan_tunnel_del +- gbp_vxlan_tunnel_del_reply +- gbp_vxlan_tunnel_details +- gbp_vxlan_tunnel_dump +- gtpu_add_del_forward +- gtpu_add_del_forward_reply +- gtpu_add_del_tunnel_v2 +- gtpu_add_del_tunnel_v2_reply +- gtpu_get_transfer_counts +- gtpu_get_transfer_counts_reply +- gtpu_tunnel_v2_details +- gtpu_tunnel_v2_dump +- ikev2_child_sa_v2_details +- ikev2_child_sa_v2_dump +- ikev2_initiate_del_child_sa +- ikev2_initiate_del_child_sa_reply +- ikev2_initiate_del_ike_sa +- ikev2_initiate_del_ike_sa_reply +- ikev2_initiate_rekey_child_sa +- ikev2_initiate_rekey_child_sa_reply +- ikev2_initiate_sa_init +- ikev2_initiate_sa_init_reply +- ikev2_nonce_get +- ikev2_nonce_get_reply +- ikev2_profile_add_del +- ikev2_profile_add_del_reply +- ikev2_profile_details +- ikev2_profile_disable_natt +- ikev2_profile_disable_natt_reply +- ikev2_profile_dump +- ikev2_profile_set_auth +- ikev2_profile_set_auth_reply +- ikev2_profile_set_id +- ikev2_profile_set_id_reply +- ikev2_profile_set_ipsec_udp_port +- ikev2_profile_set_ipsec_udp_port_reply +- ikev2_profile_set_liveness +- ikev2_profile_set_liveness_reply +- ikev2_profile_set_ts +- ikev2_profile_set_ts_reply +- ikev2_profile_set_udp_encap +- ikev2_profile_set_udp_encap_reply +- ikev2_sa_v3_details +- ikev2_sa_v3_dump +- ikev2_set_esp_transforms +- ikev2_set_esp_transforms_reply +- ikev2_set_ike_transforms +- ikev2_set_ike_transforms_reply +- ikev2_set_local_key +- ikev2_set_local_key_reply +- ikev2_set_responder +- ikev2_set_responder_hostname +- ikev2_set_responder_hostname_reply +- ikev2_set_responder_reply +- ikev2_set_sa_lifetime +- ikev2_set_sa_lifetime_reply +- ikev2_set_tunnel_interface +- ikev2_set_tunnel_interface_reply +- ikev2_traffic_selector_details +- ikev2_traffic_selector_dump +- ip_neighbor_config_get +- ip_neighbor_config_get_reply +- ip_route_add_del_v2 +- ip_route_add_del_v2_reply +- ip_route_lookup_v2 +- ip_route_lookup_v2_reply +- ip_route_v2_details +- ip_route_v2_dump +- ip_session_redirect_add +- ip_session_redirect_add_reply +- ip_session_redirect_add_v2 +- ip_session_redirect_add_v2_reply +- ip_session_redirect_del +- ip_session_redirect_del_reply +- ip_session_redirect_details +- ip_session_redirect_dump +- l2_emulation +- l2_emulation_reply +- lcp_default_ns_get_reply +- lcp_default_ns_set +- lcp_default_ns_set_reply +- lcp_itf_pair_add_del_v2 +- lcp_itf_pair_add_del_v2_reply +- lcp_itf_pair_add_del_v3 +- lcp_itf_pair_add_del_v3_reply +- lcp_itf_pair_details +- lldp_details +- mdata_enable_disable +- mdata_enable_disable_reply +- nat44_ed_vrf_tables_v2_details +- nat44_ed_vrf_tables_v2_dump +- nat44_ei_add_del_address_range +- nat44_ei_add_del_address_range_reply +- nat44_ei_add_del_static_mapping +- nat44_ei_add_del_static_mapping_reply +- nat44_ei_address_details +- nat44_ei_address_dump +- nat44_ei_del_session +- nat44_ei_del_session_reply +- nat44_ei_del_user +- nat44_ei_del_user_reply +- nat44_ei_forwarding_enable_disable +- nat44_ei_forwarding_enable_disable_reply +- nat44_ei_ha_flush +- nat44_ei_ha_flush_reply +- nat44_ei_ha_resync +- nat44_ei_ha_resync_completed_event +- nat44_ei_ha_resync_reply +- nat44_ei_ha_set_failover +- nat44_ei_ha_set_failover_reply +- nat44_ei_ha_set_listener +- nat44_ei_ha_set_listener_reply +- nat44_ei_interface_add_del_feature +- nat44_ei_interface_add_del_feature_reply +- nat44_ei_interface_details +- nat44_ei_interface_dump +- nat44_ei_ipfix_enable_disable +- nat44_ei_ipfix_enable_disable_reply +- nat44_ei_plugin_enable_disable +- nat44_ei_plugin_enable_disable_reply +- nat44_ei_set_addr_and_port_alloc_alg +- nat44_ei_set_addr_and_port_alloc_alg_reply +- nat44_ei_set_fq_options +- nat44_ei_set_fq_options_reply +- nat44_ei_set_mss_clamping +- nat44_ei_set_mss_clamping_reply +- nat44_ei_set_timeouts +- nat44_ei_set_timeouts_reply +- nat44_ei_set_workers +- nat44_ei_set_workers_reply +- nat44_ei_show_fq_options +- nat44_ei_show_fq_options_reply +- nat44_ei_show_running_config +- nat44_ei_show_running_config_reply +- nat44_ei_static_mapping_details +- nat44_ei_static_mapping_dump +- nat44_ei_user_details +- nat44_ei_user_dump +- nat44_ei_user_session_details +- nat44_ei_user_session_dump +- nat44_ei_user_session_v2_details +- nat44_ei_user_session_v2_dump +- nat44_ei_worker_details +- nat44_ei_worker_dump +- nat64_plugin_enable_disable +- nat64_plugin_enable_disable_reply +- npt66_binding_add_del +- npt66_binding_add_del_reply +- oddbuf_enable_disable +- oddbuf_enable_disable_reply +- pg_interface_enable_disable_coalesce +- pg_interface_enable_disable_coalesce_reply +- ping_finished_event +- pnat_binding_add +- pnat_binding_add_reply +- pnat_binding_add_v2 +- pnat_binding_add_v2_reply +- pnat_binding_attach +- pnat_binding_attach_reply +- pnat_binding_del +- pnat_binding_del_reply +- pnat_binding_detach +- pnat_binding_detach_reply +- pnat_bindings_details +- pnat_bindings_get +- pnat_bindings_get_reply +- pnat_flow_lookup +- pnat_flow_lookup_reply +- pnat_interfaces_details +- pnat_interfaces_get +- pnat_interfaces_get_reply +- pvti_interface_create +- pvti_interface_create_reply +- pvti_interface_delete +- pvti_interface_delete_reply +- pvti_interface_details +- pvti_interface_dump +- sample_macswap_enable_disable +- sample_macswap_enable_disable_reply +- set_ip_flow_hash_v3 +- set_ip_flow_hash_v3_reply +- sflow_direction_get +- sflow_direction_get_reply +- sflow_direction_set +- sflow_direction_set_reply +- sflow_drop_monitoring_get +- sflow_drop_monitoring_get_reply +- sflow_drop_monitoring_set +- sflow_drop_monitoring_set_reply +- sflow_enable_disable +- sflow_enable_disable_reply +- sflow_header_bytes_get +- sflow_header_bytes_get_reply +- sflow_header_bytes_set +- sflow_header_bytes_set_reply +- sflow_interface_details +- sflow_interface_dump +- sflow_polling_interval_get +- sflow_polling_interval_get_reply +- sflow_polling_interval_set +- sflow_polling_interval_set_reply +- sflow_sampling_rate_get +- sflow_sampling_rate_get_reply +- sflow_sampling_rate_set +- sflow_sampling_rate_set_reply +- sr_localsids_with_packet_stats_details +- sr_localsids_with_packet_stats_dump +- sr_mobile_localsid_add_del +- sr_mobile_localsid_add_del_reply +- sr_mobile_policy_add +- sr_mobile_policy_add_reply +- sr_policies_with_sl_index_details +- sr_policies_with_sl_index_dump +- sr_policy_add_v2 +- sr_policy_add_v2_reply +- sr_policy_mod_v2 +- sr_policy_mod_v2_reply +- sw_interface_ip6nd_ra_details +- sw_interface_ip6nd_ra_dump +- sw_interface_set_vxlan_gbp_bypass +- sw_interface_set_vxlan_gbp_bypass_reply +- test_addresses +- test_addresses2 +- test_addresses2_reply +- test_addresses3 +- test_addresses3_reply +- test_addresses_reply +- test_empty +- test_empty_reply +- test_enum +- test_enum_reply +- test_interface +- test_interface_reply +- test_prefix +- test_prefix_reply +- test_string +- test_string2 +- test_string2_reply +- test_string_reply +- test_vla +- test_vla2 +- test_vla2_reply +- test_vla3 +- test_vla3_reply +- test_vla4 +- test_vla4_reply +- test_vla5 +- test_vla5_reply +- test_vla_reply +- trace_capture_packets +- trace_capture_packets_reply +- trace_clear_cache +- trace_clear_cache_reply +- trace_clear_capture +- trace_clear_capture_reply +- trace_details +- trace_dump +- trace_dump_reply +- trace_filter_function_details +- trace_filter_function_dump +- trace_set_filter_function +- trace_set_filter_function_reply +- trace_set_filters +- trace_set_filters_reply +- trace_v2_details +- trace_v2_dump +- tracenode_enable_disable +- tracenode_enable_disable_reply +- vxlan_gbp_tunnel_add_del +- vxlan_gbp_tunnel_add_del_reply +- vxlan_gbp_tunnel_details +- vxlan_gbp_tunnel_dump +- want_ping_finished_events +- want_ping_finished_events_reply + +Patches that changed API definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +``src/vnet/pg/pg.api`` + +* `513c6bf8f `_ pg: add support for checksum offload + +``src/vnet/bfd/bfd.api`` + +* `c98ec5a0f `_ bfd: add API to configure TOS for IP of BFD packets + +``src/plugins/gre/gre.api`` + +* `74cf96576 `_ gre: Add support for GRE keys in the GRE plugin + +``src/plugins/sflow/sflow.api`` + +* `8d6879403 `_ sflow: add feature-arc at error-drop, drop-monitoring, egress-sampling diff --git a/docs/cli-reference/interface/setinterface.rst b/docs/cli-reference/interface/setinterface.rst index 7eb14adf45..03bbf52b06 100644 --- a/docs/cli-reference/interface/setinterface.rst +++ b/docs/cli-reference/interface/setinterface.rst @@ -56,7 +56,7 @@ To delete a specific interface ip address: .. code:: console - vpp# set interface ip address GigabitEthernet2/0/0 172.16.2.12/24 del + vpp# set interface ip address del GigabitEthernet2/0/0 172.16.2.12/24 To delete all interfaces addresses (IPv4 and IPv6): diff --git a/docs/configuration/reference.rst b/docs/configuration/reference.rst index 9378ce5b58..e2016b1d0e 100644 --- a/docs/configuration/reference.rst +++ b/docs/configuration/reference.rst @@ -469,12 +469,16 @@ CPU cores while skipping "skip-cores" CPU core(s) and main thread's CPU core relative ^^^^^^^^^ -Apply thread pinning configuration with respect to the available logical cores -in the current control group CPU set. +Apply thread pinning configuration with respect to the logical cores available +to the VPP process, rather than all logical cores present on the host machine. + By default, VPP applies the thread pinning configuration with respect to the -available logical cores on host (e.g. '/sys/devices/system/cpu/online'). With -the 'relative' keyword, the thread pinning configuration is applied with respect -to the available logical cores (obtained with sched_getaffinity). +available logical cores on host (e.g. '/sys/devices/system/cpu/online'), but with +the 'relative' keyword, we apply the thread pinning configuration with respect +to logical cores available to the VPP process (obtained with sched_getaffinity). + +This parameter can be useful when running VPP in an environment with restricted access +to host CPU resources (e.g. running in a container, or using taskset). .. code-block:: console diff --git a/docs/developer/extras/hs_test.rst b/docs/developer/extras/hs_test.rst index b7ace7940a..0bbda04e4f 120000 --- a/docs/developer/extras/hs_test.rst +++ b/docs/developer/extras/hs_test.rst @@ -1 +1 @@ -../../../extras/hs-test/README.rst \ No newline at end of file +../../../test-c/hs-test/README.rst \ No newline at end of file diff --git a/docs/developer/plugins/index.rst b/docs/developer/plugins/index.rst index 393eefec53..064ce6afe9 100644 --- a/docs/developer/plugins/index.rst +++ b/docs/developer/plugins/index.rst @@ -30,6 +30,7 @@ For more on plugins please refer to :ref:`add_plugin`. lb lacp flowprobe + sflow map_lw4o6 mdata dhcp6_pd diff --git a/docs/developer/plugins/sflow.rst b/docs/developer/plugins/sflow.rst new file mode 120000 index 0000000000..fec909f509 --- /dev/null +++ b/docs/developer/plugins/sflow.rst @@ -0,0 +1 @@ +../../../src/plugins/sflow/sflow.rst \ No newline at end of file diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index b407b39c8c..cd9d75089c 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -285,6 +285,8 @@ dpdk dpkg dpo dport +dropmon +DROPMON dryrun DS dsa @@ -506,6 +508,7 @@ Init initiatehost inline inlines +insmod instantiation Instantiation Integrations @@ -692,6 +695,7 @@ mldv mmap modelled modernisation +modprobe modularity Monroy mortem @@ -898,6 +902,8 @@ Promisc proto proxying ps +psample +PSAMPLE pseudocode Pseudocode psp @@ -1024,6 +1030,8 @@ setjmp settingupenvironment setUp setUpClass +sflow +sFlow sfr sha Shamir @@ -1127,6 +1135,7 @@ Tahr tapcli tcp tcpcontrolbits +taskset te teardown tearDown @@ -1239,6 +1248,7 @@ usergroup Usergroup Usermode username +USERSOCK userspace Userspace usr @@ -1384,5 +1394,3 @@ zoomout zx µs oflags -sflow -sFlow diff --git a/extras/deprecated/vom/vom.mk b/extras/deprecated/vom/vom.mk index 97fa900b84..10f7f9668f 100644 --- a/extras/deprecated/vom/vom.mk +++ b/extras/deprecated/vom/vom.mk @@ -15,6 +15,18 @@ vom_configure_depend = vpp-install vom_source = extras vom_configure_subdir = vom +# OS Detection +# +# We allow Darwin (MacOS) for docs generation; VPP build will still fail. +ifneq ($(shell uname),Darwin) +OS_ID = $(shell grep '^ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') + ifeq ($(OS_ID),rhel) + OS_VERSION_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g' | sed -e 's/\..*//') + else + OS_VERSION_ID= $(shell grep '^VERSION_ID=' /etc/os-release | cut -f2- -d= | sed -e 's/\"//g') + endif +endif + ifneq ($(shell which cmake3 2>/dev/null),) CMAKE?=cmake3 else @@ -27,9 +39,16 @@ vom_cmake_args += -DCMAKE_CXX_FLAGS="$($(TAG)_TAG_CPPFLAGS)" vom_cmake_args += -DCMAKE_SHARED_LINKER_FLAGS="$($(TAG)_TAG_LDFLAGS)" vom_cmake_args += -DCMAKE_PREFIX_PATH:PATH="$(PACKAGE_INSTALL_DIR)/../vpp" -# Use devtoolset on centos 7 -ifneq ($(wildcard /opt/rh/devtoolset-9/enable),) -vom_cmake_args += -DCMAKE_PROGRAM_PATH:PATH="/opt/rh/devtoolset-9/root/bin" +# Use devtoolset +ifeq ($(OS_ID)-$(OS_VERSION_ID),rhel-8) + ifneq ($(wildcard /opt/rh/gcc-toolset-9/enable),) + vom_cmake_args += -DCMAKE_PROGRAM_PATH:PATH="/opt/rh/gcc-toolset-9/root/bin" + endif +else + # Use devtoolset on centos 7 + ifneq ($(wildcard /opt/rh/devtoolset-9/enable),) + vom_cmake_args += -DCMAKE_PROGRAM_PATH:PATH="/opt/rh/devtoolset-9/root/bin" + endif endif vom_configure = \ diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile index bc72171a93..99a8f883d4 100644 --- a/extras/hs-test/Makefile +++ b/extras/hs-test/Makefile @@ -1,294 +1,3 @@ -export HS_ROOT=$(CURDIR) - -# sets WS_ROOT if called from extras/hs-test -ifeq ($(WS_ROOT),) -export WS_ROOT=$(HS_ROOT)/../.. -endif - -ifeq ($(VERBOSE),) -VERBOSE=false -endif - -ifeq ($(PERSIST),) -PERSIST=false -endif - -ifeq ($(UNCONFIGURE),) -UNCONFIGURE=false -endif - -ifeq ($(TEST),) -TEST=all -endif - -ifeq ($(TEST-HS),) -TEST-HS=all -endif - -ifeq ($(DEBUG),) -DEBUG=false -endif - -ifeq ($(CPUS),) -CPUS=1 -endif - -ifeq ($(PARALLEL),) -PARALLEL=1 -endif - -ifeq ($(REPEAT),) -REPEAT=0 -endif - -ifeq ($(CPU0),) -CPU0=false -endif - -ifeq ($(VPPSRC),) -VPPSRC=$(shell pwd)/../.. -endif - -ifeq ($(UBUNTU_CODENAME),) -UBUNTU_CODENAME=$(shell grep '^UBUNTU_CODENAME=' /etc/os-release | cut -f2- -d=) -endif - -ifeq ($(ARCH),) -ARCH=$(shell dpkg --print-architecture) -endif - -ifeq ($(NO_COLOR),) -VERBOSE=false -endif - -ifeq ($(TIMEOUT),) -TIMEOUT=5 -endif - -FORCE_BUILD?=true - -.PHONY: help -help: - @echo "Make targets:" - @echo " test - run tests" - @echo " test-debug - run tests (vpp debug image)" - @echo " test-leak - run memory leak tests (vpp debug image)" - @echo " test-perf - run performance tests (requires a running cluster)" - @echo " build - build test infra" - @echo " build-cov - coverage build of VPP and Docker images" - @echo " build-debug - build test infra (vpp debug image)" - @echo " build-go - just build golang files" - @echo " setup-cluster - setup KinD cluster for performance testing" - @echo " checkstyle-go - check style of .go source files" - @echo " fixstyle-go - format .go source files" - @echo " cleanup-hst - removes all docker containers and namespaces from last test run" - @echo " cleanup-perf - removes all kubernetes pods and namespaces from last test run" - @echo " list-tests - list all tests" - @echo - @echo "'make build' and 'make test' arguments:" - @echo " UBUNTU_VERSION - ubuntu version for docker image" - @echo " FORCE_BUILD=[true|false] - force docker image building" - @echo - @echo "'make test' specific arguments:" - @echo " PERSIST=[true|false] - whether clean up topology and dockers after test" - @echo " VERBOSE=[true|false] - verbose output" - @echo " UNCONFIGURE=[true|false] - unconfigure selected test" - @echo " DEBUG=[true|false] - attach VPP to GDB" - @echo " TEST=[name1,name2...] - specific test(s) to run" - @echo " SKIP=[name1,name2...] - specific test(s) to skip" - @echo " CPUS=[n-cpus] - number of cpus to allocate to VPP and containers" - @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 " CPU0=[true|false] - use cpu0" - @echo " DRYRUN=[true|false] - set up containers but don't run tests" - @echo " NO_COLOR=[true|false] - disables colorful Docker and Ginkgo output" - @echo " TIMEOUT=[minutes] - test timeout override (5 minutes by default)" - -.PHONY: list-tests -list-tests: - @go run github.com/onsi/ginkgo/v2/ginkgo --dry-run -v --no-color --seed=2 | head -n -1 | grep 'test.go' | \ - sed 's/^/* /; s/\(Suite\) /\1\//g' - -.PHONY: build-vpp-release -build-vpp-release: - @$(MAKE) -C ../.. build-release - -.PHONY: build-vpp-debug -build-vpp-debug: - @$(MAKE) -C ../.. build - -.PHONY: build-vpp-gcov -build-vpp-gcov: - @$(MAKE) -C ../.. build-gcov - -.build.ok: build - @touch .build.ok - -.build.cov.ok: build-cov - @touch .build.ok - -.build_debug.ok: build-debug - @touch .build.ok - -.PHONY: test -test: FORCE_BUILD=false -test: .deps.ok .build.ok - @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ - --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --cpu0=$(CPU0) \ - --dryrun=$(DRYRUN) --skip=$(SKIP) --no_color=$(NO_COLOR) --timeout=$(TIMEOUT); \ - ./script/compress.sh $$? - -.PHONY: test-debug -test-debug: FORCE_BUILD=false -test-debug: .deps.ok .build_debug.ok - @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ - --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --debug_build=true \ - --cpu0=$(CPU0) --dryrun=$(DRYRUN) --skip=$(SKIP) --no_color=$(NO_COLOR) --timeout=$(TIMEOUT); \ - ./script/compress.sh $$? - -.PHONY: wipe-lcov -wipe-lcov: - @lcov --zerocounters --directory $(WS_ROOT)/build-root/build-vpp_gcov-native/vpp - -.PHONY: test-cov -test-cov: FORCE_BUILD=false -test-cov: .deps.ok .build.cov.ok wipe-lcov - -@bash ./hs_test.sh --coverage=true --persist=$(PERSIST) --verbose=$(VERBOSE) \ - --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST-HS) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) --cpu0=$(CPU0) --dryrun=$(DRYRUN) --skip=$(SKIP) --no_color=$(NO_COLOR) \ - --timeout=$(TIMEOUT); \ - ./script/compress.sh $$? - $(MAKE) -C ../.. test-cov-post-standalone HS_TEST=1 - -.PHONY: test-leak -test-leak: .deps.ok .build_debug.ok - @bash ./hs_test.sh --test=$(TEST) --debug_build=true --leak_check=true --vppsrc=$(VPPSRC) --timeout=$(TIMEOUT) - -.PHONY: test-perf -test-perf: FORCE_BUILD=false -test-perf: .deps.ok .build.ok - @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ - --test=$(TEST) --vppsrc=$(VPPSRC) --repeat=$(REPEAT) \ - --skip=$(SKIP) --no_color=$(NO_COLOR) --perf=true; \ - ./script/compress.sh $$? - -.PHONY: setup-cluster -setup-cluster: - @bash ./kubernetes/setupCluster.sh - -.PHONY: build-go -build-go: - go build ./tools/http_server - -.PHONY: build -build: .deps.ok build-vpp-release build-go - @rm -f .build.ok - bash ./script/build_hst.sh release $(FORCE_BUILD) - @touch .build.ok - -.PHONY: build-cov -build-cov: .deps.ok build-vpp-gcov build-go - @rm -f .build.cov.ok - bash ./script/build_hst.sh gcov $(FORCE_BUILD) - @touch .build.cov.ok - -.PHONY: build-debug -build-debug: .deps.ok build-vpp-debug build-go - @rm -f .build.ok - bash ./script/build_hst.sh debug $(FORCE_BUILD) - @touch .build.ok - -.deps.ok: - @$(MAKE) install-deps - -.PHONY: install-deps -install-deps: - @rm -f .deps.ok - @sudo -E apt-get update - @sudo -E apt-get install -y apt-transport-https ca-certificates curl software-properties-common \ - bridge-utils gpg - @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 - @sudo -E apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - @touch .deps.ok - -.goimports.ok: - @rm -f .goimports.ok - go install golang.org/x/tools/cmd/goimports@v0.25.0 - @touch .goimports.ok - -.PHONY: checkstyle-go -checkstyle-go: .goimports.ok - $(eval GOPATH := $(shell go env GOPATH)) - @output=$$($(GOPATH)/bin/goimports -d $${WS_ROOT}); \ - status=$$?; \ - if [ $$status -ne 0 ]; then \ - exit $$status; \ - elif [ -z "$$output" ]; then \ - echo "******************************************************************************"; \ - echo "* HST Golang Checkstyle OK."; \ - echo "******************************************************************************"; \ - else \ - echo "$$output"; \ - echo "******************************************************************************"; \ - echo "* HST Golang Checkstyle FAILED. Use 'make fixstyle-go' or fix errors manually."; \ - echo "******************************************************************************"; \ - exit 1; \ - fi - -.PHONY: fixstyle-go -fixstyle-go: .goimports.ok - $(eval GOPATH := $(shell go env GOPATH)) - @echo "Modified files:" - @$(GOPATH)/bin/goimports -w -l $(WS_ROOT) - @go mod tidy - @echo "*******************************************************************" - @echo "Fixstyle done." - @echo "*******************************************************************" - -.PHONY: cleanup-hst -cleanup-hst: - @if [ ! -f ".last_hst_ppid" ]; then \ - echo "'.last_hst_ppid' file does not exist."; \ - exit 1; \ - fi - @echo "****************************" - @echo "Removing docker containers:" - @# "-" ignores errors - @-sudo docker rm $$(sudo docker stop $$(sudo docker ps -a -q --filter "name=$$(cat .last_hst_ppid)") -t 0) - @echo "****************************" - @echo "Removing IP address files:" - @find . -type f -regextype egrep -regex '.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' -exec sudo rm -v {} \; - @find . -type f -name "fd00:0*" -exec sudo rm -v {} \; - @echo "****************************" - @echo "Removing network namespaces:" - @for ns in $$(ip netns list | grep $$(cat .last_hst_ppid) | awk '{print $$1}'); do \ - echo $$ns; \ - sudo ip netns delete $$ns; \ - done - @echo "****************************" - @echo "Done." - @echo "****************************" - -.PHONY: cleanup-perf -cleanup-perf: - @if [ ! -f ".last_hst_ppid" ]; then \ - echo "'.last_hst_ppid' file does not exist."; \ - exit 1; \ - fi - @echo "****************************" - @echo "Removing kubernetes pods:" - @kubectl delete pods --all --grace-period=0 -n namespace$$(cat .last_hst_ppid) - @echo "****************************" - @echo "Removing kubernetes namespace:" - @kubectl delete namespace namespace$$(cat .last_hst_ppid) - @echo "****************************" - @echo "Done." - @echo "****************************" +# Temp redirect +%: + $(MAKE) -C ../../test-c/hs-test/ -f Makefile $@ \ No newline at end of file diff --git a/extras/hs-test/docker/Dockerfile.ab b/extras/hs-test/docker/Dockerfile.ab deleted file mode 100644 index 3ed1528c8a..0000000000 --- a/extras/hs-test/docker/Dockerfile.ab +++ /dev/null @@ -1,9 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:${UBUNTU_VERSION} - -RUN apt-get update \ - && apt-get install -y apache2-utils \ - && rm -rf /var/lib/apt/lists/* - -ENTRYPOINT ["ab"] diff --git a/extras/hs-test/docker/Dockerfile.curl b/extras/hs-test/docker/Dockerfile.curl deleted file mode 100644 index 8e9b579aad..0000000000 --- a/extras/hs-test/docker/Dockerfile.curl +++ /dev/null @@ -1,16 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:${UBUNTU_VERSION} - -ARG TARGETARCH - -RUN apt-get update \ - && apt-get install -y xz-utils wget \ - && rm -rf /var/lib/apt/lists/* - -COPY script/build_curl.sh /build_curl.sh -COPY resources/curl/* /tmp/ -RUN fallocate -l 10MB /tmp/testFile -RUN /build_curl.sh - -CMD ["/bin/sh"] diff --git a/extras/hs-test/docker/Dockerfile.h2load b/extras/hs-test/docker/Dockerfile.h2load deleted file mode 100644 index de9d083c00..0000000000 --- a/extras/hs-test/docker/Dockerfile.h2load +++ /dev/null @@ -1,9 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:${UBUNTU_VERSION} - -RUN apt-get update \ - && apt-get install -y nghttp2 \ - && rm -rf /var/lib/apt/lists/* - -ENTRYPOINT ["h2load"] diff --git a/extras/hs-test/docker/Dockerfile.nginx-http3 b/extras/hs-test/docker/Dockerfile.nginx-http3 deleted file mode 100644 index bde73e32da..0000000000 --- a/extras/hs-test/docker/Dockerfile.nginx-http3 +++ /dev/null @@ -1,31 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:${UBUNTU_VERSION} - -RUN apt-get update \ - && apt-get install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring libunwind-dev -RUN curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ -| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null -RUN echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ - http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \ - | tee /etc/apt/sources.list.d/nginx.list -RUN bash -c 'echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \ -| tee /etc/apt/preferences.d/99nginx' - -RUN apt update && apt install -y nginx=1.26.2* - -COPY resources/nginx/vcl.conf /vcl.conf -COPY resources/nginx/nginx_http3.conf /nginx.conf -COPY script/nginx_ldp.sh /usr/bin/nginx_ldp.sh -COPY resources/nginx/html/index.html /usr/share/nginx/index.html - -ENV VCL_CONFIG=/vcl.conf -ENV LDP=/usr/lib/libvcl_ldpreload.so -ENV LDP_DEBUG=0 -ENV VCL_DEBUG=0 -ENV LDP_SID_BIT=8 - -# copy vpp-data last to take advantage of caching (do not change) -COPY vpp-data/lib/* /usr/lib/ - -ENTRYPOINT ["nginx_ldp.sh", "nginx", "-c", "/nginx.conf"] diff --git a/extras/hs-test/docker/Dockerfile.wrk b/extras/hs-test/docker/Dockerfile.wrk deleted file mode 100644 index b410873255..0000000000 --- a/extras/hs-test/docker/Dockerfile.wrk +++ /dev/null @@ -1,9 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:${UBUNTU_VERSION} - -RUN apt-get update \ - && apt-get install -y wrk \ - && rm -rf /var/lib/apt/lists/* - -ENTRYPOINT ["wrk"] diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go deleted file mode 100644 index 3c59f95fe5..0000000000 --- a/extras/hs-test/echo_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package main - -import ( - "regexp" - "strconv" - - . "fd.io/hs-test/infra" -) - -func init() { - RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest) - RegisterSoloVethTests(TcpWithLossTest) - RegisterVeth6Tests(TcpWithLoss6Test) -} - -func EchoBuiltinTest(s *VethsSuite) { - serverVpp := s.Containers.ServerVpp.VppInstance - - serverVpp.Vppctl("test echo server " + - " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/1234") - - clientVpp := s.Containers.ClientVpp.VppInstance - - o := clientVpp.Vppctl("test echo client nclients 100 bytes 1 verbose" + - " syn-timeout 100 test-timeout 100" + - " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/1234") - s.Log(o) - s.AssertNotContains(o, "failed:") -} - -func EchoBuiltinBandwidthTest(s *VethsSuite) { - regex := regexp.MustCompile(`gbytes\) in (\d+\.\d+) seconds`) - serverVpp := s.Containers.ServerVpp.VppInstance - - serverVpp.Vppctl("test echo server " + - " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/1234") - - clientVpp := s.Containers.ClientVpp.VppInstance - - o := clientVpp.Vppctl("test echo client nclients 4 bytes 8m throughput 16m" + - " uri tcp://" + s.Interfaces.Server.Ip4AddressString() + "/1234") - s.Log(o) - s.AssertContains(o, "Test started") - s.AssertContains(o, "Test finished") - if regex.MatchString(o) { - matches := regex.FindStringSubmatch(o) - if len(matches) != 0 { - seconds, _ := strconv.ParseFloat(matches[1], 32) - // Make sure that we are within 0.1 of the targeted - // 2 seconds of runtime - s.AssertEqualWithinThreshold(seconds, 2, 0.1) - } else { - s.AssertEmpty("invalid echo test client output") - } - } else { - s.AssertEmpty("invalid echo test client output") - } -} - -func TcpWithLossTest(s *VethsSuite) { - serverVpp := s.Containers.ServerVpp.VppInstance - - serverVpp.Vppctl("test echo server uri tcp://%s/20022", - s.Interfaces.Server.Ip4AddressString()) - - clientVpp := s.Containers.ClientVpp.VppInstance - - // 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 host-" + s.Interfaces.Server.Name()) - - // Do echo test from client-vpp container - output := clientVpp.Vppctl("test echo client uri tcp://%s/20022 verbose echo-bytes bytes 50m", - s.Interfaces.Server.Ip4AddressString()) - s.Log(output) - s.AssertNotEqual(len(output), 0) - s.AssertNotContains(output, "failed", output) -} - -func TcpWithLoss6Test(s *Veths6Suite) { - serverVpp := s.Containers.ServerVpp.VppInstance - - serverVpp.Vppctl("test echo server uri tcp://%s/20022", - s.Interfaces.Server.Ip6AddressString()) - - clientVpp := s.Containers.ClientVpp.VppInstance - - // 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 host-" + s.Interfaces.Server.Name()) - - // Do echo test from client-vpp container - output := clientVpp.Vppctl("test echo client uri tcp://%s/20022 verbose echo-bytes bytes 50m", - s.Interfaces.Server.Ip6AddressString()) - s.Log(output) - s.AssertNotEqual(len(output), 0) - s.AssertNotContains(output, "failed", output) -} diff --git a/extras/hs-test/h2spec_extras/h2spec_extras.go b/extras/hs-test/h2spec_extras/h2spec_extras.go deleted file mode 100644 index 3c2b9dd76a..0000000000 --- a/extras/hs-test/h2spec_extras/h2spec_extras.go +++ /dev/null @@ -1,170 +0,0 @@ -package h2spec_extras - -import ( - "fmt" - - "github.com/summerwind/h2spec/config" - "github.com/summerwind/h2spec/spec" - "golang.org/x/net/http2" -) - -var key = "extras" - -func NewTestGroup(section string, name string) *spec.TestGroup { - return &spec.TestGroup{ - Key: key, - Section: section, - Name: name, - } -} - -func Spec() *spec.TestGroup { - tg := &spec.TestGroup{ - Key: key, - Name: "extras for HTTP/2 server", - } - - tg.AddTestGroup(FlowControl()) - - return tg -} - -func VerifyWindowUpdate(conn *spec.Conn, streamID, expectedIncrement uint32) error { - actual, passed := conn.WaitEventByType(spec.EventWindowUpdateFrame) - actualStr := actual.String() - switch event := actual.(type) { - case spec.WindowUpdateFrameEvent: - actualStr = fmt.Sprintf("WINDOW_UPDATE Frame (stream_id:%d, increment:%d)", event.StreamID, event.Increment) - passed = (event.StreamID == streamID) && (event.Increment == expectedIncrement) - default: - passed = false - } - - if !passed { - expected := []string{ - fmt.Sprintf("WINDOW_UPDATE Frame (stream_id:%d, increment:%d)", streamID, expectedIncrement), - } - - return &spec.TestError{ - Expected: expected, - Actual: actualStr, - } - } - return nil -} - -func FlowControl() *spec.TestGroup { - tg := NewTestGroup("1", "Flow control") - tg.AddTestCase(&spec.TestCase{ - Desc: "Sends a WINDOW_UPDATE frame on connection", - Requirement: "The endpoint MUST NOT send a flow-controlled frame with a length that exceeds the space available.", - Run: func(c *config.Config, conn *spec.Conn) error { - var streamID uint32 = 1 - - // turn off automatic connection window update - conn.WindowUpdate = false - - err := conn.Handshake() - if err != nil { - return err - } - - headers := spec.CommonHeaders(c) - headers[2].Value = "/4kB" - - // consume most of the connection window - for i := 0; i <= 14; i++ { - hp := http2.HeadersFrameParam{ - StreamID: streamID, - EndStream: true, - EndHeaders: true, - BlockFragment: conn.EncodeHeaders(headers), - } - conn.WriteHeaders(hp) - streamID += 2 - err := spec.VerifyEventType(conn, spec.EventDataFrame) - if err != nil { - return err - } - } - - hp := http2.HeadersFrameParam{ - StreamID: streamID, - EndStream: true, - EndHeaders: true, - BlockFragment: conn.EncodeHeaders(headers), - } - conn.WriteHeaders(hp) - // verify reception of DATA frame - err = spec.VerifyEventType(conn, spec.EventDataFrame) - if err != nil { - return err - } - - // increment connection window - conn.WriteWindowUpdate(0, 65535) - - // wait for DATA frame with rest of the content - actual, passed := conn.WaitEventByType(spec.EventDataFrame) - switch event := actual.(type) { - case spec.DataFrameEvent: - passed = event.Header().Length == 1 - default: - passed = false - } - - if !passed { - expected := []string{ - fmt.Sprintf("DATA Frame (length:1, flags:0x00, stream_id:%d)", streamID), - } - - return &spec.TestError{ - Expected: expected, - Actual: actual.String(), - } - } - - return nil - }, - }) - - tg.AddTestCase(&spec.TestCase{ - Desc: "Receive a WINDOW_UPDATE frame on stream", - Requirement: "The receiver of a frame sends a WINDOW_UPDATE frame as it consumes data and frees up space in flow-control windows.", - Run: func(c *config.Config, conn *spec.Conn) error { - var streamID uint32 = 1 - - err := conn.Handshake() - if err != nil { - return err - } - - headers := spec.CommonHeaders(c) - headers[0].Value = "POST" - headers = append(headers, spec.HeaderField("content-length", "12")) - hp := http2.HeadersFrameParam{ - StreamID: streamID, - EndStream: false, - EndHeaders: true, - BlockFragment: conn.EncodeHeaders(headers), - } - conn.WriteHeaders(hp) - // we send window update on stream when app read data from rx fifo, so send DATA frame and wait for WINDOW_UPDATE frame - conn.WriteData(streamID, false, []byte("AAAA")) - err = VerifyWindowUpdate(conn, streamID, 4) - if err != nil { - return err - } - // test it again - conn.WriteData(streamID, false, []byte("BBBBB")) - err = VerifyWindowUpdate(conn, streamID, 5) - if err != nil { - return err - } - // we don't send stream window update if stream is half-closed, so HEADERS frame should be received - conn.WriteData(streamID, true, []byte("CCC")) - return spec.VerifyHeadersFrame(conn, streamID) - }, - }) - return tg -} diff --git a/extras/hs-test/http2_test.go b/extras/hs-test/http2_test.go deleted file mode 100644 index 8bcca1611a..0000000000 --- a/extras/hs-test/http2_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "time" - - . "fd.io/hs-test/infra" -) - -func init() { - RegisterH2Tests(Http2TcpGetTest, Http2TcpPostTest, Http2MultiplexingTest, Http2MultiplexingMTTest, Http2TlsTest) -} - -func Http2TcpGetTest(s *H2Suite) { - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - vpp.Vppctl("http cli server") - s.Log(vpp.Vppctl("show session verbose 2")) - args := fmt.Sprintf("--max-time 10 --noproxy '*' --http2-prior-knowledge http://%s:80/show/version", serverAddress) - writeOut, log := s.RunCurlContainer(s.Containers.Curl, args) - s.Log(vpp.Vppctl("show session verbose 2")) - s.AssertContains(log, "HTTP/2 200") - s.AssertContains(writeOut, "", " not found in the result!") - s.AssertContains(writeOut, "", " not found in the result!") - - /* test session cleanup */ - httpStreamCleanupDone := false - tcpSessionCleanupDone := false - for nTries := 0; nTries < 30; nTries++ { - o := vpp.Vppctl("show session verbose 2") - if !strings.Contains(o, "[T] "+serverAddress+":80->") { - tcpSessionCleanupDone = true - } - if !strings.Contains(o, "[H2]") { - httpStreamCleanupDone = true - } - if httpStreamCleanupDone && tcpSessionCleanupDone { - break - } - time.Sleep(1 * time.Second) - } - s.AssertEqual(true, tcpSessionCleanupDone, "TCP session not cleanup") - s.AssertEqual(true, httpStreamCleanupDone, "HTTP/2 stream not cleanup") - - /* test server app stop listen */ - vpp.Vppctl("http cli server listener del") - o := vpp.Vppctl("show session verbose proto http") - s.AssertNotContains(o, "LISTEN") -} - -func Http2TcpPostTest(s *H2Suite) { - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers max-body-size 20m rx-buff-thresh 20m fifo-size 65k debug 2")) - s.Log(vpp.Vppctl("test-url-handler enable")) - args := fmt.Sprintf("--max-time 10 --noproxy '*' --data-binary @%s --http2-prior-knowledge http://%s:80/test3", CurlContainerTestFile, serverAddress) - _, log := s.RunCurlContainer(s.Containers.Curl, args) - s.AssertContains(log, "HTTP/2 200") -} - -func Http2MultiplexingTest(s *H2Suite) { - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - vpp.Vppctl("http tps uri tcp://0.0.0.0/80 no-zc") - - args := fmt.Sprintf("--log-file=%s -T10 -n21 -c1 -m100 http://%s:80/test_file_20M", s.H2loadLogFileName(s.Containers.H2load), serverAddress) - s.Containers.H2load.ExtraRunningArgs = args - s.Containers.H2load.Run() - - defer s.CollectH2loadLogs(s.Containers.H2load) - - o, _ := s.Containers.H2load.GetOutput() - s.Log(o) - s.AssertContains(o, " 0 failed") - s.AssertContains(o, " 0 errored") - s.AssertContains(o, " 0 timeout") -} - -func Http2MultiplexingMTTest(s *H2Suite) { - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - vpp.Vppctl("http tps uri tcp://0.0.0.0/80 no-zc") - - args := fmt.Sprintf("-T10 -n100 -c4 -r1 -m10 http://%s:80/test_file_20M", serverAddress) - s.Containers.H2load.ExtraRunningArgs = args - s.Containers.H2load.Run() - - o, _ := s.Containers.H2load.GetOutput() - s.Log(o) - s.AssertContains(o, " 0 failed") - s.AssertContains(o, " 0 errored") - s.AssertContains(o, " 0 timeout") -} - -func Http2TlsTest(s *H2Suite) { - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - s.Log(vpp.Vppctl("http static server uri tls://" + serverAddress + "/443 url-handlers debug")) - - args := fmt.Sprintf("--max-time 10 --noproxy '*' -k https://%s:443/version.json", serverAddress) - writeOut, log := s.RunCurlContainer(s.Containers.Curl, args) - s.Log(vpp.Vppctl("show session verbose 2")) - s.AssertContains(log, "HTTP/2 200") - s.AssertContains(log, "ALPN: server accepted h2") - s.AssertContains(writeOut, "version") -} diff --git a/extras/hs-test/infra/common/suite_common.go b/extras/hs-test/infra/common/suite_common.go deleted file mode 100644 index 72173c6261..0000000000 --- a/extras/hs-test/infra/common/suite_common.go +++ /dev/null @@ -1,191 +0,0 @@ -package hst_common - -import ( - "flag" - "fmt" - "io" - "log" - "net/http" - "os" - "strconv" - "strings" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var IsCoverage = flag.Bool("coverage", false, "use coverage run config") -var IsPersistent = flag.Bool("persist", false, "persists topology config") -var IsVerbose = flag.Bool("verbose", false, "verbose test output") -var SudoUser = flag.String("sudo_user", "root", "what user ran hs-test with sudo") -var ParallelTotal = flag.Lookup("ginkgo.parallel.total") -var IsVppDebug = flag.Bool("debug", false, "attach gdb to vpp") -var DryRun = flag.Bool("dryrun", false, "set up containers but don't run tests") -var Timeout = flag.Int("timeout", 5, "test timeout override (in minutes)") -var NumaAwareCpuAlloc bool -var TestTimeout time.Duration -var RunningInCi bool - -const ( - LogDir string = "/tmp/hs-test/" - VolumeDir string = "/volumes" -) - -type HstCommon struct { - Ppid string - ProcessIndex string - Logger *log.Logger - LogFile *os.File -} - -func (s *HstCommon) Skip(args string) { - Skip(args) -} - -func (s *HstCommon) SetupTest() { - TestCounterFunc() - s.Log("[* TEST SETUP]") -} - -func (s *HstCommon) SetupSuite() { - s.CreateLogger() - s.Log("[* SUITE SETUP]") - s.Ppid = fmt.Sprint(os.Getppid()) - // remove last number so we have space to prepend a process index (interfaces have a char limit) - s.Ppid = s.Ppid[:len(s.Ppid)-1] - s.ProcessIndex = fmt.Sprint(GinkgoParallelProcess()) -} - -func (s *HstCommon) TeardownTest() { - if *IsPersistent || *DryRun { - return - } - s.Log("[* TEST TEARDOWN]") -} - -func (s *HstCommon) TeardownSuite() { - if *IsPersistent || *DryRun { - return - } - s.Log("[* SUITE TEARDOWN]") -} - -func (s *HstCommon) GetCurrentSuiteName() string { - return CurrentSpecReport().ContainerHierarchyTexts[0] -} - -func (s *HstCommon) CreateLogger() { - suiteName := s.GetCurrentSuiteName() - 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) -} - -// Logs to files by default, logs to stdout when VERBOSE=true with GinkgoWriter -// to keep console tidy -func (s *HstCommon) Log(log any, arg ...any) { - var logStr string - if len(arg) == 0 { - logStr = fmt.Sprint(log) - } else { - logStr = fmt.Sprintf(fmt.Sprint(log), arg...) - } - logs := strings.Split(logStr, "\n") - - for _, line := range logs { - s.Logger.Println(line) - } - if *IsVerbose { - GinkgoWriter.Println(logStr) - } -} - -func (s *HstCommon) AssertNil(object interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, object).To(BeNil(), msgAndArgs...) -} - -func (s *HstCommon) AssertNotNil(object interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, object).ToNot(BeNil(), msgAndArgs...) -} - -func (s *HstCommon) AssertEqual(expected, actual interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).To(Equal(expected), msgAndArgs...) -} - -func (s *HstCommon) AssertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).ToNot(Equal(expected), msgAndArgs...) -} - -func (s *HstCommon) AssertContains(testString, contains interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, strings.ToLower(fmt.Sprint(testString))).To(ContainSubstring(strings.ToLower(fmt.Sprint(contains))), msgAndArgs...) -} - -func (s *HstCommon) AssertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, strings.ToLower(fmt.Sprint(testString))).ToNot(ContainSubstring(strings.ToLower(fmt.Sprint(contains))), msgAndArgs...) -} - -func (s *HstCommon) AssertEmpty(object interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, object).To(BeEmpty(), msgAndArgs...) -} - -func (s *HstCommon) AssertNotEmpty(object interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, object).ToNot(BeEmpty(), msgAndArgs...) -} - -func (s *HstCommon) AssertMatchError(actual, expected error, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).To(MatchError(expected), msgAndArgs...) -} - -func (s *HstCommon) AssertGreaterThan(actual, expected interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).Should(BeNumerically(">=", expected), msgAndArgs...) -} - -func (s *HstCommon) AssertEqualWithinThreshold(actual, expected, threshold interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).Should(BeNumerically("~", expected, threshold), msgAndArgs...) -} - -func (s *HstCommon) AssertTimeEqualWithinThreshold(actual, expected time.Time, threshold time.Duration, msgAndArgs ...interface{}) { - ExpectWithOffset(2, actual).Should(BeTemporally("~", expected, threshold), msgAndArgs...) -} - -func (s *HstCommon) AssertHttpStatus(resp *http.Response, expectedStatus int, msgAndArgs ...interface{}) { - ExpectWithOffset(2, resp).To(HaveHTTPStatus(expectedStatus), msgAndArgs...) -} - -func (s *HstCommon) AssertHttpHeaderWithValue(resp *http.Response, key string, value interface{}, msgAndArgs ...interface{}) { - ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue(key, value), msgAndArgs...) -} - -func (s *HstCommon) AssertHttpHeaderNotPresent(resp *http.Response, key string, msgAndArgs ...interface{}) { - ExpectWithOffset(2, resp.Header.Get(key)).To(BeEmpty(), msgAndArgs...) -} - -func (s *HstCommon) AssertHttpContentLength(resp *http.Response, expectedContentLen int64, msgAndArgs ...interface{}) { - ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue("Content-Length", strconv.FormatInt(expectedContentLen, 10)), msgAndArgs...) -} - -func (s *HstCommon) AssertHttpBody(resp *http.Response, expectedBody string, msgAndArgs ...interface{}) { - ExpectWithOffset(2, resp).To(HaveHTTPBody(expectedBody), msgAndArgs...) -} - -func (s *HstCommon) AssertChannelClosed(timeout time.Duration, channel chan error) { - EventuallyWithOffset(2, channel).WithTimeout(timeout).Should(BeClosed()) -} - -// Pass the parsed result struct and the minimum amount of data transferred in MB. -// Won't do anything when testing a coverage build. -func (s *HstCommon) AssertIperfMinTransfer(result IPerfResult, minTransferred int) { - if *IsCoverage { - s.Log("Coverage build; not asserting") - return - } - if result.Start.Details.Protocol == "TCP" { - s.AssertGreaterThan(result.End.TcpReceived.MBytes, minTransferred) - } else { - s.AssertGreaterThan(result.End.Udp.MBytes, minTransferred) - } -} diff --git a/extras/hs-test/infra/kind/pod.go b/extras/hs-test/infra/kind/pod.go deleted file mode 100644 index 1b37047149..0000000000 --- a/extras/hs-test/infra/kind/pod.go +++ /dev/null @@ -1,50 +0,0 @@ -package hst_kind - -import corev1 "k8s.io/api/core/v1" - -type Pod struct { - Name string - Image string - ContainerName string - Worker string - IpAddress string - CreatedPod *corev1.Pod -} - -// Sets pod names, image names, namespace name -func (s *KindSuite) initPods() { - wrk1 := "kind-worker" - wrk2 := "kind-worker2" - vppImg := "hs-test/vpp:latest" - nginxLdpImg := "hs-test/nginx-ldp:latest" - abImg := "hs-test/ab:latest" - clientCont := "client" - serverCont := "server" - - s.images = append(s.images, vppImg, nginxLdpImg, abImg) - s.Namespace = "namespace" + s.Ppid - - s.Pods.ClientGeneric = new(Pod) - s.Pods.ClientGeneric.Name = "client" + s.Ppid - s.Pods.ClientGeneric.Image = vppImg - s.Pods.ClientGeneric.ContainerName = clientCont - s.Pods.ClientGeneric.Worker = wrk1 - - s.Pods.ServerGeneric = new(Pod) - s.Pods.ServerGeneric.Name = "server" + s.Ppid - s.Pods.ServerGeneric.Image = vppImg - s.Pods.ServerGeneric.ContainerName = serverCont - s.Pods.ServerGeneric.Worker = wrk2 - - s.Pods.Ab = new(Pod) - s.Pods.Ab.Name = "ab" + s.Ppid - s.Pods.Ab.Image = abImg - s.Pods.Ab.ContainerName = clientCont - s.Pods.Ab.Worker = wrk1 - - s.Pods.Nginx = new(Pod) - s.Pods.Nginx.Name = "nginx-ldp" + s.Ppid - s.Pods.Nginx.Image = nginxLdpImg - s.Pods.Nginx.ContainerName = serverCont - s.Pods.Nginx.Worker = wrk2 -} diff --git a/extras/hs-test/infra/kind/suite_kind.go b/extras/hs-test/infra/kind/suite_kind.go deleted file mode 100644 index ffbd830ac4..0000000000 --- a/extras/hs-test/infra/kind/suite_kind.go +++ /dev/null @@ -1,141 +0,0 @@ -package hst_kind - -import ( - "os" - "reflect" - "runtime" - "strings" - "text/template" - - . "fd.io/hs-test/infra/common" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -type KindSuite struct { - HstCommon - ClientSet *kubernetes.Clientset - Config *rest.Config - Namespace string - KubeconfigPath string - CurrentlyRunning []string - images []string - Pods struct { - ServerGeneric *Pod - ClientGeneric *Pod - Nginx *Pod - Ab *Pod - } -} - -var kindTests = map[string][]func(s *KindSuite){} - -func RegisterKindTests(tests ...func(s *KindSuite)) { - kindTests[GetTestFilename()] = tests -} - -func (s *KindSuite) SetupTest() { - s.HstCommon.SetupTest() -} - -func (s *KindSuite) SetupSuite() { - s.HstCommon.SetupSuite() - RegisterFailHandler(func(message string, callerSkip ...int) { - Fail(message, callerSkip...) - }) - - s.initPods() - s.loadDockerImages() - - var err error - if *SudoUser == "root" { - s.KubeconfigPath = "/.kube/config" - } else { - s.KubeconfigPath = "/home/" + *SudoUser + "/.kube/config" - } - - s.Config, err = clientcmd.BuildConfigFromFlags("", s.KubeconfigPath) - s.AssertNil(err) - - s.ClientSet, err = kubernetes.NewForConfig(s.Config) - s.AssertNil(err) - - s.createNamespace(s.Namespace) -} - -func (s *KindSuite) TeardownTest() { - s.HstCommon.TeardownTest() - if len(s.CurrentlyRunning) != 0 { - for _, pod := range s.CurrentlyRunning { - s.Log(" %s", pod) - s.deletePod(s.Namespace, pod) - } - } -} - -func (s *KindSuite) TeardownSuite() { - s.Log(" %s", s.Namespace) - s.AssertNil(s.deleteNamespace(s.Namespace)) -} - -func (s *KindSuite) CreateConfigFromTemplate(targetConfigName string, templateName string, values any) { - template := template.Must(template.ParseFiles(templateName)) - - f, err := os.CreateTemp(LogDir, "hst-config") - s.AssertNil(err, err) - defer os.Remove(f.Name()) - - err = template.Execute(f, values) - s.AssertNil(err, err) - - err = f.Close() - s.AssertNil(err, err) - - s.CopyToPod(s.Pods.Nginx.Name, s.Namespace, f.Name(), targetConfigName) -} - -func (s *KindSuite) CreateNginxConfig() { - values := struct { - Workers uint8 - }{ - Workers: 1, - } - s.CreateConfigFromTemplate( - "/nginx.conf", - "./resources/nginx/nginx.conf", - values, - ) -} - -var _ = Describe("KindSuite", Ordered, ContinueOnFailure, Label("Perf"), func() { - var s KindSuite - BeforeAll(func() { - s.SetupSuite() - }) - BeforeEach(func() { - s.SetupTest() - }) - AfterEach(func() { - s.TeardownTest() - }) - AfterAll(func() { - s.TeardownSuite() - }) - - for filename, tests := range kindTests { - for _, test := range tests { - test := test - pc := reflect.ValueOf(test).Pointer() - funcValue := runtime.FuncForPC(pc) - testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] - It(testName, func(ctx SpecContext) { - s.Log(testName + ": BEGIN") - test(&s) - }, SpecTimeout(TestTimeout)) - } - } -}) diff --git a/extras/hs-test/infra/kind/utils.go b/extras/hs-test/infra/kind/utils.go deleted file mode 100644 index d6f37194b8..0000000000 --- a/extras/hs-test/infra/kind/utils.go +++ /dev/null @@ -1,66 +0,0 @@ -package hst_kind - -import ( - "bytes" - "context" - "os/exec" - "time" - - "k8s.io/client-go/tools/remotecommand" -) - -func (s *KindSuite) CopyToPod(podName string, namespace string, src string, dst string) { - cmd := exec.Command("kubectl", "--kubeconfig="+s.KubeconfigPath, "cp", src, namespace+"/"+podName+":"+dst) - out, err := cmd.CombinedOutput() - s.AssertNil(err, string(out)) -} - -func (s *KindSuite) Exec(pod *Pod, command []string) (string, error) { - var stdout, stderr bytes.Buffer - - // Prepare the request - req := s.ClientSet.CoreV1().RESTClient().Post(). - Resource("pods"). - Name(pod.Name). - Namespace(s.Namespace). - SubResource("exec"). - Param("container", pod.ContainerName). - Param("stdout", "true"). - Param("stderr", "true"). - Param("tty", "true") - - for _, cmd := range command { - req = req.Param("command", cmd) - } - s.Log("%s: %s", pod.Name, command) - - executor, err := remotecommand.NewSPDYExecutor(s.Config, "POST", req.URL()) - if err != nil { - s.Log("Error creating executor: %s", err.Error()) - } - - ctx, cancel := context.WithTimeout(context.Background(), 500*time.Second) - defer cancel() - - err = executor.StreamWithContext(ctx, remotecommand.StreamOptions{ - Stdout: &stdout, - Stderr: &stderr, - Tty: true, - }) - - output := stdout.String() + stderr.String() - - if err != nil { - return output, err - } - - return output, nil -} - -func boolPtr(b bool) *bool { - return &b -} - -func int64Ptr(integer int64) *int64 { - return &integer -} diff --git a/extras/hs-test/infra/suite_h2.go b/extras/hs-test/infra/suite_h2.go deleted file mode 100644 index 04919ad784..0000000000 --- a/extras/hs-test/infra/suite_h2.go +++ /dev/null @@ -1,374 +0,0 @@ -package hst - -import ( - "bytes" - "io" - "os" - "reflect" - "runtime" - "strings" - "time" - - "fd.io/hs-test/h2spec_extras" - . "fd.io/hs-test/infra/common" - . "github.com/onsi/ginkgo/v2" - "github.com/summerwind/h2spec/config" - "github.com/summerwind/h2spec/generic" - "github.com/summerwind/h2spec/hpack" - "github.com/summerwind/h2spec/http2" - "github.com/summerwind/h2spec/spec" -) - -var h2Tests = map[string][]func(s *H2Suite){} - -type H2Suite struct { - HstSuite - Interfaces struct { - Tap *NetInterface - } - Containers struct { - Vpp *Container - Curl *Container - H2load *Container - } -} - -func RegisterH2Tests(tests ...func(s *H2Suite)) { - h2Tests[GetTestFilename()] = tests -} - -func (s *H2Suite) SetupSuite() { - s.HstSuite.SetupSuite() - s.LoadNetworkTopology("tap") - s.LoadContainerTopology("single") - s.Interfaces.Tap = s.GetInterfaceByName("htaphost") - s.Containers.Vpp = s.GetContainerByName("vpp") - s.Containers.Curl = s.GetContainerByName("curl") - s.Containers.H2load = s.GetContainerByName("h2load") -} - -func (s *H2Suite) SetupTest() { - s.HstSuite.SetupTest() - - // Setup test conditions - var sessionConfig Stanza - sessionConfig.NewStanza("session").Append("enable").Append("use-app-socket-api").Close() - var memoryConfig Stanza - memoryConfig.NewStanza("memory").Append("main-heap-size 2G").Close() - - vpp, _ := s.Containers.Vpp.newVppInstance(s.Containers.Vpp.AllocatedCpus, memoryConfig, sessionConfig) - - s.AssertNil(vpp.Start()) - s.AssertNil(vpp.CreateTap(s.Interfaces.Tap, false, 1, 1), "failed to create tap interface") - - if *DryRun { - s.LogStartedContainers() - s.Skip("Dry run mode = true") - } -} - -func (s *H2Suite) TeardownTest() { - s.HstSuite.TeardownTest() -} - -func (s *H2Suite) VppAddr() string { - return s.Interfaces.Tap.Peer.Ip4AddressString() -} - -// Marked as pending since http plugin is not build with http/2 enabled by default -var _ = Describe("Http2Suite", Ordered, ContinueOnFailure, func() { - var s H2Suite - BeforeAll(func() { - s.SetupSuite() - }) - BeforeEach(func() { - s.SetupTest() - }) - AfterAll(func() { - s.TeardownSuite() - }) - AfterEach(func() { - s.TeardownTest() - }) - - for filename, tests := range h2Tests { - for _, test := range tests { - test := test - pc := reflect.ValueOf(test).Pointer() - funcValue := runtime.FuncForPC(pc) - testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] - It(testName, func(ctx SpecContext) { - s.Log(testName + ": BEGIN") - test(&s) - }, SpecTimeout(TestTimeout)) - } - } -}) - -type h2specTest struct { - desc string -} - -var genericTests = []h2specTest{ - {desc: "generic/1/1"}, - {desc: "generic/2/1"}, - {desc: "generic/2/2"}, - {desc: "generic/2/3"}, - {desc: "generic/2/4"}, - {desc: "generic/2/5"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "generic/3.1/1"}, - // {desc: "generic/3.1/2"}, - // {desc: "generic/3.1/3"}, - {desc: "generic/3.2/1"}, - {desc: "generic/3.2/2"}, - {desc: "generic/3.2/3"}, - // generic/3.3/* PRIORITY is deprecated - // TODO: message framing without content length using END_STREAM flag - // {desc: "generic/3.4/1"}, - {desc: "generic/3.5/1"}, - {desc: "generic/3.7/1"}, - {desc: "generic/3.8/1"}, - {desc: "generic/3.9/1"}, - {desc: "generic/3.9/2"}, - // TODO: CONTINUATION - //{desc: "generic/3.10/1"}, - //{desc: "generic/3.10/2"}, - {desc: "generic/4/1"}, - // HEAD method not supported - // {desc: "generic/4/2"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "generic/4/3"}, - // message framing using trailer section not supported - // {desc: "generic/4/4"}, - {desc: "generic/5/1"}, - {desc: "generic/5/2"}, - {desc: "generic/5/3"}, - {desc: "generic/5/4"}, - {desc: "generic/5/5"}, - {desc: "generic/5/6"}, - {desc: "generic/5/7"}, - {desc: "generic/5/8"}, - {desc: "generic/5/9"}, - {desc: "generic/5/10"}, - {desc: "generic/5/11"}, - {desc: "generic/5/12"}, - {desc: "generic/5/13"}, - {desc: "generic/5/14"}, - {desc: "generic/5/15"}, -} - -var hpackTests = []h2specTest{ - {desc: "hpack/2.3.3/1"}, - {desc: "hpack/4.2/1"}, - {desc: "hpack/5.2/1"}, - {desc: "hpack/5.2/2"}, - {desc: "hpack/5.2/3"}, - {desc: "hpack/6.1/1"}, - {desc: "hpack/6.3/1"}, -} - -var http2Tests = []h2specTest{ - {desc: "http2/3.5/1"}, - {desc: "http2/3.5/2"}, - {desc: "http2/4.1/1"}, - {desc: "http2/4.1/2"}, - {desc: "http2/4.1/3"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "http2/4.2/1"}, - {desc: "http2/4.2/2"}, - {desc: "http2/4.2/3"}, - {desc: "http2/4.3/1"}, - {desc: "http2/4.3/2"}, - {desc: "http2/4.3/3"}, - {desc: "http2/5.1.1/1"}, - {desc: "http2/5.1.1/2"}, - {desc: "http2/5.1.2/1"}, - {desc: "http2/5.1/1"}, - {desc: "http2/5.1/2"}, - {desc: "http2/5.1/3"}, - // TODO: CONTINUATION - // {desc: "http2/5.1/4"}, - {desc: "http2/5.1/5"}, - {desc: "http2/5.1/6"}, - // TODO: CONTINUATION - // {desc: "http2/5.1/7"}, - {desc: "http2/5.1/8"}, - {desc: "http2/5.1/9"}, - // TODO: CONTINUATION - // {desc: "http2/5.1/10"}, - {desc: "http2/5.1/11"}, - {desc: "http2/5.1/12"}, - // TODO: CONTINUATION - // {desc: "http2/5.1/13"}, - // http2/5.3.1/* PRIORITY is deprecated - {desc: "http2/5.4.1/1"}, - {desc: "http2/5.4.1/2"}, - {desc: "http2/5.5/1"}, - // TODO: CONTINUATION - // {desc: "http2/5.5/2"}, - {desc: "http2/6.1/1"}, - {desc: "http2/6.1/2"}, - {desc: "http2/6.1/3"}, - {desc: "http2/6.2/1"}, - {desc: "http2/6.2/2"}, - {desc: "http2/6.2/3"}, - {desc: "http2/6.2/4"}, - // http2/6.3/* PRIORITY is deprecated - {desc: "http2/6.4/1"}, - {desc: "http2/6.4/2"}, - {desc: "http2/6.4/3"}, - {desc: "http2/6.5.2/1"}, - {desc: "http2/6.5.2/2"}, - {desc: "http2/6.5.2/3"}, - {desc: "http2/6.5.2/4"}, - {desc: "http2/6.5.2/5"}, - {desc: "http2/6.5.3/1"}, - {desc: "http2/6.5.3/2"}, - {desc: "http2/6.5/1"}, - {desc: "http2/6.5/2"}, - {desc: "http2/6.5/3"}, - {desc: "http2/6.7/1"}, - {desc: "http2/6.7/2"}, - {desc: "http2/6.7/3"}, - {desc: "http2/6.7/4"}, - {desc: "http2/6.8/1"}, - {desc: "http2/6.9.1/1"}, - {desc: "http2/6.9.1/2"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "http2/6.9.1/3"}, - {desc: "http2/6.9.2/1"}, - {desc: "http2/6.9.2/2"}, - {desc: "http2/6.9.2/3"}, - {desc: "http2/6.9/1"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "http2/6.9/2"}, - {desc: "http2/6.9/3"}, - // TODO: CONTINUATION - // {desc: "http2/6.10/1"}, - // {desc: "http2/6.10/2"}, - // {desc: "http2/6.10/3"}, - // {desc: "http2/6.10/4"}, - // {desc: "http2/6.10/5"}, - // {desc: "http2/6.10/6"}, - {desc: "http2/7/1"}, - // TODO: message framing without content length using END_STREAM flag - // {desc: "http2/7/2"}, - {desc: "http2/8.1.2.1/1"}, - {desc: "http2/8.1.2.1/2"}, - {desc: "http2/8.1.2.1/3"}, - {desc: "http2/8.1.2.1/4"}, - {desc: "http2/8.1.2.2/1"}, - {desc: "http2/8.1.2.2/2"}, - {desc: "http2/8.1.2.3/1"}, - {desc: "http2/8.1.2.3/2"}, - {desc: "http2/8.1.2.3/3"}, - {desc: "http2/8.1.2.3/4"}, - {desc: "http2/8.1.2.3/5"}, - {desc: "http2/8.1.2.3/6"}, - {desc: "http2/8.1.2.3/7"}, - {desc: "http2/8.1.2.6/1"}, - {desc: "http2/8.1.2.6/2"}, - {desc: "http2/8.1.2/1"}, - {desc: "http2/8.1/1"}, - {desc: "http2/8.2/1"}, -} - -var extrasTests = []h2specTest{ - {desc: "extras/1/1"}, - {desc: "extras/1/2"}, -} - -const ( - GenericTestGroup int = 1 - HpackTestGroup int = 2 - Http2TestGroup int = 3 - ExtrasTestGroup int = 4 -) - -var specs = []struct { - tg int - tests []h2specTest -}{ - {GenericTestGroup, genericTests}, - {HpackTestGroup, hpackTests}, - {Http2TestGroup, http2Tests}, - {ExtrasTestGroup, extrasTests}, -} - -// Marked as pending since http plugin is not build with http/2 enabled by default -var _ = Describe("H2SpecSuite", Ordered, ContinueOnFailure, func() { - var s H2Suite - BeforeAll(func() { - s.SetupSuite() - }) - BeforeEach(func() { - s.SetupTest() - }) - AfterAll(func() { - s.TeardownSuite() - }) - AfterEach(func() { - s.TeardownTest() - }) - - for _, sp := range specs { - for _, test := range sp.tests { - test := test - testName := "http2_test.go/h2spec_" + strings.ReplaceAll(test.desc, "/", "_") - It(testName, func(ctx SpecContext) { - s.Log(testName + ": BEGIN") - vpp := s.Containers.Vpp.VppInstance - serverAddress := s.VppAddr() - s.Log(vpp.Vppctl("http static server uri tls://" + serverAddress + "/443 url-handlers debug 2")) - s.Log(vpp.Vppctl("test-url-handler enable")) - conf := &config.Config{ - Host: serverAddress, - Port: 443, - Path: "/test1", - Timeout: time.Second * 5, - MaxHeaderLen: 1024, - TLS: true, - Insecure: true, - Sections: []string{test.desc}, - Verbose: true, - } - // capture h2spec output so it will be in log - oldStdout := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - - var tg *spec.TestGroup - switch sp.tg { - case GenericTestGroup: - tg = generic.Spec() - break - case HpackTestGroup: - tg = hpack.Spec() - break - case Http2TestGroup: - tg = http2.Spec() - break - case ExtrasTestGroup: - tg = h2spec_extras.Spec() - break - } - tg.Test(conf) - - oChan := make(chan string) - go func() { - var buf bytes.Buffer - io.Copy(&buf, r) - oChan <- buf.String() - }() - - // restore to normal state - w.Close() - os.Stdout = oldStdout - o := <-oChan - s.Log(o) - s.AssertEqual(0, tg.FailedCount) - }) - } - } -}) diff --git a/extras/hs-test/kind_test.go b/extras/hs-test/kind_test.go deleted file mode 100644 index b1e2d23b6e..0000000000 --- a/extras/hs-test/kind_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "time" - - . "fd.io/hs-test/infra/kind" - . "github.com/onsi/ginkgo/v2" -) - -func init() { - RegisterKindTests(KindIperfVclTest, NginxRpsTest) -} - -func KindIperfVclTest(s *KindSuite) { - s.DeployPod(s.Pods.ClientGeneric) - s.DeployPod(s.Pods.ServerGeneric) - - vclPath := "/vcl.conf" - ldpPath := "/usr/lib/libvcl_ldpreload.so" - - // temporary workaround - symLink := "for file in /usr/lib/*.so; do\n" + - "if [ -e \"$file\" ]; then\n" + - "base=$(basename \"$file\")\n" + - "newlink=\"/usr/lib/${base}.25.06\"\n" + - "ln -s \"$file\" \"$newlink\"\n" + - "fi\n" + - "done" - - vclConf := "echo \"vcl {\n" + - "rx-fifo-size 4000000\n" + - "tx-fifo-size 4000000\n" + - "app-scope-local\n" + - "app-scope-global\n" + - "app-socket-api abstract:vpp/session\n" + - "}\" > /vcl.conf" - - s.Exec(s.Pods.ClientGeneric, []string{"/bin/bash", "-c", symLink}) - s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c", symLink}) - - _, err := s.Exec(s.Pods.ClientGeneric, []string{"/bin/bash", "-c", vclConf}) - s.AssertNil(err) - _, err = s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c", vclConf}) - s.AssertNil(err) - - _, err = s.Exec(s.Pods.ServerGeneric, []string{"/bin/bash", "-c", - "VCL_CONFIG=" + vclPath + " LD_PRELOAD=" + ldpPath + " iperf3 -s -D -4"}) - s.AssertNil(err) - output, err := s.Exec(s.Pods.ClientGeneric, []string{"/bin/bash", "-c", - "VCL_CONFIG=" + vclPath + " LD_PRELOAD=" + ldpPath + " iperf3 -c " + s.Pods.ServerGeneric.IpAddress}) - s.Log(output) - s.AssertNil(err) -} - -func NginxRpsTest(s *KindSuite) { - s.DeployPod(s.Pods.Nginx) - s.DeployPod(s.Pods.Ab) - s.CreateNginxConfig() - vcl := "VCL_CONFIG=/vcl.conf" - ldp := "LD_PRELOAD=/usr/lib/libvcl_ldpreload.so" - - // temporary workaround - symLink := "for file in /usr/lib/*.so; do\n" + - "if [ -e \"$file\" ]; then\n" + - "base=$(basename \"$file\")\n" + - "newlink=\"/usr/lib/${base}.25.06\"\n" + - "ln -s \"$file\" \"$newlink\"\n" + - "fi\n" + - "done" - - vclConf := "echo \"vcl {\n" + - "heapsize 64M\n" + - "rx-fifo-size 4000000\n" + - "tx-fifo-size 4000000\n" + - "segment-size 4000000000\n" + - "add-segment-size 4000000000\n" + - "event-queue-size 100000\n" + - "use-mq-eventfd\n" + - "app-socket-api abstract:vpp/session\n" + - "}\" > /vcl.conf" - - out, err := s.Exec(s.Pods.Nginx, []string{"/bin/bash", "-c", symLink}) - s.AssertNil(err, out) - - out, err = s.Exec(s.Pods.Nginx, []string{"/bin/bash", "-c", vclConf}) - s.AssertNil(err, out) - - go func() { - defer GinkgoRecover() - out, err := s.Exec(s.Pods.Nginx, []string{"/bin/bash", "-c", ldp + " " + vcl + " nginx -c /nginx.conf"}) - s.AssertNil(err, out) - }() - - // wait for nginx to start up - time.Sleep(time.Second * 2) - out, err = s.Exec(s.Pods.Ab, []string{"ab", "-k", "-r", "-n", "1000000", "-c", "1000", "http://" + s.Pods.Nginx.IpAddress + ":80/64B.json"}) - s.Log(out) - s.AssertNil(err) -} diff --git a/extras/hs-test/kubernetes/kind-config.yaml b/extras/hs-test/kubernetes/kind-config.yaml deleted file mode 100644 index f7109070b1..0000000000 --- a/extras/hs-test/kubernetes/kind-config.yaml +++ /dev/null @@ -1,10 +0,0 @@ -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -networking: - disableDefaultCNI: true - podSubnet: "11.0.0.0/16" - serviceSubnet: "11.96.0.0/12" -nodes: -- role: control-plane -- role: worker -- role: worker \ No newline at end of file diff --git a/extras/hs-test/kubernetes/setupCluster.sh b/extras/hs-test/kubernetes/setupCluster.sh deleted file mode 100755 index 9cd92a1f6b..0000000000 --- a/extras/hs-test/kubernetes/setupCluster.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -set -e - -if [ "$EUID" -eq 0 ]; then - echo "********" - echo "Do not run as root. Exiting." - echo "********" - exit 1 -fi - -echo "********" -echo "Performance tests only work on Ubuntu 22.04 for now." -echo "Do not run as root (untested) and make sure you have KinD and Kubectl installed!" -echo "https://kind.sigs.k8s.io/" -echo "https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management" -echo "********" - -kind create cluster --config kubernetes/kind-config.yaml -kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.3/manifests/tigera-operator.yaml - -echo "Sleeping for 10s, waiting for tigera operator to start up." -sleep 10 - -kubectl create -f https://raw.githubusercontent.com/projectcalico/vpp-dataplane/master/yaml/calico/installation-default.yaml -kubectl create -f kubernetes/calico-config.yaml - -echo "Done. Please wait for the cluster to come fully online before running tests." -echo "Use 'watch kubectl get pods -A' to monitor cluster status." -echo "To delete the cluster, use 'kind delete cluster'" \ No newline at end of file diff --git a/extras/hs-test/script/build_curl.sh b/extras/hs-test/script/build_curl.sh deleted file mode 100755 index 1a61b9fd70..0000000000 --- a/extras/hs-test/script/build_curl.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -wget https://github.com/stunnel/static-curl/releases/download/8.5.0/curl-static-"$TARGETARCH"-8.5.0.tar.xz -tar -xvf ./curl-static-"$TARGETARCH"-8.5.0.tar.xz -cp curl /usr/bin/curl \ No newline at end of file diff --git a/extras/hs-test/script/build_hst.sh b/extras/hs-test/script/build_hst.sh deleted file mode 100755 index ab482b09f6..0000000000 --- a/extras/hs-test/script/build_hst.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bash - -if [ "$(lsb_release -is)" != Ubuntu ]; then - echo "Host stack test framework is supported only on Ubuntu" - exit 1 -fi - -export VPP_WS=../.. -export UBUNTU_VERSION=${UBUNTU_VERSION:-"$(lsb_release -rs)"} -echo "Ubuntu version is set to ${UBUNTU_VERSION}" - -if [ "$1" == "debug" ]; then - VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp_debug-native/vpp -elif [ "$1" == "gcov" ]; then - VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp_gcov-native/vpp -else - VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp-native/vpp -fi - -LAST_STATE_FILE=".last_state_hash" - -# get current state hash and ubuntu version -current_state_hash=$(ls -l "$VPP_BUILD_ROOT"/.mu_build_install_timestamp; ls -l docker | sha1sum | awk '{print $1}') -current_state_hash=$current_state_hash$UBUNTU_VERSION$1 - -if [ -f "$LAST_STATE_FILE" ]; then - last_state_hash=$(cat "$LAST_STATE_FILE") -else - last_state_hash="" -fi - -# compare current state with last state and check FORCE_BUILD -if [ "$current_state_hash" = "$last_state_hash" ] && [ "$2" = "false" ]; then - echo "*** Skipping docker build - no new changes ***" - exit 0 -fi - -OS_ARCH="$(uname -m)" -DOCKER_BUILD_DIR="/scratch/docker-build" -DOCKER_CACHE_DIR="${DOCKER_BUILD_DIR}/docker_cache" - -if [ -d "${DOCKER_BUILD_DIR}" ] ; then - mkdir -p "${DOCKER_CACHE_DIR}" - DOCKER_HST_BUILDER="hst_builder" - set -x - if ! docker buildx ls --format "{{.Name}}" | grep -q "${DOCKER_HST_BUILDER}"; then - docker buildx create --use --driver-opt env.http_proxy="$HTTP_PROXY" --driver-opt env.https_proxy="$HTTP_PROXY" --driver-opt '"env.no_proxy='"$NO_PROXY"'"' --name=${DOCKER_HST_BUILDER} --driver=docker-container --use --bootstrap || true - fi - set -x - DOCKER_CACHE_ARGS="--builder=${DOCKER_HST_BUILDER} --load --cache-to type=local,dest=${DOCKER_CACHE_DIR},mode=max --cache-from type=local,src=${DOCKER_CACHE_DIR}" -fi - -echo "Taking build objects from ${VPP_BUILD_ROOT}" - -export HST_LDPRELOAD=${VPP_BUILD_ROOT}/lib/${OS_ARCH}-linux-gnu/libvcl_ldpreload.so -echo "HST_LDPRELOAD is set to ${HST_LDPRELOAD}" - -export PATH=${VPP_BUILD_ROOT}/bin:$PATH - -bin=vpp-data/bin -lib=vpp-data/lib - -mkdir -p ${bin} ${lib} || true -rm -rf vpp-data/bin/* || true -rm -rf vpp-data/lib/* || true - -declare -i res=0 -cp ${VPP_BUILD_ROOT}/bin/* ${bin} -res+=$? -cp -r ${VPP_BUILD_ROOT}/lib/"${OS_ARCH}"-linux-gnu/* ${lib} -res+=$? -if [ "$res" -ne 0 ]; then - echo "Failed to copy VPP files. Is VPP built? Try running 'make build' in VPP directory." - exit 1 -fi - -docker_build () { - tag=$1 - dockername=$2 - set -ex - # shellcheck disable=2086 - docker buildx build ${DOCKER_CACHE_ARGS} \ - --build-arg UBUNTU_VERSION \ - --build-arg OS_ARCH="$OS_ARCH" \ - --build-arg http_proxy="$HTTP_PROXY" \ - --build-arg https_proxy="$HTTP_PROXY" \ - --build-arg HTTP_PROXY="$HTTP_PROXY" \ - --build-arg HTTPS_PROXY="$HTTP_PROXY" \ - -t "$tag" -f docker/Dockerfile."$dockername" . - set +ex -} - -docker_build hs-test/vpp vpp -docker_build hs-test/nginx-ldp nginx -docker_build hs-test/nginx-server nginx-server -docker_build hs-test/curl curl -docker_build hs-test/envoy envoy -docker_build hs-test/nginx-http3 nginx-http3 -docker_build hs-test/ab ab -docker_build hs-test/wrk wrk -docker_build hs-test/h2load h2load - -# make it multi-user friendly -if [ -d "${DOCKER_CACHE_DIR}" ] ; then - chgrp -R docker "${DOCKER_CACHE_DIR}" - chmod -R g+rwx "${DOCKER_CACHE_DIR}" -fi - -# cleanup detached images -images=$(docker images --filter "dangling=true" -q --no-trunc) -if [ "$images" != "" ]; then - # shellcheck disable=SC2086 - docker rmi $images -fi - -echo "$current_state_hash" > "$LAST_STATE_FILE" diff --git a/extras/hs-test/topo-containers/2peerVethLdp.yaml b/extras/hs-test/topo-containers/2peerVethLdp.yaml deleted file mode 100644 index bd6e63a945..0000000000 --- a/extras/hs-test/topo-containers/2peerVethLdp.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -volumes: - - volume: &server-vol - host-dir: "$HST_VOLUME_DIR/server-share" - container-dir: "/tmp/server-share" - is-default-work-dir: true - - volume: &client-vol - host-dir: "$HST_VOLUME_DIR/client-share" - container-dir: "/tmp/client-share" - is-default-work-dir: true - -containers: - - name: "server-vpp" - volumes: - - <<: *server-vol - - name: "client-vpp" - volumes: - - <<: *client-vol diff --git a/extras/hs-test/vars b/extras/hs-test/vars deleted file mode 100644 index d1ca078fe2..0000000000 --- a/extras/hs-test/vars +++ /dev/null @@ -1,7 +0,0 @@ -export VPP_WS=../../ - -export HST_LDPRELOAD=${VPP_WS}/build-root/build-vpp-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so -export PATH=${VPP_WS}/build-root/build-vpp-native/vpp/bin:$PATH - -export UBUNTU_VERSION=$(lsb_release -rs) -export HST_EXTENDED_TESTS=false diff --git a/extras/rpm/vpp.spec b/extras/rpm/vpp.spec index 6bfb12471e..a18f57107a 100644 --- a/extras/rpm/vpp.spec +++ b/extras/rpm/vpp.spec @@ -100,6 +100,7 @@ svm - vm library vlib - vector processing library vlib-api - binary API library vnet - network stack library +vpp_crypto_engines - cryptography libraries %package devel Summary: VPP header files, static libraries @@ -202,6 +203,7 @@ install -p -m 644 %{_mu_build_dir}/../src/vpp/conf/80-vpp.conf %{buildroot}/etc/ mkdir -p -m755 %{buildroot}%{_libdir} mkdir -p -m755 %{buildroot}/etc/bash_completion.d mkdir -p -m755 %{buildroot}/usr/share/vpp +mkdir -p -m755 %{buildroot}/usr/%{_lib}/vpp_crypto_engines for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/*/lib* -type f -name '*.so.*.*' -print ) do install -p -m 755 $file %{buildroot}%{_libdir} @@ -218,6 +220,11 @@ for file in $(find %{_mu_build_dir}/%{_vpp_install_dir}/vpp/share/vpp/api -type do install -p -m 644 $file %{buildroot}/usr/share/vpp/api done +for file in $(cd %{_mu_build_dir}/%{_vpp_install_dir}/vpp/%{_lib}/vpp_crypto_engines && find -type f -print) +do + install -p -m 755 %{_mu_build_dir}/%{_vpp_install_dir}/vpp/%{_lib}/vpp_crypto_engines/$file \ + %{buildroot}/usr/%{_lib}/vpp_crypto_engines/$file +done # Lua bindings mkdir -p -m755 %{buildroot}/usr/share/doc/vpp/examples/lua/examples/cli @@ -369,6 +376,8 @@ fi /usr/bin/vat2 /usr/bin/vpp* /usr/bin/svm* +/usr/bin/vcl_test_client +/usr/bin/vcl_test_server %config(noreplace) /etc/sysctl.d/80-vpp.conf %config(noreplace) /etc/vpp/startup.conf /usr/share/vpp/api/* @@ -385,8 +394,14 @@ fi %exclude %{_libdir}/vpp_plugins %exclude %{_libdir}/vpp_api_test_plugins %exclude %{_libdir}/vat2_plugins +%exclude %{_libdir}/libefa.so* +%exclude %{_libdir}/libibverbs.so* +%exclude %{_libdir}/libmana.so* +%exclude %{_libdir}/libmlx4.so* +%exclude %{_libdir}/libmlx5.so* %{_libdir}/* /usr/share/vpp/api/* +/usr/%{_lib}/vpp_crypto_engines/* %files api-lua %defattr(644,root,root,644) @@ -416,4 +431,4 @@ fi /usr/%{_lib}/vpp_plugins/* /usr/%{_lib}/vpp_api_test_plugins/* /usr/%{_lib}/vat2_plugins/* -/usr/share/vpp/api/* +/usr/share/vpp/api/* \ No newline at end of file diff --git a/extras/scripts/host-stack/tls-certs/generate-tls-ca.sh b/extras/scripts/host-stack/tls-certs/generate-tls-ca.sh new file mode 100644 index 0000000000..efecadbecc --- /dev/null +++ b/extras/scripts/host-stack/tls-certs/generate-tls-ca.sh @@ -0,0 +1,41 @@ +#!/usr/bin/bash + +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Cisco Systems, Inc. + +# Generate ca private key and certificate +openssl genrsa -out ca-key.pem 2048 +openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 3650 -subj "/C=US/ST=CA/L=San Jose/O=Cisco/CN=Fd.io Test Root CA" + +# Generate intermediate CA key +openssl genrsa -out intermediate-key.pem 2048 + +# Create intermediate CA certificate request +openssl req -new -key intermediate-key.pem -out intermediate.csr -subj "/C=US/ST=CA/L=San Jose/O=Cisco/CN=Fd.io Test Intermediate CA" + +# Sign intermediate certificate with root CA +openssl x509 -req -in intermediate.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out intermediate-cert.pem -days 3650 + +# Create a chain file (root + intermediate) +cat ca-cert.pem intermediate-cert.pem > ca-chain.pem + +# Create CRL configuration +cat > crl.conf << EOF +[ ca ] +default_ca = CA_default + +[ CA_default ] +database = index.txt +serial = serial +crlnumber = crlnumber +default_crl_days = 30 +default_md = sha256 +EOF + +# Initialize files +touch index.txt +echo 01 > serial +echo 01 > crlnumber + +# Generate empty CRL +openssl ca -config crl.conf -gencrl -keyfile ca-key.pem -cert ca-cert.pem -out ca-crl.pem \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index de1ee713d5..71f0010bba 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.19) if (DEFINED VPP_PLATFORM_C_COMPILER_NAMES) set(CMAKE_C_COMPILER_NAMES ${VPP_PLATFORM_C_COMPILER_NAME}) diff --git a/src/cmake/cpu.cmake b/src/cmake/cpu.cmake index b1b802a550..68f1a71671 100644 --- a/src/cmake/cpu.cmake +++ b/src/cmake/cpu.cmake @@ -241,6 +241,13 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") CACHE_PREFETCH_BYTES 64 OFF ) + + add_vpp_march_variant(neoversev2 + FLAGS -mcpu=neoverse-v2+crypto + N_PREFETCHES 6 + CACHE_PREFETCH_BYTES 64 + ) + endif() macro(vpp_library_set_multiarch_sources lib) diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 43ad4cc2a2..e62acc2854 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -16,6 +16,27 @@ include_directories ( ${CMAKE_CURRENT_BINARY_DIR} ) +set(VPP_PLUGINS + "" + CACHE + STRING "Comma-separated list of plugins included in build" +) + +if(NOT VPP_PLUGINS STREQUAL "") + string(REGEX REPLACE "[ \t]*,[ \t]*" ";" _plugins "${VPP_PLUGINS}") + list(FILTER _plugins EXCLUDE REGEX "^$") + + foreach(p IN LISTS _plugins) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${p}/CMakeLists.txt") + add_subdirectory("${p}") + else() + message(FATAL_ERROR + "VPP plugin '${p}' not found: expected '${CMAKE_CURRENT_SOURCE_DIR}/${p}/CMakeLists.txt'") + endif() + endforeach() + return() +endif() + ############################################################################## # find and add all plugin subdirs ############################################################################## diff --git a/src/plugins/af_packet/af_packet.c b/src/plugins/af_packet/af_packet.c index 56d90c0c98..86c2685870 100644 --- a/src/plugins/af_packet/af_packet.c +++ b/src/plugins/af_packet/af_packet.c @@ -434,6 +434,14 @@ create_packet_sock (int host_if_index, tpacket_req_u_t *rx_req, return ret; } +static u32 +af_packet_make_fanout_id (af_packet_if_t *apif) +{ + u16 if_hash = + hash_memory (apif->host_if_name, strlen ((char *) apif->host_if_name), 0); + return (apif->dev_instance & 0xffff) ^ (if_hash & 0xff00); +} + int af_packet_queue_init (vlib_main_t *vm, af_packet_if_t *apif, af_packet_create_if_arg_t *arg, @@ -506,9 +514,9 @@ af_packet_queue_init (vlib_main_t *vm, af_packet_if_t *apif, if (rx_queue || tx_queue) { - ret = - create_packet_sock (apif->host_if_index, rx_req, tx_req, &fd, &ring, - apif->dev_instance, &arg->flags, apif->version); + ret = create_packet_sock (apif->host_if_index, rx_req, tx_req, &fd, + &ring, af_packet_make_fanout_id (apif), + &arg->flags, apif->version); if (ret != 0) goto error; diff --git a/src/plugins/af_packet/cli.c b/src/plugins/af_packet/cli.c index 2af3fb17ee..0f09badce7 100644 --- a/src/plugins/af_packet/cli.c +++ b/src/plugins/af_packet/cli.c @@ -47,6 +47,7 @@ af_packet_create_command_fn (vlib_main_t * vm, unformat_input_t * input, af_packet_create_if_arg_t _arg, *arg = &_arg; clib_error_t *error = NULL; u8 hwaddr[6]; + u32 nqs; int r; clib_memset (arg, 0, sizeof (*arg)); @@ -79,10 +80,10 @@ af_packet_create_command_fn (vlib_main_t * vm, unformat_input_t * input, else if (unformat (line_input, "tx-per-block %u", &arg->tx_frames_per_block)) ; - else if (unformat (line_input, "num-rx-queues %u", &arg->num_rxqs)) - ; - else if (unformat (line_input, "num-tx-queues %u", &arg->num_txqs)) - ; + else if (unformat (line_input, "num-rx-queues %u", &nqs)) + arg->num_rxqs = nqs; + else if (unformat (line_input, "num-tx-queues %u", &nqs)) + arg->num_txqs = nqs; else if (unformat (line_input, "qdisc-bypass-disable")) arg->flags &= ~AF_PACKET_IF_FLAGS_QDISC_BYPASS; else if (unformat (line_input, "cksum-gso-disable")) diff --git a/src/plugins/af_packet/device.c b/src/plugins/af_packet/device.c index 797666a147..8f5ba1c568 100644 --- a/src/plugins/af_packet/device.c +++ b/src/plugins/af_packet/device.c @@ -333,11 +333,11 @@ fill_gso_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr) if (b0->flags & VNET_BUFFER_F_IS_IP4) { ip4_header_t *ip4; + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; - vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size; vnet_hdr->hdr_len = l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz; - vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - vnet_hdr->csum_start = l4_hdr_offset; // 0x22; + vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size; + vnet_hdr->csum_start = l4_hdr_offset; vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset); if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) @@ -349,11 +349,11 @@ fill_gso_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr) else if (b0->flags & VNET_BUFFER_F_IS_IP6) { ip6_header_t *ip6; + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size; vnet_hdr->hdr_len = l4_hdr_offset + vnet_buffer2 (b0)->gso_l4_hdr_sz; - vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - vnet_hdr->csum_start = l4_hdr_offset; // 0x36; + vnet_hdr->gso_size = vnet_buffer2 (b0)->gso_size; + vnet_hdr->csum_start = l4_hdr_offset; vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset); tcp_header_t *tcp = @@ -373,46 +373,50 @@ fill_cksum_offload (vlib_buffer_t *b0, vnet_virtio_net_hdr_t *vnet_hdr) ip4 = (ip4_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset); if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) ip4->checksum = ip4_header_checksum (ip4); - vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - vnet_hdr->csum_start = l4_hdr_offset; if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM) { tcp_header_t *tcp = (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset); tcp->checksum = ip4_pseudo_header_cksum (ip4); - vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->hdr_len = l4_hdr_offset + tcp_header_bytes (tcp); + vnet_hdr->csum_start = l4_hdr_offset; + vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); } else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM) { udp_header_t *udp = (udp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset); udp->checksum = ip4_pseudo_header_cksum (ip4); - vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum); + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->hdr_len = l4_hdr_offset + sizeof (udp_header_t); + vnet_hdr->csum_start = l4_hdr_offset; + vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum); } } else if (b0->flags & VNET_BUFFER_F_IS_IP6) { ip6_header_t *ip6; - vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - vnet_hdr->csum_start = l4_hdr_offset; ip6 = (ip6_header_t *) (b0->data + vnet_buffer (b0)->l3_hdr_offset); if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM) { tcp_header_t *tcp = (tcp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset); tcp->checksum = ip6_pseudo_header_cksum (ip6); - vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->hdr_len = l4_hdr_offset + tcp_header_bytes (tcp); + vnet_hdr->csum_start = l4_hdr_offset; + vnet_hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum); } else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM) { udp_header_t *udp = (udp_header_t *) (b0->data + vnet_buffer (b0)->l4_hdr_offset); udp->checksum = ip6_pseudo_header_cksum (ip6); - vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum); + vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; vnet_hdr->hdr_len = l4_hdr_offset + sizeof (udp_header_t); + vnet_hdr->csum_start = l4_hdr_offset; + vnet_hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum); } } } diff --git a/src/plugins/af_xdp/input.c b/src/plugins/af_xdp/input.c index 9177b3ffc5..72c3738fa2 100644 --- a/src/plugins/af_xdp/input.c +++ b/src/plugins/af_xdp/input.c @@ -88,7 +88,12 @@ af_xdp_device_input_refill_db (vlib_main_t * vm, if (clib_spinlock_trylock_if_init (&rxq->syscall_lock)) { - int ret = recvmsg (rxq->xsk_fd, 0, MSG_DONTWAIT); + struct msghdr msg = { 0 }; + struct iovec iov = { 0 }; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + int ret = recvmsg (rxq->xsk_fd, &msg, MSG_DONTWAIT); clib_spinlock_unlock_if_init (&rxq->syscall_lock); if (PREDICT_FALSE (ret < 0)) { diff --git a/src/plugins/af_xdp/output.c b/src/plugins/af_xdp/output.c index a59c01ca6e..00dc0e50c2 100644 --- a/src/plugins/af_xdp/output.c +++ b/src/plugins/af_xdp/output.c @@ -209,6 +209,8 @@ af_xdp_device_output_tx_try (vlib_main_t * vm, af_xdp_log (VLIB_LOG_LEVEL_ERR, ad, "vlib_buffer_chain_linearize failed"); vlib_buffer_free_one (vm, vlib_get_buffer_index (vm, b[0])); + b += 1; + n -= 1; continue; } } diff --git a/src/plugins/dev_ena/ena.c b/src/plugins/dev_ena/ena.c index a81a33d5f2..6e7afaa772 100644 --- a/src/plugins/dev_ena/ena.c +++ b/src/plugins/dev_ena/ena.c @@ -170,8 +170,9 @@ ena_init (vlib_main_t *vm, vnet_dev_t *dev) *ed->host_info = host_info; ed->host_info->num_cpus = vlib_get_n_threads (); - strncpy ((char *) ed->host_info->kernel_ver_str, VPP_BUILD_VER, - sizeof (ed->host_info->kernel_ver_str) - 1); + snprintf ((char *) ed->host_info->kernel_ver_str, + sizeof (ed->host_info->kernel_ver_str), "%.*s", + (int) (sizeof (ed->host_info->kernel_ver_str) - 1), VPP_BUILD_VER); ena_set_mem_addr (vm, dev, &host_attr.os_info_ba, ed->host_info); if ((rv = ena_aq_set_feature (vm, dev, ENA_ADMIN_FEAT_ID_HOST_ATTR_CONFIG, diff --git a/src/plugins/dev_octeon/init.c b/src/plugins/dev_octeon/init.c index ad5fca1f7d..b7dc20b719 100644 --- a/src/plugins/dev_octeon/init.c +++ b/src/plugins/dev_octeon/init.c @@ -87,6 +87,15 @@ static vnet_dev_arg_t oct_port_args[] = { .type = VNET_DEV_ARG_TYPE_BOOL, .default_val.boolean = false, }, + { + .id = OCT_PORT_ARG_RSS_FLOW_KEY, + .name = "rss_flow_key", + .desc = "RSS Flow Key Bitmap, applicable to network devices only", + .type = VNET_DEV_ARG_TYPE_UINT32, + .default_val.uint32 = FLOW_KEY_TYPE_IPV4 | FLOW_KEY_TYPE_IPV6 | + FLOW_KEY_TYPE_TCP | FLOW_KEY_TYPE_UDP | + FLOW_KEY_TYPE_SCTP, + }, { .id = OCT_PORT_ARG_END, .name = "end", @@ -211,6 +220,16 @@ oct_init_nix (vlib_main_t *vm, vnet_dev_t *dev) .tx_offloads = { .ip4_cksum = 1, }, + + }, + .default_rss_key = { + .key = { + 0xfe, 0xed, 0x0b, 0xad, 0xfe, 0xed, 0x0b, 0xad, 0xad, 0x0b, 0xed, 0xfe, + 0xad, 0x0b, 0xed, 0xfe, 0x13, 0x57, 0x9b, 0xef, 0x24, 0x68, 0xac, 0x0e, + 0x91, 0x72, 0x53, 0x11, 0x82, 0x64, 0x20, 0x44, 0x12, 0xef, 0x34, 0xcd, + 0x56, 0xbc, 0x78, 0x9a, 0x9a, 0x78, 0xbc, 0x56, 0xcd, 0x34, 0xef, 0x12, + }, + .length = 48, }, .ops = { .init = oct_port_init, diff --git a/src/plugins/dev_octeon/octeon.h b/src/plugins/dev_octeon/octeon.h index a77dc8a11a..765cdbb556 100644 --- a/src/plugins/dev_octeon/octeon.h +++ b/src/plugins/dev_octeon/octeon.h @@ -33,6 +33,7 @@ typedef enum typedef enum { OCT_PORT_ARG_EN_ETH_PAUSE_FRAME = 1, + OCT_PORT_ARG_RSS_FLOW_KEY = 2, OCT_PORT_ARG_END } oct_port_args_t; @@ -83,6 +84,7 @@ typedef struct u8 q_intr_enabled : 1; struct roc_npc npc; oct_flow_entry_t *flow_entries; + u32 rss_flowkey; } oct_port_t; typedef struct diff --git a/src/plugins/dev_octeon/port.c b/src/plugins/dev_octeon/port.c index 957af9160e..a9d170e90d 100644 --- a/src/plugins/dev_octeon/port.c +++ b/src/plugins/dev_octeon/port.c @@ -18,17 +18,6 @@ VLIB_REGISTER_LOG_CLASS (oct_log, static) = { .subclass_name = "port", }; -static const u8 default_rss_key[] = { - 0xfe, 0xed, 0x0b, 0xad, 0xfe, 0xed, 0x0b, 0xad, 0xad, 0x0b, 0xed, 0xfe, - 0xad, 0x0b, 0xed, 0xfe, 0x13, 0x57, 0x9b, 0xef, 0x24, 0x68, 0xac, 0x0e, - 0x91, 0x72, 0x53, 0x11, 0x82, 0x64, 0x20, 0x44, 0x12, 0xef, 0x34, 0xcd, - 0x56, 0xbc, 0x78, 0x9a, 0x9a, 0x78, 0xbc, 0x56, 0xcd, 0x34, 0xef, 0x12 -}; - -static const u32 default_rss_flowkey = - (FLOW_KEY_TYPE_IPV4 | FLOW_KEY_TYPE_IPV6 | FLOW_KEY_TYPE_TCP | - FLOW_KEY_TYPE_UDP | FLOW_KEY_TYPE_SCTP); - static const u64 rxq_cfg = ROC_NIX_LF_RX_CFG_DIS_APAD | ROC_NIX_LF_RX_CFG_IP6_UDP_OPT | ROC_NIX_LF_RX_CFG_L2_LEN_ERR | ROC_NIX_LF_RX_CFG_DROP_RE | @@ -143,6 +132,8 @@ oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port) if (arg->id == OCT_PORT_ARG_EN_ETH_PAUSE_FRAME && vnet_dev_arg_get_bool (arg)) is_pause_frame_enable = true; + else if (arg->id == OCT_PORT_ARG_RSS_FLOW_KEY) + cp->rss_flowkey = vnet_dev_arg_get_uint32 (arg); } if ((rrv = roc_nix_lf_alloc (nix, ifs->num_rx_queues, ifs->num_tx_queues, @@ -186,13 +177,13 @@ oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port) return oct_roc_err (dev, rrv, "roc_nix_tm_hierarchy_enable() failed"); } - if ((rrv = roc_nix_rss_default_setup (nix, default_rss_flowkey))) + if ((rrv = roc_nix_rss_default_setup (nix, cp->rss_flowkey))) { oct_port_deinit (vm, port); return oct_roc_err (dev, rrv, "roc_nix_rss_default_setup() failed"); } - roc_nix_rss_key_set (nix, default_rss_key); + roc_nix_rss_key_set (nix, port->rss_key.key); cp->npc.roc_nix = nix; cp->npc.flow_prealloc_size = OCT_FLOW_PREALLOC_SIZE; @@ -493,6 +484,28 @@ oct_port_start (vlib_main_t *vm, vnet_dev_port_t *port) goto done; } + if (!(roc_nix_is_sdp (nix) || roc_nix_is_lbk (nix))) + { + + rv = roc_nix_npc_promisc_ena_dis (nix, port->promisc); + if (rv) + { + return oct_roc_err (dev, rv, "roc_nix_npc_promisc_ena_dis failed"); + } + + if (roc_nix_is_pf (nix)) + { + + rv = roc_nix_mac_promisc_mode_enable (nix, port->promisc); + if (rv) + { + return oct_roc_err (dev, rv, + "roc_nix_mac_promisc_mode_enable(%s) failed", + port->promisc ? "true" : "false"); + } + } + } + vnet_dev_poll_port_add (vm, port, 0.5, oct_port_poll); if (roc_nix_eeprom_info_get (nix, &eeprom_info) == 0) @@ -601,6 +614,7 @@ oct_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port, { vnet_dev_t *dev = port->dev; oct_device_t *cd = vnet_dev_get_data (dev); + oct_port_t *cp = vnet_dev_get_port_data (port); struct roc_nix *nix = cd->nix; vnet_dev_rv_t rv = VNET_DEV_OK; i32 rrv; @@ -627,7 +641,7 @@ oct_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port, } } - rrv = roc_nix_rss_default_setup (nix, default_rss_flowkey); + rrv = roc_nix_rss_default_setup (nix, cp->rss_flowkey); if (rrv) rv = oct_roc_err (dev, rrv, "roc_nix_rss_default_setup() failed"); } @@ -653,6 +667,19 @@ oct_op_config_max_rx_len (vlib_main_t *vm, vnet_dev_port_t *port, return rv; } +vnet_dev_rv_t +oct_op_config_set_rss_key (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_rss_key_t *k) +{ + vnet_dev_t *dev = port->dev; + oct_device_t *cd = vnet_dev_get_data (dev); + vnet_dev_rv_t rv = VNET_DEV_OK; + + roc_nix_rss_key_set (cd->nix, k->key); + + return rv; +} + vnet_dev_rv_t oct_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port, vnet_dev_port_cfg_change_req_t *req) @@ -672,6 +699,7 @@ oct_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port, case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR: case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR: case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR: + case VNET_DEV_PORT_CFG_SET_RSS_KEY: break; case VNET_DEV_PORT_CFG_ADD_RX_FLOW: @@ -717,6 +745,10 @@ oct_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port, rv = oct_op_config_max_rx_len (vm, port, req->max_rx_frame_size); break; + case VNET_DEV_PORT_CFG_SET_RSS_KEY: + rv = oct_op_config_set_rss_key (vm, port, &req->rss_key); + break; + case VNET_DEV_PORT_CFG_ADD_RX_FLOW: case VNET_DEV_PORT_CFG_DEL_RX_FLOW: case VNET_DEV_PORT_CFG_GET_RX_FLOW_COUNTER: diff --git a/src/plugins/dev_octeon/roc_helper.c b/src/plugins/dev_octeon/roc_helper.c index 0f872047fb..ccc381d2eb 100644 --- a/src/plugins/dev_octeon/roc_helper.c +++ b/src/plugins/dev_octeon/roc_helper.c @@ -134,7 +134,7 @@ oct_plt_memzone_lookup (const char *name) pool_foreach (mem_pool, memzone_list.mem_pool) { - if (!clib_strcmp (mem_pool->name, name)) + if (!strcmp (mem_pool->name, name)) return mem_pool; } diff --git a/src/plugins/dev_octeon/rx_node.c b/src/plugins/dev_octeon/rx_node.c index f70c07642a..3651952db5 100644 --- a/src/plugins/dev_octeon/rx_node.c +++ b/src/plugins/dev_octeon/rx_node.c @@ -107,9 +107,13 @@ oct_rx_batch (vlib_main_t *vm, oct_rx_node_ctx_t *ctx, u32 b0_err_flags = 0, b1_err_flags = 0; u32 b2_err_flags = 0, b3_err_flags = 0; u32 n_left, err_flags = 0; + u32 err_flag_x4, err_flag; oct_nix_rx_cqe_desc_t *d = ctx->next_desc; vlib_buffer_t *b[4]; + bt.flags |= + (VNET_BUFFER_F_L4_CHECKSUM_COMPUTED | VNET_BUFFER_F_L4_CHECKSUM_CORRECT); + for (n_left = n; n_left >= 8; d += 4, n_left -= 4, ctx->to_next += 4) { u32 segs = 0; @@ -153,7 +157,24 @@ oct_rx_batch (vlib_main_t *vm, oct_rx_node_ctx_t *ctx, b2_err_flags = (d[2].parse.w[0] >> 20) & 0xFFF; b3_err_flags = (d[3].parse.w[0] >> 20) & 0xFFF; - err_flags |= b0_err_flags | b1_err_flags | b2_err_flags | b3_err_flags; + err_flag_x4 = b0_err_flags | b1_err_flags | b2_err_flags | b3_err_flags; + + if (PREDICT_FALSE (err_flag_x4)) + { + if (b0_err_flags) + b[0]->flags &= ~(VNET_BUFFER_F_L4_CHECKSUM_CORRECT | + VNET_BUFFER_F_L4_CHECKSUM_COMPUTED); + if (b1_err_flags) + b[1]->flags &= ~(VNET_BUFFER_F_L4_CHECKSUM_CORRECT | + VNET_BUFFER_F_L4_CHECKSUM_COMPUTED); + if (b2_err_flags) + b[2]->flags &= ~(VNET_BUFFER_F_L4_CHECKSUM_CORRECT | + VNET_BUFFER_F_L4_CHECKSUM_COMPUTED); + if (b3_err_flags) + b[3]->flags &= ~(VNET_BUFFER_F_L4_CHECKSUM_CORRECT | + VNET_BUFFER_F_L4_CHECKSUM_COMPUTED); + err_flags |= err_flag_x4; + } } for (; n_left; d += 1, n_left -= 1, ctx->to_next += 1) @@ -167,7 +188,13 @@ oct_rx_batch (vlib_main_t *vm, oct_rx_node_ctx_t *ctx, if (d[0].sg0.segs > 1) oct_rx_attach_tail (vm, ctx, b[0], d + 0); - err_flags |= ((d[0].parse.w[0] >> 20) & 0xFFF); + err_flag = ((d[0].parse.w[0] >> 20) & 0xFFF); + if (PREDICT_FALSE (err_flag)) + { + b[0]->flags &= ~(VNET_BUFFER_F_L4_CHECKSUM_CORRECT | + VNET_BUFFER_F_L4_CHECKSUM_COMPUTED); + err_flags |= err_flag; + } } plt_write64 ((crq->cq.wdata | n), crq->cq.door); diff --git a/src/plugins/dhcp/client.c b/src/plugins/dhcp/client.c index d81d293557..1add8d5960 100644 --- a/src/plugins/dhcp/client.c +++ b/src/plugins/dhcp/client.c @@ -510,7 +510,11 @@ send_dhcp_pkt (dhcp_client_main_t * dcm, dhcp_client_t * c, vnet_buffer (b)->ip.adj_index[VLIB_TX] = c->ai_bcast; } else - node_index = dcm->ip4_lookup_node_index; + { + node_index = dcm->ip4_lookup_node_index; + vnet_buffer (b)->sw_if_index[VLIB_TX] = + fib_table_get_index_for_sw_if_index (FIB_PROTOCOL_IP4, c->sw_if_index); + } /* Enqueue the packet right now */ f = vlib_get_frame_to_node (vm, node_index); diff --git a/src/plugins/dns/dns.c b/src/plugins/dns/dns.c index de01474703..b73d18a741 100644 --- a/src/plugins/dns/dns.c +++ b/src/plugins/dns/dns.c @@ -654,7 +654,8 @@ delete_random_entry (dns_main_t * dm) return VNET_API_ERROR_UNSPECIFIED; #endif - dns_cache_lock (dm, 3); + CLIB_SPINLOCK_ASSERT_LOCKED (&dm->cache_lock); + limit = pool_elts (dm->entries); start_index = random_u32 (&dm->random_seed) % limit; @@ -670,12 +671,10 @@ delete_random_entry (dns_main_t * dm) && ((ep->flags & DNS_CACHE_ENTRY_FLAG_STATIC) == 0)) { rv = vnet_dns_delete_entry_by_index_nolock (dm, victim_index); - dns_cache_unlock (dm); return rv; } } } - dns_cache_unlock (dm); clib_warning ("Couldn't find an entry to delete?"); return VNET_API_ERROR_UNSPECIFIED; diff --git a/src/plugins/dpdk/device/common.c b/src/plugins/dpdk/device/common.c index 7671fc2639..9de39b07f6 100644 --- a/src/plugins/dpdk/device/common.c +++ b/src/plugins/dpdk/device/common.c @@ -41,7 +41,8 @@ static struct { RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM, VNET_HW_IF_CAP_TX_IP4_OUTER_CKSUM }, { RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM, VNET_HW_IF_CAP_TX_UDP_OUTER_CKSUM }, { RTE_ETH_TX_OFFLOAD_TCP_TSO, VNET_HW_IF_CAP_TCP_GSO }, - { RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO, VNET_HW_IF_CAP_VXLAN_TNL_GSO } + { RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO, VNET_HW_IF_CAP_VXLAN_TNL_GSO }, + { RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO, VNET_HW_IF_CAP_IPIP_TNL_GSO } }; void @@ -100,8 +101,9 @@ dpdk_device_setup (dpdk_device_t * xd) RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM; if (xd->conf.disable_tx_checksum_offload == 0) - txo |= RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM | - RTE_ETH_TX_OFFLOAD_UDP_CKSUM; + txo |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | + RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | + RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_UDP_CKSUM; if (xd->conf.disable_multi_seg == 0) { @@ -118,7 +120,7 @@ dpdk_device_setup (dpdk_device_t * xd) /* per-device offload config */ if (xd->conf.enable_tso) txo |= RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_TSO | - RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO; + RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO | RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO; if (xd->conf.disable_rx_scatter) rxo &= ~RTE_ETH_RX_OFFLOAD_SCATTER; @@ -513,6 +515,70 @@ dpdk_get_vmbus_device (const struct rte_eth_dev_info *info) } #endif /* __linux__ */ +clib_error_t * +dpdk_read_eeprom (vnet_main_t *vnm, vnet_hw_interface_t *hi, + vnet_interface_eeprom_t **eeprom) +{ + dpdk_main_t *dm = &dpdk_main; + vnet_interface_main_t *im = &vnm->interface_main; + dpdk_device_t *xd; + vnet_device_class_t *dc; + struct rte_eth_dev_module_info mi = { 0 }; + struct rte_dev_eeprom_info ei = { 0 }; + + dc = vec_elt_at_index (im->device_classes, hi->dev_class_index); + *eeprom = NULL; + + if (dc->index != dpdk_device_class.index) + { + return clib_error_return (0, "Interface %v is not a DPDK interface", + hi->name); + } + + if (hi->dev_instance >= vec_len (dm->devices)) + { + return clib_error_return (0, "Invalid device instance %u", + hi->dev_instance); + } + + xd = vec_elt_at_index (dm->devices, hi->dev_instance); + + /* Get module info */ + if (rte_eth_dev_get_module_info (xd->port_id, &mi) != 0) + { + return clib_error_return ( + 0, "Module info not available for interface %v", hi->name); + } + if (mi.eeprom_len > 1024) + { + return clib_error_return (0, "EEPROM invalid length: %u bytes", + mi.eeprom_len); + } + + /* Allocate EEPROM structure */ + *eeprom = clib_mem_alloc (sizeof (vnet_interface_eeprom_t)); + if (!*eeprom) + { + return clib_error_return (0, "Memory allocation failed"); + } + + /* Get EEPROM data */ + ei.length = mi.eeprom_len; + ei.data = (*eeprom)->eeprom_raw; + + if (rte_eth_dev_get_module_eeprom (xd->port_id, &ei) != 0) + { + clib_mem_free (*eeprom); + *eeprom = NULL; + return clib_error_return (0, "EEPROM read error for interface %v", + hi->name); + } + + (*eeprom)->eeprom_len = mi.eeprom_len; + (*eeprom)->eeprom_type = mi.type; + return 0; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/dpdk/device/device.c b/src/plugins/dpdk/device/device.c index 5fd936d174..6b3edb0155 100644 --- a/src/plugins/dpdk/device/device.c +++ b/src/plugins/dpdk/device/device.c @@ -199,7 +199,7 @@ dpdk_buffer_tx_offload (dpdk_device_t * xd, vlib_buffer_t * b, int is_ip4 = b->flags & VNET_BUFFER_F_IS_IP4; u32 tso = b->flags & VNET_BUFFER_F_GSO, max_pkt_len; u32 ip_cksum, tcp_cksum, udp_cksum, outer_hdr_len = 0; - u32 outer_ip_cksum, vxlan_tunnel; + u32 outer_ip_cksum, vxlan_tunnel, ipip_tunnel; u64 ol_flags; vnet_buffer_oflags_t oflags = 0; @@ -213,6 +213,7 @@ dpdk_buffer_tx_offload (dpdk_device_t * xd, vlib_buffer_t * b, udp_cksum = oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM; outer_ip_cksum = oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM; vxlan_tunnel = oflags & VNET_BUFFER_OFFLOAD_F_TNL_VXLAN; + ipip_tunnel = oflags & VNET_BUFFER_OFFLOAD_F_TNL_IPIP; ol_flags = is_ip4 ? RTE_MBUF_F_TX_IPV4 : RTE_MBUF_F_TX_IPV6; ol_flags |= ip_cksum ? RTE_MBUF_F_TX_IP_CKSUM : 0; @@ -235,6 +236,21 @@ dpdk_buffer_tx_offload (dpdk_device_t * xd, vlib_buffer_t * b, vnet_buffer2 (b)->outer_l3_hdr_offset; outer_hdr_len = mb->outer_l2_len + mb->outer_l3_len; } + else if (ipip_tunnel) + { + ol_flags |= outer_ip_cksum ? + RTE_MBUF_F_TX_OUTER_IPV4 | RTE_MBUF_F_TX_OUTER_IP_CKSUM : + RTE_MBUF_F_TX_OUTER_IPV6; + ol_flags |= RTE_MBUF_F_TX_TUNNEL_IPIP; + mb->l2_len = 0; + mb->l3_len = + vnet_buffer (b)->l4_hdr_offset - vnet_buffer (b)->l3_hdr_offset; + mb->outer_l2_len = + vnet_buffer2 (b)->outer_l3_hdr_offset - b->current_data; + mb->outer_l3_len = + vnet_buffer (b)->l3_hdr_offset - vnet_buffer2 (b)->outer_l3_hdr_offset; + outer_hdr_len = mb->outer_l2_len + mb->outer_l3_len; + } else { mb->l2_len = vnet_buffer (b)->l3_hdr_offset - b->current_data; @@ -762,6 +778,7 @@ VNET_DEVICE_CLASS (dpdk_device_class) = { .flow_ops_function = dpdk_flow_ops_fn, .set_rss_queues_function = dpdk_interface_set_rss_queues, .rx_mode_change_function = dpdk_interface_rx_mode_change, + .eeprom_read_function = dpdk_read_eeprom, }; #define UP_DOWN_FLAG_EVENT 1 diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h index 70d9cc715d..347418ca00 100644 --- a/src/plugins/dpdk/device/dpdk.h +++ b/src/plugins/dpdk/device/dpdk.h @@ -461,6 +461,9 @@ vnet_flow_dev_ops_function_t dpdk_flow_ops_fn; clib_error_t *unformat_rss_fn (unformat_input_t * input, uword * rss_fn); +clib_error_t *dpdk_read_eeprom (vnet_main_t *vnm, vnet_hw_interface_t *hi, + vnet_interface_eeprom_t **eeprom); + struct rte_pci_device *dpdk_get_pci_device (const struct rte_eth_dev_info *info); struct rte_vmbus_device * diff --git a/src/plugins/dpdk/device/dpdk_priv.h b/src/plugins/dpdk/device/dpdk_priv.h index 2067b11853..288b1d96e3 100644 --- a/src/plugins/dpdk/device/dpdk_priv.h +++ b/src/plugins/dpdk/device/dpdk_priv.h @@ -202,6 +202,9 @@ dpdk_update_counters (dpdk_device_t * xd, f64 now) #define RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM DEV_TX_OFFLOAD_OUTER_UDP_CKSUM #define RTE_ETH_TX_OFFLOAD_TCP_TSO DEV_TX_OFFLOAD_TCP_TSO #define RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO DEV_TX_OFFLOAD_VXLAN_TNL_TSO +#define RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO DEV_TX_OFFLOAD_GRE_TNL_TSO +#define RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO DEV_TX_OFFLOAD_IPIP_TNL_TSO +#define RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO DEV_TX_OFFLOAD_GENEVE_TNL_TSO #define RTE_ETH_TX_OFFLOAD_MULTI_SEGS DEV_TX_OFFLOAD_MULTI_SEGS #define RTE_ETH_RX_OFFLOAD_IPV4_CKSUM DEV_RX_OFFLOAD_IPV4_CKSUM #define RTE_ETH_RX_OFFLOAD_SCATTER DEV_RX_OFFLOAD_SCATTER diff --git a/src/plugins/gre/FEATURE.yaml b/src/plugins/gre/FEATURE.yaml index 4b35b870dc..029a59a40f 100644 --- a/src/plugins/gre/FEATURE.yaml +++ b/src/plugins/gre/FEATURE.yaml @@ -6,8 +6,7 @@ features: - Encap/Decap flags to control the copying of DSCP, ECN, DF from overlay to underlay and vice-versa. - L2 tunnels -missing: - - GRE keys + - GRE keys for IPv4 and IPv6 description: "An implementation of Generic Routing Encapsulation (GRE)" state: production properties: [API, CLI, MULTITHREAD] diff --git a/src/plugins/gre/gre.api b/src/plugins/gre/gre.api index 9c69ba4007..1f680c8d89 100644 --- a/src/plugins/gre/gre.api +++ b/src/plugins/gre/gre.api @@ -20,6 +20,17 @@ import "vnet/interface_types.api"; import "vnet/tunnel/tunnel_types.api"; import "vnet/ip/ip_types.api"; +/* Enable the in-progress messages */ +option status = "in_progress"; + +/* + * Define the service relationships + */ +service { + rpc gre_tunnel_dump returns gre_tunnel_dump_reply events gre_tunnel_details; + rpc gre_tunnel_dump_v2 returns gre_tunnel_dump_v2_reply events gre_tunnel_details_v2; +}; + /** \brief A GRE tunnel type */ enum gre_tunnel_type : u8 @@ -55,6 +66,32 @@ typedef gre_tunnel vl_api_address_t dst; }; +/** \brief A composite type uniquely defining a GRE tunnel with key support. + @param type - tunnel type (see enum definition), 0: L3, 1: TEB, 2: ERSPAN + @param mode - P2P or P2MP + @param flags - to control encap/decap behaviour + @param session_id - session for ERSPAN tunnel, range 0-1023 + @param instance - optional unique custom device instance, else ~0. + @param outer_table_id - Encap FIB table ID + @param sw_if_index - ignored on create/delete, present in details. + @param src - Source IP address + @param dst - Destination IP address, can be multicast + @param key - GRE key value (RFC 2890), 0 for no key +*/ +typedef gre_tunnel_v2 +{ + vl_api_gre_tunnel_type_t type; + vl_api_tunnel_mode_t mode; + vl_api_tunnel_encap_decap_flags_t flags; + u16 session_id; + u32 instance; + u32 outer_table_id; + vl_api_interface_index_t sw_if_index; + vl_api_address_t src; + vl_api_address_t dst; + u32 key; +}; + /** \brief Add or delete a single GRE tunnel. @param client_index - opaque cookie to identify the sender. @param context - sender context, to match reply w/ request. @@ -81,6 +118,32 @@ define gre_tunnel_add_del_reply vl_api_interface_index_t sw_if_index; }; +/** \brief Add or delete a single GRE tunnel with key support. + @param client_index - opaque cookie to identify the sender. + @param context - sender context, to match reply w/ request. + @param is_add - add if true, delete if false. + @param tunnel - tunnel definition to add or delete (with key field). +*/ +define gre_tunnel_add_del_v2 +{ + u32 client_index; + u32 context; + bool is_add; + vl_api_gre_tunnel_v2_t tunnel; +}; + +/** \brief Add or delete a single GRE tunnel with key support. + @param context - sender context, to match reply w/ request. + @param retval - return code for the request. + @param sw_if_index - the interface corresponding to the affected tunnel. +*/ +define gre_tunnel_add_del_v2_reply +{ + u32 context; + i32 retval; + vl_api_interface_index_t sw_if_index; +}; + /** \brief Dump details of all or just a single GRE tunnel. @param client_index - opaque cookie to identify the sender. @param context - sender context, to match reply w/ request. @@ -93,6 +156,29 @@ define gre_tunnel_dump vl_api_interface_index_t sw_if_index; }; +/** \brief Reply for gre_tunnel_dump - empty since actual data is sent via gre_tunnel_details. + @param context - sender context, to match reply w/ request. + @param retval - return code for the request. +*/ +define gre_tunnel_dump_reply +{ + u32 context; + i32 retval; +}; + +/** \brief Dump details of all or just a single GRE tunnel with key support. + @param client_index - opaque cookie to identify the sender. + @param context - sender context, to match reply w/ request. + @param sw_if_index - filter for tunnel of this interface index, ~0 for all. +*/ +autoreply define gre_tunnel_dump_v2 +{ + u32 client_index; + u32 context; + vl_api_interface_index_t sw_if_index; +}; + + /** \brief Details response for one of the requested GRE tunnels. @param context - sender context, to match reply w/ request. @param tunnel - definition of the dumped tunnel. @@ -103,6 +189,16 @@ define gre_tunnel_details vl_api_gre_tunnel_t tunnel; }; +/** \brief Details response for one of the requested GRE tunnels with key support. + @param context - sender context, to match reply w/ request. + @param tunnel - definition of the dumped tunnel (with key field). +*/ +define gre_tunnel_details_v2 +{ + u32 context; + vl_api_gre_tunnel_v2_t tunnel; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/plugins/gre/gre.c b/src/plugins/gre/gre.c index ce11ee9ecb..21a628b449 100644 --- a/src/plugins/gre/gre.c +++ b/src/plugins/gre/gre.c @@ -232,7 +232,11 @@ gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, if (!is_ipv6) { - vec_validate (rewrite, sizeof (*h4) - 1); + /* Allocate space for maximum header size including key */ + if (gre_key_is_valid (t->gre_key)) + vec_validate (rewrite, sizeof (*h4) + sizeof (gre_key_t) - 1); + else + vec_validate (rewrite, sizeof (*h4) - 1); h4 = (ip4_and_gre_header_t *) rewrite; gre = &h4->gre; h4->ip4.ip_version_and_header_length = 0x45; @@ -245,7 +249,11 @@ gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, } else { - vec_validate (rewrite, sizeof (*h6) - 1); + /* Allocate space for maximum header size including key */ + if (gre_key_is_valid (t->gre_key)) + vec_validate (rewrite, sizeof (*h6) + sizeof (gre_key_t) - 1); + else + vec_validate (rewrite, sizeof (*h6) - 1); h6 = (ip6_and_gre_header_t *) rewrite; gre = &h6->gre; h6->ip6.ip_version_traffic_class_and_flow_label = @@ -265,9 +273,18 @@ gre_build_rewrite (vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, gre->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_SEQUENCE); } else - gre->protocol = - clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type)); - + { + gre->protocol = + clib_host_to_net_u16 (gre_proto_from_vnet_link (link_type)); + gre->flags_and_version = 0; // Clear flags first + /* Add key only for non-ERSPAN tunnels */ + if (gre_key_is_valid (t->gre_key)) + { + gre_header_with_key_t *grek = (gre_header_with_key_t *) gre; + grek->flags_and_version = clib_host_to_net_u16 (GRE_FLAGS_KEY); + grek->key = clib_host_to_net_u32 (t->gre_key); + } + } return (rewrite); } diff --git a/src/plugins/gre/gre.h b/src/plugins/gre/gre.h index ce57454f9b..03f0df163d 100644 --- a/src/plugins/gre/gre.h +++ b/src/plugins/gre/gre.h @@ -31,7 +31,7 @@ extern vnet_hw_interface_class_t mgre_hw_interface_class; typedef enum { -#define gre_error(n,s) GRE_ERROR_##n, +#define gre_error(n, s) GRE_ERROR_##n, #include #undef gre_error GRE_N_ERROR, @@ -45,10 +45,10 @@ typedef enum * and output of mirrored packet from a L2 network only. There is * no support for receiving ERSPAN packets from a GRE ERSPAN tunnel */ -#define foreach_gre_tunnel_type \ - _(L3, "L3") \ - _(TEB, "TEB") \ - _(ERSPAN, "ERSPAN") \ +#define foreach_gre_tunnel_type \ + _ (L3, "L3") \ + _ (TEB, "TEB") \ + _ (ERSPAN, "ERSPAN") /** * @brief The GRE tunnel type @@ -60,8 +60,22 @@ typedef enum gre_tunnel_type_t_ #undef _ } __clib_packed gre_tunnel_type_t; -extern u8 *format_gre_tunnel_type (u8 * s, va_list * args); +/** + * @brief GRE key type (RFC 2890) + */ +typedef u32 gre_key_t; + +/** + * @brief Check if a GRE key is valid (non-zero) + */ +#define gre_key_is_valid(_key) ((_key) != 0) +extern u8 *format_gre_tunnel_type (u8 *s, va_list *args); + +/** + * @brief Format a GRE key for display + */ +format_function_t format_gre_key; /** * A GRE payload protocol registration @@ -94,15 +108,16 @@ typedef struct gre_tunnel_key_common_t_ struct { u32 fib_index; + gre_key_t gre_key; u16 session_id; gre_tunnel_type_t type; tunnel_mode_t mode; }; - u64 as_u64; + u64 as_u64[2]; }; -} gre_tunnel_key_common_t; +} __clib_packed gre_tunnel_key_common_t; -STATIC_ASSERT_SIZEOF (gre_tunnel_key_common_t, sizeof (u64)); +STATIC_ASSERT_SIZEOF (gre_tunnel_key_common_t, 2 * sizeof (u64)); /** * @brief Key for a IPv4 GRE Tunnel @@ -126,7 +141,7 @@ typedef struct gre_tunnel_key4_t_ gre_tunnel_key_common_t gtk_common; } __attribute__ ((packed)) gre_tunnel_key4_t; -STATIC_ASSERT_SIZEOF (gre_tunnel_key4_t, 2 * sizeof (u64)); +STATIC_ASSERT_SIZEOF (gre_tunnel_key4_t, 3 * sizeof (u64)); /** * @brief Key for a IPv6 GRE Tunnel @@ -144,7 +159,7 @@ typedef struct gre_tunnel_key6_t_ gre_tunnel_key_common_t gtk_common; } __attribute__ ((packed)) gre_tunnel_key6_t; -STATIC_ASSERT_SIZEOF (gre_tunnel_key6_t, 5 * sizeof (u64)); +STATIC_ASSERT_SIZEOF (gre_tunnel_key6_t, 6 * sizeof (u64)); /** * Union of the two possible key types @@ -205,6 +220,8 @@ typedef struct u32 sw_if_index; gre_tunnel_type_t type; tunnel_mode_t mode; + gre_key_t gre_key; + tunnel_encap_decap_flags_t flags; /** @@ -220,14 +237,14 @@ typedef struct /** * GRE header sequence number (SN) used for ERSPAN type 2 header, must be * bumped automically to be thread safe. As multiple GRE tunnels are created - * for the same fib-idx/DIP/SIP with different ERSPAN session number, they all - * share the same SN which is kept per FIB/DIP/SIP, as specified by RFC2890. + * for the same fib-idx/DIP/SIP with different ERSPAN session number, they + * all share the same SN which is kept per FIB/DIP/SIP, as specified by + * RFC2890. */ gre_sn_t *gre_sn; - - u32 dev_instance; /* Real device instance in tunnel vector */ - u32 user_instance; /* Instance name being shown to user */ + u32 dev_instance; /* Real device instance in tunnel vector */ + u32 user_instance; /* Instance name being shown to user */ } gre_tunnel_t; typedef struct @@ -307,7 +324,7 @@ typedef CLIB_PACKED (struct { }) ip6_and_gre_header_t; always_inline gre_protocol_info_t * -gre_get_protocol_info (gre_main_t * em, gre_protocol_t protocol) +gre_get_protocol_info (gre_main_t *em, gre_protocol_t protocol) { uword *p = hash_get (em->protocol_info_by_protocol, protocol); return p ? vec_elt_at_index (em->protocol_infos, p[0]) : 0; @@ -315,12 +332,11 @@ gre_get_protocol_info (gre_main_t * em, gre_protocol_t protocol) extern gre_main_t gre_main; -extern clib_error_t *gre_interface_admin_up_down (vnet_main_t * vnm, +extern clib_error_t *gre_interface_admin_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags); extern void gre_tunnel_stack (adj_index_t ai); -extern void gre_update_adj (vnet_main_t * vnm, - u32 sw_if_index, adj_index_t ai); +extern void gre_update_adj (vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai); typedef struct mgre_walk_ctx_t_ { @@ -350,12 +366,12 @@ unformat_function_t unformat_gre_protocol_net_byte_order; unformat_function_t unformat_gre_header; unformat_function_t unformat_pg_gre_header; -void -gre_register_input_protocol (vlib_main_t * vm, gre_protocol_t protocol, - u32 node_index, gre_tunnel_type_t tunnel_type); +void gre_register_input_protocol (vlib_main_t *vm, gre_protocol_t protocol, + u32 node_index, + gre_tunnel_type_t tunnel_type); /* manually added to the interface output node in gre.c */ -#define GRE_OUTPUT_NEXT_LOOKUP 1 +#define GRE_OUTPUT_NEXT_LOOKUP 1 typedef struct { @@ -367,61 +383,62 @@ typedef struct ip46_address_t src, dst; u32 outer_table_id; u16 session_id; + gre_key_t gre_key; tunnel_encap_decap_flags_t flags; } vnet_gre_tunnel_add_del_args_t; -extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t * a, - u32 * sw_if_indexp); +extern int vnet_gre_tunnel_add_del (vnet_gre_tunnel_add_del_args_t *a, + u32 *sw_if_indexp); static inline void -gre_mk_key4 (ip4_address_t src, - ip4_address_t dst, - u32 fib_index, - gre_tunnel_type_t ttype, - tunnel_mode_t tmode, u16 session_id, gre_tunnel_key4_t * key) +gre_mk_key4 (ip4_address_t src, ip4_address_t dst, u32 fib_index, + gre_tunnel_type_t ttype, tunnel_mode_t tmode, u16 session_id, + gre_key_t gre_key, gre_tunnel_key4_t *key) { + clib_memset (key, 0, sizeof (*key)); // Zero entire structure first key->gtk_src = src; key->gtk_dst = dst; key->gtk_common.type = ttype; key->gtk_common.mode = tmode; key->gtk_common.fib_index = fib_index; key->gtk_common.session_id = session_id; + key->gtk_common.gre_key = gre_key; } static inline int -gre_match_key4 (const gre_tunnel_key4_t * key1, - const gre_tunnel_key4_t * key2) +gre_match_key4 (const gre_tunnel_key4_t *key1, const gre_tunnel_key4_t *key2) { return ((key1->gtk_as_u64 == key2->gtk_as_u64) && - (key1->gtk_common.as_u64 == key2->gtk_common.as_u64)); + (key1->gtk_common.as_u64[0] == key2->gtk_common.as_u64[0]) && + (key1->gtk_common.as_u64[1] == key2->gtk_common.as_u64[1])); } static inline void -gre_mk_key6 (const ip6_address_t * src, - const ip6_address_t * dst, - u32 fib_index, - gre_tunnel_type_t ttype, - tunnel_mode_t tmode, u16 session_id, gre_tunnel_key6_t * key) +gre_mk_key6 (const ip6_address_t *src, const ip6_address_t *dst, u32 fib_index, + gre_tunnel_type_t ttype, tunnel_mode_t tmode, u16 session_id, + gre_key_t gre_key, gre_tunnel_key6_t *key) { + clib_memset (key, 0, sizeof (*key)); // Zero entire structure first key->gtk_src = *src; key->gtk_dst = *dst; key->gtk_common.type = ttype; key->gtk_common.mode = tmode; key->gtk_common.fib_index = fib_index; key->gtk_common.session_id = session_id; + key->gtk_common.gre_key = gre_key; } static inline int -gre_match_key6 (const gre_tunnel_key6_t * key1, - const gre_tunnel_key6_t * key2) +gre_match_key6 (const gre_tunnel_key6_t *key1, const gre_tunnel_key6_t *key2) { return (ip6_address_is_equal (&key1->gtk_src, &key2->gtk_src) && ip6_address_is_equal (&key1->gtk_dst, &key2->gtk_dst) && - (key1->gtk_common.as_u64 == key2->gtk_common.as_u64)); + (key1->gtk_common.as_u64[0] == key2->gtk_common.as_u64[0]) && + (key1->gtk_common.as_u64[1] == key2->gtk_common.as_u64[1])); } static inline void -gre_mk_sn_key (const gre_tunnel_t * gt, gre_sn_key_t * key) +gre_mk_sn_key (const gre_tunnel_t *gt, gre_sn_key_t *key) { key->src = gt->tunnel_src; key->dst = gt->tunnel_dst.fp_addr; diff --git a/src/plugins/gre/gre_api.c b/src/plugins/gre/gre_api.c index 5149f92fb8..168f2e153f 100644 --- a/src/plugins/gre/gre_api.c +++ b/src/plugins/gre/gre_api.c @@ -114,6 +114,7 @@ vl_api_gre_tunnel_add_del_t_handler (vl_api_gre_tunnel_add_del_t *mp) a->session_id = ntohs (mp->tunnel.session_id); a->outer_table_id = ntohl (mp->tunnel.outer_table_id); a->flags = flags; + a->gre_key = 0; // No key in the v1 API rv = vnet_gre_tunnel_add_del (a, &sw_if_index); @@ -122,6 +123,61 @@ vl_api_gre_tunnel_add_del_t_handler (vl_api_gre_tunnel_add_del_t *mp) ({ rmp->sw_if_index = ntohl (sw_if_index); })); } +static void +vl_api_gre_tunnel_add_del_v2_t_handler (vl_api_gre_tunnel_add_del_v2_t *mp) +{ + vnet_gre_tunnel_add_del_args_t _a = {}, *a = &_a; + vl_api_gre_tunnel_add_del_v2_reply_t *rmp; + tunnel_encap_decap_flags_t flags; + u32 sw_if_index = ~0; + ip46_type_t itype[2]; + int rv = 0; + + itype[0] = ip_address_decode (&mp->tunnel.src, &a->src); + itype[1] = ip_address_decode (&mp->tunnel.dst, &a->dst); + + if (itype[0] != itype[1]) + { + rv = VNET_API_ERROR_INVALID_PROTOCOL; + goto out; + } + + if (ip46_address_is_equal (&a->src, &a->dst)) + { + rv = VNET_API_ERROR_SAME_SRC_DST; + goto out; + } + + rv = gre_tunnel_type_decode (mp->tunnel.type, &a->type); + + if (rv) + goto out; + + rv = tunnel_mode_decode (mp->tunnel.mode, &a->mode); + + if (rv) + goto out; + + rv = tunnel_encap_decap_flags_decode (mp->tunnel.flags, &flags); + + if (rv) + goto out; + + a->is_add = mp->is_add; + a->is_ipv6 = (itype[0] == IP46_TYPE_IP6); + a->instance = ntohl (mp->tunnel.instance); + a->session_id = ntohs (mp->tunnel.session_id); + a->outer_table_id = ntohl (mp->tunnel.outer_table_id); + a->flags = flags; + a->gre_key = ntohl (mp->tunnel.key); // Key field present in v2 API + + rv = vnet_gre_tunnel_add_del (a, &sw_if_index); + +out: + REPLY_MACRO2 (VL_API_GRE_TUNNEL_ADD_DEL_V2_REPLY, + ({ rmp->sw_if_index = ntohl (sw_if_index); })); +} + static void send_gre_tunnel_details (gre_tunnel_t *t, vl_api_gre_tunnel_dump_t *mp) { @@ -145,6 +201,31 @@ send_gre_tunnel_details (gre_tunnel_t *t, vl_api_gre_tunnel_dump_t *mp) })); } +static void +send_gre_tunnel_details_v2 (gre_tunnel_t *t, vl_api_gre_tunnel_dump_v2_t *mp) +{ + vl_api_gre_tunnel_details_v2_t *rmp; + + REPLY_MACRO_DETAILS2 ( + VL_API_GRE_TUNNEL_DETAILS_V2, ({ + ip_address_encode (&t->tunnel_src, IP46_TYPE_ANY, &rmp->tunnel.src); + ip_address_encode (&t->tunnel_dst.fp_addr, IP46_TYPE_ANY, + &rmp->tunnel.dst); + + rmp->tunnel.outer_table_id = htonl ( + fib_table_get_table_id (t->outer_fib_index, t->tunnel_dst.fp_proto)); + + rmp->tunnel.type = gre_tunnel_type_encode (t->type); + rmp->tunnel.mode = tunnel_mode_encode (t->mode); + rmp->tunnel.flags = tunnel_encap_decap_flags_encode (t->flags); + rmp->tunnel.instance = htonl (t->user_instance); + rmp->tunnel.sw_if_index = htonl (t->sw_if_index); + rmp->tunnel.session_id = htons (t->session_id); + rmp->tunnel.key = + htonl (t->gre_key); // Include the GRE key in the v2 API + })); +} + static void vl_api_gre_tunnel_dump_t_handler (vl_api_gre_tunnel_dump_t *mp) { @@ -179,6 +260,40 @@ vl_api_gre_tunnel_dump_t_handler (vl_api_gre_tunnel_dump_t *mp) } } +static void +vl_api_gre_tunnel_dump_v2_t_handler (vl_api_gre_tunnel_dump_v2_t *mp) +{ + vl_api_registration_t *reg; + gre_main_t *gm = &gre_main; + gre_tunnel_t *t; + u32 sw_if_index; + + reg = vl_api_client_index_to_registration (mp->client_index); + if (!reg) + return; + + sw_if_index = ntohl (mp->sw_if_index); + + if (~0 == sw_if_index) + { + pool_foreach (t, gm->tunnels) + { + send_gre_tunnel_details_v2 (t, mp); + } + } + + else + { + if ((sw_if_index >= vec_len (gm->tunnel_index_by_sw_if_index)) || + (~0 == gm->tunnel_index_by_sw_if_index[sw_if_index])) + { + return; + } + t = &gm->tunnels[gm->tunnel_index_by_sw_if_index[sw_if_index]]; + send_gre_tunnel_details_v2 (t, mp); + } +} + /* * gre_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/plugins/gre/interface.c b/src/plugins/gre/interface.c index bd9a607850..414a7f8171 100644 --- a/src/plugins/gre/interface.c +++ b/src/plugins/gre/interface.c @@ -43,6 +43,20 @@ format_gre_tunnel_type (u8 *s, va_list *args) return (s); } +/** + * @brief Format a GRE key for display + */ +u8 * +format_gre_key (u8 *s, va_list *args) +{ + gre_key_t key = va_arg (*args, gre_key_t); + + if (!gre_key_is_valid (key)) + return format (s, "INVALID"); + else + return format (s, "%u", key); +} + static u8 * format_gre_tunnel (u8 *s, va_list *args) { @@ -57,6 +71,9 @@ format_gre_tunnel (u8 *s, va_list *args) s = format (s, "payload %U ", format_gre_tunnel_type, t->type); s = format (s, "%U ", format_tunnel_mode, t->mode); + if (gre_key_is_valid (t->gre_key)) + s = format (s, "key %U ", format_gre_key, t->gre_key); + if (t->type == GRE_TUNNEL_TYPE_ERSPAN) s = format (s, "session %d ", t->session_id); @@ -76,13 +93,13 @@ gre_tunnel_db_find (const vnet_gre_tunnel_add_del_args_t *a, if (!a->is_ipv6) { gre_mk_key4 (a->src.ip4, a->dst.ip4, outer_fib_index, a->type, a->mode, - a->session_id, &key->gtk_v4); + a->session_id, a->gre_key, &key->gtk_v4); p = hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4); } else { gre_mk_key6 (&a->src.ip6, &a->dst.ip6, outer_fib_index, a->type, a->mode, - a->session_id, &key->gtk_v6); + a->session_id, a->gre_key, &key->gtk_v6); p = hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6); } @@ -247,11 +264,11 @@ gre_teib_mk_key (const gre_tunnel_t *t, const teib_entry_t *ne, if (FIB_PROTOCOL_IP4 == nh->fp_proto) gre_mk_key4 (t->tunnel_src.ip4, nh->fp_addr.ip4, teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0, - &key->gtk_v4); + t->gre_key, &key->gtk_v4); else gre_mk_key6 (&t->tunnel_src.ip6, &nh->fp_addr.ip6, teib_entry_get_fib_index (ne), t->type, TUNNEL_MODE_P2P, 0, - &key->gtk_v6); + t->gre_key, &key->gtk_v6); } /** @@ -373,6 +390,8 @@ vnet_gre_tunnel_add (vnet_gre_tunnel_add_del_args_t *a, u32 outer_fib_index, pool_get_aligned (gm->tunnels, t, CLIB_CACHE_LINE_BYTES); clib_memset (t, 0, sizeof (*t)); + // added for GRE Key - only mark as present if key is non-zero + t->gre_key = a->gre_key; /* Reconcile the real dev_instance and a possible requested instance */ u32 t_idx = t - gm->tunnels; /* tunnel index (or instance) */ @@ -646,7 +665,7 @@ create_gre_tunnel_command_fn (vlib_main_t *vm, unformat_input_t *input, u8 is_add = 1; u32 sw_if_index; clib_error_t *error = NULL; - + u32 key = 0; // added GRE key /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -672,6 +691,8 @@ create_gre_tunnel_command_fn (vlib_main_t *vm, unformat_input_t *input, else if (unformat (line_input, "flags %U", unformat_tunnel_encap_decap_flags, &flags)) ; + else if (unformat (line_input, "key %u", &key)) + ; else { error = clib_error_return (0, "unknown input `%U'", @@ -713,6 +734,7 @@ create_gre_tunnel_command_fn (vlib_main_t *vm, unformat_input_t *input, a->is_ipv6 = !ip46_address_is_ip4 (&src); a->instance = instance; a->flags = flags; + a->gre_key = key; clib_memcpy (&a->src, &src, sizeof (a->src)); clib_memcpy (&a->dst, &dst, sizeof (a->dst)); @@ -756,7 +778,8 @@ VLIB_CLI_COMMAND (create_gre_tunnel_command, static) = { .path = "create gre tunnel", .short_help = "create gre tunnel src dst [instance ] " "[outer-fib-id ] [teb | erspan ] [del] " - "[multipoint]", + "[multipoint]" + "[key ]", .function = create_gre_tunnel_command_fn, }; diff --git a/src/plugins/gre/node.c b/src/plugins/gre/node.c index 5235888cc6..541cae31a4 100644 --- a/src/plugins/gre/node.c +++ b/src/plugins/gre/node.c @@ -102,7 +102,7 @@ gre_tunnel_get (const gre_main_t *gm, vlib_node_runtime_t *node, { const uword *p; p = is_ipv6 ? hash_get_mem (gm->tunnel_by_key6, &key->gtk_v6) : - hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4); + hash_get_mem (gm->tunnel_by_key4, &key->gtk_v4); if (PREDICT_FALSE (!p)) { *next = GRE_INPUT_NEXT_DROP; @@ -172,8 +172,17 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip6[1] = vlib_buffer_get_current (b[1]); gre[0] = (void *) (ip6[0] + 1); gre[1] = (void *) (ip6[1] + 1); - vlib_buffer_advance (b[0], sizeof (*ip6[0]) + sizeof (*gre[0])); - vlib_buffer_advance (b[1], sizeof (*ip6[0]) + sizeof (*gre[0])); + /* Calculate total header size for each packet */ + u16 gre_hdr_size0 = sizeof (*gre[0]); + u16 gre_hdr_size1 = sizeof (*gre[1]); + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size0 += sizeof (gre_key_t); + if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size1 += sizeof (gre_key_t); + + /* Single buffer advance for each packet */ + vlib_buffer_advance (b[0], sizeof (*ip6[0]) + gre_hdr_size0); + vlib_buffer_advance (b[1], sizeof (*ip6[1]) + gre_hdr_size1); } else { @@ -182,8 +191,30 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip4[1] = vlib_buffer_get_current (b[1]); gre[0] = (void *) (ip4[0] + 1); gre[1] = (void *) (ip4[1] + 1); - vlib_buffer_advance (b[0], sizeof (*ip4[0]) + sizeof (*gre[0])); - vlib_buffer_advance (b[1], sizeof (*ip4[0]) + sizeof (*gre[0])); + /* Calculate total header size for each packet */ + u16 gre_hdr_size0 = sizeof (*gre[0]); + u16 gre_hdr_size1 = sizeof (*gre[1]); + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size0 += sizeof (gre_key_t); + if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size1 += sizeof (gre_key_t); + + /* Single buffer advance for each packet */ + vlib_buffer_advance (b[0], sizeof (*ip4[0]) + gre_hdr_size0); + vlib_buffer_advance (b[1], sizeof (*ip4[1]) + gre_hdr_size1); + } + + /* GRE key processing here */ + gre_key_t gre_key[2] = { 0, 0 }; + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + { + gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[0]; + gre_key[0] = clib_net_to_host_u32 (grek->key); + } + if (gre[1]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + { + gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[1]; + gre_key[1] = clib_net_to_host_u32 (grek->key); } if (PREDICT_TRUE (cached_protocol == gre[0]->protocol)) @@ -215,11 +246,11 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, type[1] = ni[1].tunnel_type; b[0]->error = nidx[0] == SPARSE_VEC_INVALID_INDEX ? - node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : - node->errors[GRE_ERROR_NONE]; + node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : + node->errors[GRE_ERROR_NONE]; b[1]->error = nidx[1] == SPARSE_VEC_INVALID_INDEX ? - node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : - node->errors[GRE_ERROR_NONE]; + node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : + node->errors[GRE_ERROR_NONE]; version[0] = clib_net_to_host_u16 (gre[0]->flags_and_version); version[1] = clib_net_to_host_u16 (gre[1]->flags_and_version); @@ -241,10 +272,10 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, { gre_mk_key6 (&ip6[0]->dst_address, &ip6[0]->src_address, vnet_buffer (b[0])->ip.fib_index, type[0], - TUNNEL_MODE_P2P, 0, &key[0].gtk_v6); + TUNNEL_MODE_P2P, 0, gre_key[0], &key[0].gtk_v6); gre_mk_key6 (&ip6[1]->dst_address, &ip6[1]->src_address, vnet_buffer (b[1])->ip.fib_index, type[1], - TUNNEL_MODE_P2P, 0, &key[1].gtk_v6); + TUNNEL_MODE_P2P, 0, gre_key[1], &key[1].gtk_v6); matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6); matched[1] = gre_match_key6 (&cached_key.gtk_v6, &key[1].gtk_v6); } @@ -252,10 +283,10 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, { gre_mk_key4 (ip4[0]->dst_address, ip4[0]->src_address, vnet_buffer (b[0])->ip.fib_index, type[0], - TUNNEL_MODE_P2P, 0, &key[0].gtk_v4); + TUNNEL_MODE_P2P, 0, gre_key[0], &key[0].gtk_v4); gre_mk_key4 (ip4[1]->dst_address, ip4[1]->src_address, vnet_buffer (b[1])->ip.fib_index, type[1], - TUNNEL_MODE_P2P, 0, &key[1].gtk_v4); + TUNNEL_MODE_P2P, 0, gre_key[1], &key[1].gtk_v4); matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4); matched[1] = gre_match_key4 (&cached_key.gtk_v4, &key[1].gtk_v4); } @@ -328,14 +359,33 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, /* ip6_local hands us the ip header, not the gre header */ ip6[0] = vlib_buffer_get_current (b[0]); gre[0] = (void *) (ip6[0] + 1); - vlib_buffer_advance (b[0], sizeof (*ip6[0]) + sizeof (*gre[0])); + + /* Calculate total header size */ + u16 gre_hdr_size = sizeof (*gre[0]); + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size += sizeof (gre_key_t); + /* Single buffer advance */ + vlib_buffer_advance (b[0], sizeof (*ip6[0]) + gre_hdr_size); } else { /* ip4_local hands us the ip header, not the gre header */ ip4[0] = vlib_buffer_get_current (b[0]); gre[0] = (void *) (ip4[0] + 1); - vlib_buffer_advance (b[0], sizeof (*ip4[0]) + sizeof (*gre[0])); + /* Calculate total header size */ + u16 gre_hdr_size = sizeof (*gre[0]); + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + gre_hdr_size += sizeof (gre_key_t); + /* Single buffer advance */ + vlib_buffer_advance (b[0], sizeof (*ip4[0]) + gre_hdr_size); + } + + /* GRE key processing here */ + gre_key_t gre_key = 0; + if (gre[0]->flags_and_version & clib_host_to_net_u16 (GRE_FLAGS_KEY)) + { + gre_header_with_key_t *grek = (gre_header_with_key_t *) gre[0]; + gre_key = clib_net_to_host_u32 (grek->key); } if (PREDICT_TRUE (cached_protocol == gre[0]->protocol)) @@ -354,8 +404,8 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, type[0] = ni[0].tunnel_type; b[0]->error = nidx[0] == SPARSE_VEC_INVALID_INDEX ? - node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : - node->errors[GRE_ERROR_NONE]; + node->errors[GRE_ERROR_UNKNOWN_PROTOCOL] : + node->errors[GRE_ERROR_NONE]; version[0] = clib_net_to_host_u16 (gre[0]->flags_and_version); version[0] &= GRE_VERSION_MASK; @@ -370,14 +420,14 @@ gre_input (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, { gre_mk_key6 (&ip6[0]->dst_address, &ip6[0]->src_address, vnet_buffer (b[0])->ip.fib_index, type[0], - TUNNEL_MODE_P2P, 0, &key[0].gtk_v6); + TUNNEL_MODE_P2P, 0, gre_key, &key[0].gtk_v6); matched[0] = gre_match_key6 (&cached_key.gtk_v6, &key[0].gtk_v6); } else { gre_mk_key4 (ip4[0]->dst_address, ip4[0]->src_address, vnet_buffer (b[0])->ip.fib_index, type[0], - TUNNEL_MODE_P2P, 0, &key[0].gtk_v4); + TUNNEL_MODE_P2P, 0, gre_key, &key[0].gtk_v4); matched[0] = gre_match_key4 (&cached_key.gtk_v4, &key[0].gtk_v4); } @@ -435,46 +485,46 @@ static char *gre_error_strings[] = { }; VLIB_REGISTER_NODE (gre4_input_node) = { - .name = "gre4-input", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), + .name = "gre4-input", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), - .n_errors = GRE_N_ERROR, - .error_strings = gre_error_strings, + .n_errors = GRE_N_ERROR, + .error_strings = gre_error_strings, - .n_next_nodes = GRE_INPUT_N_NEXT, - .next_nodes = { + .n_next_nodes = GRE_INPUT_N_NEXT, + .next_nodes = { #define _(s, n) [GRE_INPUT_NEXT_##s] = n, - foreach_gre_input_next + foreach_gre_input_next #undef _ - }, + }, - .format_buffer = format_gre_header_with_length, - .format_trace = format_gre_rx_trace, - .unformat_buffer = unformat_gre_header, -}; + .format_buffer = format_gre_header_with_length, + .format_trace = format_gre_rx_trace, + .unformat_buffer = unformat_gre_header, + }; VLIB_REGISTER_NODE (gre6_input_node) = { - .name = "gre6-input", - /* Takes a vector of packets. */ - .vector_size = sizeof (u32), + .name = "gre6-input", + /* Takes a vector of packets. */ + .vector_size = sizeof (u32), - .runtime_data_bytes = sizeof (gre_input_runtime_t), + .runtime_data_bytes = sizeof (gre_input_runtime_t), - .n_errors = GRE_N_ERROR, - .error_strings = gre_error_strings, + .n_errors = GRE_N_ERROR, + .error_strings = gre_error_strings, - .n_next_nodes = GRE_INPUT_N_NEXT, - .next_nodes = { + .n_next_nodes = GRE_INPUT_N_NEXT, + .next_nodes = { #define _(s, n) [GRE_INPUT_NEXT_##s] = n, - foreach_gre_input_next + foreach_gre_input_next #undef _ - }, + }, - .format_buffer = format_gre_header_with_length, - .format_trace = format_gre_rx_trace, - .unformat_buffer = unformat_gre_header, -}; + .format_buffer = format_gre_header_with_length, + .format_trace = format_gre_rx_trace, + .unformat_buffer = unformat_gre_header, + }; #ifndef CLIB_MARCH_VARIANT void diff --git a/src/plugins/hs_apps/CMakeLists.txt b/src/plugins/hs_apps/CMakeLists.txt index 1d83175f64..a30105397a 100644 --- a/src/plugins/hs_apps/CMakeLists.txt +++ b/src/plugins/hs_apps/CMakeLists.txt @@ -11,6 +11,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +if(NOT VPP_BUILD_VCL) + return() +endif() + ############################################################################## # vpp builtin hs apps ############################################################################## diff --git a/src/plugins/hs_apps/echo_client.c b/src/plugins/hs_apps/echo_client.c index 54e806a9ba..93e729602a 100644 --- a/src/plugins/hs_apps/echo_client.c +++ b/src/plugins/hs_apps/echo_client.c @@ -16,6 +16,7 @@ */ #include +#include static ec_main_t ec_main; @@ -58,6 +59,14 @@ ec_worker_get (clib_thread_index_t thread_index) return vec_elt_at_index (ec_main.wrk, thread_index); } +static inline void +ec_sessions_stop_clean () +{ + ec_main_t *ecm = &ec_main; + ecm->test_timeout += 1; + ecm->end_test = true; +} + static inline ec_session_t * ec_session_alloc (ec_worker_t *wrk) { @@ -76,22 +85,36 @@ ec_session_get (ec_worker_t *wrk, u32 ec_index) return pool_elt_at_index (wrk->sessions, ec_index); } +static void +update_rtt_stats (f64 session_rtt) +{ + ec_main_t *ecm = &ec_main; + clib_spinlock_lock (&ecm->rtt_stats.w_lock); + ecm->rtt_stats.sum_rtt += session_rtt; + ecm->rtt_stats.n_sum++; + if (session_rtt < ecm->rtt_stats.min_rtt) + ecm->rtt_stats.min_rtt = session_rtt; + if (session_rtt > ecm->rtt_stats.max_rtt) + ecm->rtt_stats.max_rtt = session_rtt; + clib_spinlock_unlock (&ecm->rtt_stats.w_lock); +} + static void send_data_chunk (ec_main_t *ecm, ec_session_t *es) { - const u64 max_burst = 128000; u8 *test_data = ecm->connect_test_data; - int test_buf_len, test_buf_offset, rv; + int test_buf_len, rv; u64 bytes_to_send; - u32 bytes_this_chunk; + u32 bytes_this_chunk, test_buf_offset; svm_fifo_t *f = es->tx_fifo; test_buf_len = vec_len (test_data); ASSERT (test_buf_len > 0); if (ecm->run_time) - bytes_to_send = clib_min (svm_fifo_max_enqueue_prod (f), max_burst); + bytes_to_send = + clib_min (svm_fifo_max_enqueue_prod (f), ecm->max_chunk_bytes); else - bytes_to_send = clib_min (es->bytes_to_send, max_burst); + bytes_to_send = clib_min (es->bytes_to_send, ecm->max_chunk_bytes); if (ecm->throughput) bytes_to_send = clib_min (es->bytes_paced_current, bytes_to_send); test_buf_offset = es->bytes_sent % test_buf_len; @@ -129,6 +152,7 @@ send_data_chunk (ec_main_t *ecm, ec_session_t *es) hdr.data_length = rv; hdr.data_offset = 0; + hdr.gso_size = 0; clib_memcpy_fast (&hdr.rmt_ip, &at->rmt_ip, sizeof (ip46_address_t)); hdr.is_ip4 = at->is_ip4; @@ -145,15 +169,32 @@ send_data_chunk (ec_main_t *ecm, ec_session_t *es) bytes_this_chunk = clib_min (bytes_this_chunk, max_enqueue); if (!ecm->throughput) bytes_this_chunk = clib_min (bytes_this_chunk, 1460); - rv = - app_send_dgram ((app_session_t *) es, test_data + test_buf_offset, - bytes_this_chunk, 0); + if (ecm->cfg.test_bytes) + { + /* Include buffer offset info to also be able to verify + * out-of-order packets */ + svm_fifo_seg_t data_segs[3] = { + { NULL, 0 }, + { (u8 *) &test_buf_offset, sizeof (u32) }, + { test_data + test_buf_offset, bytes_this_chunk } + }; + rv = app_send_dgram_segs ((app_session_t *) es, data_segs, 2, + bytes_this_chunk + sizeof (u32), 0); + if (rv) + rv -= sizeof (u32); + } + else + rv = app_send_dgram ((app_session_t *) es, + test_data + test_buf_offset, bytes_this_chunk, + 0); } } /* If we managed to enqueue data... */ if (rv > 0) { + if (es->is_dgram) + es->dgrams_sent++; /* Account for it... */ es->bytes_sent += rv; if (ecm->run_time) @@ -190,21 +231,53 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es) { ec_main_t *ecm = &ec_main; svm_fifo_t *rx_fifo = es->rx_fifo; + session_dgram_pre_hdr_t ph; int n_read, i; + u8 *rx_buf_start = wrk->rx_buf; + u32 test_buf_offset = es->bytes_received; if (ecm->cfg.test_bytes) { n_read = app_recv ((app_session_t *) es, wrk->rx_buf, vec_len (wrk->rx_buf)); + if (ecm->transport_proto != TRANSPORT_PROTO_TCP) + { + test_buf_offset = *(u32 *) wrk->rx_buf; + rx_buf_start = wrk->rx_buf + sizeof (u32); + n_read -= sizeof (u32); + es->dgrams_received++; + } } else { - n_read = svm_fifo_max_dequeue_cons (rx_fifo); - svm_fifo_dequeue_drop (rx_fifo, n_read); + if (!es->is_dgram) + { + n_read = svm_fifo_max_dequeue_cons (rx_fifo); + svm_fifo_dequeue_drop (rx_fifo, n_read); + } + else + { + n_read = svm_fifo_max_dequeue_cons (rx_fifo); + if (n_read <= sizeof (session_dgram_hdr_t)) + return; + svm_fifo_peek (rx_fifo, 0, sizeof (ph), (u8 *) &ph); + if (n_read < (ph.data_length + SESSION_CONN_HDR_LEN)) + return; + svm_fifo_dequeue_drop (rx_fifo, + ph.data_length + SESSION_CONN_HDR_LEN); + n_read = ph.data_length; + es->dgrams_received++; + } } if (n_read > 0) { + if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes && + (es->rtt_stat & EC_UDP_RTT_RX_FLAG) == 0) + { + es->rtt_stat |= EC_UDP_RTT_RX_FLAG; + update_rtt_stats (vlib_time_now (vlib_get_main ()) - es->send_rtt); + } if (ecm->cfg.verbose) { ELOG_TYPE_DECLARE (e) = @@ -224,16 +297,23 @@ receive_data_chunk (ec_worker_t *wrk, ec_session_t *es) { for (i = 0; i < n_read; i++) { - if (wrk->rx_buf[i] != ((es->bytes_received + i) & 0xff)) + if (rx_buf_start[i] != ((test_buf_offset + i) & 0xff)) { ec_err ("read %d error at byte %lld, 0x%x not 0x%x", n_read, - es->bytes_received + i, wrk->rx_buf[i], - ((es->bytes_received + i) & 0xff)); + test_buf_offset + i, rx_buf_start[i], + ((test_buf_offset + i) & 0xff)); ecm->test_failed = 1; } } } - ASSERT (n_read <= es->bytes_to_receive); + if (n_read > es->bytes_to_receive) + { + ec_err ("expected %llu, received %llu bytes!", + es->bytes_received + es->bytes_to_receive, + es->bytes_received + n_read); + ecm->test_failed = 1; + es->bytes_to_receive = n_read; + } es->bytes_to_receive -= n_read; es->bytes_received += n_read; } @@ -294,7 +374,7 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) ecm->repeats = 0; } - time_now = vlib_time_now (ecm->vlib_main); + time_now = vlib_time_now (vm); /* * Handle connections in this batch */ @@ -308,6 +388,12 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) if (es->bytes_to_send > 0) { + if (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes && + (es->rtt_stat & EC_UDP_RTT_TX_FLAG) == 0) + { + es->send_rtt = time_now; + es->rtt_stat |= EC_UDP_RTT_TX_FLAG; + } send_data_chunk (ecm, es); if (ecm->throughput) es->time_to_send += ecm->pacing_window_len; @@ -319,14 +405,29 @@ ec_node_fn (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) delete_session = 0; } - if (PREDICT_FALSE (delete_session == 1) || ecm->timer_expired) + if (PREDICT_FALSE (delete_session == 1) || ecm->end_test) { clib_atomic_fetch_add (&ecm->tx_total, es->bytes_sent); clib_atomic_fetch_add (&ecm->rx_total, es->bytes_received); + clib_atomic_fetch_add (&ecm->tx_total_dgrams, es->dgrams_sent); + clib_atomic_fetch_add (&ecm->rx_total_dgrams, es->dgrams_received); s = session_get_from_handle_if_valid (es->vpp_session_handle); if (s) { + if (ecm->transport_proto == TRANSPORT_PROTO_TCP) + { + transport_connection_t *tc; + tcp_connection_t *tcpc; + tc = transport_get_connection ( + TRANSPORT_PROTO_TCP, s->connection_index, s->thread_index); + if (PREDICT_TRUE (tc != NULL)) + { + tcpc = tcp_get_connection_from_transport (tc); + update_rtt_stats (tcpc->srtt * TCP_TICK); + } + } + vnet_disconnect_args_t _a, *a = &_a; a->handle = session_handle (s); a->app_index = ecm->app_index; @@ -380,11 +481,13 @@ ec_reset_runtime_config (ec_main_t *ecm) ecm->tls_engine = CRYPTO_ENGINE_OPENSSL; ecm->no_copy = 0; ecm->run_test = EC_STARTING; - ecm->timer_expired = false; + ecm->end_test = false; ecm->ready_connections = 0; ecm->connect_conn_index = 0; ecm->rx_total = 0; ecm->tx_total = 0; + ecm->rx_total_dgrams = 0; + ecm->tx_total_dgrams = 0; ecm->barrier_acq_needed = 0; ecm->prealloc_sessions = 0; ecm->prealloc_fifos = 0; @@ -396,6 +499,18 @@ ec_reset_runtime_config (ec_main_t *ecm) ecm->run_time = 0; ecm->throughput = 0; ecm->pacing_window_len = 1; + ecm->max_chunk_bytes = 128 << 10; + ecm->report_interval = 0; + ecm->report_interval_total = 0; + ecm->last_print_time = 0; + ecm->last_total_tx_bytes = 0; + ecm->last_total_rx_bytes = 0; + ecm->last_total_rx_dgrams = 0; + ecm->last_total_tx_dgrams = 0; + clib_memset (&ecm->rtt_stats, 0, sizeof (ec_rttstat_t)); + ecm->rtt_stats.min_rtt = CLIB_F64_MAX; + if (ecm->rtt_stats.w_lock == NULL) + clib_spinlock_init (&ecm->rtt_stats.w_lock); vec_free (ecm->connect_uri); } @@ -506,6 +621,7 @@ ec_cleanup (ec_main_t *ecm) ecm->pacing_window_len = 1; if (ecm->barrier_acq_needed) vlib_worker_thread_barrier_sync (ecm->vlib_main); + clib_spinlock_free (&ecm->rtt_stats.w_lock); } static int @@ -670,7 +786,9 @@ ec_calc_tput (ec_main_t *ecm) /* find a suitable pacing window length & data chunk size */ bytes_paced_target = ecm->throughput * ecm->pacing_window_len / ecm->n_clients; - while (bytes_paced_target > target_size_threshold) + while ( + bytes_paced_target > target_size_threshold || + (ecm->transport_proto == TRANSPORT_PROTO_UDP && bytes_paced_target > 1460)) { ecm->pacing_window_len /= 2; bytes_paced_target /= 2; @@ -793,6 +911,7 @@ ec_session_disconnect (session_t *s) { ec_main_t *ecm = &ec_main; vnet_disconnect_args_t _a = { 0 }, *a = &_a; + a->handle = session_handle (s); a->app_index = ecm->app_index; vnet_disconnect_session (a); @@ -914,6 +1033,7 @@ static clib_error_t * ec_attach () { vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair; + app_ca_trust_add_args_t _ca_args = {}, *ca_args = &_ca_args; ec_main_t *ecm = &ec_main; vnet_app_attach_args_t _a, *a = &_a; u32 prealloc_fifos; @@ -931,12 +1051,10 @@ ec_attach () prealloc_fifos = ecm->prealloc_fifos ? ecm->expected_connections : 1; - options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678; options[APP_OPTIONS_SEGMENT_SIZE] = ecm->private_segment_size; options[APP_OPTIONS_ADD_SEGMENT_SIZE] = ecm->private_segment_size; options[APP_OPTIONS_RX_FIFO_SIZE] = ecm->fifo_size; options[APP_OPTIONS_TX_FIFO_SIZE] = ecm->fifo_size; - options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = ecm->private_segment_count; options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos; options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN; options[APP_OPTIONS_TLS_ENGINE] = ecm->tls_engine; @@ -963,6 +1081,13 @@ ec_attach () vnet_app_add_cert_key_pair (ck_pair); ecm->ckpair_index = ck_pair->index; + vec_validate (ca_args->ca_chain, test_ca_chain_rsa_len - 1); + clib_memcpy (ca_args->ca_chain, test_ca_chain_rsa, test_ca_chain_rsa_len); + vec_validate (ca_args->crl, test_ca_crl_len - 1); + clib_memcpy (ca_args->crl, test_ca_crl, test_ca_crl_len); + app_crypto_add_ca_trust (ecm->app_index, ca_args); + ecm->ca_trust_index = ca_args->index; + ecm->test_client_attached = 1; return 0; @@ -1027,6 +1152,7 @@ ec_connect_rpc (void *args) &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_CRYPTO, sizeof (transport_endpt_crypto_cfg_t)); ext_cfg->crypto.ckpair_index = ecm->ckpair_index; + ext_cfg->crypto.ca_trust_index = ecm->ca_trust_index; } rv = vnet_connect (a); @@ -1142,18 +1268,194 @@ ec_ctrl_test_stop () goto cleanup; \ } +static void +ec_print_timeout_stats (vlib_main_t *vm) +{ + ec_main_t *ecm = &ec_main; + u64 received_bytes = 0, sent_bytes = 0; + ec_worker_t *wrk; + ec_session_t *sess; + vec_foreach (wrk, ecm->wrk) + { + pool_foreach (sess, wrk->sessions) + { + received_bytes += sess->bytes_received; + sent_bytes += sess->bytes_sent; + } + } + ec_cli ("Timeout at %.6f with %d sessions still active...", + vlib_time_now (vm), ecm->ready_connections); + if (ecm->transport_proto == TRANSPORT_PROTO_UDP) + { + ec_cli ("Received %llu bytes out of %llu sent (%llu target)", + received_bytes, sent_bytes, ecm->bytes_to_send * ecm->n_clients); + } +} + +static void +ec_print_periodic_stats (vlib_main_t *vm, bool print_header, bool print_footer) +{ + ec_main_t *ecm = &ec_main; + f64 time_now, print_delta, interval_start, interval_end; + u64 total_bytes, + received_bytes = 0, sent_bytes = 0, dgrams_sent = 0, dgrams_received = 0, + last_total_bytes = ecm->last_total_tx_bytes + ecm->last_total_rx_bytes; + ec_worker_t *wrk; + ec_session_t *sess; + vec_foreach (wrk, ecm->wrk) + { + pool_foreach (sess, wrk->sessions) + { + received_bytes += sess->bytes_received; + sent_bytes += sess->bytes_sent; + if (ecm->transport_proto == TRANSPORT_PROTO_UDP) + { + dgrams_received += sess->dgrams_received; + dgrams_sent += sess->dgrams_sent; + } + } + } + time_now = vlib_time_now (vm); + interval_end = time_now - ecm->test_start_time; + interval_start = ecm->last_print_time - ecm->test_start_time; + total_bytes = received_bytes + sent_bytes; + print_delta = time_now - ecm->last_print_time; + + if (ecm->transport_proto == TRANSPORT_PROTO_UDP) + { + u8 *tput = 0; + if (print_header) + { + ec_cli ("-----------------------------------------------------------" + "-------------"); + if (ecm->report_interval_total) + ec_cli ("Run time (s) Transmitted Received Throughput " + "Sent/received dgrams"); + else + ec_cli ("Interval (s) Transmitted Received Throughput " + "Sent/received dgrams"); + } + if (ecm->report_interval_total) + { + tput = + format (tput, "%Ub/s", format_base10, + flt_round_nearest ((f64) total_bytes / + (time_now - ecm->test_start_time)) * + 8); + ec_cli ("%-13.1f %-13U %-10U %-12s %llu/%llu", interval_end, + format_base10, sent_bytes, format_base10, received_bytes, + tput, dgrams_sent, dgrams_received); + } + else + { + tput = + format (tput, "%Ub/s", format_base10, + flt_round_nearest ((f64) (total_bytes - last_total_bytes) / + print_delta) * + 8); + ec_cli ("%.1f-%-9.1f %-13U %-10U %-12s %llu/%llu", interval_start, + interval_end, format_base10, + sent_bytes - ecm->last_total_tx_bytes, format_base10, + received_bytes - ecm->last_total_rx_bytes, tput, + (dgrams_sent - ecm->last_total_tx_dgrams), + (dgrams_received - ecm->last_total_rx_dgrams)); + } + if (print_footer) + ec_cli ("-------------------------------------------------------------" + "-----------"); + ecm->last_total_tx_dgrams = dgrams_sent; + ecm->last_total_rx_dgrams = dgrams_received; + vec_free (tput); + } + else + { + if (print_header) + { + ec_cli ("-------------------------------------------------"); + if (ecm->report_interval_total) + ec_cli ("Run time (s) Transmitted Received Throughput"); + else + ec_cli ("Interval (s) Transmitted Received Throughput"); + } + if (ecm->report_interval_total) + ec_cli ("%-13.1f %-13U %-10U %Ub/s", interval_end, format_base10, + sent_bytes, format_base10, received_bytes, format_base10, + flt_round_nearest ((f64) total_bytes / + (time_now - ecm->test_start_time)) * + 8); + else + ec_cli ("%.1f-%-9.1f %-13U %-10U %Ub/s", interval_start, interval_end, + format_base10, sent_bytes - ecm->last_total_tx_bytes, + format_base10, received_bytes - ecm->last_total_rx_bytes, + format_base10, + flt_round_nearest (((f64) (total_bytes - last_total_bytes)) / + print_delta) * + 8); + if (print_footer) + ec_cli ("-------------------------------------------------"); + } + ecm->last_print_time = time_now; + ecm->last_total_tx_bytes = sent_bytes; + ecm->last_total_rx_bytes = received_bytes; +} + +static void +ec_print_final_stats (vlib_main_t *vm, f64 total_delta) +{ + ec_main_t *ecm = &ec_main; + u64 total_bytes; + f64 dgram_loss; + char *transfer_type; + + if (ecm->transport_proto == TRANSPORT_PROTO_TCP || + (ecm->transport_proto == TRANSPORT_PROTO_UDP && ecm->echo_bytes)) + { + /* display rtt stats in milliseconds */ + if (ecm->rtt_stats.n_sum == 1) + ec_cli ("%.05fms roundtrip", ecm->rtt_stats.min_rtt * 1000); + else if (ecm->rtt_stats.n_sum > 1) + ec_cli ("%.05fms/%.05fms/%.05fms min/avg/max roundtrip", + ecm->rtt_stats.min_rtt * 1000, + ecm->rtt_stats.sum_rtt / ecm->rtt_stats.n_sum * 1000, + ecm->rtt_stats.max_rtt * 1000); + else + ec_cli ("error measuring roundtrip time"); + } + if (ecm->transport_proto == TRANSPORT_PROTO_UDP) + { + ec_cli ("sent total %llu datagrams, received total %llu datagrams", + ecm->tx_total_dgrams, ecm->rx_total_dgrams); + dgram_loss = (ecm->tx_total_dgrams ? + ((f64) (ecm->tx_total_dgrams - ecm->rx_total_dgrams) / + (f64) ecm->tx_total_dgrams * 100.0) : + 0.0); + if (ecm->echo_bytes && dgram_loss > 0.0) + ec_cli ("lost %llu datagrams (%.2f%%)", + ecm->tx_total_dgrams - ecm->rx_total_dgrams, dgram_loss); + } + total_bytes = (ecm->echo_bytes ? ecm->rx_total : ecm->tx_total); + transfer_type = ecm->echo_bytes ? "full-duplex" : "half-duplex"; + ec_cli ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds", total_bytes, + total_bytes / (1ULL << 20), total_bytes / (1ULL << 30), total_delta); + ec_cli ("%u bytes/second %s", + flt_round_nearest (((f64) total_bytes) / (total_delta)), + transfer_type); + ec_cli ("%UBps %s", format_base10, + flt_round_nearest (((f64) total_bytes) / (total_delta)), + transfer_type); +} + static clib_error_t * ec_command_fn (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd) { unformat_input_t _line_input, *line_input = &_line_input; - char *default_uri = "tcp://6.0.1.1/1234", *transfer_type; + char *default_uri = "tcp://6.0.1.1/1234"; ec_main_t *ecm = &ec_main; uword *event_data = 0, event_type; clib_error_t *error = 0; - int rv, timed_run_conflict = 0, had_config = 1; - u64 total_bytes; - f64 delta; + int rv, timed_run_conflict = 0, tput_conflict = 0, had_config = 1; + f64 delta, wait_time = 0; if (ecm->test_client_attached) return clib_error_return (0, "failed: already running!"); @@ -1182,11 +1484,11 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, &ecm->bytes_to_send)) timed_run_conflict++; else if (unformat (line_input, "test-timeout %f", &ecm->test_timeout)) - ; + timed_run_conflict++; else if (unformat (line_input, "syn-timeout %f", &ecm->syn_timeout)) ; else if (unformat (line_input, "run-time %f", &ecm->run_time)) - ; + ecm->test_timeout = ecm->run_time; else if (unformat (line_input, "echo-bytes")) ecm->echo_bytes = 1; else if (unformat (line_input, "fifo-size %U", unformat_memory_size, @@ -1198,9 +1500,12 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, else if (unformat (line_input, "private-segment-size %U", unformat_memory_size, &ecm->private_segment_size)) ; - else if (unformat (line_input, "throughput %U", unformat_memory_size, + else if (unformat (line_input, "throughput %U", unformat_base10, &ecm->throughput)) - ; + ecm->throughput /= 8; + else if (unformat (line_input, "max-tx-chunk %U", unformat_memory_size, + &ecm->max_chunk_bytes)) + tput_conflict = 1; else if (unformat (line_input, "preallocate-fifos")) ecm->prealloc_fifos = 1; else if (unformat (line_input, "preallocate-sessions")) @@ -1208,6 +1513,14 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, else if (unformat (line_input, "client-batch %d", &ecm->connections_per_batch)) ; + else if (unformat (line_input, "report-interval %u", + &ecm->report_interval)) + ; + else if (unformat (line_input, "report-interval-total %u", + &ecm->report_interval)) + ecm->report_interval_total = 1; + else if (unformat (line_input, "report-interval")) + ecm->report_interval = 1; else if (unformat (line_input, "appns %_%v%_", &ecm->appns_id)) ; else if (unformat (line_input, "all-scope")) @@ -1235,6 +1548,9 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, if (timed_run_conflict && ecm->run_time) return clib_error_return (0, "failed: invalid arguments for a timed run!"); + if (ecm->throughput && tput_conflict) + return clib_error_return ( + 0, "failed: can't set fixed tx chunk for a throughput run!"); parse_config: @@ -1304,10 +1620,13 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, goto stop_test; case EC_CLI_CONNECTS_DONE: - delta = vlib_time_now (vm) - ecm->syn_start_time; - if (delta != 0.0) - ec_cli ("%d three-way handshakes in %.2f seconds %.2f/s", - ecm->n_clients, delta, ((f64) ecm->n_clients) / delta); + if (ecm->transport_proto == TRANSPORT_PROTO_TCP) + { + delta = vlib_time_now (vm) - ecm->syn_start_time; + if (delta != 0.0) + ec_cli ("%d three-way handshakes in %.2f seconds %.2f/s", + ecm->n_clients, delta, ((f64) ecm->n_clients) / delta); + } break; case EC_CLI_CONNECTS_FAILED: @@ -1322,46 +1641,81 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, } /* Testing officially starts now */ ecm->test_start_time = vlib_time_now (ecm->vlib_main); + if (ecm->report_interval) + ecm->last_print_time = ecm->test_start_time; ec_cli ("Test started at %.6f", ecm->test_start_time); /* - * If a timed run, wait and expire timer + * Wait for the sessions to finish or test_timeout (timeout or length + * of timed run) seconds pass. If providing periodic reports, wake up + * every now and then to print them and loop. */ - if (ecm->run_time) + u8 main_loop_done = false, print_header = true, report_timeout = false; + do { - vlib_process_suspend (vm, ecm->run_time); - ec_main.timer_expired = true; - } + if (ecm->report_interval) + { + delta = vlib_time_now (vm) - ecm->test_start_time; + if (delta + (f64) ecm->report_interval > ecm->test_timeout) + { + report_timeout = true; + wait_time = ecm->test_timeout - delta; + } + else + wait_time = (f64) ecm->report_interval; + } + else + { + report_timeout = true; + wait_time = (f64) ecm->test_timeout; + } - /* - * Wait for the sessions to finish or test_timeout seconds pass - */ - vlib_process_wait_for_event_or_clock (vm, ecm->test_timeout); - event_type = vlib_process_get_events (vm, &event_data); - switch (event_type) - { - case ~0: - ec_cli ("Timeout at %.6f with %d sessions still active...", - vlib_time_now (ecm->vlib_main), ecm->ready_connections); - error = clib_error_return (0, "failed: timeout with %d sessions", - ecm->ready_connections); - goto stop_test; + vlib_process_wait_for_event_or_clock (vm, wait_time); + event_type = vlib_process_get_events (vm, &event_data); + switch (event_type) + { + case ~0: + if (report_timeout) + { + if (ecm->run_time) + { + ec_sessions_stop_clean (); + break; + } + ec_print_timeout_stats (vm); + if (ecm->transport_proto != TRANSPORT_PROTO_UDP) + error = + clib_error_return (0, "failed: timeout with %d sessions", + ecm->ready_connections); + else if (ecm->echo_bytes) + { + ec_sessions_stop_clean (); + break; + } + goto stop_test; + } + else + { + ec_print_periodic_stats (vm, print_header, false); + if (PREDICT_FALSE (print_header)) + print_header = false; + } + break; - case EC_CLI_TEST_DONE: - ecm->test_end_time = vlib_time_now (vm); - ec_cli ("Test finished at %.6f", ecm->test_end_time); - break; + case EC_CLI_TEST_DONE: + ecm->test_end_time = vlib_time_now (vm); + main_loop_done = true; + break; - default: - ec_cli ("unexpected event(3): %d", event_type); - error = - clib_error_return (0, "failed: unexpected event(3): %d", event_type); - goto stop_test; + default: + ec_cli ("unexpected event(3): %d", event_type); + error = clib_error_return (0, "failed: unexpected event(3): %d", + event_type); + goto stop_test; + } } + while (!main_loop_done); - /* - * Done. Compute stats - */ delta = ecm->test_end_time - ecm->test_start_time; if (delta == 0.0) { @@ -1369,15 +1723,12 @@ ec_command_fn (vlib_main_t *vm, unformat_input_t *input, error = clib_error_return (0, "failed: zero delta-t"); goto stop_test; } - - total_bytes = (ecm->echo_bytes ? ecm->rx_total : ecm->tx_total); - transfer_type = ecm->echo_bytes ? "full-duplex" : "half-duplex"; - ec_cli ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds", total_bytes, - total_bytes / (1ULL << 20), total_bytes / (1ULL << 30), delta); - ec_cli ("%.2f bytes/second %s", ((f64) total_bytes) / (delta), - transfer_type); - ec_cli ("%.4f gbit/second %s", (((f64) total_bytes * 8.0) / delta / 1e9), - transfer_type); + /* Print last interval */ + if (ecm->report_interval && + vlib_time_now (vm) - ecm->last_print_time >= 0.1f) + ec_print_periodic_stats (vm, print_header, true); + ec_cli ("Test finished at %.6f", ecm->test_end_time); + ec_print_final_stats (vm, delta); if (ecm->cfg.test_bytes && ecm->test_failed) error = clib_error_return (0, "failed: test bytes"); @@ -1433,7 +1784,9 @@ VLIB_CLI_COMMAND (ec_command, static) = { "[run-time