diff options
173 files changed, 4228 insertions, 1758 deletions
diff --git a/.gitignore b/.gitignore index 3d2c2fc12b6..5537f0dd791 100644 --- a/.gitignore +++ b/.gitignore @@ -122,7 +122,8 @@ compile_commands.json /extras/hs-test/vpp-data /extras/hs-test/hs-test /extras/hs-test/http_server -/extras/hs-test/.build.vpp +/extras/hs-test/.build.ok +/extras/hs-test/summary/ # ./configure /CMakeFiles diff --git a/MAINTAINERS b/MAINTAINERS index c310e728227..fd456c04a6c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -192,7 +192,7 @@ I: sr M: Pablo Camarillo <pcamaril@cisco.com> M: Ahmed Abdelsalam <ahabdels@cisco.com> F: src/vnet/srv6/ -F: src/vnet/srmpls/ +F: src/plugin/srmpls/ F: src/examples/srv6-sample-localsid/ VNET IPSec @@ -892,3 +892,8 @@ M: vpp-dev Mailing List <vpp-dev@fd.io> C: Missing Maintainer F: * F: */ + +Netmap +I: netmap +M: Tom Jones <thj@freebsd.org> +F: src/plugins/netmap/ @@ -86,6 +86,7 @@ DEB_DEPENDS += nasm DEB_DEPENDS += iperf ethtool # for 'make test TEST=vm_vpp_interfaces' DEB_DEPENDS += libpcap-dev DEB_DEPENDS += tshark +DEB_DEPENDS += jq # for extracting test summary from .json report (hs-test) LIBFFI=libffi6 # works on all but 20.04 and debian-testing diff --git a/build/external/mlx_rdma_dpdk_matrix.txt b/build/external/mlx_rdma_dpdk_matrix.txt index a0f21c56616..b2245cc49a0 100644 --- a/build/external/mlx_rdma_dpdk_matrix.txt +++ b/build/external/mlx_rdma_dpdk_matrix.txt @@ -1,2 +1,2 @@ -rdma=46.1 dpdk=23.07 rdma=49.0 dpdk=23.11 +rdma=51.0 dpdk=24.03 diff --git a/build/external/packages/dpdk.mk b/build/external/packages/dpdk.mk index 2c5a9030275..c03d1a14703 100644 --- a/build/external/packages/dpdk.mk +++ b/build/external/packages/dpdk.mk @@ -19,9 +19,10 @@ DPDK_FAILSAFE_PMD ?= n DPDK_MACHINE ?= default DPDK_MLX_IBV_LINK ?= static -dpdk_version ?= 23.11 +dpdk_version ?= 24.03 dpdk_base_url ?= http://fast.dpdk.org/rel dpdk_tarball := dpdk-$(dpdk_version).tar.xz +dpdk_tarball_md5sum_24.03 := a98da848d6ba09808ef00f9a26aaa49a dpdk_tarball_md5sum_23.11 := 896c09f5b45b452bd77287994650b916 dpdk_tarball_md5sum_23.07 := 2b6d57f077585cb15b885482362fd47f dpdk_tarball_md5sum_23.03 := 3cf8ebbcd412d5726db230f2eeb90cc9 @@ -32,8 +33,11 @@ dpdk_tarball_md5sum_21.11 := 58660bbbe9e95abce86e47692b196555 dpdk_tarball_md5sum := $(dpdk_tarball_md5sum_$(dpdk_version)) dpdk_url := $(dpdk_base_url)/$(dpdk_tarball) dpdk_tarball_strip_dirs := 1 +ifeq ($(shell uname), FreeBSD) +dpdk_depends := $(if $(ARCH_X86_64), ipsec-mb) +else dpdk_depends := rdma-core $(if $(ARCH_X86_64), ipsec-mb) - +endif DPDK_MLX_DEFAULT := $(shell if grep -q "rdma=$(rdma-core_version) dpdk=$(dpdk_version)" mlx_rdma_dpdk_matrix.txt; then echo 'y'; else echo 'n'; fi) DPDK_MLX4_PMD ?= $(DPDK_MLX_DEFAULT) DPDK_MLX5_PMD ?= $(DPDK_MLX_DEFAULT) @@ -133,14 +137,19 @@ endif DPDK_DRIVERS_DISABLED := $(shell echo $(DPDK_DRIVERS_DISABLED) | tr -d '\\\t ') DPDK_LIBS_DISABLED := $(shell echo $(DPDK_LIBS_DISABLED) | tr -d '\\\t ') +SED=sed +ifeq ($shell(uname), FreeBSD) +SED=gsed +endif + HASH := \# # post-meson-setup snippet to alter rte_build_config.h define dpdk_config if grep -q RTE_$(1) $(dpdk_src_dir)/config/rte_config.h ; then \ -sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ +$(SED) -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ $(dpdk_src_dir)/config/rte_config.h; \ elif grep -q RTE_$(1) $(dpdk_build_dir)/rte_build_config.h ; then \ -sed -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ +$(SED) -i -e 's/$(HASH)define RTE_$(1).*/$(HASH)define RTE_$(1) $(DPDK_$(1))/' \ $(dpdk_build_dir)/rte_build_config.h; \ else \ echo '$(HASH)define RTE_$(1) $(DPDK_$(1))' \ @@ -156,7 +165,7 @@ if [[ "$(DPDK_$(1))" == "y" ]]; then \ >> $(dpdk_build_dir)/rte_build_config.h ; \ fi; \ elif [[ "$(DPDK_$(1))" == "n" ]]; then \ - sed -i '/$(HASH)define RTE_$(1) .*/d' $(dpdk_build_dir)/rte_build_config.h \ + $(SED) -i '/$(HASH)define RTE_$(1) .*/d' $(dpdk_build_dir)/rte_build_config.h \ $(dpdk_src_dir)/config/rte_config.h ; \ fi endef @@ -172,6 +181,7 @@ DPDK_MESON_ARGS = \ -Db_pie=true \ -Dmachine=$(DPDK_MACHINE) \ --buildtype=$(DPDK_BUILD_TYPE) \ + -Denable_kmods=false \ ${DPDK_MLX_CONFIG_FLAG} PIP_DOWNLOAD_DIR = $(CURDIR)/downloads/ diff --git a/build/external/packages/rdma-core.mk b/build/external/packages/rdma-core.mk index e0527ce6fab..f015322775f 100644 --- a/build/external/packages/rdma-core.mk +++ b/build/external/packages/rdma-core.mk @@ -23,10 +23,10 @@ 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 := 49.0 +rdma-core_version := 51.0 rdma-core_tarball := rdma-core-$(rdma-core_version).tar.gz -rdma-core_tarball_md5sum_46.1 := 3ac7c00717ea2720df5d90f8a43ae33a rdma-core_tarball_md5sum_49.0 := 9fe3909f19c7e0276c9e546411bbb49c +rdma-core_tarball_md5sum_51.0 := ed95d79f782ea00bd7233d453abd60b3 rdma-core_tarball_md5sum := $(rdma-core_tarball_md5sum_$(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/docs/developer/corefeatures/sr/sr_mpls.rst b/docs/developer/corefeatures/sr/sr_mpls.rst index d2fe4025326..9e676db4f07 120000 --- a/docs/developer/corefeatures/sr/sr_mpls.rst +++ b/docs/developer/corefeatures/sr/sr_mpls.rst @@ -1 +1 @@ -../../../../src/vnet/srmpls/sr_doc.rst
\ No newline at end of file +../../../../src/plugins/srmpls/sr_doc.rst
\ No newline at end of file diff --git a/docs/gettingstarted/progressivevpp/index.rst b/docs/gettingstarted/progressivevpp/index.rst index 7d1a2e2b237..efe31b12db5 100644 --- a/docs/gettingstarted/progressivevpp/index.rst +++ b/docs/gettingstarted/progressivevpp/index.rst @@ -6,7 +6,7 @@ Progressive VPP Tutorial ######################## -Learn to run FD.io VPP on a single Ubuntu 16.04 VM using Vagrant with this walkthrough +Learn to run FD.io VPP on a single Ubuntu VM using Vagrant with this walkthrough covering basic FD.io VPP scenarios. Useful FD.io VPP commands will be used, and will discuss basic operations, and the state of a running FD.io VPP on a system. diff --git a/docs/gettingstarted/progressivevpp/settingupenvironment.rst b/docs/gettingstarted/progressivevpp/settingupenvironment.rst index 8c67c79b188..a8fe16aa4ce 100644 --- a/docs/gettingstarted/progressivevpp/settingupenvironment.rst +++ b/docs/gettingstarted/progressivevpp/settingupenvironment.rst @@ -3,15 +3,15 @@ Setting up your environment =========================== -All of these exercises are designed to be performed on an Ubuntu 16.04 (Xenial) box. +All of these exercises are designed to be performed on an Ubuntu 22.04 (Jammy) box. -* If you have an Ubuntu 18.04 box on which you have sudo or root access, you can feel free to use that. -* If you do not, a Vagrantfile is provided to setup a basic Ubuntu 18.04 box for you in the the steps below. +* If you have an Ubuntu 22.04 box on which you have sudo or root access, you can feel free to use that. +* If you do not, a Vagrantfile is provided to setup a basic Ubuntu 22.04 box for you in the the steps below. -Install Virtual Box and Vagrant +Install Libvirt and Vagrant ------------------------------- -You will need to install Virtual Box and Vagrant. +You will need to install Libvirt and Vagrant. Create a Vagrant Directory --------------------------- @@ -32,21 +32,16 @@ Create a file called **Vagrantfile** with the following contents: Vagrant.configure(2) do |config| - config.vm.box = "bento/ubuntu-18.04" - config.vm.box_check_update = false + config.vm.box = "generic/ubuntu2204" vmcpu=(ENV['VPP_VAGRANT_VMCPU'] || 2) vmram=(ENV['VPP_VAGRANT_VMRAM'] || 4096) config.ssh.forward_agent = true - config.vm.provider "virtualbox" do |vb| - vb.customize ["modifyvm", :id, "--ioapic", "on"] + config.vm.provider "libvirt" do |vb| vb.memory = "#{vmram}" vb.cpus = "#{vmcpu}" - #support for the SSE4.x instruction is required in some versions of VB. - vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.1", "1"] - vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.2", "1"] end end @@ -97,7 +92,7 @@ We write this file with the following contents: .. code-block:: console $ sudo bash - # echo "deb [trusted=yes] https://packagecloud.io/fdio/release/ubuntu bionic main" > /etc/apt/sources.list.d/99fd.io.list + # echo "deb https://packagecloud.io/fdio/release/ubuntu jammy main" > /etc/apt/sources.list.d/99fd.io.list # Get the key. diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 2348c8dc391..f90ffa89216 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -1047,6 +1047,7 @@ srcIP srcPortDefinition srcUP srh +srmpls Srmpls srtp SRTP diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile index f0ec755afb2..6ee89bc2770 100644 --- a/extras/hs-test/Makefile +++ b/extras/hs-test/Makefile @@ -23,6 +23,14 @@ ifeq ($(CPUS),) CPUS=1 endif +ifeq ($(PARALLEL),) +PARALLEL=1 +endif + +ifeq ($(REPEAT),) +REPEAT=0 +endif + ifeq ($(VPPSRC),) VPPSRC=$(shell pwd)/../.. endif @@ -35,13 +43,14 @@ ifeq ($(ARCH),) ARCH=$(shell dpkg --print-architecture) endif -list_tests = @(grep -r ') Test' *_test.go | cut -d '*' -f2 | cut -d '(' -f1 | \ - tr -d ' ' | tr ')' '/' | sed 's/Suite//') +list_tests = @go run github.com/onsi/ginkgo/v2/ginkgo --dry-run -v --no-color --seed=2 | head -n -1 | grep 'Test' | \ + sed 's/^/* /; s/\(Suite\) /\1\//g' .PHONY: help help: @echo "Make targets:" @echo " test - run tests" + @echo " test-debug - run tests (vpp debug image)" @echo " build - build test infra" @echo " build-debug - build test infra (vpp debug image)" @echo " build-go - just build golang files" @@ -60,6 +69,8 @@ help: @echo " TEST=[test-name] - specific test to run" @echo " CPUS=[n-cpus] - number of cpus to run with vpp" @echo " VPPSRC=[path-to-vpp-src] - path to vpp source files (for gdb)" + @echo " PARALLEL=[n-cpus] - number of test processes to spawn to run in parallel" + @echo " REPEAT=[n] - repeat tests up to N times or until a failure occurs" @echo @echo "List of all tests:" $(call list_tests) @@ -68,30 +79,49 @@ help: list-tests: $(call list_tests) +.PHONY: build-vpp-release build-vpp-release: @make -C ../.. build-release +.PHONY: build-vpp-debug build-vpp-debug: @make -C ../.. build +.build.ok: build + @touch .build.ok + +.build_debug.ok: build-debug + @touch .build.ok + .PHONY: test -test: .deps.ok .build.vpp +test: .deps.ok .build.ok + -bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ + --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ + --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) + $(call jq-summary) + @bash ./script/compress.sh + +.PHONY: test-debug +test-debug: .deps.ok .build_debug.ok @bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) + --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) +.PHONY: build-go build-go: go build ./tools/http_server +.PHONY: build build: .deps.ok build-vpp-release build-go - @rm -f .build.vpp + @rm -f .build.ok bash ./script/build_hst.sh release - @touch .build.vpp + @touch .build.ok +.PHONY: build-debug build-debug: .deps.ok build-vpp-debug build-go - @rm -f .build.vpp + @rm -f .build.ok bash ./script/build_hst.sh debug - @touch .build.vpp + @touch .build.ok .deps.ok: @sudo make install-deps @@ -101,17 +131,20 @@ install-deps: @rm -f .deps.ok @apt-get update \ && apt-get install -y apt-transport-https ca-certificates curl software-properties-common \ - && apt-get install -y golang apache2-utils wrk bridge-utils + apache2-utils wrk bridge-utils @if [ ! -f /usr/share/keyrings/docker-archive-keyring.gpg ] ; then \ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg; \ echo "deb [arch=$(ARCH) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(UBUNTU_CODENAME) stable" \ | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ; \ apt-get update; \ fi - @apt-get install -y docker-ce @touch .deps.ok .PHONY: fixstyle fixstyle: @gofmt -w . @go mod tidy + +# splitting this into multiple lines breaks the command +jq-summary = @jq -r '.[0] | .SpecReports[] | select(.State == "failed") | select(.Failure != null) | "TestName: \(.LeafNodeText)\nMessage:\n\(.Failure.Message)\n Full Stack Trace:\n\(.Failure.Location.FullStackTrace)\n"' summary/report.json > summary/failed-summary.log \ + && echo "Summary generated -> failed-summary.log" diff --git a/extras/hs-test/README.rst b/extras/hs-test/README.rst index 6db832b7fbe..1dc1039b33f 100644 --- a/extras/hs-test/README.rst +++ b/extras/hs-test/README.rst @@ -9,7 +9,10 @@ End-to-end tests often want multiple VPP instances, network namespaces, differen and to execute external tools or commands. With such requirements the existing VPP test framework is not sufficient. For this, ``Go`` was chosen as a high level language, allowing rapid development, with ``Docker`` and ``ip`` being the tools for creating required topology. -Go's package `testing`_ together with `go test`_ command form the base framework upon which the *hs-test* is built and run. +`Ginkgo`_ forms the base framework upon which the *hs-test* is built and run. +All tests are technically in a single suite because we are only using ``package main``. We simulate suite behavior by grouping tests by the topology they require. +This allows us to run those mentioned groups in parallel, but not individual tests in parallel. + Anatomy of a test case ---------------------- @@ -24,15 +27,16 @@ Anatomy of a test case **Action flow when running a test case**: #. It starts with running ``make test``. Optional arguments are VERBOSE, PERSIST (topology configuration isn't cleaned up after test run), - and TEST=<test-name> to run specific test. -#. ``make list-tests`` (or ``make help``) shows all test names. -#. ``go test`` compiles package ``main`` along with any files with names matching the file pattern ``*_test.go`` - and then runs the resulting test binaries -#. The go test framework runs each function matching :ref:`naming convention<test-convention>`. Each of these corresponds to a `test suite`_ -#. Testify toolkit's ``suite.Run(t *testing.T, suite TestingSuite)`` function runs the suite and does the following: - + TEST=<test-name> to run a specific test and PARALLEL=[n-cpus]. +#. ``make list-tests`` (or ``make help``) shows all tests. The current `list of tests`_ is at the bottom of this document. +#. ``Ginkgo`` looks for a spec suite in the current directory and then compiles it to a .test binary +#. The Ginkgo test framework runs each function that was registered manually using ``registerMySuiteTest(s *MySuite)``. Each of these functions correspond to a suite +#. Ginkgo's ``RunSpecs(t, "Suite description")`` function is the entry point and does the following: + + #. Ginkgo compiles the spec, builds a spec tree + #. ``Describe`` container nodes in suite\_\*_test.go files are run (in series by default, or in parallel with the argument PARALLEL=[n-cpus]) #. Suite is initialized. The topology is loaded and configured in this step - #. Test suite runs all the tests attached to it + #. Registered tests are run in generated ``It`` subject nodes #. Execute tear-down functions, which currently consists of stopping running containers and clean-up of test topology @@ -43,23 +47,25 @@ This describes adding a new test case to an existing suite. For adding a new suite, please see `Modifying the framework`_ below. #. To write a new test case, create a file whose name ends with ``_test.go`` or pick one that already exists -#. Declare method whose name starts with ``Test`` and specifies its receiver as a pointer to the suite's struct (defined in ``framework_test.go``) +#. Declare method whose name ends with ``Test`` and specifies its parameter as a pointer to the suite's struct (defined in ``suite_*_test.go``) #. Implement test behaviour inside the test method. This typically includes the following: - #. Retrieve a running container in which to run some action. Method ``getContainerByName`` - from ``HstSuite`` struct serves this purpose - #. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI - #. Run arbitrary commands inside the containers with ``exec`` method - #. Run other external tool with one of the preexisting functions in the ``utils.go`` file. - For example, use ``wget`` with ``startWget`` function - #. Use ``exechelper`` or just plain ``exec`` packages to run whatever else - #. Verify results of your tests using ``assert`` methods provided by the test suite, - implemented by HstSuite struct + #. Retrieve a running container in which to run some action. Method ``getContainerByName`` + from ``HstSuite`` struct serves this purpose + #. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI + #. Run arbitrary commands inside the containers with ``exec`` method + #. Run other external tool with one of the preexisting functions in the ``utils.go`` file. + For example, use ``wget`` with ``startWget`` function + #. Use ``exechelper`` or just plain ``exec`` packages to run whatever else + #. Verify results of your tests using ``assert`` methods provided by the test suite, implemented by HstSuite struct or use ``Gomega`` assert functions. + +#. Create an ``init()`` function and register the test using ``register*SuiteTests(testCaseFunction)`` + **Example test case** Assumed are two docker containers, each with its own VPP instance running. One VPP then pings the other. -This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./test -run TestMySuite/TestMyCase``. +This can be put in file ``extras/hs-test/my_test.go`` and run with command ``make test TEST=MyTest`` or ``ginkgo -v --trace --focus MyTest``. :: @@ -69,7 +75,11 @@ This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./t "fmt" ) - func (s *MySuite) TestMyCase() { + func init(){ + registerMySuiteTest(MyTest) + } + + func MyTest(s *MySuite) { clientVpp := s.getContainerByName("client-vpp").vppInstance serverVethAddress := s.netInterfaces["server-iface"].AddressString() @@ -86,8 +96,7 @@ Modifying the framework .. _test-convention: -#. Adding a new suite takes place in ``framework_test.go`` and by creating a new file for the suite. - Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced +#. To add a new suite, create a new file. Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced by the actual name #. Make a ``struct``, in the suite file, with at least ``HstSuite`` struct as its member. @@ -99,7 +108,17 @@ Modifying the framework HstSuite } -#. In suite file, implement ``SetupSuite`` method which testify runs once before starting any of the tests. +#. Create a new slice that will contain test functions with a pointer to the suite's struct: ``var myTests = []func(s *MySuite){}`` + +#. Then create a new function that will append test functions to that slice: + + :: + + func registerMySuiteTests(tests ...func(s *MySuite)) { + nginxTests = append(myTests, tests...) + } + +#. In suite file, implement ``SetupSuite`` method which Ginkgo runs once before starting any of the tests. It's important here to call ``configureNetworkTopology`` method, pass the topology name to the function in a form of file name of one of the *yaml* files in ``topo-network`` folder. Without the extension. In this example, *myTopology* corresponds to file ``extras/hs-test/topo-network/myTopology.yaml`` @@ -111,6 +130,8 @@ Modifying the framework :: func (s *MySuite) SetupSuite() { + s.HstSuite.SetupSuite() + // Add custom setup code here s.configureNetworkTopology("myTopology") @@ -123,19 +144,62 @@ Modifying the framework :: func (s *MySuite) SetupTest() { + s.HstSuite.setupTest() s.SetupVolumes() s.SetupContainers() } -#. In order for ``go test`` to run this suite, we need to create a normal test function and pass our suite to ``suite.Run``. - These functions are placed at the end of ``framework_test.go`` +#. In order for ``Ginkgo`` to run this suite, we need to create a ``Describe`` container node with setup nodes and an ``It`` subject node. + Place them at the end of the suite file + + * Declare a suite struct variable before anything else + * To use ``BeforeAll()`` and ``AfterAll()``, the container has to be marked as ``Ordered`` + * Because the container is now marked as Ordered, if a test fails, all the subsequent tests are skipped. + To override this behavior, decorate the container node with ``ContinueOnFailure`` :: - func TestMySuite(t *testing.T) { - var m MySuite - suite.Run(t, &m) - } + var _ = Describe("MySuite", Ordered, ContinueOnFailure, func() { + var s MySuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + for _, test := range mySuiteTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + test(&s) + }, SpecTimeout(time.Minute*5)) + } + }) + +#. Notice the loop - it will generate multiple ``It`` nodes, each running a different test. + ``test := test`` is necessary, otherwise only the last test in a suite will run. + For a more detailed description, check Ginkgo's documentation: https://onsi.github.io/ginkgo/#dynamically-generating-specs\. + +#. ``funcValue.Name()`` returns the full name of a function (e.g. ``fd.io/hs-test.MyTest``), however, we only need the test name (``MyTest``). + +#. To run certain tests solo, create a new slice that will only contain tests that have to run solo and a new register function. + Add a ``Serial`` decorator to the container node and ``Label("SOLO")`` to the ``It`` subject node: + + :: + + var _ = Describe("MySuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + ... + It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + test(&s) + }, SpecTimeout(time.Minute*5)) + }) #. Next step is to add test cases to the suite. For that, see section `Adding a test case`_ above @@ -186,14 +250,9 @@ Alternatively copy the executable from host system to the Docker image, similarl **Skipping tests** ``HstSuite`` provides several methods that can be called in tests for skipping it conditionally or unconditionally such as: -``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``. +``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``. You can also use Ginkgo's ``Skip()``. However the tests currently run under test suites which set up topology and containers before actual test is run. For the reason of saving -test run time it is not advisable to use aforementioned skip methods and instead prefix test name with ``Skip``: - -:: - - func (s *MySuite) SkipTest(){ - +test run time it is not advisable to use aforementioned skip methods and instead, just don't register the test. **Debugging a test** @@ -201,11 +260,11 @@ It is possible to debug VPP by attaching ``gdb`` before test execution by adding :: - $ make test TEST=TestVeths/TestLDPreloadIperfVpp DEBUG=true + $ make test TEST=LDPreloadIperfVppTest DEBUG=true ... run following command in different terminal: - docker exec -it server-vpp gdb -ex "attach $(docker exec server-vpp pidof vpp)" - Afterwards press CTRL+C to continue + docker exec -it server-vpp2456109 gdb -ex "attach $(docker exec server-vpp2456109 pidof vpp)" + Afterwards press CTRL+\ to continue If a test consists of more VPP instances then this is done for each of them. @@ -223,8 +282,38 @@ Generally, these will be updated on a per-need basis, for example when a bug is or a new version incompatibility issue occurs. -.. _testing: https://pkg.go.dev/testing -.. _go test: https://pkg.go.dev/cmd/go#hdr-Test_packages -.. _test suite: https://github.com/stretchr/testify#suite-package +.. _ginkgo: https://onsi.github.io/ginkgo/ .. _volumes: https://docs.docker.com/storage/volumes/ +**List of tests** + +.. _list of tests: + +Please update this list whenever you add a new test by pasting the output below. + +* NsSuite/HttpTpsTest +* NsSuite/VppProxyHttpTcpTest +* NsSuite/VppProxyHttpTlsTest +* NsSuite/EnvoyProxyHttpTcpTest +* NginxSuite/MirroringTest +* VethsSuiteSolo TcpWithLossTest [SOLO] +* NoTopoSuiteSolo HttpStaticPromTest [SOLO] +* TapSuite/LinuxIperfTest +* NoTopoSuite/NginxHttp3Test +* NoTopoSuite/NginxAsServerTest +* NoTopoSuite/NginxPerfCpsTest +* NoTopoSuite/NginxPerfRpsTest +* NoTopoSuite/NginxPerfWrkTest +* VethsSuite/EchoBuiltinTest +* VethsSuite/HttpCliTest +* VethsSuite/LDPreloadIperfVppTest +* VethsSuite/VppEchoQuicTest +* VethsSuite/VppEchoTcpTest +* VethsSuite/VppEchoUdpTest +* VethsSuite/XEchoVclClientUdpTest +* VethsSuite/XEchoVclClientTcpTest +* VethsSuite/XEchoVclServerUdpTest +* VethsSuite/XEchoVclServerTcpTest +* VethsSuite/VclEchoTcpTest +* VethsSuite/VclEchoUdpTest +* VethsSuite/VclRetryAttachTest diff --git a/extras/hs-test/address_allocator.go b/extras/hs-test/address_allocator.go index 72bc298fd3f..e05ea76b9bb 100644 --- a/extras/hs-test/address_allocator.go +++ b/extras/hs-test/address_allocator.go @@ -12,7 +12,7 @@ import ( type AddressCounter = int type Ip4AddressAllocator struct { - networks map[int]AddressCounter + networks map[int]AddressCounter chosenOctet int assignedIps []string } @@ -47,7 +47,7 @@ func (a *Ip4AddressAllocator) NewIp4InterfaceAddress(inputNetworkNumber ...int) // Creates a file every time an IP is assigned: used to keep track of addresses in use. // If an address is not in use, 'counter' is then copied to 'chosenOctet' and it is used for the remaining tests. // Also checks host IP addresses. -func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error){ +func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) { hostIps, _ := exechelper.CombinedOutput("ip a") counter := 10 var address string @@ -56,7 +56,7 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress if a.chosenOctet != 0 { address = fmt.Sprintf("10.%v.%v.%v", a.chosenOctet, networkNumber, numberOfAddresses) file, err := os.Create(address) - if err != nil{ + if err != nil { return "", errors.New("unable to create file: " + fmt.Sprint(err)) } file.Close() @@ -68,14 +68,14 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress counter++ } else if os.IsNotExist(err) { file, err := os.Create(address) - if err != nil{ + if err != nil { return "", errors.New("unable to create file: " + fmt.Sprint(err)) - } + } file.Close() a.chosenOctet = counter break } else { - return "", errors.New("an error occured while checking if a file exists: " + fmt.Sprint(err)) + return "", errors.New("an error occurred while checking if a file exists: " + fmt.Sprint(err)) } } } @@ -84,8 +84,8 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress return address, nil } -func (a *Ip4AddressAllocator) deleteIpAddresses(){ - for ip := range a.assignedIps{ +func (a *Ip4AddressAllocator) deleteIpAddresses() { + for ip := range a.assignedIps { os.Remove(a.assignedIps[ip]) } } diff --git a/extras/hs-test/container.go b/extras/hs-test/container.go index 87e8aa38e98..45f41d26a87 100644 --- a/extras/hs-test/container.go +++ b/extras/hs-test/container.go @@ -9,6 +9,7 @@ import ( "time" "github.com/edwarnicke/exechelper" + . "github.com/onsi/ginkgo/v2" ) const ( @@ -38,7 +39,7 @@ type Container struct { vppInstance *VppInstance } -func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Container, error) { +func newContainer(suite *HstSuite, yamlInput ContainerConfig) (*Container, error) { containerName := yamlInput["name"].(string) if len(containerName) == 0 { err := fmt.Errorf("container name must not be blank") @@ -48,7 +49,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont var container = new(Container) container.volumes = make(map[string]Volume) container.envVars = make(map[string]string) - container.name = containerName + pid + container.name = containerName container.suite = suite if image, ok := yamlInput["image"]; ok { @@ -76,7 +77,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont } if _, ok := yamlInput["volumes"]; ok { - workingVolumeDir := logDir + container.suite.T().Name() + pid + volumeDir + workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + volumeDir workDirReplacer := strings.NewReplacer("$HST_DIR", workDir) volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir) for _, volu := range yamlInput["volumes"].([]interface{}) { @@ -249,7 +250,7 @@ func (c *Container) copy(sourceFileName string, targetFileName string) error { } func (c *Container) createFile(destFileName string, content string) error { - f, err := os.CreateTemp("/tmp", "hst-config" + c.suite.pid) + f, err := os.CreateTemp("/tmp", "hst-config"+c.suite.pid) if err != nil { return err } @@ -273,7 +274,7 @@ func (c *Container) execServer(command string, arguments ...any) { serverCommand := fmt.Sprintf(command, arguments...) containerExecCommand := "docker exec -d" + c.getEnvVarsAsCliOption() + " " + c.name + " " + serverCommand - c.suite.T().Helper() + GinkgoHelper() c.suite.log(containerExecCommand) c.suite.assertNil(exechelper.Run(containerExecCommand)) } @@ -282,7 +283,7 @@ func (c *Container) exec(command string, arguments ...any) string { cliCommand := fmt.Sprintf(command, arguments...) containerExecCommand := "docker exec" + c.getEnvVarsAsCliOption() + " " + c.name + " " + cliCommand - c.suite.T().Helper() + GinkgoHelper() c.suite.log(containerExecCommand) byteOutput, err := exechelper.CombinedOutput(containerExecCommand) c.suite.assertNil(err, err) @@ -291,12 +292,12 @@ func (c *Container) exec(command string, arguments ...any) string { func (c *Container) getLogDirPath() string { testId := c.suite.getTestId() - testName := c.suite.T().Name() + testName := CurrentSpecReport().LeafNodeText logDirPath := logDir + testName + "/" + testId + "/" cmd := exec.Command("mkdir", "-p", logDirPath) if err := cmd.Run(); err != nil { - c.suite.T().Fatalf("mkdir error: %v", err) + Fail("mkdir error: " + fmt.Sprint(err)) } return logDirPath @@ -313,12 +314,12 @@ func (c *Container) saveLogs() { cmd = exec.Command("docker", "logs", "--details", "-t", c.name) output, err := cmd.CombinedOutput() if err != nil { - c.suite.T().Fatalf("fetching logs error: %v", err) + Fail("fetching logs error: " + fmt.Sprint(err)) } f, err := os.Create(testLogFilePath) if err != nil { - c.suite.T().Fatalf("file create error: %v", err) + Fail("file create error: " + fmt.Sprint(err)) } fmt.Fprint(f, string(output)) f.Close() diff --git a/extras/hs-test/cpu.go b/extras/hs-test/cpu.go index e17bc11fbe0..a976f47d8a5 100644 --- a/extras/hs-test/cpu.go +++ b/extras/hs-test/cpu.go @@ -2,11 +2,14 @@ package main import ( "bufio" + "errors" "fmt" "os" + "os/exec" + "strings" ) -var CPU_PATH = "/sys/fs/cgroup/cpuset.cpus.effective" +var CgroupPath = "/sys/fs/cgroup/" type CpuContext struct { cpuAllocator *CpuAllocatorT @@ -36,9 +39,27 @@ func (c *CpuAllocatorT) Allocate(nCpus int) (*CpuContext, error) { return &cpuCtx, nil } -func (c *CpuAllocatorT) readCpus(fname string) error { +func (c *CpuAllocatorT) readCpus() error { var first, last int - file, err := os.Open(CPU_PATH) + + // Path depends on cgroup version. We need to check which version is in use. + // For that following command can be used: 'stat -fc %T /sys/fs/cgroup/' + // In case the output states 'cgroup2fs' then cgroups v2 is used, 'tmpfs' in case cgroups v1. + cmd := exec.Command("stat", "-fc", "%T", "/sys/fs/cgroup/") + byteOutput, err := cmd.CombinedOutput() + if err != nil { + return err + } + CpuPath := CgroupPath + if strings.Contains(string(byteOutput), "tmpfs") { + CpuPath += "cpuset/cpuset.effective_cpus" + } else if strings.Contains(string(byteOutput), "cgroup2fs") { + CpuPath += "cpuset.cpus.effective" + } else { + return errors.New("cgroup unknown fs: " + string(byteOutput)) + } + + file, err := os.Open(CpuPath) if err != nil { return err } @@ -60,7 +81,7 @@ func (c *CpuAllocatorT) readCpus(fname string) error { func CpuAllocator() (*CpuAllocatorT, error) { if cpuAllocator == nil { cpuAllocator = new(CpuAllocatorT) - err := cpuAllocator.readCpus(CPU_PATH) + err := cpuAllocator.readCpus() if err != nil { return nil, err } diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp index 6b057581d4b..ace83c593c6 100644 --- a/extras/hs-test/docker/Dockerfile.vpp +++ b/extras/hs-test/docker/Dockerfile.vpp @@ -16,6 +16,8 @@ COPY \ $DIR/unittest_plugin.so \ $DIR/quic_plugin.so \ $DIR/http_static_plugin.so \ + $DIR/ping_plugin.so \ + $DIR/nsim_plugin.so \ $DIR/prom_plugin.so \ $DIR/tlsopenssl_plugin.so \ /usr/lib/x86_64-linux-gnu/vpp_plugins/ diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go index 690f6d1378e..0515b5e0411 100644 --- a/extras/hs-test/echo_test.go +++ b/extras/hs-test/echo_test.go @@ -1,6 +1,11 @@ package main -func (s *VethsSuite) TestEchoBuiltin() { +func init() { + registerVethTests(EchoBuiltinTest) + registerSoloVethTests(TcpWithLossTest) +} + +func EchoBuiltinTest(s *VethsSuite) { serverVpp := s.getContainerByName("server-vpp").vppInstance serverVeth := s.getInterfaceByName(serverInterfaceName) @@ -16,7 +21,7 @@ func (s *VethsSuite) TestEchoBuiltin() { s.assertNotContains(o, "failed:") } -func (s *VethsSuite) TestTcpWithLoss() { +func TcpWithLossTest(s *VethsSuite) { serverVpp := s.getContainerByName("server-vpp").vppInstance serverVeth := s.getInterfaceByName(serverInterfaceName) @@ -26,14 +31,14 @@ func (s *VethsSuite) TestTcpWithLoss() { clientVpp := s.getContainerByName("client-vpp").vppInstance // Ensure that VPP doesn't abort itself with NSIM enabled - // Warning: Removing this ping will make the test fail! + // Warning: Removing this ping will make VPP crash! clientVpp.vppctl("ping %s", serverVeth.ip4AddressString()) // Add loss of packets with Network Delay Simulator clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" + " packet-size 1400 packets-per-drop 1000") - clientVpp.vppctl("nsim output-feature enable-disable " + s.getInterfaceByName(clientInterfaceName).name) + clientVpp.vppctl("nsim output-feature enable-disable host-" + s.getInterfaceByName(clientInterfaceName).name) // Do echo test from client-vpp container output := clientVpp.vppctl("test echo client uri tcp://%s/20022 verbose echo-bytes mbytes 50", diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go index 84aa570e681..8773fa2417d 100644 --- a/extras/hs-test/framework_test.go +++ b/extras/hs-test/framework_test.go @@ -3,30 +3,11 @@ package main import ( "testing" - "github.com/stretchr/testify/suite" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" ) -func TestTapSuite(t *testing.T) { - var m TapSuite - suite.Run(t, &m) -} - -func TestNs(t *testing.T) { - var m NsSuite - suite.Run(t, &m) -} - -func TestVeths(t *testing.T) { - var m VethsSuite - suite.Run(t, &m) -} - -func TestNoTopo(t *testing.T) { - var m NoTopoSuite - suite.Run(t, &m) -} - -func TestNginx(t *testing.T) { - var m NginxSuite - suite.Run(t, &m) +func TestHst(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "HST") } diff --git a/extras/hs-test/go.mod b/extras/hs-test/go.mod index 00e1213079d..0f3854d2148 100644 --- a/extras/hs-test/go.mod +++ b/extras/hs-test/go.mod @@ -4,19 +4,28 @@ go 1.21 require ( github.com/edwarnicke/exechelper v1.0.3 - github.com/stretchr/testify v1.8.4 - go.fd.io/govpp v0.9.0 + go.fd.io/govpp v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-logr/logr v1.4.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.17.0 // indirect +) + +require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/kr/text v0.2.0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect + github.com/onsi/ginkgo/v2 v2.16.0 + github.com/onsi/gomega v1.32.0 github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/vishvananda/netns v0.0.4 // indirect golang.org/x/sys v0.16.0 // indirect diff --git a/extras/hs-test/go.sum b/extras/hs-test/go.sum index df596738622..479b0289814 100644 --- a/extras/hs-test/go.sum +++ b/extras/hs-test/go.sum @@ -1,3 +1,6 @@ +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -6,10 +9,17 @@ github.com/edwarnicke/exechelper v1.0.3 h1:OY2ocGAITTqnEDvZk0dRQSeMIQvyH0SyL/4nc github.com/edwarnicke/exechelper v1.0.3/go.mod h1:R65OUPKns4bgeHkCmfSHbmqLBU8aHZxTgLmEyUBUk4U= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= +github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -18,8 +28,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM= +github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= +github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -28,22 +40,27 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= -go.fd.io/govpp v0.9.0 h1:EHUXhQ+dph2K2An4YMqmd/WBE3Fcqsg97KVmdLJoSoU= -go.fd.io/govpp v0.9.0/go.mod h1:9QoqjEbvfuuXNfjHS0A7YS+7QQVVaQ9cMioOWpSM4rY= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +go.fd.io/govpp v0.10.0 h1:lL93SbqOILjON2pMvazrlHRekGYTRy0Qmj57RuAkxR0= +go.fd.io/govpp v0.10.0/go.mod h1:5m3bZM9ck+2EGC2O3ASmSSJAaoouyOlVWtiwj5BdCv0= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/extras/hs-test/hst_suite.go b/extras/hs-test/hst_suite.go index c5c8edbb829..725fee73f24 100644 --- a/extras/hs-test/hst_suite.go +++ b/extras/hs-test/hst_suite.go @@ -5,14 +5,16 @@ import ( "errors" "flag" "fmt" + "io" + "log" "os" "os/exec" "strings" "time" "github.com/edwarnicke/exechelper" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/suite" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" "gopkg.in/yaml.v3" ) @@ -28,7 +30,6 @@ var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp") var vppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory") type HstSuite struct { - suite.Suite containers map[string]*Container volumes []string netConfigs []NetConfig @@ -38,15 +39,23 @@ type HstSuite struct { cpuAllocator *CpuAllocatorT cpuContexts []*CpuContext cpuPerVpp int - pid string + pid string + logger *log.Logger + logFile *os.File } func (s *HstSuite) SetupSuite() { + s.createLogger() + s.log("Suite Setup") + RegisterFailHandler(func(message string, callerSkip ...int) { + s.hstFail() + Fail(message, callerSkip...) + }) var err error s.pid = fmt.Sprint(os.Getpid()) s.cpuAllocator, err = CpuAllocator() if err != nil { - s.FailNow("failed to init cpu allocator: %v", err) + Fail("failed to init cpu allocator: " + fmt.Sprint(err)) } s.cpuPerVpp = *nConfiguredCpus } @@ -63,10 +72,13 @@ func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) { } func (s *HstSuite) TearDownSuite() { + defer s.logFile.Close() + s.log("Suite Teardown") s.unconfigureNetworkTopology() } func (s *HstSuite) TearDownTest() { + s.log("Test Teardown") if *isPersistent { return } @@ -85,6 +97,7 @@ func (s *HstSuite) skipIfUnconfiguring() { } func (s *HstSuite) SetupTest() { + s.log("Test Setup") s.skipIfUnconfiguring() s.setupVolumes() s.setupContainers() @@ -106,15 +119,15 @@ func (s *HstSuite) setupContainers() { } } -func logVppInstance(container *Container, maxLines int){ - if container.vppInstance == nil{ +func (s *HstSuite) logVppInstance(container *Container, maxLines int) { + if container.vppInstance == nil { return } logSource := container.getHostWorkDir() + defaultLogFilePath file, err := os.Open(logSource) - if err != nil{ + if err != nil { return } defer file.Close() @@ -123,7 +136,7 @@ func logVppInstance(container *Container, maxLines int){ var lines []string var counter int - for scanner.Scan(){ + for scanner.Scan() { lines = append(lines, scanner.Text()) counter++ if counter > maxLines { @@ -132,82 +145,81 @@ func logVppInstance(container *Container, maxLines int){ } } - fmt.Println("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:") - for _, line := range lines{ - fmt.Println(line) + s.log("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:") + for _, line := range lines { + s.log(line) } - fmt.Printf("^^^^^^^^^^^^^^^\n\n") + s.log("^^^^^^^^^^^^^^^\n\n") } func (s *HstSuite) hstFail() { - fmt.Println("Containers: " + fmt.Sprint(s.containers)) - for _, container := range s.containers{ + s.log("Containers: " + fmt.Sprint(s.containers)) + for _, container := range s.containers { out, err := container.log(20) - if err != nil{ + if err != nil { fmt.Printf("An error occured while obtaining '%s' container logs: %s\n", container.name, fmt.Sprint(err)) - break + continue } - fmt.Printf("\nvvvvvvvvvvvvvvv " + - container.name + ":\n" + - out + - "^^^^^^^^^^^^^^^\n\n") - logVppInstance(container, 20) + s.log("\nvvvvvvvvvvvvvvv " + + container.name + ":\n" + + out + + "^^^^^^^^^^^^^^^\n\n") + s.logVppInstance(container, 20) } - s.T().FailNow() } func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) { - if !assert.Nil(s.T(), object, msgAndArgs...) { - s.hstFail() - } + Expect(object).To(BeNil(), msgAndArgs...) } func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) { - if !assert.NotNil(s.T(), object, msgAndArgs...) { - s.hstFail() - } + Expect(object).ToNot(BeNil(), msgAndArgs...) } func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) { - if !assert.Equal(s.T(), expected, actual, msgAndArgs...) { - s.hstFail() - } + Expect(actual).To(Equal(expected), msgAndArgs...) } func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) { - if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) { - s.hstFail() - } + Expect(actual).ToNot(Equal(expected), msgAndArgs...) } func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) { - if !assert.Contains(s.T(), testString, contains, msgAndArgs...) { - s.hstFail() - } + Expect(testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...) } func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) { - if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) { - s.hstFail() - } + Expect(testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...) } func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) { - if !assert.NotEmpty(s.T(), object, msgAndArgs...) { - s.hstFail() + Expect(object).ToNot(BeEmpty(), msgAndArgs...) +} + +func (s *HstSuite) createLogger(){ + suiteName := CurrentSpecReport().ContainerHierarchyTexts[0] + var err error + s.logFile, err = os.Create("summary/" + suiteName + ".log") + if err != nil { + Fail("Unable to create log file.") } + s.logger = log.New(io.Writer(s.logFile), "", log.LstdFlags) } -func (s *HstSuite) log(args ...any) { +// Logs to files by default, logs to stdout when VERBOSE=true with GinkgoWriter +// to keep console tidy +func (s *HstSuite) log(arg any) { + logs := strings.Split(fmt.Sprint(arg), "\n") + for _, line := range logs { + s.logger.Println(line) + } if *isVerbose { - s.T().Helper() - s.T().Log(args...) + GinkgoWriter.Println(arg) } } -func (s *HstSuite) skip(args ...any) { - s.log(args...) - s.T().SkipNow() +func (s *HstSuite) skip(args string) { + Skip(args) } func (s *HstSuite) SkipIfMultiWorker(args ...any) { @@ -249,11 +261,11 @@ func (s *HstSuite) getNetNamespaceByName(name string) string { } func (s *HstSuite) getInterfaceByName(name string) *NetInterface { - return s.netInterfaces[name + s.pid] + return s.netInterfaces[name+s.pid] } func (s *HstSuite) getContainerByName(name string) *Container { - return s.containers[name + s.pid] + return s.containers[name+s.pid] } /* @@ -261,25 +273,25 @@ func (s *HstSuite) getContainerByName(name string) *Container { * are not able to modify the original container and affect other tests by doing that */ func (s *HstSuite) getTransientContainerByName(name string) *Container { - containerCopy := *s.containers[name + s.pid] + containerCopy := *s.containers[name+s.pid] return &containerCopy } func (s *HstSuite) loadContainerTopology(topologyName string) { data, err := os.ReadFile(containerTopologyDir + topologyName + ".yaml") if err != nil { - s.T().Fatalf("read error: %v", err) + Fail("read error: " + fmt.Sprint(err)) } var yamlTopo YamlTopology err = yaml.Unmarshal(data, &yamlTopo) if err != nil { - s.T().Fatalf("unmarshal error: %v", err) + Fail("unmarshal error: " + fmt.Sprint(err)) } for _, elem := range yamlTopo.Volumes { volumeMap := elem["volume"].(VolumeConfig) hostDir := volumeMap["host-dir"].(string) - workingVolumeDir := logDir + s.T().Name() + s.pid + volumeDir + workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + volumeDir volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir) hostDir = volDirReplacer.Replace(hostDir) s.volumes = append(s.volumes, hostDir) @@ -287,10 +299,11 @@ func (s *HstSuite) loadContainerTopology(topologyName string) { s.containers = make(map[string]*Container) for _, elem := range yamlTopo.Containers { - newContainer, err := newContainer(s, elem, s.pid) + newContainer, err := newContainer(s, elem) newContainer.suite = s + newContainer.name += newContainer.suite.pid if err != nil { - s.T().Fatalf("container config error: %v", err) + Fail("container config error: " + fmt.Sprint(err)) } s.containers[newContainer.name] = newContainer } @@ -299,12 +312,12 @@ func (s *HstSuite) loadContainerTopology(topologyName string) { func (s *HstSuite) loadNetworkTopology(topologyName string) { data, err := os.ReadFile(networkTopologyDir + topologyName + ".yaml") if err != nil { - s.T().Fatalf("read error: %v", err) + Fail("read error: " + fmt.Sprint(err)) } var yamlTopo YamlTopology err = yaml.Unmarshal(data, &yamlTopo) if err != nil { - s.T().Fatalf("unmarshal error: %v", err) + Fail("unmarshal error: " + fmt.Sprint(err)) } s.ip4AddrAllocator = NewIp4AddressAllocator() @@ -316,10 +329,10 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) { } if peer, ok := elem["peer"].(NetDevConfig); ok { - if peer["name"].(string) != ""{ + if peer["name"].(string) != "" { peer["name"] = peer["name"].(string) + s.pid } - if _, ok := peer["netns"]; ok{ + if _, ok := peer["netns"]; ok { peer["netns"] = peer["netns"].(string) + s.pid } } @@ -341,7 +354,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) { if namespace, err := newNetNamespace(elem); err == nil { s.netConfigs = append(s.netConfigs, &namespace) } else { - s.T().Fatalf("network config error: %v", err) + Fail("network config error: " + fmt.Sprint(err)) } } case Veth, Tap: @@ -350,7 +363,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) { s.netConfigs = append(s.netConfigs, netIf) s.netInterfaces[netIf.Name()] = netIf } else { - s.T().Fatalf("network config error: %v", err) + Fail("network config error: " + fmt.Sprint(err)) } } case Bridge: @@ -358,7 +371,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) { if bridge, err := newBridge(elem); err == nil { s.netConfigs = append(s.netConfigs, &bridge) } else { - s.T().Fatalf("network config error: %v", err) + Fail("network config error: " + fmt.Sprint(err)) } } } @@ -374,7 +387,7 @@ func (s *HstSuite) configureNetworkTopology(topologyName string) { for _, nc := range s.netConfigs { if err := nc.configure(); err != nil { - s.T().Fatalf("network config error: %v", err) + Fail("Network config error: " + fmt.Sprint(err)) } } } @@ -389,7 +402,7 @@ func (s *HstSuite) unconfigureNetworkTopology() { } func (s *HstSuite) getTestId() string { - testName := s.T().Name() + testName := CurrentSpecReport().LeafNodeText if s.testIds == nil { s.testIds = map[string]string{} diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 943c8a591d4..f52d2816930 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -2,11 +2,25 @@ package main import ( "fmt" + "net/http" "os" "strings" + "time" + + . "github.com/onsi/ginkgo/v2" ) -func (s *NsSuite) TestHttpTps() { +func init() { + registerNsTests(HttpTpsTest) + registerVethTests(HttpCliTest, HttpCliConnectErrorTest) + registerNoTopoTests(NginxHttp3Test, NginxAsServerTest, + NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, HeaderServerTest, + HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest, + HttpCliBadRequestTest) + registerNoTopoSoloTests(HttpStaticPromTest) +} + +func HttpTpsTest(s *NsSuite) { iface := s.getInterfaceByName(clientInterface) client_ip := iface.ip4AddressString() port := "8080" @@ -18,13 +32,16 @@ func (s *NsSuite) TestHttpTps() { // configure vpp in the container container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080") - go s.startWget(finished, client_ip, port, "test_file_10M", clientNetns) + go func() { + defer GinkgoRecover() + s.startWget(finished, client_ip, port, "test_file_10M", clientNetns) + }() // wait for client err := <-finished - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) } -func (s *VethsSuite) TestHttpCli() { +func HttpCliTest(s *VethsSuite) { serverContainer := s.getContainerByName("server-vpp") clientContainer := s.getContainerByName("client-vpp") @@ -35,13 +52,27 @@ func (s *VethsSuite) TestHttpCli() { uri := "http://" + serverVeth.ip4AddressString() + "/80" o := clientContainer.vppInstance.vppctl("http cli client" + - " uri " + uri + " query /show/version") + " uri " + uri + " query /show/vlib/graph") s.log(o) s.assertContains(o, "<html>", "<html> not found in the result!") } -func (s *NoTopoSuite) TestNginxHttp3() { +func HttpCliConnectErrorTest(s *VethsSuite) { + clientContainer := s.getContainerByName("client-vpp") + + serverVeth := s.getInterfaceByName(serverInterfaceName) + + uri := "http://" + serverVeth.ip4AddressString() + "/80" + + o := clientContainer.vppInstance.vppctl("http cli client" + + " uri " + uri + " query /show/vlib/graph") + + s.log(o) + s.assertContains(o, "failed to connect") +} + +func NginxHttp3Test(s *NoTopoSuite) { s.SkipUnlessExtendedTestsBuilt() query := "index.html" @@ -57,23 +88,102 @@ func (s *NoTopoSuite) TestNginxHttp3() { args := fmt.Sprintf("curl --noproxy '*' --local-port 55444 --http3-only -k https://%s:8443/%s", serverAddress, query) curlCont.extraRunningArgs = args o, err := curlCont.combinedOutput() - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.assertContains(o, "<http>", "<http> not found in the result!") } -func (s *NoTopoSuite) TestHttpStaticProm() { +func HttpStaticPromTest(s *NoTopoSuite) { finished := make(chan error, 1) query := "stats.prom" vpp := s.getContainerByName("vpp").vppInstance serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() s.log(vpp.vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers")) s.log(vpp.vppctl("prom enable")) - go s.startWget(finished, serverAddress, "80", query, "") + time.Sleep(time.Second * 5) + go func() { + defer GinkgoRecover() + s.startWget(finished, serverAddress, "80", query, "") + }() err := <-finished - s.assertNil(err, err) + s.assertNil(err) +} + +func HttpStaticMovedTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + vpp.container.exec("mkdir -p /tmp/tmp.aaa") + vpp.container.createFile("/tmp/tmp.aaa/index.html", "<http><body><p>Hello</p></body></http>") + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + s.log(vpp.vppctl("http static server www-root /tmp uri tcp://" + serverAddress + "/80 debug")) + + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/tmp.aaa", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := client.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(301, resp.StatusCode) + s.assertNotEqual("", resp.Header.Get("Location")) +} + +func HttpStaticNotFoundTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + s.log(vpp.vppctl("http static server www-root /tmp uri tcp://" + serverAddress + "/80 debug")) + + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/notfound.html", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := http.DefaultClient.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(404, resp.StatusCode) +} + +func HttpCliMethodNotAllowedTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + vpp.vppctl("http cli server") + + req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := http.DefaultClient.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(405, resp.StatusCode) + // TODO: need to be fixed in http code + //s.assertNotEqual("", resp.Header.Get("Allow")) +} + +func HttpCliBadRequestTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + vpp.vppctl("http cli server") + + req, err := http.NewRequest("GET", "http://"+serverAddress+":80", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := http.DefaultClient.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(400, resp.StatusCode) +} + +func HeaderServerTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + vpp.vppctl("http cli server") + + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/show/version", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := http.DefaultClient.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual("http_cli_server", resp.Header.Get("Server")) } -func (s *NoTopoSuite) TestNginxAsServer() { +func NginxAsServerTest(s *NoTopoSuite) { query := "return_ok" finished := make(chan error, 1) @@ -86,7 +196,10 @@ func (s *NoTopoSuite) TestNginxAsServer() { serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() defer func() { os.Remove(query) }() - go s.startWget(finished, serverAddress, "80", query, "") + go func() { + defer GinkgoRecover() + s.startWget(finished, serverAddress, "80", query, "") + }() s.assertNil(<-finished) } @@ -124,9 +237,11 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { args += " -r" args += " http://" + serverAddress + ":80/64B.json" abCont.extraRunningArgs = args + time.Sleep(time.Second * 10) o, err := abCont.combinedOutput() rps := parseString(o, "Requests per second:") - s.log(rps, err) + s.log(rps) + s.log(err) s.assertNil(err, "err: '%s', output: '%s'", err, o) } else { wrkCont := s.getContainerByName("wrk") @@ -135,20 +250,21 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { wrkCont.extraRunningArgs = args o, err := wrkCont.combinedOutput() rps := parseString(o, "requests") - s.log(rps, err) + s.log(rps) + s.log(err) s.assertNil(err, "err: '%s', output: '%s'", err, o) } return nil } -func (s *NoTopoSuite) TestNginxPerfCps() { +func NginxPerfCpsTest(s *NoTopoSuite) { s.assertNil(runNginxPerf(s, "cps", "ab")) } -func (s *NoTopoSuite) TestNginxPerfRps() { +func NginxPerfRpsTest(s *NoTopoSuite) { s.assertNil(runNginxPerf(s, "rps", "ab")) } -func (s *NoTopoSuite) TestNginxPerfWrk() { +func NginxPerfWrkTest(s *NoTopoSuite) { s.assertNil(runNginxPerf(s, "", "wrk")) } diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go index 8d9168d3d5d..24d2de39485 100644 --- a/extras/hs-test/ldp_test.go +++ b/extras/hs-test/ldp_test.go @@ -3,9 +3,15 @@ package main import ( "fmt" "os" + + . "github.com/onsi/ginkgo/v2" ) -func (s *VethsSuite) TestLDPreloadIperfVpp() { +func init() { + registerVethTests(LDPreloadIperfVppTest) +} + +func LDPreloadIperfVppTest(s *VethsSuite) { var clnVclConf, srvVclConf Stanza serverContainer := s.getContainerByName("server-vpp") @@ -14,10 +20,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() { clientContainer := s.getContainerByName("client-vpp") clientVclFileName := clientContainer.getHostWorkDir() + "/vcl_cln.conf" - ldpreload := os.Getenv("HST_LDPRELOAD") - s.assertNotEqual("", ldpreload) - - ldpreload = "LD_PRELOAD=" + ldpreload + ldpreload := "LD_PRELOAD=../../build-root/build-vpp-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so" stopServerCh := make(chan struct{}, 1) srvCh := make(chan error, 1) @@ -36,7 +39,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() { append("use-mq-eventfd"). append(clientAppSocketApi).close(). saveToFile(clientVclFileName) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", serverContainer.getHostWorkDir()) @@ -49,26 +52,32 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() { append("use-mq-eventfd"). append(serverAppSocketApi).close(). saveToFile(serverVclFileName) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.log("attaching server to vpp") srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+serverVclFileName) - go s.startServerApp(srvCh, stopServerCh, srvEnv) + go func() { + defer GinkgoRecover() + s.startServerApp(srvCh, stopServerCh, srvEnv) + }() err = <-srvCh - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.log("attaching client to vpp") var clnRes = make(chan string, 1) clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName) serverVethAddress := s.getInterfaceByName(serverInterfaceName).ip4AddressString() - go s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes) + go func() { + defer GinkgoRecover() + s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes) + }() s.log(<-clnRes) // wait for client's result err = <-clnCh - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) // stop server stopServerCh <- struct{}{} diff --git a/extras/hs-test/linux_iperf_test.go b/extras/hs-test/linux_iperf_test.go index 06247e45240..e323f7fb721 100644 --- a/extras/hs-test/linux_iperf_test.go +++ b/extras/hs-test/linux_iperf_test.go @@ -1,6 +1,16 @@ package main -func (s *TapSuite) TestLinuxIperf() { +import ( + "fmt" + + . "github.com/onsi/ginkgo/v2" +) + +func init() { + registerTapTests(LinuxIperfTest) +} + +func LinuxIperfTest(s *TapSuite) { clnCh := make(chan error) stopServerCh := make(chan struct{}) srvCh := make(chan error, 1) @@ -9,13 +19,19 @@ func (s *TapSuite) TestLinuxIperf() { stopServerCh <- struct{}{} }() - go s.startServerApp(srvCh, stopServerCh, nil) + go func() { + defer GinkgoRecover() + s.startServerApp(srvCh, stopServerCh, nil) + }() err := <-srvCh - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.log("server running") ipAddress := s.getInterfaceByName(tapInterfaceName).ip4AddressString() - go s.startClientApp(ipAddress, nil, clnCh, clnRes) + go func() { + defer GinkgoRecover() + s.startClientApp(ipAddress, nil, clnCh, clnRes) + }() s.log("client running") s.log(<-clnRes) err = <-clnCh diff --git a/extras/hs-test/mirroring_test.go b/extras/hs-test/mirroring_test.go index 91f43f45682..6c5a860b01c 100644 --- a/extras/hs-test/mirroring_test.go +++ b/extras/hs-test/mirroring_test.go @@ -4,7 +4,11 @@ import ( "github.com/edwarnicke/exechelper" ) -func (s *NginxSuite) TestMirroring() { +func init() { + registerNginxTests(MirroringTest) +} + +func MirroringTest(s *NginxSuite) { proxyAddress := s.getInterfaceByName(mirroringClientInterfaceName).peer.ip4AddressString() path := "/64B.json" diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go index c2f9b6f2825..ac5f94c8535 100644 --- a/extras/hs-test/proxy_test.go +++ b/extras/hs-test/proxy_test.go @@ -5,8 +5,13 @@ import ( "os" "github.com/edwarnicke/exechelper" + . "github.com/onsi/ginkgo/v2" ) +func init() { + registerNsTests(VppProxyHttpTcpTest, VppProxyHttpTlsTest, EnvoyProxyHttpTcpTest) +} + func testProxyHttpTcp(s *NsSuite, proto string) error { var outputFile string = "test" + s.pid + ".data" var srcFilePid string = "httpTestFile" + s.pid @@ -19,12 +24,15 @@ func testProxyHttpTcp(s *NsSuite, proto string) error { // create test file err := exechelper.Run(fmt.Sprintf("ip netns exec %s truncate -s %s %s", serverNetns, fileSize, srcFilePid)) - s.assertNil(err, "failed to run truncate command: " + fmt.Sprint(err)) + s.assertNil(err, "failed to run truncate command: "+fmt.Sprint(err)) defer func() { os.Remove(srcFilePid) }() s.log("test file created...") - go s.startHttpServer(serverRunning, stopServer, ":666", serverNetns) + go func() { + defer GinkgoRecover() + s.startHttpServer(serverRunning, stopServer, ":666", serverNetns) + }() // TODO better error handling and recovery <-serverRunning @@ -64,21 +72,21 @@ func configureVppProxy(s *NsSuite, proto string) { clientVeth.ip4AddressString(), serverVeth.peer.ip4AddressString(), ) - s.log("proxy configured...", output) + s.log("proxy configured: " + output) } -func (s *NsSuite) TestVppProxyHttpTcp() { +func VppProxyHttpTcpTest(s *NsSuite) { proto := "tcp" configureVppProxy(s, proto) err := testProxyHttpTcp(s, proto) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) } -func (s *NsSuite) TestVppProxyHttpTls() { +func VppProxyHttpTlsTest(s *NsSuite) { proto := "tls" configureVppProxy(s, proto) err := testProxyHttpTcp(s, proto) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) } func configureEnvoyProxy(s *NsSuite) { @@ -100,8 +108,8 @@ func configureEnvoyProxy(s *NsSuite) { s.assertNil(envoyContainer.start()) } -func (s *NsSuite) TestEnvoyProxyHttpTcp() { +func EnvoyProxyHttpTcpTest(s *NsSuite) { configureEnvoyProxy(s) err := testProxyHttpTcp(s, "tcp") - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) } diff --git a/extras/hs-test/raw_session_test.go b/extras/hs-test/raw_session_test.go index 670ed582522..5c66df0b1ce 100644 --- a/extras/hs-test/raw_session_test.go +++ b/extras/hs-test/raw_session_test.go @@ -1,15 +1,19 @@ package main -func (s *VethsSuite) TestVppEchoQuic() { +func init() { + registerVethTests(VppEchoQuicTest, VppEchoTcpTest) +} + +func VppEchoQuicTest(s *VethsSuite) { s.testVppEcho("quic") } -// udp echo currently broken in vpp, skipping -func (s *VethsSuite) SkipTestVppEchoUdp() { +// TODO: udp echo currently broken in vpp +func VppEchoUdpTest(s *VethsSuite) { s.testVppEcho("udp") } -func (s *VethsSuite) TestVppEchoTcp() { +func VppEchoTcpTest(s *VethsSuite) { s.testVppEcho("tcp") } diff --git a/extras/hs-test/script/compress.sh b/extras/hs-test/script/compress.sh new file mode 100644 index 00000000000..92a2fbd6789 --- /dev/null +++ b/extras/hs-test/script/compress.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +if [ "${COMPRESS_FAILED_TEST_LOGS}" == "yes" -a -s "${HS_SUMMARY}/failed-summary.log" ] +then + echo -n "Copying docker logs..." + dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText' ${HS_SUMMARY}/report.json) + for dirName in $dirs; do + logDir=/tmp/hs-test/$dirName + if [ -d "$logDir" ]; then + mkdir -p $WORKSPACE/archives/summary + cp -r $logDir $WORKSPACE/archives/summary/ + fi + done + echo "Done." + + if [ -n "$WORKSPACE" ] + then + echo -n "Copying failed test logs into build log archive directory ($WORKSPACE/archives)... " + mkdir -p $WORKSPACE/archives/summary + cp -a ${HS_SUMMARY}/* $WORKSPACE/archives/summary + echo "Done." + fi + + echo -n "Compressing files in $WORKSPACE/archives from test runs... " + cd $WORKSPACE/archives + find . -type f \( -name "*.json" -o -name "*.log" \) -exec gzip {} \; + echo "Done." + +else + echo "Not compressing files in temporary directories from test runs." + exit 0 +fi + +exit 1
\ No newline at end of file diff --git a/extras/hs-test/suite_nginx_test.go b/extras/hs-test/suite_nginx_test.go index 8f40590d1f2..c559496e71b 100644 --- a/extras/hs-test/suite_nginx_test.go +++ b/extras/hs-test/suite_nginx_test.go @@ -1,18 +1,37 @@ package main +import ( + "reflect" + "runtime" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" +) + // These correspond to names used in yaml config const ( - vppProxyContainerName = "vpp-proxy" - nginxProxyContainerName = "nginx-proxy" - nginxServerContainerName = "nginx-server" + vppProxyContainerName = "vpp-proxy" + nginxProxyContainerName = "nginx-proxy" + nginxServerContainerName = "nginx-server" mirroringClientInterfaceName = "hstcln" mirroringServerInterfaceName = "hstsrv" ) +var nginxTests = []func(s *NginxSuite){} +var nginxSoloTests = []func(s *NginxSuite){} + type NginxSuite struct { HstSuite } +func registerNginxTests(tests ...func(s *NginxSuite)) { + nginxTests = append(nginxTests, tests...) +} +func registerNginxSoloTests(tests ...func(s *NginxSuite)) { + nginxSoloTests = append(nginxSoloTests, tests...) +} + func (s *NginxSuite) SetupSuite() { s.HstSuite.SetupSuite() s.loadNetworkTopology("2taps") @@ -60,3 +79,56 @@ func (s *NginxSuite) SetupTest() { proxyVpp.waitForApp("nginx-", 5) } + +var _ = Describe("NginxSuite", Ordered, ContinueOnFailure, func() { + var s NginxSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + for _, test := range nginxTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) + +var _ = Describe("NginxSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s NginxSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range nginxSoloTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) diff --git a/extras/hs-test/suite_no_topo_test.go b/extras/hs-test/suite_no_topo_test.go index bbf0cfda685..625dca9f3cf 100644 --- a/extras/hs-test/suite_no_topo_test.go +++ b/extras/hs-test/suite_no_topo_test.go @@ -1,15 +1,34 @@ package main +import ( + "reflect" + "runtime" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" +) + const ( - singleTopoContainerVpp = "vpp" - singleTopoContainerNginx = "nginx" - tapInterfaceName = "htaphost" + singleTopoContainerVpp = "vpp" + singleTopoContainerNginx = "nginx" + tapInterfaceName = "htaphost" ) +var noTopoTests = []func(s *NoTopoSuite){} +var noTopoSoloTests = []func(s *NoTopoSuite){} + type NoTopoSuite struct { HstSuite } +func registerNoTopoTests(tests ...func(s *NoTopoSuite)) { + noTopoTests = append(noTopoTests, tests...) +} +func registerNoTopoSoloTests(tests ...func(s *NoTopoSuite)) { + noTopoSoloTests = append(noTopoSoloTests, tests...) +} + func (s *NoTopoSuite) SetupSuite() { s.HstSuite.SetupSuite() s.loadNetworkTopology("tap") @@ -35,3 +54,57 @@ func (s *NoTopoSuite) SetupTest() { s.assertNil(vpp.createTap(tapInterface), "failed to create tap interface") } + +var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() { + var s NoTopoSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range noTopoTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) + +var _ = Describe("NoTopoSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s NoTopoSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range noTopoSoloTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) diff --git a/extras/hs-test/suite_ns_test.go b/extras/hs-test/suite_ns_test.go index 46d5bef92ad..85b90911c2f 100644 --- a/extras/hs-test/suite_ns_test.go +++ b/extras/hs-test/suite_ns_test.go @@ -1,15 +1,35 @@ package main +import ( + "fmt" + "reflect" + "runtime" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" +) + // These correspond to names used in yaml config const ( clientInterface = "hclnvpp" serverInterface = "hsrvvpp" ) +var nsTests = []func(s *NsSuite){} +var nsSoloTests = []func(s *NsSuite){} + type NsSuite struct { HstSuite } +func registerNsTests(tests ...func(s *NsSuite)) { + nsTests = append(nsTests, tests...) +} +func registerNsSoloTests(tests ...func(s *NsSuite)) { + nsSoloTests = append(nsSoloTests, tests...) +} + func (s *NsSuite) SetupSuite() { s.HstSuite.SetupSuite() s.configureNetworkTopology("ns") @@ -34,12 +54,66 @@ func (s *NsSuite) SetupTest() { s.assertNil(vpp.start()) idx, err := vpp.createAfPacket(s.getInterfaceByName(serverInterface)) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.assertNotEqual(0, idx) idx, err = vpp.createAfPacket(s.getInterfaceByName(clientInterface)) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.assertNotEqual(0, idx) container.exec("chmod 777 -R %s", container.getContainerWorkDir()) } + +var _ = Describe("NsSuite", Ordered, ContinueOnFailure, func() { + var s NsSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range nsTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) + +var _ = Describe("NsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s NsSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range nsSoloTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) diff --git a/extras/hs-test/suite_tap_test.go b/extras/hs-test/suite_tap_test.go index 8b0950a797e..ebf0f9b3cbc 100644 --- a/extras/hs-test/suite_tap_test.go +++ b/extras/hs-test/suite_tap_test.go @@ -1,15 +1,84 @@ package main import ( + "reflect" + "runtime" + "strings" "time" + + . "github.com/onsi/ginkgo/v2" ) type TapSuite struct { HstSuite } +var tapTests = []func(s *TapSuite){} +var tapSoloTests = []func(s *TapSuite){} + +func registerTapTests(tests ...func(s *TapSuite)) { + tapTests = append(tapTests, tests...) +} +func registerTapSoloTests(tests ...func(s *TapSuite)) { + tapSoloTests = append(tapSoloTests, tests...) +} + func (s *TapSuite) SetupSuite() { time.Sleep(1 * time.Second) s.HstSuite.SetupSuite() s.configureNetworkTopology("tap") } + +var _ = Describe("TapSuite", Ordered, ContinueOnFailure, func() { + var s TapSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range tapTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) + +var _ = Describe("TapSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s TapSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + for _, test := range tapSoloTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) diff --git a/extras/hs-test/suite_veth_test.go b/extras/hs-test/suite_veth_test.go index 061eee07d1f..d47bf8c52a9 100644 --- a/extras/hs-test/suite_veth_test.go +++ b/extras/hs-test/suite_veth_test.go @@ -1,7 +1,13 @@ package main import ( + "fmt" + "reflect" + "runtime" + "strings" "time" + + . "github.com/onsi/ginkgo/v2" ) // These correspond to names used in yaml config @@ -10,10 +16,20 @@ const ( clientInterfaceName = "cln" ) +var vethTests = []func(s *VethsSuite){} +var vethSoloTests = []func(s *VethsSuite){} + type VethsSuite struct { HstSuite } +func registerVethTests(tests ...func(s *VethsSuite)) { + vethTests = append(vethTests, tests...) +} +func registerSoloVethTests(tests ...func(s *VethsSuite)) { + vethSoloTests = append(vethSoloTests, tests...) +} + func (s *VethsSuite) SetupSuite() { time.Sleep(1 * time.Second) s.HstSuite.SetupSuite() @@ -36,7 +52,7 @@ func (s *VethsSuite) SetupTest() { cpus := s.AllocateCpus() serverVpp, err := serverContainer.newVppInstance(cpus, sessionConfig) - s.assertNotNil(serverVpp, err) + s.assertNotNil(serverVpp, fmt.Sprint(err)) s.setupServerVpp() @@ -45,7 +61,7 @@ func (s *VethsSuite) SetupTest() { cpus = s.AllocateCpus() clientVpp, err := clientContainer.newVppInstance(cpus, sessionConfig) - s.assertNotNil(clientVpp, err) + s.assertNotNil(clientVpp, fmt.Sprint(err)) s.setupClientVpp() } @@ -56,7 +72,7 @@ func (s *VethsSuite) setupServerVpp() { serverVeth := s.getInterfaceByName(serverInterfaceName) idx, err := serverVpp.createAfPacket(serverVeth) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.assertNotEqual(0, idx) } @@ -66,6 +82,63 @@ func (s *VethsSuite) setupClientVpp() { clientVeth := s.getInterfaceByName(clientInterfaceName) idx, err := clientVpp.createAfPacket(clientVeth) - s.assertNil(err, err) + s.assertNil(err, fmt.Sprint(err)) s.assertNotEqual(0, idx) } + +var _ = Describe("VethsSuite", Ordered, ContinueOnFailure, func() { + var s VethsSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + + }) + AfterEach(func() { + s.TearDownTest() + }) + + // https://onsi.github.io/ginkgo/#dynamically-generating-specs + for _, test := range vethTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) + +var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { + var s VethsSuite + BeforeAll(func() { + s.SetupSuite() + }) + BeforeEach(func() { + s.SetupTest() + }) + AfterAll(func() { + s.TearDownSuite() + }) + AfterEach(func() { + s.TearDownTest() + }) + + // https://onsi.github.io/ginkgo/#dynamically-generating-specs + for _, test := range vethSoloTests { + test := test + pc := reflect.ValueOf(test).Pointer() + funcValue := runtime.FuncForPC(pc) + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") + test(&s) + }, SpecTimeout(time.Minute*5)) + } +}) diff --git a/extras/hs-test/test b/extras/hs-test/test index c3b9eaef145..fd17feb2c50 100755 --- a/extras/hs-test/test +++ b/extras/hs-test/test @@ -8,6 +8,8 @@ persist_set=0 unconfigure_set=0 debug_set=0 vppsrc= +ginkgo_args= +parallel= for i in "$@" do @@ -49,8 +51,18 @@ case "${i}" in tc_name="${i#*=}" if [ $tc_name != "all" ]; then single_test=1 - args="$args -run $tc_name -verbose" + ginkgo_args="$ginkgo_args --focus $tc_name -vv" + args="$args -verbose" + else + ginkgo_args="$ginkgo_args -v" fi + ;; + --parallel=*) + ginkgo_args="$ginkgo_args -procs=${i#*=}" + ;; + --repeat=*) + ginkgo_args="$ginkgo_args --repeat=${i#*=}" + ;; esac done @@ -74,4 +86,6 @@ if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then exit 1 fi -sudo -E go test -timeout=20m -buildvcs=false -v $args +mkdir -p summary + +sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --no-color --trace --json-report=summary/report.json $ginkgo_args -- $args diff --git a/extras/hs-test/vcl_test.go b/extras/hs-test/vcl_test.go index cb6aaa4adc0..fdcd60ad503 100644 --- a/extras/hs-test/vcl_test.go +++ b/extras/hs-test/vcl_test.go @@ -5,6 +5,11 @@ import ( "time" ) +func init() { + registerVethTests(XEchoVclClientUdpTest, XEchoVclClientTcpTest, XEchoVclServerUdpTest, + XEchoVclServerTcpTest, VclEchoTcpTest, VclEchoUdpTest, VclRetryAttachTest) +} + func getVclConfig(c *Container, ns_id_optional ...string) string { var s Stanza ns_id := "default" @@ -23,11 +28,11 @@ func getVclConfig(c *Container, ns_id_optional ...string) string { return s.close().toString() } -func (s *VethsSuite) TestXEchoVclClientUdp() { +func XEchoVclClientUdpTest(s *VethsSuite) { s.testXEchoVclClient("udp") } -func (s *VethsSuite) TestXEchoVclClientTcp() { +func XEchoVclClientTcpTest(s *VethsSuite) { s.testXEchoVclClient("tcp") } @@ -49,11 +54,11 @@ func (s *VethsSuite) testXEchoVclClient(proto string) { s.assertContains(o, "CLIENT RESULTS") } -func (s *VethsSuite) TestXEchoVclServerUdp() { +func XEchoVclServerUdpTest(s *VethsSuite) { s.testXEchoVclServer("udp") } -func (s *VethsSuite) TestXEchoVclServerTcp() { +func XEchoVclServerTcpTest(s *VethsSuite) { s.testXEchoVclServer("tcp") } @@ -97,16 +102,15 @@ func (s *VethsSuite) testVclEcho(proto string) { s.log(o) } -func (s *VethsSuite) TestVclEchoTcp() { +func VclEchoTcpTest(s *VethsSuite) { s.testVclEcho("tcp") } -func (s *VethsSuite) TestVclEchoUdp() { +func VclEchoUdpTest(s *VethsSuite) { s.testVclEcho("udp") } -// this test takes too long, for now it's being skipped -func (s *VethsSuite) SkipTestVclRetryAttach() { +func VclRetryAttachTest(s *VethsSuite) { s.testRetryAttach("tcp") } diff --git a/extras/hs-test/vppinstance.go b/extras/hs-test/vppinstance.go index 1a058c8e0e3..9b400cfcb77 100644 --- a/extras/hs-test/vppinstance.go +++ b/extras/hs-test/vppinstance.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io" "os" "os/exec" "os/signal" @@ -10,7 +11,9 @@ import ( "syscall" "time" + "github.com/sirupsen/logrus" "github.com/edwarnicke/exechelper" + . "github.com/onsi/ginkgo/v2" "go.fd.io/govpp" "go.fd.io/govpp/api" @@ -59,6 +62,8 @@ plugins { plugin http_static_plugin.so { enable } plugin prom_plugin.so { enable } plugin tlsopenssl_plugin.so { enable } + plugin ping_plugin.so { enable } + plugin nsim_plugin.so { enable } } logging { @@ -103,6 +108,10 @@ func (vpp *VppInstance) getEtcDir() string { } func (vpp *VppInstance) start() error { + // Replace default logger in govpp with our own + govppLogger := logrus.New() + govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().logger.Writer(), GinkgoWriter)) + core.SetLogger(govppLogger) // Create folders containerWorkDir := vpp.container.getContainerWorkDir() @@ -131,9 +140,10 @@ func (vpp *VppInstance) start() error { vpp.container.createFile(vppcliFileName, cliContent) vpp.container.exec("chmod 0755 " + vppcliFileName) + vpp.getSuite().log("starting vpp") if *isVppDebug { sig := make(chan os.Signal, 1) - signal.Notify(sig, syscall.SIGINT) + signal.Notify(sig, syscall.SIGQUIT) cont := make(chan bool, 1) go func() { <-sig @@ -143,7 +153,7 @@ func (vpp *VppInstance) start() error { vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"") fmt.Println("run following command in different terminal:") fmt.Println("docker exec -it " + vpp.container.name + " gdb -ex \"attach $(docker exec " + vpp.container.name + " pidof vpp)\"") - fmt.Println("Afterwards press CTRL+C to continue") + fmt.Println("Afterwards press CTRL+\\ to continue") <-cont fmt.Println("continuing...") } else { @@ -151,6 +161,7 @@ func (vpp *VppInstance) start() error { vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"") } + vpp.getSuite().log("connecting to vpp") // Connect to VPP and store the connection sockAddress := vpp.container.getHostWorkDir() + defaultApiSocketFilePath conn, connEv, err := govpp.AsyncConnect( @@ -207,7 +218,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int { tokens := strings.Split(strings.TrimSpace(line), " ") val, err := strconv.Atoi(tokens[0]) if err != nil { - vpp.getSuite().FailNow("failed to parse stat value %s", err) + Fail("failed to parse stat value %s" + fmt.Sprint(err)) return 0 } return val @@ -217,6 +228,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int { } func (vpp *VppInstance) waitForApp(appName string, timeout int) { + vpp.getSuite().log("waiting for app " + appName) for i := 0; i < timeout; i++ { o := vpp.vppctl("show app") if strings.Contains(o, appName) { @@ -240,6 +252,7 @@ func (vpp *VppInstance) createAfPacket( } createReply := &af_packet.AfPacketCreateV2Reply{} + vpp.getSuite().log("create af-packet interface " + veth.Name()) if err := vpp.apiChannel.SendRequest(createReq).ReceiveReply(createReply); err != nil { return 0, err } @@ -252,6 +265,7 @@ func (vpp *VppInstance) createAfPacket( } upReply := &interfaces.SwInterfaceSetFlagsReply{} + vpp.getSuite().log("set af-packet interface " + veth.Name() + " up") if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil { return 0, err } @@ -273,6 +287,7 @@ func (vpp *VppInstance) createAfPacket( } addressReply := &interfaces.SwInterfaceAddDelAddressReply{} + vpp.getSuite().log("af-packet interface " + veth.Name() + " add address " + veth.ip4Address) if err := vpp.apiChannel.SendRequest(addressReq).ReceiveReply(addressReply); err != nil { return 0, err } @@ -292,6 +307,7 @@ func (vpp *VppInstance) addAppNamespace( } reply := &session.AppNamespaceAddDelV2Reply{} + vpp.getSuite().log("add app namespace " + namespaceId) if err := vpp.apiChannel.SendRequest(req).ReceiveReply(reply); err != nil { return err } @@ -301,6 +317,7 @@ func (vpp *VppInstance) addAppNamespace( } sessionReply := &session.SessionEnableDisableReply{} + vpp.getSuite().log("enable app namespace " + namespaceId) if err := vpp.apiChannel.SendRequest(sessionReq).ReceiveReply(sessionReply); err != nil { return err } @@ -325,6 +342,7 @@ func (vpp *VppInstance) createTap( } createTapReply := &tapv2.TapCreateV2Reply{} + vpp.getSuite().log("create tap interface " + tap.Name()) // Create tap interface if err := vpp.apiChannel.SendRequest(createTapReq).ReceiveReply(createTapReply); err != nil { return err @@ -338,6 +356,7 @@ func (vpp *VppInstance) createTap( } addAddressReply := &interfaces.SwInterfaceAddDelAddressReply{} + vpp.getSuite().log("tap interface " + tap.Name() + " add address " + tap.peer.ip4Address) if err := vpp.apiChannel.SendRequest(addAddressReq).ReceiveReply(addAddressReply); err != nil { return err } @@ -349,6 +368,7 @@ func (vpp *VppInstance) createTap( } upReply := &interfaces.SwInterfaceSetFlagsReply{} + vpp.getSuite().log("set tap interface " + tap.Name() + " up") if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil { return err } @@ -360,7 +380,6 @@ func (vpp *VppInstance) saveLogs() { logTarget := vpp.container.getLogDirPath() + "vppinstance-" + vpp.container.name + ".log" logSource := vpp.container.getHostWorkDir() + defaultLogFilePath cmd := exec.Command("cp", logSource, logTarget) - vpp.getSuite().T().Helper() vpp.getSuite().log(cmd.String()) cmd.Run() } diff --git a/src/plugins/acl/acl_test.c b/src/plugins/acl/acl_test.c index fddb3d532ff..98803a916cb 100644 --- a/src/plugins/acl/acl_test.c +++ b/src/plugins/acl/acl_test.c @@ -18,6 +18,8 @@ *------------------------------------------------------------------ */ +#include <byteswap.h> + #include <vat/vat.h> #include <vlibapi/api.h> #include <vlibmemory/api.h> @@ -112,7 +114,7 @@ static void vl_api_acl_interface_list_details_t_handler int i; vat_main_t * vam = acl_test_main.vat_main; u8 *out = 0; - vl_api_acl_interface_list_details_t_endian(mp); + vl_api_acl_interface_list_details_t_endian (mp, 0 /* from network */); out = format(out, "sw_if_index: %d, count: %d, n_input: %d\n", mp->sw_if_index, mp->count, mp->n_input); out = format(out, " input "); for(i=0; i<mp->count; i++) { @@ -139,7 +141,8 @@ static void vl_api_acl_interface_etype_whitelist_details_t_handler int i; vat_main_t * vam = acl_test_main.vat_main; u8 *out = 0; - vl_api_acl_interface_etype_whitelist_details_t_endian(mp); + vl_api_acl_interface_etype_whitelist_details_t_endian ( + mp, 0 /* from network */); out = format(out, "sw_if_index: %d, count: %d, n_input: %d\n", mp->sw_if_index, mp->count, mp->n_input); out = format(out, " input "); for(i=0; i<mp->count; i++) { @@ -171,15 +174,15 @@ vl_api_acl_rule_t_pretty_format (u8 *out, vl_api_acl_rule_t * a) inet_ntop(af, &a->src_prefix.address.un, (void *)src, sizeof(src)); inet_ntop(af, &a->dst_prefix.address.un, (void *)dst, sizeof(dst)); - out = format(out, "%s action %d src %s/%d dst %s/%d proto %d sport %d-%d dport %d-%d tcpflags %d mask %d", - a->src_prefix.address.af ? "ipv6" : "ipv4", a->is_permit, - src, a->src_prefix.len, - dst, a->dst_prefix.len, - a->proto, - a->srcport_or_icmptype_first, a->srcport_or_icmptype_last, - a->dstport_or_icmpcode_first, a->dstport_or_icmpcode_last, - a->tcp_flags_value, a->tcp_flags_mask); - return(out); + out = format (out, + "%s action %d src %s/%d dst %s/%d proto %d sport %d-%d dport " + "%d-%d tcpflags %d mask %d", + a->src_prefix.address.af ? "ipv6" : "ipv4", a->is_permit, src, + a->src_prefix.len, dst, a->dst_prefix.len, a->proto, + a->srcport_or_icmptype_first, a->srcport_or_icmptype_last, + a->dstport_or_icmpcode_first, a->dstport_or_icmpcode_last, + a->tcp_flags_value, a->tcp_flags_mask); + return (out); } @@ -189,9 +192,10 @@ static void vl_api_acl_details_t_handler { int i; vat_main_t * vam = acl_test_main.vat_main; - vl_api_acl_details_t_endian(mp); - u8 *out = 0; - out = format(0, "acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); + vl_api_acl_details_t_endian (mp, 0 /* from network */); + u8 *out = 0; + out = format (0, "acl_index: %d, count: %d\n tag {%s}\n", + mp->acl_index, mp->count, mp->tag); for(i=0; i<mp->count; i++) { out = format(out, " "); out = vl_api_acl_rule_t_pretty_format(out, &mp->r[i]); @@ -223,8 +227,9 @@ static void vl_api_macip_acl_details_t_handler { int i; vat_main_t * vam = acl_test_main.vat_main; - vl_api_macip_acl_details_t_endian(mp); - u8 *out = format(0,"MACIP acl_index: %d, count: %d\n tag {%s}\n", mp->acl_index, mp->count, mp->tag); + vl_api_macip_acl_details_t_endian (mp, 0 /* from network */); + u8 *out = format (0, "MACIP acl_index: %d, count: %d\n tag {%s}\n", + mp->acl_index, mp->count, mp->tag); for(i=0; i<mp->count; i++) { out = format(out, " "); out = vl_api_macip_acl_rule_t_pretty_format(out, &mp->r[i]); diff --git a/src/plugins/acl/sess_mgmt_node.c b/src/plugins/acl/sess_mgmt_node.c index e049a3ffa85..418baef9b6b 100644 --- a/src/plugins/acl/sess_mgmt_node.c +++ b/src/plugins/acl/sess_mgmt_node.c @@ -371,8 +371,9 @@ send_one_worker_interrupt (vlib_main_t * vm, acl_main_t * am, } void -aclp_post_session_change_request (acl_main_t * am, u32 target_thread, - u32 target_session, u32 request_type) +aclp_post_session_change_request (acl_main_t *am, u32 target_thread, + u32 target_session, + acl_fa_sess_req_t request_type) { acl_fa_per_worker_data_t *pw_me = &am->per_worker_data[os_get_thread_index ()]; diff --git a/src/plugins/crypto_native/CMakeLists.txt b/src/plugins/crypto_native/CMakeLists.txt index 9b6091610d9..5499ed4608a 100644 --- a/src/plugins/crypto_native/CMakeLists.txt +++ b/src/plugins/crypto_native/CMakeLists.txt @@ -12,8 +12,8 @@ # limitations under the License. if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*") - list(APPEND VARIANTS "slm\;-march=silvermont") - list(APPEND VARIANTS "hsw\;-march=haswell") + list(APPEND VARIANTS "slm\;-march=silvermont -maes") + list(APPEND VARIANTS "hsw\;-march=haswell -maes") if(compiler_flag_march_skylake_avx512 AND compiler_flag_mprefer_vector_width_256) list(APPEND VARIANTS "skx\;-march=skylake-avx512 -mprefer-vector-width=256") endif() @@ -23,16 +23,15 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|x86_64.*|AMD64.*") if(compiler_flag_march_alderlake) list(APPEND VARIANTS "adl\;-march=alderlake -mprefer-vector-width=256") endif() - set (COMPILE_FILES aes_cbc.c aes_gcm.c aes_ctr.c) - set (COMPILE_OPTS -Wall -fno-common -maes) endif() if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)") list(APPEND VARIANTS "armv8\;-march=armv8.1-a+crc+crypto") - set (COMPILE_FILES aes_cbc.c aes_gcm.c aes_ctr.c) - set (COMPILE_OPTS -Wall -fno-common) endif() +set (COMPILE_FILES aes_cbc.c aes_gcm.c aes_ctr.c sha2.c) +set (COMPILE_OPTS -Wall -fno-common) + if (NOT VARIANTS) return() endif() diff --git a/src/plugins/crypto_native/aes_cbc.c b/src/plugins/crypto_native/aes_cbc.c index c84390c3108..dd7ca3f1cf1 100644 --- a/src/plugins/crypto_native/aes_cbc.c +++ b/src/plugins/crypto_native/aes_cbc.c @@ -249,18 +249,30 @@ decrypt: return n_ops; } -#define foreach_aes_cbc_handler_type _(128) _(192) _(256) - -#define _(x) \ -static u32 aes_ops_dec_aes_cbc_##x \ -(vlib_main_t * vm, vnet_crypto_op_t * ops[], u32 n_ops) \ -{ return aes_ops_dec_aes_cbc (vm, ops, n_ops, AES_KEY_##x); } \ -static u32 aes_ops_enc_aes_cbc_##x \ -(vlib_main_t * vm, vnet_crypto_op_t * ops[], u32 n_ops) \ -{ return aes_ops_enc_aes_cbc (vm, ops, n_ops, AES_KEY_##x); } \ - -foreach_aes_cbc_handler_type; -#undef _ +static int +aes_cbc_cpu_probe () +{ +#if defined(__VAES__) && defined(__AVX512F__) + if (clib_cpu_supports_vaes () && clib_cpu_supports_avx512f ()) + return 50; +#elif defined(__VAES__) + if (clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_aes ()) + return 10; +#elif __aarch64__ + if (clib_cpu_supports_aarch64_aes ()) + return 10; +#endif + return -1; +} static void * aes_cbc_key_exp_128 (vnet_crypto_key_t *key) @@ -289,43 +301,39 @@ aes_cbc_key_exp_256 (vnet_crypto_key_t *key) return kd; } -#include <fcntl.h> - -clib_error_t * -#if defined(__VAES__) && defined(__AVX512F__) -crypto_native_aes_cbc_init_icl (vlib_main_t *vm) -#elif defined(__VAES__) -crypto_native_aes_cbc_init_adl (vlib_main_t *vm) -#elif __AVX512F__ -crypto_native_aes_cbc_init_skx (vlib_main_t * vm) -#elif __aarch64__ -crypto_native_aes_cbc_init_neon (vlib_main_t * vm) -#elif __AVX2__ -crypto_native_aes_cbc_init_hsw (vlib_main_t * vm) -#else -crypto_native_aes_cbc_init_slm (vlib_main_t * vm) -#endif -{ - crypto_native_main_t *cm = &crypto_native_main; +#define foreach_aes_cbc_handler_type _ (128) _ (192) _ (256) + +#define _(x) \ + static u32 aes_ops_enc_aes_cbc_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_enc_aes_cbc (vm, ops, n_ops, AES_KEY_##x); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##x##_cbc_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##x##_CBC_ENC, \ + .fn = aes_ops_enc_aes_cbc_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; \ + \ + static u32 aes_ops_dec_aes_cbc_##x (vlib_main_t *vm, \ + vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return aes_ops_dec_aes_cbc (vm, ops, n_ops, AES_KEY_##x); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##x##_cbc_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##x##_CBC_DEC, \ + .fn = aes_ops_dec_aes_cbc_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; \ + \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##x##_cbc) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##x##_CBC, \ + .key_fn = aes_cbc_key_exp_##x, \ + .probe = aes_cbc_cpu_probe, \ + }; -#define _(x) \ - vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \ - VNET_CRYPTO_OP_AES_##x##_CBC_ENC, \ - aes_ops_enc_aes_cbc_##x); \ - vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \ - VNET_CRYPTO_OP_AES_##x##_CBC_DEC, \ - aes_ops_dec_aes_cbc_##x); \ - cm->key_fn[VNET_CRYPTO_ALG_AES_##x##_CBC] = aes_cbc_key_exp_##x; - foreach_aes_cbc_handler_type; +foreach_aes_cbc_handler_type; #undef _ - return 0; -} - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/crypto_native/aes_ctr.c b/src/plugins/crypto_native/aes_ctr.c index 3a219510419..d02a7b69b9d 100644 --- a/src/plugins/crypto_native/aes_ctr.c +++ b/src/plugins/crypto_native/aes_ctr.c @@ -81,32 +81,50 @@ aes_ctr_key_exp (vnet_crypto_key_t *key, aes_key_size_t ks) foreach_aes_ctr_handler_type; #undef _ -clib_error_t * +static int +probe () +{ #if defined(__VAES__) && defined(__AVX512F__) -crypto_native_aes_ctr_init_icl (vlib_main_t *vm) + if (clib_cpu_supports_vaes () && clib_cpu_supports_avx512f ()) + return 50; #elif defined(__VAES__) -crypto_native_aes_ctr_init_adl (vlib_main_t *vm) -#elif __AVX512F__ -crypto_native_aes_ctr_init_skx (vlib_main_t *vm) -#elif __AVX2__ -crypto_native_aes_ctr_init_hsw (vlib_main_t *vm) + if (clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_aes ()) + return 10; #elif __aarch64__ -crypto_native_aes_ctr_init_neon (vlib_main_t *vm) -#else -crypto_native_aes_ctr_init_slm (vlib_main_t *vm) + if (clib_cpu_supports_aarch64_aes ()) + return 10; #endif -{ - crypto_native_main_t *cm = &crypto_native_main; + return -1; +} -#define _(x) \ - vnet_crypto_register_ops_handlers ( \ - vm, cm->crypto_engine_index, VNET_CRYPTO_OP_AES_##x##_CTR_ENC, \ - aes_ops_aes_ctr_##x, aes_ops_aes_ctr_##x##_chained); \ - vnet_crypto_register_ops_handlers ( \ - vm, cm->crypto_engine_index, VNET_CRYPTO_OP_AES_##x##_CTR_DEC, \ - aes_ops_aes_ctr_##x, aes_ops_aes_ctr_##x##_chained); \ - cm->key_fn[VNET_CRYPTO_ALG_AES_##x##_CTR] = aes_ctr_key_exp_##x; - foreach_aes_ctr_handler_type; +#define _(b) \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_ctr_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_CTR_ENC, \ + .fn = aes_ops_aes_ctr_##b, \ + .cfn = aes_ops_aes_ctr_##b##_chained, \ + .probe = probe, \ + }; \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_ctr_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_CTR_DEC, \ + .fn = aes_ops_aes_ctr_##b, \ + .cfn = aes_ops_aes_ctr_##b##_chained, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##b##_ctr) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##b##_CTR, \ + .key_fn = aes_ctr_key_exp_##b, \ + .probe = probe, \ + }; + +_ (128) _ (192) _ (256) #undef _ - return 0; -} diff --git a/src/plugins/crypto_native/aes_gcm.c b/src/plugins/crypto_native/aes_gcm.c index 6589d411975..220788d4e97 100644 --- a/src/plugins/crypto_native/aes_gcm.c +++ b/src/plugins/crypto_native/aes_gcm.c @@ -118,40 +118,49 @@ aes_gcm_key_exp (vnet_crypto_key_t *key, aes_key_size_t ks) foreach_aes_gcm_handler_type; #undef _ -clib_error_t * +static int +probe () +{ #if defined(__VAES__) && defined(__AVX512F__) -crypto_native_aes_gcm_init_icl (vlib_main_t *vm) + if (clib_cpu_supports_vpclmulqdq () && clib_cpu_supports_vaes () && + clib_cpu_supports_avx512f ()) + return 50; #elif defined(__VAES__) -crypto_native_aes_gcm_init_adl (vlib_main_t *vm) -#elif __AVX512F__ -crypto_native_aes_gcm_init_skx (vlib_main_t *vm) -#elif __AVX2__ -crypto_native_aes_gcm_init_hsw (vlib_main_t *vm) + if (clib_cpu_supports_vpclmulqdq () && clib_cpu_supports_vaes ()) + return 40; +#elif defined(__AVX512F__) + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_avx512f ()) + return 30; +#elif defined(__AVX2__) + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_avx2 ()) + return 20; +#elif __AES__ + if (clib_cpu_supports_pclmulqdq () && clib_cpu_supports_aes ()) + return 10; #elif __aarch64__ -crypto_native_aes_gcm_init_neon (vlib_main_t *vm) -#else -crypto_native_aes_gcm_init_slm (vlib_main_t *vm) + if (clib_cpu_supports_aarch64_aes ()) + return 10; #endif -{ - crypto_native_main_t *cm = &crypto_native_main; - -#define _(x) \ - vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \ - VNET_CRYPTO_OP_AES_##x##_GCM_ENC, \ - aes_ops_enc_aes_gcm_##x); \ - vnet_crypto_register_ops_handler (vm, cm->crypto_engine_index, \ - VNET_CRYPTO_OP_AES_##x##_GCM_DEC, \ - aes_ops_dec_aes_gcm_##x); \ - cm->key_fn[VNET_CRYPTO_ALG_AES_##x##_GCM] = aes_gcm_key_exp_##x; - foreach_aes_gcm_handler_type; -#undef _ - return 0; + return -1; } -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ +#define _(b) \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_gcm_enc) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_GCM_ENC, \ + .fn = aes_ops_enc_aes_gcm_##b, \ + .probe = probe, \ + }; \ + \ + CRYPTO_NATIVE_OP_HANDLER (aes_##b##_gcm_dec) = { \ + .op_id = VNET_CRYPTO_OP_AES_##b##_GCM_DEC, \ + .fn = aes_ops_dec_aes_gcm_##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (aes_##b##_gcm) = { \ + .alg_id = VNET_CRYPTO_ALG_AES_##b##_GCM, \ + .key_fn = aes_gcm_key_exp_##b, \ + .probe = probe, \ + }; + +_ (128) _ (192) _ (256) +#undef _ diff --git a/src/plugins/crypto_native/crypto_native.h b/src/plugins/crypto_native/crypto_native.h index c15b8cbd1da..3d18e8cabd0 100644 --- a/src/plugins/crypto_native/crypto_native.h +++ b/src/plugins/crypto_native/crypto_native.h @@ -19,33 +19,66 @@ #define __crypto_native_h__ typedef void *(crypto_native_key_fn_t) (vnet_crypto_key_t * key); +typedef int (crypto_native_variant_probe_t) (); + +typedef struct crypto_native_op_handler +{ + struct crypto_native_op_handler *next; + vnet_crypto_op_id_t op_id; + vnet_crypto_ops_handler_t *fn; + vnet_crypto_chained_ops_handler_t *cfn; + crypto_native_variant_probe_t *probe; + int priority; +} crypto_native_op_handler_t; + +typedef struct crypto_native_key_handler +{ + struct crypto_native_key_handler *next; + vnet_crypto_alg_t alg_id; + crypto_native_key_fn_t *key_fn; + crypto_native_variant_probe_t *probe; + int priority; +} crypto_native_key_handler_t; typedef struct { u32 crypto_engine_index; crypto_native_key_fn_t *key_fn[VNET_CRYPTO_N_ALGS]; void **key_data; + crypto_native_op_handler_t *op_handlers; + crypto_native_key_handler_t *key_handlers; } crypto_native_main_t; extern crypto_native_main_t crypto_native_main; -#define foreach_crypto_native_march_variant \ - _ (slm) _ (hsw) _ (skx) _ (icl) _ (adl) _ (neon) - -#define _(v) \ - clib_error_t __clib_weak *crypto_native_aes_cbc_init_##v (vlib_main_t *vm); \ - clib_error_t __clib_weak *crypto_native_aes_ctr_init_##v (vlib_main_t *vm); \ - clib_error_t __clib_weak *crypto_native_aes_gcm_init_##v (vlib_main_t *vm); - -foreach_crypto_native_march_variant; -#undef _ +#define CRYPTO_NATIVE_OP_HANDLER(x) \ + static crypto_native_op_handler_t __crypto_native_op_handler_##x; \ + static void __clib_constructor __crypto_native_op_handler_cb_##x (void) \ + { \ + crypto_native_main_t *cm = &crypto_native_main; \ + int priority = __crypto_native_op_handler_##x.probe (); \ + if (priority >= 0) \ + { \ + __crypto_native_op_handler_##x.priority = priority; \ + __crypto_native_op_handler_##x.next = cm->op_handlers; \ + cm->op_handlers = &__crypto_native_op_handler_##x; \ + } \ + } \ + static crypto_native_op_handler_t __crypto_native_op_handler_##x +#define CRYPTO_NATIVE_KEY_HANDLER(x) \ + static crypto_native_key_handler_t __crypto_native_key_handler_##x; \ + static void __clib_constructor __crypto_native_key_handler_cb_##x (void) \ + { \ + crypto_native_main_t *cm = &crypto_native_main; \ + int priority = __crypto_native_key_handler_##x.probe (); \ + if (priority >= 0) \ + { \ + __crypto_native_key_handler_##x.priority = priority; \ + __crypto_native_key_handler_##x.next = cm->key_handlers; \ + cm->key_handlers = &__crypto_native_key_handler_##x; \ + } \ + } \ + static crypto_native_key_handler_t __crypto_native_key_handler_##x #endif /* __crypto_native_h__ */ -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/plugins/crypto_native/main.c b/src/plugins/crypto_native/main.c index 8a59be319b9..2bc0d98f196 100644 --- a/src/plugins/crypto_native/main.c +++ b/src/plugins/crypto_native/main.c @@ -63,95 +63,52 @@ clib_error_t * crypto_native_init (vlib_main_t * vm) { crypto_native_main_t *cm = &crypto_native_main; - clib_error_t *error = 0; - if (clib_cpu_supports_x86_aes () == 0 && - clib_cpu_supports_aarch64_aes () == 0) + if (cm->op_handlers == 0) return 0; cm->crypto_engine_index = vnet_crypto_register_engine (vm, "native", 100, "Native ISA Optimized Crypto"); - if (0); -#if __x86_64__ - else if (crypto_native_aes_cbc_init_icl && clib_cpu_supports_vaes () && - clib_cpu_supports_avx512f ()) - error = crypto_native_aes_cbc_init_icl (vm); - else if (crypto_native_aes_cbc_init_adl && clib_cpu_supports_vaes ()) - error = crypto_native_aes_cbc_init_adl (vm); - else if (crypto_native_aes_cbc_init_skx && clib_cpu_supports_avx512f ()) - error = crypto_native_aes_cbc_init_skx (vm); - else if (crypto_native_aes_cbc_init_hsw && clib_cpu_supports_avx2 ()) - error = crypto_native_aes_cbc_init_hsw (vm); - else if (crypto_native_aes_cbc_init_slm) - error = crypto_native_aes_cbc_init_slm (vm); -#endif -#if __aarch64__ - else if (crypto_native_aes_cbc_init_neon) - error = crypto_native_aes_cbc_init_neon (vm); -#endif - else - error = clib_error_return (0, "No AES CBC implemenation available"); - - if (error) - return error; - - if (0) - ; -#if __x86_64__ - else if (crypto_native_aes_ctr_init_icl && clib_cpu_supports_vaes () && - clib_cpu_supports_avx512f ()) - error = crypto_native_aes_ctr_init_icl (vm); - else if (crypto_native_aes_ctr_init_adl && clib_cpu_supports_vaes ()) - error = crypto_native_aes_ctr_init_adl (vm); - else if (crypto_native_aes_ctr_init_skx && clib_cpu_supports_avx512f ()) - error = crypto_native_aes_ctr_init_skx (vm); - else if (crypto_native_aes_ctr_init_hsw && clib_cpu_supports_avx2 ()) - error = crypto_native_aes_ctr_init_hsw (vm); - else if (crypto_native_aes_ctr_init_slm) - error = crypto_native_aes_ctr_init_slm (vm); -#endif -#if __aarch64__ - else if (crypto_native_aes_ctr_init_neon) - error = crypto_native_aes_ctr_init_neon (vm); -#endif - else - error = clib_error_return (0, "No AES CTR implemenation available"); - - if (error) - return error; - -#if __x86_64__ - if (clib_cpu_supports_pclmulqdq ()) + crypto_native_op_handler_t *oh = cm->op_handlers; + crypto_native_key_handler_t *kh = cm->key_handlers; + crypto_native_op_handler_t **best_by_op_id = 0; + crypto_native_key_handler_t **best_by_alg_id = 0; + + while (oh) { - if (crypto_native_aes_gcm_init_icl && clib_cpu_supports_vaes () && - clib_cpu_supports_avx512f ()) - error = crypto_native_aes_gcm_init_icl (vm); - else if (crypto_native_aes_gcm_init_adl && clib_cpu_supports_vaes ()) - error = crypto_native_aes_gcm_init_adl (vm); - else if (crypto_native_aes_gcm_init_skx && clib_cpu_supports_avx512f ()) - error = crypto_native_aes_gcm_init_skx (vm); - else if (crypto_native_aes_gcm_init_hsw && clib_cpu_supports_avx2 ()) - error = crypto_native_aes_gcm_init_hsw (vm); - else if (crypto_native_aes_gcm_init_slm) - error = crypto_native_aes_gcm_init_slm (vm); - else - error = clib_error_return (0, "No AES GCM implemenation available"); - - if (error) - return error; + vec_validate (best_by_op_id, oh->op_id); + + if (best_by_op_id[oh->op_id] == 0 || + best_by_op_id[oh->op_id]->priority < oh->priority) + best_by_op_id[oh->op_id] = oh; + + oh = oh->next; } -#endif -#if __aarch64__ - if (crypto_native_aes_gcm_init_neon) - error = crypto_native_aes_gcm_init_neon (vm); - else - error = clib_error_return (0, "No AES GCM implemenation available"); - - if (error) - return error; -#endif + + while (kh) + { + vec_validate (best_by_alg_id, kh->alg_id); + + if (best_by_alg_id[kh->alg_id] == 0 || + best_by_alg_id[kh->alg_id]->priority < kh->priority) + best_by_alg_id[kh->alg_id] = kh; + + kh = kh->next; + } + + vec_foreach_pointer (oh, best_by_op_id) + if (oh) + vnet_crypto_register_ops_handlers (vm, cm->crypto_engine_index, + oh->op_id, oh->fn, oh->cfn); + + vec_foreach_pointer (kh, best_by_alg_id) + if (kh) + cm->key_fn[kh->alg_id] = kh->key_fn; + + vec_free (best_by_op_id); + vec_free (best_by_alg_id); vnet_crypto_register_key_handler (vm, cm->crypto_engine_index, crypto_native_key_handler); diff --git a/src/plugins/crypto_native/sha2.c b/src/plugins/crypto_native/sha2.c new file mode 100644 index 00000000000..459ce6d8e79 --- /dev/null +++ b/src/plugins/crypto_native/sha2.c @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2024 Cisco Systems, Inc. + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vnet/crypto/crypto.h> +#include <crypto_native/crypto_native.h> +#include <vppinfra/crypto/sha2.h> + +static_always_inline u32 +crypto_native_ops_hash_sha2 (vlib_main_t *vm, vnet_crypto_op_t *ops[], + u32 n_ops, vnet_crypto_op_chunk_t *chunks, + clib_sha2_type_t type, int maybe_chained) +{ + vnet_crypto_op_t *op = ops[0]; + clib_sha2_ctx_t ctx; + u32 n_left = n_ops; + +next: + if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS) + { + vnet_crypto_op_chunk_t *chp = chunks + op->chunk_index; + clib_sha2_init (&ctx, type); + for (int j = 0; j < op->n_chunks; j++, chp++) + clib_sha2_update (&ctx, chp->src, chp->len); + clib_sha2_final (&ctx, op->digest); + } + else + clib_sha2 (type, op->src, op->len, op->digest); + + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + + if (--n_left) + { + op += 1; + goto next; + } + + return n_ops; +} + +static_always_inline u32 +crypto_native_ops_hmac_sha2 (vlib_main_t *vm, vnet_crypto_op_t *ops[], + u32 n_ops, vnet_crypto_op_chunk_t *chunks, + clib_sha2_type_t type) +{ + crypto_native_main_t *cm = &crypto_native_main; + vnet_crypto_op_t *op = ops[0]; + u32 n_left = n_ops; + clib_sha2_hmac_ctx_t ctx; + u8 buffer[64]; + u32 sz, n_fail = 0; + + for (; n_left; n_left--, op++) + { + clib_sha2_hmac_init ( + &ctx, type, (clib_sha2_hmac_key_data_t *) cm->key_data[op->key_index]); + if (op->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS) + { + vnet_crypto_op_chunk_t *chp = chunks + op->chunk_index; + for (int j = 0; j < op->n_chunks; j++, chp++) + clib_sha2_hmac_update (&ctx, chp->src, chp->len); + } + else + clib_sha2_hmac_update (&ctx, op->src, op->len); + + clib_sha2_hmac_final (&ctx, buffer); + + if (op->digest_len) + { + sz = op->digest_len; + if (op->flags & VNET_CRYPTO_OP_FLAG_HMAC_CHECK) + { + if ((memcmp (op->digest, buffer, sz))) + { + n_fail++; + op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; + continue; + } + } + else + clib_memcpy_fast (op->digest, buffer, sz); + } + else + { + sz = clib_sha2_variants[type].digest_size; + if (op->flags & VNET_CRYPTO_OP_FLAG_HMAC_CHECK) + { + if ((memcmp (op->digest, buffer, sz))) + { + n_fail++; + op->status = VNET_CRYPTO_OP_STATUS_FAIL_BAD_HMAC; + continue; + } + } + else + clib_memcpy_fast (op->digest, buffer, sz); + } + + op->status = VNET_CRYPTO_OP_STATUS_COMPLETED; + } + + return n_ops - n_fail; +} + +static void * +sha2_key_add (vnet_crypto_key_t *key, clib_sha2_type_t type) +{ + clib_sha2_hmac_key_data_t *kd; + + kd = clib_mem_alloc_aligned (sizeof (*kd), CLIB_CACHE_LINE_BYTES); + clib_sha2_hmac_key_data (type, key->data, vec_len (key->data), kd); + + return kd; +} + +static int +probe () +{ +#if defined(__SHA__) && defined(__x86_64__) + if (clib_cpu_supports_sha ()) + return 50; +#elif defined(__ARM_FEATURE_SHA2) + if (clib_cpu_supports_sha2 ()) + return 10; +#endif + return -1; +} + +#define _(b) \ + static u32 crypto_native_ops_hash_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return crypto_native_ops_hash_sha2 (vm, ops, n_ops, 0, CLIB_SHA2_##b, 0); \ + } \ + \ + static u32 crypto_native_ops_chained_hash_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, \ + u32 n_ops) \ + { \ + return crypto_native_ops_hash_sha2 (vm, ops, n_ops, chunks, \ + CLIB_SHA2_##b, 1); \ + } \ + \ + static u32 crypto_native_ops_hmac_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], u32 n_ops) \ + { \ + return crypto_native_ops_hmac_sha2 (vm, ops, n_ops, 0, CLIB_SHA2_##b); \ + } \ + \ + static u32 crypto_native_ops_chained_hmac_sha##b ( \ + vlib_main_t *vm, vnet_crypto_op_t *ops[], vnet_crypto_op_chunk_t *chunks, \ + u32 n_ops) \ + { \ + return crypto_native_ops_hmac_sha2 (vm, ops, n_ops, chunks, \ + CLIB_SHA2_##b); \ + } \ + \ + static void *sha2_##b##_key_add (vnet_crypto_key_t *k) \ + { \ + return sha2_key_add (k, CLIB_SHA2_##b); \ + } \ + \ + CRYPTO_NATIVE_OP_HANDLER (crypto_native_hash_sha##b) = { \ + .op_id = VNET_CRYPTO_OP_SHA##b##_HASH, \ + .fn = crypto_native_ops_hash_sha##b, \ + .cfn = crypto_native_ops_chained_hash_sha##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_OP_HANDLER (crypto_native_hmac_sha##b) = { \ + .op_id = VNET_CRYPTO_OP_SHA##b##_HMAC, \ + .fn = crypto_native_ops_hmac_sha##b, \ + .cfn = crypto_native_ops_chained_hmac_sha##b, \ + .probe = probe, \ + }; \ + CRYPTO_NATIVE_KEY_HANDLER (crypto_native_hmac_sha##b) = { \ + .alg_id = VNET_CRYPTO_ALG_HMAC_SHA##b, \ + .key_fn = sha2_##b##_key_add, \ + .probe = probe, \ + }; + +_ (224) +_ (256) + +#undef _ diff --git a/src/plugins/dev_iavf/port.c b/src/plugins/dev_iavf/port.c index 982436d9b45..90e81e960c4 100644 --- a/src/plugins/dev_iavf/port.c +++ b/src/plugins/dev_iavf/port.c @@ -42,29 +42,35 @@ iavf_port_vlan_strip_disable (vlib_main_t *vm, vnet_dev_port_t *port) vnet_dev_t *dev = port->dev; iavf_port_t *ap = vnet_dev_get_port_data (port); virtchnl_vlan_caps_t vc; - vnet_dev_rv_t rv; + vnet_dev_rv_t rv = VNET_DEV_ERR_NOT_SUPPORTED; u32 outer, inner; const u32 mask = VIRTCHNL_VLAN_ETHERTYPE_8100; - if ((ap->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) == 0) - return iavf_vc_op_disable_vlan_stripping (vm, dev); + if (ap->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) + { + if ((rv = iavf_vc_op_get_offload_vlan_v2_caps (vm, dev, &vc))) + return rv; - if ((rv = iavf_vc_op_get_offload_vlan_v2_caps (vm, dev, &vc))) - return rv; + outer = vc.offloads.stripping_support.outer; + inner = vc.offloads.stripping_support.inner; - outer = vc.offloads.stripping_support.outer; - inner = vc.offloads.stripping_support.inner; + outer = outer & VIRTCHNL_VLAN_TOGGLE ? outer & mask : 0; + inner = inner & VIRTCHNL_VLAN_TOGGLE ? inner & mask : 0; - outer = outer & VIRTCHNL_VLAN_TOGGLE ? outer & mask : 0; - inner = inner & VIRTCHNL_VLAN_TOGGLE ? inner & mask : 0; + virtchnl_vlan_setting_t vs = { + .vport_id = ap->vsi_id, + .outer_ethertype_setting = outer, + .inner_ethertype_setting = inner, + }; - virtchnl_vlan_setting_t vs = { - .vport_id = ap->vsi_id, - .outer_ethertype_setting = outer, - .inner_ethertype_setting = inner, - }; + if ((rv = iavf_vc_op_disable_vlan_stripping_v2 (vm, dev, &vs))) + return rv; + } - return iavf_vc_op_disable_vlan_stripping_v2 (vm, dev, &vs); + if (ap->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN) + return iavf_vc_op_disable_vlan_stripping (vm, dev); + + return rv; } vnet_dev_rv_t @@ -275,7 +281,12 @@ iavf_port_init (vlib_main_t *vm, vnet_dev_port_t *port) u64_bit_set (&ap->intr_mode_per_rxq_bitmap, q->queue_id, 1); if ((rv = iavf_port_vlan_strip_disable (vm, port))) - return rv; + { + if (rv == VNET_DEV_ERR_NOT_SUPPORTED) + log_warn (port->dev, "device doesn't support vlan stripping"); + else + return rv; + } if ((rv = iavf_port_init_rss (vm, port))) return rv; diff --git a/src/plugins/dev_octeon/init.c b/src/plugins/dev_octeon/init.c index 47be8a8f9a4..97a11e0d0d7 100644 --- a/src/plugins/dev_octeon/init.c +++ b/src/plugins/dev_octeon/init.c @@ -51,7 +51,9 @@ static struct } _ (0xa063, RVU_PF, "Marvell Octeon Resource Virtualization Unit PF"), - _ (0xa0f8, RVU_VF, "Marvell Octeon Resource Virtualization Unit VF"), + _ (0xa064, RVU_VF, "Marvell Octeon Resource Virtualization Unit VF"), + _ (0xa0f8, LBK_VF, "Marvell Octeon Loopback Unit VF"), + _ (0xa0f7, SDP_VF, "Marvell Octeon System DPI Packet Interface Unit VF"), _ (0xa0f3, CPT_VF, "Marvell Octeon Cryptographic Accelerator Unit VF"), #undef _ }; @@ -113,7 +115,7 @@ oct_init_nix (vlib_main_t *vm, vnet_dev_t *dev) if ((rrv = roc_nix_dev_init (cd->nix))) return cnx_return_roc_err (dev, rrv, "roc_nix_dev_init"); - if (roc_nix_npc_mac_addr_get (cd->nix, mac_addr)) + if ((rrv = roc_nix_npc_mac_addr_get (cd->nix, mac_addr))) return cnx_return_roc_err (dev, rrv, "roc_nix_npc_mac_addr_get"); vnet_dev_port_add_args_t port_add_args = { @@ -239,12 +241,19 @@ oct_init (vlib_main_t *vm, vnet_dev_t *dev) strncpy ((char *) cd->plt_pci_dev.name, dev->device_id, sizeof (cd->plt_pci_dev.name) - 1); - if (cd->type == OCT_DEVICE_TYPE_RVU_PF || cd->type == OCT_DEVICE_TYPE_RVU_VF) - return oct_init_nix (vm, dev); - else if (cd->type == OCT_DEVICE_TYPE_CPT_VF) - return oct_init_cpt (vm, dev); - else - return VNET_DEV_ERR_UNSUPPORTED_DEVICE; + switch (cd->type) + { + case OCT_DEVICE_TYPE_RVU_PF: + case OCT_DEVICE_TYPE_RVU_VF: + case OCT_DEVICE_TYPE_SDP_VF: + return oct_init_nix (vm, dev); + + case OCT_DEVICE_TYPE_CPT_VF: + return oct_init_cpt (vm, dev); + + default: + return VNET_DEV_ERR_UNSUPPORTED_DEVICE; + } return 0; } diff --git a/src/plugins/dev_octeon/octeon.h b/src/plugins/dev_octeon/octeon.h index 72d2d56a437..e43cde0a35f 100644 --- a/src/plugins/dev_octeon/octeon.h +++ b/src/plugins/dev_octeon/octeon.h @@ -22,6 +22,8 @@ typedef enum OCT_DEVICE_TYPE_UNKNOWN = 0, OCT_DEVICE_TYPE_RVU_PF, OCT_DEVICE_TYPE_RVU_VF, + OCT_DEVICE_TYPE_LBK_VF, + OCT_DEVICE_TYPE_SDP_VF, OCT_DEVICE_TYPE_CPT_VF, } __clib_packed oct_device_type_t; @@ -161,7 +163,8 @@ vnet_dev_rv_t oct_flow_query (vlib_main_t *, vnet_dev_port_t *, u32, uword, _ (AURA_BATCH_ALLOC_ISSUE_FAIL, aura_batch_alloc_issue_fail, ERROR, \ "aura batch alloc issue failed") \ _ (AURA_BATCH_ALLOC_NOT_READY, aura_batch_alloc_not_ready, ERROR, \ - "aura batch alloc not ready") + "aura batch alloc not ready") \ + _ (MTU_EXCEEDED, mtu_exceeded, ERROR, "mtu exceeded") typedef enum { diff --git a/src/plugins/dev_octeon/port.c b/src/plugins/dev_octeon/port.c index a82e48004b5..98a4c28b37d 100644 --- a/src/plugins/dev_octeon/port.c +++ b/src/plugins/dev_octeon/port.c @@ -379,6 +379,82 @@ oct_port_stop (vlib_main_t *vm, vnet_dev_port_t *port) } vnet_dev_rv_t +oct_validate_config_promisc_mode (vnet_dev_port_t *port, int enable) +{ + vnet_dev_t *dev = port->dev; + oct_device_t *cd = vnet_dev_get_data (dev); + struct roc_nix *nix = cd->nix; + + if (roc_nix_is_vf_or_sdp (nix)) + return VNET_DEV_ERR_UNSUPPORTED_DEVICE; + + return VNET_DEV_OK; +} + +vnet_dev_rv_t +oct_op_config_promisc_mode (vlib_main_t *vm, vnet_dev_port_t *port, int enable) +{ + vnet_dev_t *dev = port->dev; + oct_device_t *cd = vnet_dev_get_data (dev); + struct roc_nix *nix = cd->nix; + int rv; + + rv = roc_nix_npc_promisc_ena_dis (nix, enable); + if (rv) + { + return oct_roc_err (dev, rv, "roc_nix_npc_promisc_ena_dis failed"); + } + + rv = roc_nix_mac_promisc_mode_enable (nix, enable); + if (rv) + { + return oct_roc_err (dev, rv, + "roc_nix_mac_promisc_mode_enable(%s) failed", + enable ? "true" : "false"); + } + + return VNET_DEV_OK; +} + +static vnet_dev_rv_t +oct_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port, + vnet_dev_hw_addr_t *addr, int is_add, + int is_primary) +{ + vnet_dev_t *dev = port->dev; + oct_device_t *cd = vnet_dev_get_data (dev); + struct roc_nix *nix = cd->nix; + vnet_dev_rv_t rv = VNET_DEV_OK; + + i32 rrv; + + if (is_primary) + { + if (is_add) + { + /* Update mac address at NPC */ + rrv = roc_nix_npc_mac_addr_set (nix, (u8 *) addr); + if (rrv) + rv = oct_roc_err (dev, rrv, "roc_nix_npc_mac_addr_set() failed"); + + /* Update mac address at CGX for PFs only */ + if (!roc_nix_is_vf_or_sdp (nix)) + { + rrv = roc_nix_mac_addr_set (nix, (u8 *) addr); + if (rrv) + { + /* Rollback to previous mac address */ + roc_nix_npc_mac_addr_set (nix, + (u8 *) &port->primary_hw_addr); + rv = oct_roc_err (dev, rrv, "roc_nix_mac_addr_set() failed"); + } + } + } + } + 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) { @@ -392,6 +468,8 @@ oct_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port, break; case VNET_DEV_PORT_CFG_PROMISC_MODE: + rv = oct_validate_config_promisc_mode (port, req->promisc); + break; 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: @@ -421,9 +499,13 @@ oct_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port, switch (req->type) { case VNET_DEV_PORT_CFG_PROMISC_MODE: + rv = oct_op_config_promisc_mode (vm, port, req->promisc); break; case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR: + rv = oct_port_add_del_eth_addr (vm, port, &req->addr, + /* is_add */ 1, + /* is_primary */ 1); break; case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR: diff --git a/src/plugins/dev_octeon/tx_node.c b/src/plugins/dev_octeon/tx_node.c index 0dbf8759d35..a2e4b07de8a 100644 --- a/src/plugins/dev_octeon/tx_node.c +++ b/src/plugins/dev_octeon/tx_node.c @@ -22,8 +22,11 @@ typedef struct u32 n_tx_bytes; u32 n_drop; vlib_buffer_t *drop[VLIB_FRAME_SIZE]; + u32 n_exd_mtu; + vlib_buffer_t *exd_mtu[VLIB_FRAME_SIZE]; u32 batch_alloc_not_ready; u32 batch_alloc_issue_fail; + int max_pkt_len; u16 lmt_id; u64 lmt_ioaddr; lmt_line_t *lmt_lines; @@ -133,7 +136,8 @@ oct_batch_free (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq) static_always_inline u8 oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, - lmt_line_t *line, u32 flags, int simple, int trace) + lmt_line_t *line, u32 flags, int simple, int trace, u32 *n, + u8 *dpl) { u8 n_dwords = 2; u32 total_len = 0; @@ -148,6 +152,12 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, }, }; + if (PREDICT_FALSE (vlib_buffer_length_in_chain (vm, b) > ctx->max_pkt_len)) + { + ctx->exd_mtu[ctx->n_exd_mtu++] = b; + return 0; + } + if (!simple && flags & VLIB_BUFFER_NEXT_PRESENT) { u8 n_tail_segs = 0; @@ -159,7 +169,7 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, tail_segs[n_tail_segs++] = t; if (n_tail_segs > 5) { - ctx->drop[ctx->n_drop++] = t; + ctx->drop[ctx->n_drop++] = b; return 0; } } @@ -231,6 +241,9 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, for (u32 i = 0; i < n_dwords; i++) line->dwords[i] = d.as_u128[i]; + *dpl = n_dwords; + *n = *n + 1; + return n_dwords; } @@ -240,7 +253,7 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, { u8 dwords_per_line[16], *dpl = dwords_per_line; u64 lmt_arg, ioaddr, n_lines; - u32 n_left, or_flags_16 = 0; + u32 n_left, or_flags_16 = 0, n = 0; const u32 not_simple_flags = VLIB_BUFFER_NEXT_PRESENT | VNET_BUFFER_F_OFFLOAD; lmt_line_t *l = ctx->lmt_lines; @@ -248,7 +261,7 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, /* Data Store Memory Barrier - outer shareable domain */ asm volatile("dmb oshst" ::: "memory"); - for (n_left = n_pkts; n_left >= 8; n_left -= 8, b += 8, l += 8) + for (n_left = n_pkts; n_left >= 8; n_left -= 8, b += 8) { u32 f0, f1, f2, f3, f4, f5, f6, f7, or_f = 0; vlib_prefetch_buffer_header (b[8], LOAD); @@ -269,48 +282,54 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, if ((or_f & not_simple_flags) == 0) { int simple = 1; - oct_tx_enq1 (vm, ctx, b[0], l, f0, simple, trace); - oct_tx_enq1 (vm, ctx, b[1], l + 1, f1, simple, trace); + oct_tx_enq1 (vm, ctx, b[0], l, f0, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[1], l + n, f1, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[13], LOAD); - oct_tx_enq1 (vm, ctx, b[2], l + 2, f2, simple, trace); - oct_tx_enq1 (vm, ctx, b[3], l + 3, f3, simple, trace); + oct_tx_enq1 (vm, ctx, b[2], l + n, f2, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[3], l + n, f3, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[14], LOAD); - oct_tx_enq1 (vm, ctx, b[4], l + 4, f4, simple, trace); - oct_tx_enq1 (vm, ctx, b[5], l + 5, f5, simple, trace); + oct_tx_enq1 (vm, ctx, b[4], l + n, f4, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[5], l + n, f5, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[15], LOAD); - oct_tx_enq1 (vm, ctx, b[6], l + 6, f6, simple, trace); - oct_tx_enq1 (vm, ctx, b[7], l + 7, f7, simple, trace); - dpl[0] = dpl[1] = dpl[2] = dpl[3] = 2; - dpl[4] = dpl[5] = dpl[6] = dpl[7] = 2; + oct_tx_enq1 (vm, ctx, b[6], l + n, f6, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[7], l + n, f7, simple, trace, &n, &dpl[n]); } else { int simple = 0; - dpl[0] = oct_tx_enq1 (vm, ctx, b[0], l, f0, simple, trace); - dpl[1] = oct_tx_enq1 (vm, ctx, b[1], l + 1, f1, simple, trace); + oct_tx_enq1 (vm, ctx, b[0], l, f0, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[1], l + n, f1, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[13], LOAD); - dpl[2] = oct_tx_enq1 (vm, ctx, b[2], l + 2, f2, simple, trace); - dpl[3] = oct_tx_enq1 (vm, ctx, b[3], l + 3, f3, simple, trace); + oct_tx_enq1 (vm, ctx, b[2], l + n, f2, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[3], l + n, f3, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[14], LOAD); - dpl[4] = oct_tx_enq1 (vm, ctx, b[4], l + 4, f4, simple, trace); - dpl[5] = oct_tx_enq1 (vm, ctx, b[5], l + 5, f5, simple, trace); + oct_tx_enq1 (vm, ctx, b[4], l + n, f4, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[5], l + n, f5, simple, trace, &n, &dpl[n]); vlib_prefetch_buffer_header (b[15], LOAD); - dpl[6] = oct_tx_enq1 (vm, ctx, b[6], l + 6, f6, simple, trace); - dpl[7] = oct_tx_enq1 (vm, ctx, b[7], l + 7, f7, simple, trace); + oct_tx_enq1 (vm, ctx, b[6], l + n, f6, simple, trace, &n, &dpl[n]); + oct_tx_enq1 (vm, ctx, b[7], l + n, f7, simple, trace, &n, &dpl[n]); } - dpl += 8; + dpl += n; + l += n; + n = 0; } - for (; n_left > 0; n_left -= 1, b += 1, l += 1) + for (; n_left > 0; n_left -= 1, b += 1) { u32 f0 = b[0]->flags; - dpl++[0] = oct_tx_enq1 (vm, ctx, b[0], l, f0, 0, trace); + oct_tx_enq1 (vm, ctx, b[0], l, f0, 0, trace, &n, &dpl[n]); or_flags_16 |= f0; + dpl += n; + l += n; + n = 0; } lmt_arg = ctx->lmt_id; ioaddr = ctx->lmt_ioaddr; - n_lines = n_pkts; + n_lines = dpl - dwords_per_line; + + if (PREDICT_FALSE (!n_lines)) + return n_pkts; if (PREDICT_FALSE (or_flags_16 & VLIB_BUFFER_NEXT_PRESENT)) { @@ -350,6 +369,8 @@ VNET_DEV_NODE_FN (oct_tx_node) vnet_dev_tx_node_runtime_t *rt = vnet_dev_get_tx_node_runtime (node); vnet_dev_tx_queue_t *txq = rt->tx_queue; oct_txq_t *ctq = vnet_dev_get_tx_queue_data (txq); + vnet_dev_t *dev = txq->port->dev; + oct_device_t *cd = vnet_dev_get_data (dev); u32 node_index = node->node_index; u32 *from = vlib_frame_vector_args (frame); u32 n, n_enq, n_left, n_pkts = frame->n_vectors; @@ -363,6 +384,7 @@ VNET_DEV_NODE_FN (oct_tx_node) .sq = ctq->sq.qid, .sizem1 = 1, }, + .max_pkt_len = roc_nix_max_pkt_len (cd->nix), .lmt_id = lmt_id, .lmt_ioaddr = ctq->io_addr, .lmt_lines = ctq->lmt_addr + (lmt_id << ROC_LMT_LINE_SIZE_LOG2), @@ -396,7 +418,7 @@ VNET_DEV_NODE_FN (oct_tx_node) n += oct_tx_enq16 (vm, &ctx, txq, b, n_left, /* trace */ 0); } - ctq->n_enq = n_enq + n; + ctq->n_enq = n_enq + n - ctx.n_drop - ctx.n_exd_mtu; if (n < n_pkts) { @@ -411,6 +433,10 @@ VNET_DEV_NODE_FN (oct_tx_node) vlib_error_count (vm, node->node_index, OCT_TX_NODE_CTR_CHAIN_TOO_LONG, ctx.n_drop); + if (PREDICT_FALSE (ctx.n_exd_mtu)) + vlib_error_count (vm, node->node_index, OCT_TX_NODE_CTR_MTU_EXCEEDED, + ctx.n_exd_mtu); + if (ctx.batch_alloc_not_ready) vlib_error_count (vm, node_index, OCT_TX_NODE_CTR_AURA_BATCH_ALLOC_NOT_READY, @@ -431,5 +457,13 @@ VNET_DEV_NODE_FN (oct_tx_node) n_pkts -= ctx.n_drop; } + if (PREDICT_FALSE (ctx.n_exd_mtu)) + { + u32 bi[VLIB_FRAME_SIZE]; + vlib_get_buffer_indices (vm, ctx.exd_mtu, bi, ctx.n_exd_mtu); + vlib_buffer_free (vm, bi, ctx.n_exd_mtu); + n_pkts -= ctx.n_exd_mtu; + } + return n_pkts; } diff --git a/src/plugins/dpdk/CMakeLists.txt b/src/plugins/dpdk/CMakeLists.txt index 48b1548f9c2..48c56f35282 100644 --- a/src/plugins/dpdk/CMakeLists.txt +++ b/src/plugins/dpdk/CMakeLists.txt @@ -90,8 +90,10 @@ else() ############################################################################## # libnuma ############################################################################## - vpp_plugin_find_library(dpdk NUMA_LIB "numa") - list(APPEND DPDK_LINK_LIBRARIES ${NUMA_LIB}) + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + vpp_plugin_find_library(dpdk NUMA_LIB "numa") + list(APPEND DPDK_LINK_LIBRARIES ${NUMA_LIB}) + endif() ############################################################################## # Mellanox libraries diff --git a/src/plugins/dpdk/device/cli.c b/src/plugins/dpdk/device/cli.c index c838800deb4..77f9a27f97b 100644 --- a/src/plugins/dpdk/device/cli.c +++ b/src/plugins/dpdk/device/cli.c @@ -89,12 +89,18 @@ show_dpdk_physmem (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { clib_error_t *err = 0; - u32 pipe_max_size; int fds[2]; u8 *s = 0; int n, n_try; FILE *f; + /* + * XXX: Pipes on FreeBSD grow dynamically up to 64KB (FreeBSD 15), don't + * manually tweak this value on FreeBSD at the moment. + */ +#ifdef __linux__ + u32 pipe_max_size; + err = clib_sysfs_read ("/proc/sys/fs/pipe-max-size", "%u", &pipe_max_size); if (err) @@ -112,6 +118,7 @@ show_dpdk_physmem (vlib_main_t * vm, unformat_input_t * input, err = clib_error_return_unix (0, "fcntl(F_SETPIPE_SZ)"); goto error; } +#endif /* __linux__ */ if (fcntl (fds[0], F_SETFL, O_NONBLOCK) == -1) { diff --git a/src/plugins/dpdk/device/common.c b/src/plugins/dpdk/device/common.c index dc6b0c1c952..7a49c5aaef2 100644 --- a/src/plugins/dpdk/device/common.c +++ b/src/plugins/dpdk/device/common.c @@ -491,6 +491,7 @@ dpdk_get_pci_device (const struct rte_eth_dev_info *info) return NULL; } +#ifdef __linux__ /* If this device is VMBUS return pointer to info, otherwise NULL */ struct rte_vmbus_device * dpdk_get_vmbus_device (const struct rte_eth_dev_info *info) @@ -507,6 +508,7 @@ dpdk_get_vmbus_device (const struct rte_eth_dev_info *info) else return NULL; } +#endif /* __linux__ */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h index c22a67a07e7..88a4d9ff618 100644 --- a/src/plugins/dpdk/device/dpdk.h +++ b/src/plugins/dpdk/device/dpdk.h @@ -24,7 +24,9 @@ #include <rte_eal.h> #include <rte_bus_pci.h> +#ifdef __linux__ #include <rte_bus_vmbus.h> +#endif /* __linux__ */ #include <rte_ethdev.h> #include <rte_version.h> #include <rte_net.h> @@ -35,7 +37,9 @@ #include <bus_driver.h> #include <bus_pci_driver.h> +#ifdef __linux__ #include <bus_vmbus_driver.h> +#endif /* __linux__ */ #endif #include <vnet/devices/devices.h> diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index d15cfd7233a..e416efe2e4d 100644 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -187,9 +187,11 @@ dpdk_find_startup_config (struct rte_eth_dev_info *di) { dpdk_main_t *dm = &dpdk_main; struct rte_pci_device *pci_dev; - struct rte_vmbus_device *vmbus_dev; vlib_pci_addr_t pci_addr; +#ifdef __linux__ + struct rte_vmbus_device *vmbus_dev; vlib_vmbus_addr_t vmbus_addr; +#endif /* __linux__ */ uword *p = 0; if ((pci_dev = dpdk_get_pci_device (di))) @@ -202,6 +204,7 @@ dpdk_find_startup_config (struct rte_eth_dev_info *di) hash_get (dm->conf->device_config_index_by_pci_addr, pci_addr.as_u32); } +#ifdef __linux__ if ((vmbus_dev = dpdk_get_vmbus_device (di))) { unformat_input_t input_vmbus; @@ -216,6 +219,7 @@ dpdk_find_startup_config (struct rte_eth_dev_info *di) &vmbus_addr); unformat_free (&input_vmbus); } +#endif /* __linux__ */ if (p) return pool_elt_at_index (dm->conf->dev_confs, p[0]); @@ -566,8 +570,18 @@ dpdk_bind_devices_to_uio (dpdk_config_main_t * conf) continue; } +#ifdef __FreeBSD__ + /* + * The defines for the PCI_CLASS_* types are platform specific and differ + * on FreeBSD. + */ + if (d->device_class != PCI_CLASS_NETWORK && + d->device_class != PCI_CLASS_PROCESSOR_CO) + continue; +#else if (d->device_class != PCI_CLASS_NETWORK_ETHERNET && d->device_class != PCI_CLASS_PROCESSOR_CO) continue; +#endif /* __FreeBSD__ */ if (num_whitelisted) { @@ -1031,12 +1045,14 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) dpdk_main_t *dm = &dpdk_main; clib_error_t *error = 0; dpdk_config_main_t *conf = &dpdk_config_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); dpdk_device_config_t *devconf; vlib_pci_addr_t pci_addr = { 0 }; vlib_vmbus_addr_t vmbus_addr = { 0 }; unformat_input_t sub_input; +#ifdef __linux + vlib_thread_main_t *tm = vlib_get_thread_main (); uword default_hugepage_sz, x; +#endif /* __linux__ */ u8 *s, *tmp = 0; int ret, i; int num_whitelisted = 0; @@ -1045,15 +1061,11 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) u8 no_vmbus = 0; u8 file_prefix = 0; u8 *socket_mem = 0; - u8 *huge_dir_path = 0; u32 vendor, device, domain, bus, func; void *fmt_func; void *fmt_addr; f64 poll_interval; - huge_dir_path = - format (0, "%s/hugepages%c", vlib_unix_get_runtime_dir (), 0); - conf->device_config_index_by_pci_addr = hash_create (0, sizeof (uword)); mhash_init (&conf->device_config_index_by_vmbus_addr, sizeof (uword), sizeof (vlib_vmbus_addr_t)); @@ -1248,6 +1260,11 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) { vec_add1 (conf->eal_init_args, (u8 *) "--in-memory"); +#ifdef __linux__ + /* + * FreeBSD performs huge page prealloc through a dedicated kernel mode + * this process is only required on Linux. + */ default_hugepage_sz = clib_mem_get_default_hugepage_size (); clib_bitmap_foreach (x, tm->cpu_socket_bitmap) @@ -1262,6 +1279,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) if ((e = clib_sysfs_prealloc_hugepages(x, 0, n_pages))) clib_error_report (e); } +#endif /* __linux__ */ } /* on/off dpdk's telemetry thread */ @@ -1270,6 +1288,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) vec_add1 (conf->eal_init_args, (u8 *) "--no-telemetry"); } +#ifdef __linux__ if (!file_prefix) { tmp = format (0, "--file-prefix%c", 0); @@ -1277,6 +1296,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) tmp = format (0, "vpp%c", 0); vec_add1 (conf->eal_init_args, tmp); } +#endif if (no_pci == 0 && geteuid () == 0) dpdk_bind_devices_to_uio (conf); @@ -1396,11 +1416,6 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input) RTE_VECT_SIMD_256 : RTE_VECT_SIMD_512); - /* lazy umount hugepages */ - umount2 ((char *) huge_dir_path, MNT_DETACH); - rmdir ((char *) huge_dir_path); - vec_free (huge_dir_path); - /* main thread 1st */ if ((error = dpdk_buffer_pools_create (vm))) return error; diff --git a/src/plugins/dpdk/main.c b/src/plugins/dpdk/main.c index 47007219482..9781d0ed7f0 100644 --- a/src/plugins/dpdk/main.c +++ b/src/plugins/dpdk/main.c @@ -13,13 +13,6 @@ * limitations under the License. */ -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <linux/vfio.h> -#include <sys/ioctl.h> - #include <vnet/vnet.h> #include <vnet/plugin/plugin.h> #include <dpdk/device/dpdk.h> diff --git a/src/plugins/fateshare/fateshare.c b/src/plugins/fateshare/fateshare.c index 33ee167bce3..971d32303db 100644 --- a/src/plugins/fateshare/fateshare.c +++ b/src/plugins/fateshare/fateshare.c @@ -17,6 +17,7 @@ #include <vnet/vnet.h> #include <vnet/plugin/plugin.h> +#include <vppinfra/unix.h> #include <fateshare/fateshare.h> #include <vlibapi/api.h> @@ -26,7 +27,11 @@ #include <sys/types.h> #include <sys/wait.h> +#ifdef __linux__ #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG +#else +#include <sys/procctl.h> +#endif /* __linux__ */ #include <limits.h> fateshare_main_t fateshare_main; @@ -86,12 +91,23 @@ launch_monitor (fateshare_main_t *kmp) { dup2 (logfd, 1); dup2 (logfd, 2); +#ifdef __linux__ int r = prctl (PR_SET_PDEATHSIG, SIGTERM); if (r == -1) { perror (0); exit (1); } +#else + int r, s = SIGTERM; + + r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s); + if (r == -1) + { + perror (0); + exit (1); + } +#endif /* __linux__ */ pid_t current_ppid = getppid (); if (current_ppid != ppid_before_fork) { @@ -197,24 +213,30 @@ fateshare_config (vlib_main_t *vm, unformat_input_t *input) if (fmp->monitor_cmd == 0) { - char *p, path[PATH_MAX]; - int rv; + char *p; + u8 *path; /* find executable path */ - if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1) + path = os_get_exec_path (); + + if (path == 0) return clib_error_return ( - 0, "could not stat /proc/self/exe - set monitor manually"); + 0, "could not get exec path - set monitor manually"); - /* readlink doesn't provide null termination */ - path[rv] = 0; + /* add null termination */ + vec_add1 (path, 0); /* strip filename */ - if ((p = strrchr (path, '/')) == 0) - return clib_error_return ( - 0, "could not determine vpp directory - set monitor manually"); + if ((p = strrchr ((char *) path, '/')) == 0) + { + vec_free (path); + return clib_error_return ( + 0, "could not determine vpp directory - set monitor manually"); + } *p = 0; fmp->monitor_cmd = format (0, "%s/vpp_fateshare_monitor\0", path); + vec_free (path); } if (fmp->monitor_logfile == 0) { diff --git a/src/plugins/fateshare/vpp_fateshare_monitor.c b/src/plugins/fateshare/vpp_fateshare_monitor.c index 7b203884c4e..7af451ccffe 100644 --- a/src/plugins/fateshare/vpp_fateshare_monitor.c +++ b/src/plugins/fateshare/vpp_fateshare_monitor.c @@ -4,7 +4,12 @@ #include <sys/types.h> #include <sys/wait.h> +#ifdef __linux__ #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG +#else +#include <signal.h> +#include <sys/procctl.h> +#endif /* __linux__ */ #include <sys/stat.h> #include <fcntl.h> @@ -82,6 +87,7 @@ launch_command (char *scmd, char *logname_base) } /* child */ +#ifdef __linux__ int r = prctl (PR_SET_PDEATHSIG, SIGTERM); if (r == -1) { @@ -89,6 +95,17 @@ launch_command (char *scmd, char *logname_base) sleep (5); exit (1); } +#else + int r, s = SIGTERM; + + r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s); + if (r == -1) + { + perror ("procctl"); + exit (1); + } +#endif /* __linux__ */ + if (getppid () != ppid_before_fork) { sleep (5); @@ -180,12 +197,23 @@ main (int argc, char **argv) exit (2); } +#ifdef __linux__ int r = prctl (PR_SET_PDEATHSIG, SIGTERM); if (r == -1) { perror (0); exit (1); } +#else + int r, s = SIGTERM; + + r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s); + if (r == -1) + { + perror ("procctl"); + exit (1); + } +#endif /* __linux__ */ /* Establish handler. */ struct sigaction sa; diff --git a/src/plugins/hs_apps/CMakeLists.txt b/src/plugins/hs_apps/CMakeLists.txt index bd43eb34afa..179c9c7a4c4 100644 --- a/src/plugins/hs_apps/CMakeLists.txt +++ b/src/plugins/hs_apps/CMakeLists.txt @@ -55,7 +55,7 @@ if(VPP_BUILD_VCL_TESTS) ) add_vpp_executable(${test} SOURCES "vcl/${test}.c" - LINK_LIBRARIES vppcom pthread + LINK_LIBRARIES vppcom pthread ${EPOLL_LIB} NO_INSTALL ) endforeach() @@ -68,7 +68,7 @@ if(VPP_BUILD_VCL_TESTS) SOURCES "vcl/${test}.c" vcl/vcl_test_protos.c - LINK_LIBRARIES vppcom pthread + LINK_LIBRARIES vppcom pthread ${EPOLL_LIB} NO_INSTALL ) endforeach() diff --git a/src/plugins/hs_apps/http_cli.c b/src/plugins/hs_apps/http_cli.c index 5d4d49c0fba..f42f65342c3 100644 --- a/src/plugins/hs_apps/http_cli.c +++ b/src/plugins/hs_apps/http_cli.c @@ -323,6 +323,13 @@ hcs_ts_rx_callback (session_t *ts) return 0; } + if (msg.data.len == 0) + { + hs->tx_buf = 0; + start_send_data (hs, HTTP_STATUS_BAD_REQUEST); + return 0; + } + /* send the command to a new/recycled vlib process */ vec_validate (args.buf, msg.data.len - 1); rv = svm_fifo_dequeue (ts->rx_fifo, msg.data.len, args.buf); diff --git a/src/plugins/hs_apps/http_client_cli.c b/src/plugins/hs_apps/http_client_cli.c index f44d4e1bcd1..a99169bafea 100644 --- a/src/plugins/hs_apps/http_client_cli.c +++ b/src/plugins/hs_apps/http_client_cli.c @@ -13,11 +13,9 @@ * limitations under the License. */ -#include <vnet/session/application.h> #include <vnet/session/application_interface.h> #include <vnet/session/session.h> #include <http/http.h> -#include <hs_apps/http_cli.h> #define HCC_DEBUG 0 @@ -68,6 +66,8 @@ typedef struct typedef enum { HCC_REPLY_RECEIVED = 100, + HCC_TRANSPORT_CLOSED, + HCC_CONNECT_FAILED, } hcc_cli_signal_t; static hcc_main_t hcc_main; @@ -136,6 +136,8 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as, { clib_warning ("connected error: hc_index(%d): %U", hc_index, format_session_error, err); + vlib_process_signal_event_mt (hcm->vlib_main, hcm->cli_node_index, + HCC_CONNECT_FAILED, 0); return -1; } @@ -273,6 +275,17 @@ hcc_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf) hcc_session_free (s->thread_index, hs); } +static void +hcc_ts_transport_closed (session_t *s) +{ + hcc_main_t *hcm = &hcc_main; + + HCC_DBG ("transport closed"); + + vlib_process_signal_event_mt (hcm->vlib_main, hcm->cli_node_index, + HCC_TRANSPORT_CLOSED, 0); +} + static session_cb_vft_t hcc_session_cb_vft = { .session_accept_callback = hcc_ts_accept_callback, .session_disconnect_callback = hcc_ts_disconnect_callback, @@ -281,6 +294,7 @@ static session_cb_vft_t hcc_session_cb_vft = { .builtin_app_tx_callback = hcc_ts_tx_callback, .session_reset_callback = hcc_ts_reset_callback, .session_cleanup_callback = hcc_ts_cleanup_callback, + .session_transport_closed_callback = hcc_ts_transport_closed, }; static clib_error_t * @@ -370,7 +384,7 @@ hcc_connect () } static clib_error_t * -hcc_run (vlib_main_t *vm) +hcc_run (vlib_main_t *vm, int print_output) { vlib_thread_main_t *vtm = vlib_get_thread_main (); hcc_main_t *hcm = &hcc_main; @@ -407,11 +421,18 @@ hcc_run (vlib_main_t *vm) goto cleanup; case HCC_REPLY_RECEIVED: - vlib_cli_output (vm, "%v", hcm->http_response); + if (print_output) + vlib_cli_output (vm, "%v", hcm->http_response); vec_free (hcm->http_response); break; + case HCC_TRANSPORT_CLOSED: + err = clib_error_return (0, "error, transport closed"); + break; + case HCC_CONNECT_FAILED: + err = clib_error_return (0, "failed to connect"); + break; default: - clib_error_return (0, "unexpected event %d", event_type); + err = clib_error_return (0, "unexpected event %d", event_type); break; } @@ -448,7 +469,7 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input, u64 seg_size; u8 *appns_id = 0; clib_error_t *err = 0; - int rv; + int rv, print_output = 1; hcm->prealloc_fifos = 0; hcm->private_segment_size = 0; @@ -472,6 +493,8 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input, hcm->fifo_size <<= 10; else if (unformat (line_input, "uri %s", &hcm->uri)) ; + else if (unformat (line_input, "no-output")) + print_output = 0; else if (unformat (line_input, "appns %_%v%_", &appns_id)) ; else if (unformat (line_input, "secret %lu", &hcm->appns_secret)) @@ -506,7 +529,7 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input, vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */); vlib_worker_thread_barrier_release (vm); - err = hcc_run (vm); + err = hcc_run (vm, print_output); if (hcc_detach ()) { @@ -526,7 +549,7 @@ done: VLIB_CLI_COMMAND (hcc_command, static) = { .path = "http cli client", .short_help = "[appns <app-ns> secret <appns-secret>] uri http://<ip-addr> " - "query <query-string>", + "query <query-string> [no-output]", .function = hcc_command_fn, .is_mp_safe = 1, }; diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 036e6929987..893dd877c29 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -74,14 +74,14 @@ format_http_state (u8 *s, va_list *va) return format (s, "unknown"); } -static inline void -http_state_change (http_conn_t *hc, http_state_t state) -{ - HTTP_DBG (1, "changing http state %U -> %U", format_http_state, - hc->http_state, format_http_state, state); - ASSERT (hc->http_state != state); - hc->http_state = state; -} +#define http_state_change(_hc, _state) \ + do \ + { \ + HTTP_DBG (1, "changing http state %U -> %U", format_http_state, \ + (_hc)->http_state, format_http_state, _state); \ + (_hc)->http_state = _state; \ + } \ + while (0) static inline http_worker_t * http_worker_get (u32 thread_index) @@ -140,6 +140,7 @@ http_listener_free (http_conn_t *lhc) { http_main_t *hm = &http_main; + vec_free (lhc->app_name); if (CLIB_DEBUG) memset (lhc, 0xfc, sizeof (*lhc)); pool_put (hm->listener_pool, lhc); @@ -266,17 +267,21 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts, app_worker_t *app_wrk; int rv; + ho_hc = http_conn_get_w_thread (ho_hc_index, 0); + ASSERT (ho_hc->state == HTTP_CONN_STATE_CONNECTING); + if (err) { - clib_warning ("ERROR: %d", err); + clib_warning ("half-open hc index %d, error: %U", ho_hc_index, + format_session_error, err); + app_wrk = app_worker_get_if_valid (ho_hc->h_pa_wrk_index); + if (app_wrk) + app_worker_connect_notify (app_wrk, 0, err, ho_hc->h_pa_app_api_ctx); return 0; } new_hc_index = http_conn_alloc_w_thread (ts->thread_index); hc = http_conn_get_w_thread (new_hc_index, ts->thread_index); - ho_hc = http_conn_get_w_thread (ho_hc_index, 0); - - ASSERT (ho_hc->state == HTTP_CONN_STATE_CONNECTING); clib_memcpy_fast (hc, ho_hc, sizeof (*hc)); @@ -372,12 +377,12 @@ static const char *http_redirect_template = "HTTP/1.1 %s\r\n"; static const char *http_response_template = "HTTP/1.1 %s\r\n" "Date: %U GMT\r\n" "Expires: %U GMT\r\n" - "Server: VPP Static\r\n" + "Server: %s\r\n" "Content-Type: %s\r\n" "Content-Length: %lu\r\n\r\n"; static const char *http_request_template = "GET %s HTTP/1.1\r\n" - "User-Agent: VPP HTTP client\r\n" + "User-Agent: %s\r\n" "Accept: */*\r\n"; static u32 @@ -520,17 +525,19 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp) http_msg_t msg = {}; app_worker_t *app_wrk; session_t *as; - http_status_code_t ec; rv = http_read_message (hc); /* Nothing yet, wait for data or timer expire */ if (rv) - return HTTP_SM_STOP; + { + HTTP_DBG (1, "no data to deq"); + return HTTP_SM_STOP; + } if (vec_len (hc->rx_buf) < 8) { - ec = HTTP_STATUS_BAD_REQUEST; + clib_warning ("response buffer too short"); goto error; } @@ -546,9 +553,7 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp) if (rv) { clib_warning ("failed to parse http reply"); - session_transport_closing_notify (&hc->connection); - http_disconnect_transport (hc); - return -1; + goto error; } msg.data.len = content_length; u32 dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset; @@ -577,7 +582,7 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp) { hc->rx_buf_offset = 0; vec_reset_length (hc->rx_buf); - http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD); + http_state_change (hc, HTTP_STATE_WAIT_APP_METHOD); } else { @@ -585,23 +590,20 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp) } app_wrk = app_worker_get_if_valid (as->app_wrk_index); - app_worker_rx_notify (app_wrk, as); + if (app_wrk) + app_worker_rx_notify (app_wrk, as); return HTTP_SM_STOP; } else { - HTTP_DBG (0, "Unknown http method %v", hc->rx_buf); - ec = HTTP_STATUS_METHOD_NOT_ALLOWED; + clib_warning ("Unknown http method %v", hc->rx_buf); goto error; } - return HTTP_SM_STOP; error: - - http_send_error (hc, ec); session_transport_closing_notify (&hc->connection); + session_transport_closed_notify (&hc->connection); http_disconnect_transport (hc); - return HTTP_SM_ERROR; } @@ -734,6 +736,7 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) * Add headers. For now: * - current time * - expiration time + * - server name * - content type * - data length */ @@ -741,6 +744,10 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) switch (msg.code) { + case HTTP_STATUS_NOT_FOUND: + case HTTP_STATUS_METHOD_NOT_ALLOWED: + case HTTP_STATUS_BAD_REQUEST: + case HTTP_STATUS_INTERNAL_ERROR: case HTTP_STATUS_OK: header = format (0, http_response_template, http_status_code_str[msg.code], @@ -748,6 +755,8 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) format_clib_timebase_time, now, /* Expires */ format_clib_timebase_time, now + 600.0, + /* Server */ + hc->app_name, /* Content type */ http_content_type_str[msg.content_type], /* Length */ @@ -759,6 +768,7 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) /* Location: http(s)://new-place already queued up as data */ break; default: + clib_warning ("unsupported status code: %d", msg.code); return HTTP_SM_ERROR; } @@ -791,7 +801,6 @@ error: static http_sm_result_t http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) { - http_status_code_t sc; http_msg_t msg; session_t *as; u8 *buf = 0, *request; @@ -806,29 +815,31 @@ http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) if (msg.data.type > HTTP_MSG_DATA_PTR) { clib_warning ("no data"); - sc = HTTP_STATUS_INTERNAL_ERROR; goto error; } if (msg.type != HTTP_MSG_REQUEST) { clib_warning ("unexpected message type %d", msg.type); - sc = HTTP_STATUS_INTERNAL_ERROR; goto error; } - sc = msg.code; + /* currently we support only GET method */ + if (msg.method_type != HTTP_REQ_GET) + { + clib_warning ("unsupported method %d", msg.method_type); + goto error; + } vec_validate (buf, msg.data.len - 1); rv = svm_fifo_dequeue (as->tx_fifo, msg.data.len, buf); ASSERT (rv == msg.data.len); - request = format (0, http_request_template, buf); + request = format (0, http_request_template, buf, hc->app_name); offset = http_send_data (hc, request, vec_len (request), 0); if (offset != vec_len (request)) { clib_warning ("sending request failed!"); - sc = HTTP_STATUS_INTERNAL_ERROR; goto error; } @@ -837,83 +848,85 @@ http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) vec_free (buf); vec_free (request); - return HTTP_SM_CONTINUE; + return HTTP_SM_STOP; error: - clib_warning ("unexpected msg type from app %u", msg.type); - http_send_error (hc, sc); + svm_fifo_dequeue_drop_all (as->tx_fifo); session_transport_closing_notify (&hc->connection); + session_transport_closed_notify (&hc->connection); http_disconnect_transport (hc); - return HTTP_SM_STOP; -} - -static void -http_app_enqueue (http_conn_t *hc, session_t *as) -{ - app_worker_t *app_wrk; - u32 dlen, max_enq, n_enq; - int rv; - - dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset; - if (!dlen) - return; - - max_enq = svm_fifo_max_enqueue (as->rx_fifo); - n_enq = clib_min (max_enq, dlen); - rv = svm_fifo_enqueue (as->rx_fifo, n_enq, &hc->rx_buf[hc->rx_buf_offset]); - if (rv < 0) - return; - - hc->rx_buf_offset += rv; - if (hc->rx_buf_offset >= vec_len (hc->rx_buf)) - { - vec_reset_length (hc->rx_buf); - hc->rx_buf_offset = 0; - } - - app_wrk = app_worker_get_if_valid (as->app_wrk_index); - ASSERT (app_wrk); - app_worker_rx_notify (app_wrk, as); + return HTTP_SM_ERROR; } static http_sm_result_t http_state_client_io_more_data (http_conn_t *hc, transport_send_params_t *sp) { session_t *as, *ts; - u32 max_deq; - int n_read; + app_worker_t *app_wrk; + svm_fifo_seg_t _seg, *seg = &_seg; + u32 max_len, max_deq, max_enq, n_segs = 1; + int rv, len; as = session_get_from_handle (hc->h_pa_session_handle); ts = session_get_from_handle (hc->h_tc_session_handle); - http_app_enqueue (hc, as); + max_deq = svm_fifo_max_dequeue (ts->rx_fifo); + if (max_deq == 0) + { + HTTP_DBG (1, "no data to deq"); + return HTTP_SM_STOP; + } - if (hc->to_recv == 0) + max_enq = svm_fifo_max_enqueue (as->rx_fifo); + if (max_enq == 0) { - http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD); + HTTP_DBG (1, "app's rx fifo full"); + svm_fifo_add_want_deq_ntf (as->rx_fifo, SVM_FIFO_WANT_DEQ_NOTIF); return HTTP_SM_STOP; } - max_deq = svm_fifo_max_dequeue (ts->rx_fifo); - if (max_deq > 0) + max_len = clib_min (max_enq, max_deq); + len = svm_fifo_segments (ts->rx_fifo, 0, seg, &n_segs, max_len); + if (len < 0) { - vec_validate (hc->rx_buf, max_deq - 1); - n_read = svm_fifo_dequeue (ts->rx_fifo, max_deq, hc->rx_buf); - ASSERT (n_read == max_deq); + HTTP_DBG (1, "svm_fifo_segments() len %d", len); + return HTTP_SM_STOP; + } - if (svm_fifo_is_empty (ts->rx_fifo)) - svm_fifo_unset_event (ts->rx_fifo); + rv = svm_fifo_enqueue_segments (as->rx_fifo, seg, 1, 0 /* allow partial */); + if (rv < 0) + { + clib_warning ("data enqueue failed, rv: %d", rv); + return HTTP_SM_ERROR; + } - hc->to_recv -= n_read; - vec_set_len (hc->rx_buf, n_read); + svm_fifo_dequeue_drop (ts->rx_fifo, rv); + if (rv > hc->to_recv) + { + clib_warning ("http protocol error: received more data than expected"); + session_transport_closing_notify (&hc->connection); + http_disconnect_transport (hc); + http_state_change (hc, HTTP_STATE_WAIT_APP_METHOD); + return HTTP_SM_ERROR; } + hc->to_recv -= rv; + HTTP_DBG (1, "drained %d from ts; remains %d", rv, hc->to_recv); - if (hc->rx_buf_offset < vec_len (hc->rx_buf) || - svm_fifo_max_dequeue_cons (ts->rx_fifo)) + if (hc->to_recv == 0) { - session_enqueue_notify (ts); + hc->rx_buf_offset = 0; + vec_reset_length (hc->rx_buf); + http_state_change (hc, HTTP_STATE_WAIT_APP_METHOD); } - return HTTP_SM_CONTINUE; + + app_wrk = app_worker_get_if_valid (as->app_wrk_index); + if (app_wrk) + app_worker_rx_notify (app_wrk, as); + + if (svm_fifo_max_dequeue_cons (ts->rx_fifo)) + session_enqueue_notify (ts); + + return HTTP_SM_STOP; } static http_sm_result_t @@ -983,6 +996,7 @@ static void http_req_run_state_machine (http_conn_t *hc, transport_send_params_t *sp) { http_sm_result_t res; + do { res = state_funcs[hc->http_state](hc, sp); @@ -1010,6 +1024,12 @@ http_ts_rx_callback (session_t *ts) return -1; } + if (hc->state == HTTP_CONN_STATE_CLOSED) + { + svm_fifo_dequeue_drop_all (ts->tx_fifo); + return 0; + } + http_req_run_state_machine (hc, 0); if (hc->state == HTTP_CONN_STATE_TRANSPORT_CLOSED) @@ -1153,6 +1173,11 @@ http_transport_connect (transport_endpoint_cfg_t *tep) hc->state = HTTP_CONN_STATE_CONNECTING; cargs->api_context = hc_index; + if (vec_len (app->name)) + hc->app_name = vec_dup (app->name); + else + hc->app_name = format (0, "VPP HTTP client"); + HTTP_DBG (1, "hc ho_index %x", hc_index); if ((error = vnet_connect (cargs))) @@ -1205,6 +1230,11 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep) lhc->c_s_index = app_listener_index; lhc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP; + if (vec_len (app->name)) + lhc->app_name = vec_dup (app->name); + else + lhc->app_name = format (0, "VPP server app"); + return lhc_index; } @@ -1245,7 +1275,11 @@ http_transport_close (u32 hc_index, u32 thread_index) http_disconnect_transport (hc); return; } - + else if (hc->state == HTTP_CONN_STATE_CLOSED) + { + HTTP_DBG (1, "nothing to do, already closed"); + return; + } as = session_get_from_handle (hc->h_pa_session_handle); /* Nothing more to send, confirm close */ diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h index dbae5ac4611..c9912dd6db8 100644 --- a/src/plugins/http/http.h +++ b/src/plugins/http/http.h @@ -227,6 +227,7 @@ typedef struct http_tc_ http_conn_state_t state; u32 timer_handle; + u8 *app_name; /* * Current request diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api index 58b7fc05d9e..de276e7f3ea 100644 --- a/src/plugins/ikev2/ikev2.api +++ b/src/plugins/ikev2/ikev2.api @@ -72,8 +72,6 @@ define ikev2_sa_dump { u32 client_index; u32 context; - - option status = "in_progress"; }; /** \brief Dump all SAs @@ -86,6 +84,17 @@ define ikev2_sa_v2_dump u32 context; }; +/** \brief Dump all SAs + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define ikev2_sa_v3_dump +{ + u32 client_index; + u32 context; + option status = "in_progress"; +}; + /** \brief Details about IKE SA @param context - sender context, to match reply w/ request @param retval - return code @@ -97,7 +106,6 @@ define ikev2_sa_details i32 retval; vl_api_ikev2_sa_t sa; - option status = "in_progress"; }; /** \brief Details about IKE SA @@ -113,6 +121,20 @@ define ikev2_sa_v2_details vl_api_ikev2_sa_v2_t sa; }; +/** \brief Details about IKE SA + @param context - sender context, to match reply w/ request + @param retval - return code + @param sa - SA data +*/ +define ikev2_sa_v3_details +{ + u32 context; + i32 retval; + + vl_api_ikev2_sa_v3_t sa; + option status = "in_progress"; +}; + /** \brief Dump child SA of specific SA @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @@ -125,7 +147,6 @@ define ikev2_child_sa_dump u32 sa_index; option vat_help = "sa_index <index>"; - option status = "in_progress"; }; /** \brief Child SA details @@ -139,6 +160,34 @@ define ikev2_child_sa_details i32 retval; vl_api_ikev2_child_sa_t child_sa; +}; + +/** \brief Dump child SA of specific SA + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sa_index - index of specific sa +*/ +define ikev2_child_sa_v2_dump +{ + u32 client_index; + u32 context; + + u32 sa_index; + option vat_help = "sa_index <index>"; + option status = "in_progress"; +}; + +/** \brief Child SA details + @param context - sender context, to match reply w/ request + @param retval - return code + @param child_sa - child SA data +*/ +define ikev2_child_sa_v2_details +{ + u32 context; + i32 retval; + + vl_api_ikev2_child_sa_v2_t child_sa; option status = "in_progress"; }; diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index d559565487e..9bea2c96d12 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -1888,7 +1888,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) } static ikev2_profile_t * -ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, +ikev2_select_profile (vlib_main_t *vm, ikev2_main_t *km, ikev2_sa_t *sa, ikev2_sa_transform_t *tr_prf, u8 *key_pad) { ikev2_profile_t *ret = 0, *p; @@ -1928,6 +1928,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, if (!clib_memcmp (auth, sa_auth->data, vec_len (sa_auth->data))) { ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED); + sa->auth_timestamp = vlib_time_now (vm); vec_free (auth); ret = p; break; @@ -1946,6 +1947,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, if (ikev2_verify_sign (p->auth.key, sa_auth->data, authmsg) == 1) { ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED); + sa->auth_timestamp = vlib_time_now (vm); ret = p; break; } @@ -1961,7 +1963,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, } static void -ikev2_sa_auth (ikev2_sa_t *sa) +ikev2_sa_auth (ikev2_sa_t *sa, vlib_main_t *vm) { ikev2_main_t *km = &ikev2_main; ikev2_profile_t *sel_p = 0; @@ -1982,7 +1984,7 @@ ikev2_sa_auth (ikev2_sa_t *sa) } key_pad = format (0, "%s", IKEV2_KEY_PAD); - sel_p = ikev2_select_profile (km, sa, tr_prf, key_pad); + sel_p = ikev2_select_profile (vm, km, sa, tr_prf, key_pad); if (sel_p) { @@ -2230,6 +2232,8 @@ ikev2_create_tunnel_interface (vlib_main_t *vm, ikev2_sa_t *sa, clib_memset (&a, 0, sizeof (a)); + child->timestamp = vlib_time_now (vm); + if (!child->r_proposals) { ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); @@ -3424,7 +3428,7 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); res = ikev2_process_auth_req (vm, sa0, ike0, rlen); if (res) - ikev2_sa_auth (sa0); + ikev2_sa_auth (sa0, vm); else vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index bb44e9f364f..c9608aa660b 100644 --- a/src/plugins/ikev2/ikev2_api.c +++ b/src/plugins/ikev2/ikev2_api.c @@ -173,7 +173,7 @@ send_profile (ikev2_profile_t * profile, vl_api_registration_t * reg, rmp->profile.lifetime_jitter = profile->lifetime_jitter; rmp->profile.handover = profile->handover; - vl_api_ikev2_profile_t_endian (&rmp->profile); + vl_api_ikev2_profile_t_endian (&rmp->profile, 1 /* to network */); vl_api_send_msg (reg, (u8 *) rmp); } @@ -291,7 +291,7 @@ send_sa (ikev2_sa_t * sa, vl_api_ikev2_sa_dump_t * mp, u32 api_sa_index) ikev2_copy_stats (&rsa->stats, &sa->stats); - vl_api_ikev2_sa_t_endian(rsa); + vl_api_ikev2_sa_t_endian (rsa, 1 /* to network */); }); } @@ -382,7 +382,7 @@ send_sa_v2 (ikev2_sa_t *sa, vl_api_ikev2_sa_v2_dump_t *mp, u32 api_sa_index) ikev2_copy_stats (&rsa->stats, &sa->stats); - vl_api_ikev2_sa_v2_t_endian (rsa); + vl_api_ikev2_sa_v2_t_endian (rsa, 1 /* to network */); }); } @@ -405,6 +405,100 @@ vl_api_ikev2_sa_v2_dump_t_handler (vl_api_ikev2_sa_v2_dump_t *mp) } static void +send_sa_v3 (ikev2_sa_t *sa, vl_api_ikev2_sa_v3_dump_t *mp, u32 api_sa_index) +{ + ikev2_main_t *km = &ikev2_main; + vl_api_ikev2_sa_v3_details_t *rmp = 0; + int rv = 0; + ikev2_sa_transform_t *tr; + ikev2_profile_t *p; + p = pool_elt_at_index (km->profiles, sa->profile_index); + vlib_main_t *vm = vlib_get_main (); + + REPLY_MACRO2_ZERO (VL_API_IKEV2_SA_V3_DETAILS, { + vl_api_ikev2_sa_v3_t *rsa = &rmp->sa; + vl_api_ikev2_keys_t *k = &rsa->keys; + + int size_data = sizeof (rsa->profile_name) - 1; + if (vec_len (p->name) < size_data) + size_data = vec_len (p->name); + clib_memcpy (rsa->profile_name, p->name, size_data); + + rsa->state = ikev2_state_encode (sa->state); + + rsa->uptime = vlib_time_now (vm) - sa->auth_timestamp; + + rsa->sa_index = api_sa_index; + ip_address_encode2 (&sa->iaddr, &rsa->iaddr); + ip_address_encode2 (&sa->raddr, &rsa->raddr); + rsa->ispi = sa->ispi; + rsa->rspi = sa->rspi; + cp_id (&rsa->i_id, &sa->i_id); + cp_id (&rsa->r_id, &sa->r_id); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + if (tr) + cp_sa_transform (&rsa->encryption, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + if (tr) + cp_sa_transform (&rsa->prf, tr); + + tr = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + cp_sa_transform (&rsa->integrity, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + if (tr) + cp_sa_transform (&rsa->dh, tr); + + k->sk_d_len = vec_len (sa->sk_d); + clib_memcpy (&k->sk_d, sa->sk_d, k->sk_d_len); + + k->sk_ai_len = vec_len (sa->sk_ai); + clib_memcpy (&k->sk_ai, sa->sk_ai, k->sk_ai_len); + + k->sk_ar_len = vec_len (sa->sk_ar); + clib_memcpy (&k->sk_ar, sa->sk_ar, k->sk_ar_len); + + k->sk_ei_len = vec_len (sa->sk_ei); + clib_memcpy (&k->sk_ei, sa->sk_ei, k->sk_ei_len); + + k->sk_er_len = vec_len (sa->sk_er); + clib_memcpy (&k->sk_er, sa->sk_er, k->sk_er_len); + + k->sk_pi_len = vec_len (sa->sk_pi); + clib_memcpy (&k->sk_pi, sa->sk_pi, k->sk_pi_len); + + k->sk_pr_len = vec_len (sa->sk_pr); + clib_memcpy (&k->sk_pr, sa->sk_pr, k->sk_pr_len); + + ikev2_copy_stats (&rsa->stats, &sa->stats); + + vl_api_ikev2_sa_v3_t_endian (rsa, 1 /* to network */); + }); +} + +static void +vl_api_ikev2_sa_v3_dump_t_handler (vl_api_ikev2_sa_v3_dump_t *mp) +{ + ikev2_main_t *km = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + + vec_foreach (tkm, km->per_thread_data) + { + pool_foreach (sa, tkm->sas) + { + u32 api_sa_index = + ikev2_encode_sa_index (sa - tkm->sas, tkm - km->per_thread_data); + send_sa_v3 (sa, mp, api_sa_index); + } + } +} + +static void send_child_sa (ikev2_child_sa_t * child, vl_api_ikev2_child_sa_dump_t * mp, u32 child_sa_index, u32 sa_index) @@ -455,7 +549,7 @@ send_child_sa (ikev2_child_sa_t * child, k->sk_ar_len); } - vl_api_ikev2_child_sa_t_endian (&rmp->child_sa); + vl_api_ikev2_child_sa_t_endian (&rmp->child_sa, 1 /* to network */); }); } @@ -488,6 +582,85 @@ vl_api_ikev2_child_sa_dump_t_handler (vl_api_ikev2_child_sa_dump_t * mp) } static void +send_child_sa_v2 (ikev2_child_sa_t *child, vl_api_ikev2_child_sa_v2_dump_t *mp, + u32 child_sa_index, u32 sa_index) +{ + vl_api_ikev2_child_sa_v2_details_t *rmp = 0; + int rv = 0; + ikev2_sa_transform_t *tr; + vlib_main_t *vm = vlib_get_main (); + + REPLY_MACRO2_ZERO (VL_API_IKEV2_CHILD_SA_V2_DETAILS, { + vl_api_ikev2_keys_t *k = &rmp->child_sa.keys; + rmp->child_sa.child_sa_index = child_sa_index; + rmp->child_sa.uptime = vlib_time_now (vm) - child->timestamp; + rmp->child_sa.sa_index = sa_index; + rmp->child_sa.i_spi = child->i_proposals ? child->i_proposals[0].spi : 0; + rmp->child_sa.r_spi = child->r_proposals ? child->r_proposals[0].spi : 0; + + tr = + ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + if (tr) + cp_sa_transform (&rmp->child_sa.encryption, tr); + + tr = ikev2_sa_get_td_for_type (child->r_proposals, + IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + cp_sa_transform (&rmp->child_sa.integrity, tr); + + tr = + ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ESN); + if (tr) + cp_sa_transform (&rmp->child_sa.esn, tr); + + k->sk_ei_len = vec_len (child->sk_ei); + clib_memcpy (&k->sk_ei, child->sk_ei, k->sk_ei_len); + + k->sk_er_len = vec_len (child->sk_er); + clib_memcpy (&k->sk_er, child->sk_er, k->sk_er_len); + + if (vec_len (child->sk_ai)) + { + k->sk_ai_len = vec_len (child->sk_ai); + clib_memcpy (&k->sk_ai, child->sk_ai, k->sk_ai_len); + + k->sk_ar_len = vec_len (child->sk_ar); + clib_memcpy (&k->sk_ar, child->sk_ar, k->sk_ar_len); + } + + vl_api_ikev2_child_sa_v2_t_endian (&rmp->child_sa, 1 /* to network */); + }); +} + +static void +vl_api_ikev2_child_sa_v2_dump_t_handler (vl_api_ikev2_child_sa_v2_dump_t *mp) +{ + ikev2_main_t *im = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + ikev2_child_sa_t *child; + u32 sai = ~0, ti = ~0; + + ikev2_decode_sa_index (clib_net_to_host_u32 (mp->sa_index), &sai, &ti); + + if (vec_len (im->per_thread_data) <= ti) + return; + + tkm = vec_elt_at_index (im->per_thread_data, ti); + + if (pool_len (tkm->sas) <= sai || pool_is_free_index (tkm->sas, sai)) + return; + + sa = pool_elt_at_index (tkm->sas, sai); + + vec_foreach (child, sa->childs) + { + u32 child_sa_index = child - sa->childs; + send_child_sa_v2 (child, mp, child_sa_index, sai); + } +} + +static void vl_api_ikev2_traffic_selector_dump_t_handler (vl_api_ikev2_traffic_selector_dump_t * mp) { @@ -527,7 +700,7 @@ static void rmp->ts.sa_index = api_sa_index; rmp->ts.child_sa_index = child_sa_index; cp_ts (&rmp->ts, ts, mp->is_initiator); - vl_api_ikev2_ts_t_endian (&rmp->ts); + vl_api_ikev2_ts_t_endian (&rmp->ts, 1 /* to network */); }); } } diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 733ae478b83..975774c48d5 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -74,12 +74,16 @@ format_ikev2_child_sa (u8 * s, va_list * va) ikev2_ts_t *ts; ikev2_sa_transform_t *tr; u8 *c = 0; + vlib_main_t *vm = vlib_get_main (); u32 indent = format_get_indent (s); indent += 1; s = format (s, "child sa %u:", index); + s = format (s, "\n uptime: %f (s)\n ", + vlib_time_now (vm) - child->timestamp); + tr = ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); c = format (c, "%U ", format_ikev2_sa_transform, tr); @@ -135,6 +139,7 @@ format_ikev2_sa (u8 * s, va_list * va) ikev2_sa_transform_t *tr; ikev2_child_sa_t *child; u32 indent = 1; + vlib_main_t *vm = vlib_get_main (); ikev2_main_t *km = &ikev2_main; ikev2_profile_t *p; @@ -168,6 +173,9 @@ format_ikev2_sa (u8 * s, va_list * va) s = format (s, "\n state: %s", stateNames[sa->state]); } + s = + format (s, "\n uptime: %f (s)\n", vlib_time_now (vm) - sa->auth_timestamp); + s = format (s, "\n%U", format_white_space, indent); s = format (s, "nonce i:%U\n%Ur:%U\n", diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index a11538f92c7..0639809e9b1 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -307,6 +307,8 @@ typedef struct f64 time_to_expiration; u8 is_expired; i8 rekey_retries; + + f64 timestamp; } ikev2_child_sa_t; typedef struct @@ -488,6 +490,8 @@ typedef struct u8 keys_generated; ikev2_stats_t stats; + + f64 auth_timestamp; } ikev2_sa_t; diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c index 18d01dc6ffb..93683a5b5dc 100644 --- a/src/plugins/ikev2/ikev2_test.c +++ b/src/plugins/ikev2/ikev2_test.c @@ -391,7 +391,7 @@ vl_api_ikev2_sa_details_t_handler (vl_api_ikev2_sa_details_t * mp) ip_address_t iaddr; ip_address_t raddr; vl_api_ikev2_keys_t *k = &sa->keys; - vl_api_ikev2_sa_t_endian (sa); + vl_api_ikev2_sa_t_endian (sa, 0 /* from network */); ip_address_decode2 (&sa->iaddr, &iaddr); ip_address_decode2 (&sa->raddr, &raddr); @@ -461,7 +461,7 @@ vl_api_ikev2_sa_v2_details_t_handler (vl_api_ikev2_sa_v2_details_t *mp) ip_address_t iaddr; ip_address_t raddr; vl_api_ikev2_keys_t *k = &sa->keys; - vl_api_ikev2_sa_v2_t_endian (sa); + vl_api_ikev2_sa_v2_t_endian (sa, 0 /* from network */); ip_address_decode2 (&sa->iaddr, &iaddr); ip_address_decode2 (&sa->raddr, &raddr); @@ -497,6 +497,76 @@ vl_api_ikev2_sa_v2_details_t_handler (vl_api_ikev2_sa_v2_details_t *mp) } static int +api_ikev2_sa_v3_dump (vat_main_t *vam) +{ + ikev2_test_main_t *im = &ikev2_test_main; + vl_api_ikev2_sa_v3_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + /* Construct the API message */ + M (IKEV2_SA_V3_DUMP, mp); + + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + if (!im->ping_id) + im->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (im->ping_id); + mp_ping->client_index = vam->my_client_index; + vam->result_ready = 0; + + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_ikev2_sa_v3_details_t_handler (vl_api_ikev2_sa_v3_details_t *mp) +{ + vat_main_t *vam = ikev2_test_main.vat_main; + vl_api_ikev2_sa_v3_t *sa = &mp->sa; + ip_address_t iaddr; + ip_address_t raddr; + vl_api_ikev2_keys_t *k = &sa->keys; + vl_api_ikev2_sa_v3_t_endian (sa, 0 /* from network */); + + ip_address_decode2 (&sa->iaddr, &iaddr); + ip_address_decode2 (&sa->raddr, &raddr); + + fformat (vam->ofp, "profile name %s sa index: %d\n", mp->sa.profile_name, + mp->sa.sa_index); + fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip_address, + &iaddr, sa->ispi, format_ip_address, &raddr, sa->rspi); + fformat (vam->ofp, " %U ", format_ikev2_sa_transform, &sa->encryption); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->prf); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->integrity); + fformat (vam->ofp, "%U \n", format_ikev2_sa_transform, &sa->dh); + + fformat (vam->ofp, " SK_d %U\n", format_hex_bytes, k->sk_d, k->sk_d_len); + + fformat (vam->ofp, " SK_a i:%U\n r:%U\n", format_hex_bytes, + k->sk_ai, k->sk_ai_len, format_hex_bytes, k->sk_ar, k->sk_ar_len); + + fformat (vam->ofp, " SK_e i:%U\n r:%U\n", format_hex_bytes, + k->sk_ei, k->sk_ei_len, format_hex_bytes, k->sk_er, k->sk_er_len); + + fformat (vam->ofp, " SK_p i:%U\n r:%U\n", format_hex_bytes, + k->sk_pi, k->sk_pi_len, format_hex_bytes, k->sk_pr, k->sk_pr_len); + + fformat (vam->ofp, " identifier (i) %U\n", format_ikev2_id_type_and_data, + &sa->i_id); + fformat (vam->ofp, " identifier (r) %U\n", format_ikev2_id_type_and_data, + &sa->r_id); + + vam->result_ready = 1; +} + +static int api_ikev2_child_sa_dump (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -549,7 +619,84 @@ vl_api_ikev2_child_sa_details_t_handler (vl_api_ikev2_child_sa_details_t * mp) vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_child_sa_t *child_sa = &mp->child_sa; vl_api_ikev2_keys_t *k = &child_sa->keys; - vl_api_ikev2_child_sa_t_endian (child_sa); + vl_api_ikev2_child_sa_t_endian (child_sa, 0 /* from network */); + + fformat (vam->ofp, " child sa %u:\n", child_sa->child_sa_index); + + fformat (vam->ofp, " %U ", format_ikev2_sa_transform, + &child_sa->encryption); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &child_sa->integrity); + fformat (vam->ofp, "%U \n", format_ikev2_sa_transform, &child_sa->esn); + + fformat (vam->ofp, " spi(i) %lx spi(r) %lx\n", child_sa->i_spi, + child_sa->r_spi); + + fformat (vam->ofp, " SK_e i:%U\n r:%U\n", format_hex_bytes, + k->sk_ei, k->sk_ei_len, format_hex_bytes, k->sk_er, k->sk_er_len); + if (k->sk_ai_len) + { + fformat (vam->ofp, " SK_a i:%U\n r:%U\n", format_hex_bytes, + k->sk_ai, k->sk_ai_len, format_hex_bytes, k->sk_ar, + k->sk_ar_len); + } + vam->result_ready = 1; +} + +static int +api_ikev2_child_sa_v2_dump (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + ikev2_test_main_t *im = &ikev2_test_main; + vl_api_ikev2_child_sa_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + u32 sa_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sa_index %d", &sa_index)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sa_index == ~0) + return -99; + + /* Construct the API message */ + M (IKEV2_CHILD_SA_DUMP, mp); + + mp->sa_index = clib_net_to_host_u32 (sa_index); + + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + if (!im->ping_id) + im->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (im->ping_id); + mp_ping->client_index = vam->my_client_index; + vam->result_ready = 0; + + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_ikev2_child_sa_v2_details_t_handler ( + vl_api_ikev2_child_sa_details_t *mp) +{ + vat_main_t *vam = ikev2_test_main.vat_main; + vl_api_ikev2_child_sa_t *child_sa = &mp->child_sa; + vl_api_ikev2_keys_t *k = &child_sa->keys; + vl_api_ikev2_child_sa_t_endian (child_sa, 0 /* from network */); fformat (vam->ofp, " child sa %u:\n", child_sa->child_sa_index); @@ -637,7 +784,7 @@ static void vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_ts_t *ts = &mp->ts; ip_address_t start_addr, end_addr; - vl_api_ikev2_ts_t_endian (ts); + vl_api_ikev2_ts_t_endian (ts, 0 /* from network */); ip_address_decode2 (&ts->start_addr, &start_addr); ip_address_decode2 (&ts->end_addr, &end_addr); diff --git a/src/plugins/ikev2/ikev2_types.api b/src/plugins/ikev2/ikev2_types.api index f0e50165501..2492611703d 100644 --- a/src/plugins/ikev2/ikev2_types.api +++ b/src/plugins/ikev2/ikev2_types.api @@ -128,6 +128,19 @@ typedef ikev2_child_sa vl_api_ikev2_sa_transform_t esn; }; +typedef ikev2_child_sa_v2 +{ + u32 sa_index; + u32 child_sa_index; + u32 i_spi; + u32 r_spi; + vl_api_ikev2_keys_t keys; + vl_api_ikev2_sa_transform_t encryption; + vl_api_ikev2_sa_transform_t integrity; + vl_api_ikev2_sa_transform_t esn; + f64 uptime; +}; + typedef ikev2_sa_stats { u16 n_keepalives; @@ -197,4 +210,30 @@ typedef ikev2_sa_v2 vl_api_ikev2_sa_transform_t dh; vl_api_ikev2_sa_stats_t stats; +}; + +typedef ikev2_sa_v3 +{ + u32 sa_index; + string profile_name[64]; + vl_api_ikev2_state_t state; + + u64 ispi; + u64 rspi; + vl_api_address_t iaddr; + vl_api_address_t raddr; + + vl_api_ikev2_keys_t keys; + + /* ID */ + vl_api_ikev2_id_t i_id; + vl_api_ikev2_id_t r_id; + + vl_api_ikev2_sa_transform_t encryption; + vl_api_ikev2_sa_transform_t integrity; + vl_api_ikev2_sa_transform_t prf; + vl_api_ikev2_sa_transform_t dh; + + vl_api_ikev2_sa_stats_t stats; + f64 uptime; };
\ No newline at end of file diff --git a/src/plugins/lisp/lisp-cp/lisp_types.h b/src/plugins/lisp/lisp-cp/lisp_types.h index 21bd72178d7..e92f8f80c70 100644 --- a/src/plugins/lisp/lisp-cp/lisp_types.h +++ b/src/plugins/lisp/lisp-cp/lisp_types.h @@ -198,7 +198,8 @@ u8 gid_address_len (gid_address_t * a); void *gid_address_cast (gid_address_t * gid, gid_address_type_t type); void gid_address_copy (gid_address_t * dst, gid_address_t * src); u32 gid_address_parse (u8 * offset, gid_address_t * a); -void gid_address_ip_set (gid_address_t * dst, void *src, u8 version); +void gid_address_ip_set (gid_address_t *dst, void *src, + ip_address_family_t version); #define gid_address_type(_a) (_a)->type #define gid_address_ippref(_a) (_a)->ippref diff --git a/src/plugins/marvell/pp2/cli.c b/src/plugins/marvell/pp2/cli.c index f4ecb1873c9..5072a3c035b 100644 --- a/src/plugins/marvell/pp2/cli.c +++ b/src/plugins/marvell/pp2/cli.c @@ -31,7 +31,7 @@ mrvl_pp2_create_command_fn (vlib_main_t * vm, unformat_input_t * input, { unformat_input_t _line_input, *line_input = &_line_input; mrvl_pp2_create_if_args_t args = { 0 }; - uint val; + unsigned int val; /* Get a line of input. */ if (!unformat_user (input, unformat_line_input, line_input)) diff --git a/src/plugins/nat/nat44-ed/nat44_ed_api.c b/src/plugins/nat/nat44-ed/nat44_ed_api.c index 1f01410afce..b6c9d51d777 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_api.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_api.c @@ -442,7 +442,8 @@ send_nat44_ed_output_interface_details (u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_nat44_ed_output_interface_details_t_endian (rmp); + vl_api_nat44_ed_output_interface_details_t_endian (rmp, + 1 /* to network */); rmp->_vl_msg_id = htons (rmp->_vl_msg_id); rmp->context = htonl (rmp->context); })); diff --git a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c index 4ba51bcaea6..9b4dac3b356 100644 --- a/src/plugins/nat/nat44-ed/nat44_ed_in2out.c +++ b/src/plugins/nat/nat44-ed/nat44_ed_in2out.c @@ -523,6 +523,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, nat_6t_flow_dport_rewrite_set (&s->o2i, l_port); } nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); + nat_6t_flow_saddr_rewrite_set (&s->o2i, r_addr.as_u32); if (nat_ed_alloc_addr_and_port ( sm, rx_fib_index, tx_sw_if_index, proto, thread_index, l_addr, @@ -567,6 +568,7 @@ slow_path_ed (vlib_main_t *vm, snat_main_t *sm, vlib_buffer_t *b, } nat_6t_flow_daddr_rewrite_set (&s->o2i, l_addr.as_u32); nat_6t_flow_txfib_rewrite_set (&s->o2i, rx_fib_index); + nat_6t_flow_saddr_rewrite_set (&s->o2i, r_addr.as_u32); if (nat_ed_ses_o2i_flow_hash_add_del (sm, thread_index, s, 2)) { nat_elog_notice (sm, "out2in key add failed"); diff --git a/src/plugins/nat/nat44-ei/nat44_ei_api.c b/src/plugins/nat/nat44-ei/nat44_ei_api.c index 8671a556929..454a5032c6a 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_api.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_api.c @@ -751,7 +751,8 @@ send_nat44_ei_output_interface_details (u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_nat44_ei_output_interface_details_t_endian (rmp); + vl_api_nat44_ei_output_interface_details_t_endian (rmp, + 1 /* to network */); rmp->_vl_msg_id = htons (rmp->_vl_msg_id); rmp->context = htonl (rmp->context); })); diff --git a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c index 01b333a5234..3b981d69986 100644 --- a/src/plugins/nat/nat44-ei/nat44_ei_in2out.c +++ b/src/plugins/nat/nat44-ei/nat44_ei_in2out.c @@ -859,7 +859,7 @@ nat44_ei_icmp_in2out (vlib_buffer_t *b0, ip4_header_t *ip0, nat44_ei_main_t *nm = &nat44_ei_main; vlib_main_t *vm = vlib_get_main (); ip4_address_t addr; - u16 port; + u16 port = 0; u32 fib_index; nat_protocol_t proto; icmp_echo_header_t *echo0, *inner_echo0 = 0; diff --git a/src/plugins/nat/pnat/pnat_api.c b/src/plugins/nat/pnat/pnat_api.c index 02e61219d1e..a4e7ff192bf 100644 --- a/src/plugins/nat/pnat/pnat_api.c +++ b/src/plugins/nat/pnat/pnat_api.c @@ -116,7 +116,8 @@ static void send_bindings_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_bindings_details_t_endian(rmp); + vl_api_pnat_bindings_details_t_endian( + rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); @@ -158,7 +159,7 @@ static void send_interfaces_details(u32 index, vl_api_registration_t *rp, /* Endian hack until apigen registers _details * endian functions */ - vl_api_pnat_interfaces_details_t_endian(rmp); + vl_api_pnat_interfaces_details_t_endian(rmp, 1 /* to network */); rmp->_vl_msg_id = htons(rmp->_vl_msg_id); rmp->context = htonl(rmp->context); })); diff --git a/src/plugins/netmap/CMakeLists.txt b/src/plugins/netmap/CMakeLists.txt new file mode 100644 index 00000000000..d53a9e0911a --- /dev/null +++ b/src/plugins/netmap/CMakeLists.txt @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2024 Tom Jones <thj@freebsd.org> +# +# This software was developed by Tom Jones <thj@freebsd.org> under sponsorship +# from the FreeBSD Foundation. +# + +if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") + message(WARNING "Netmap is only currently support on FreeBSD - netmap plugin disabled") + return() +endif() + +add_vpp_plugin(netmap + SOURCES + plugin.c + netmap.c + node.c + device.c + cli.c + netmap_api.c + + MULTIARCH_SOURCES + node.c + device.c + + INSTALL_HEADERS + netmap.h + net_netmap.h + + API_FILES + netmap.api +) diff --git a/extras/deprecated/netmap/FEATURE.yaml b/src/plugins/netmap/FEATURE.yaml index e23e5c243e7..a9dfb2163e4 100644 --- a/extras/deprecated/netmap/FEATURE.yaml +++ b/src/plugins/netmap/FEATURE.yaml @@ -1,11 +1,11 @@ --- name: Netmap Device -maintainer: Damjan Marion <damarion@cisco.com> +maintainer: Tom Jones <thj@freebsd.org> features: - L4 checksum offload description: "Create a netmap interface, which is a high speed user-space - interface that allows VPP to patch into a linux namespace, - a linux container, or a physical NIC without the use of DPDK." + interface that allows VPP to patch to a physical or virtual NIC + without the use of DPDK" missing: - API dump state: production diff --git a/extras/deprecated/netmap/cli.c b/src/plugins/netmap/cli.c index 713632947a1..b54d397ecbe 100644 --- a/extras/deprecated/netmap/cli.c +++ b/src/plugins/netmap/cli.c @@ -22,8 +22,8 @@ #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> -#include <vnet/devices/netmap/net_netmap.h> -#include <vnet/devices/netmap/netmap.h> +#include <netmap/net_netmap.h> +#include <netmap/netmap.h> static clib_error_t * netmap_create_command_fn (vlib_main_t * vm, unformat_input_t * input, diff --git a/extras/deprecated/netmap/device.c b/src/plugins/netmap/device.c index 47407aaaa26..505deb988c4 100644 --- a/extras/deprecated/netmap/device.c +++ b/src/plugins/netmap/device.c @@ -23,8 +23,8 @@ #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> -#include <vnet/devices/netmap/net_netmap.h> -#include <vnet/devices/netmap/netmap.h> +#include <netmap/net_netmap.h> +#include <netmap/netmap.h> #define foreach_netmap_tx_func_error \ _(NO_FREE_SLOTS, "no free tx slots") \ diff --git a/extras/deprecated/netmap/net_netmap.h b/src/plugins/netmap/net_netmap.h index fd4253b7c0c..ecccedd4484 100644 --- a/extras/deprecated/netmap/net_netmap.h +++ b/src/plugins/netmap/net_netmap.h @@ -39,10 +39,10 @@ #ifndef _NET_NETMAP_H_ #define _NET_NETMAP_H_ -#define NETMAP_API 11 /* current API version */ +#define NETMAP_API 14 /* current API version */ -#define NETMAP_MIN_API 11 /* min and max versions accepted */ -#define NETMAP_MAX_API 15 +#define NETMAP_MIN_API 14 /* min and max versions accepted */ +#define NETMAP_MAX_API 15 /* * Some fields should be cache-aligned to reduce contention. * The alignment is architecture and OS dependent, but rather than diff --git a/extras/deprecated/netmap/netmap.api b/src/plugins/netmap/netmap.api index a14753cad9c..a14753cad9c 100644 --- a/extras/deprecated/netmap/netmap.api +++ b/src/plugins/netmap/netmap.api diff --git a/extras/deprecated/netmap/netmap.c b/src/plugins/netmap/netmap.c index 7cab6bb0289..ebef215eb3b 100644 --- a/extras/deprecated/netmap/netmap.c +++ b/src/plugins/netmap/netmap.c @@ -20,22 +20,17 @@ #include <sys/ioctl.h> #include <sys/types.h> #include <fcntl.h> -#include <vnet/devices/netmap/net_netmap.h> #include <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vnet/ethernet/ethernet.h> -#include <vnet/devices/netmap/netmap.h> -netmap_main_t netmap_main; +#include <netmap/net_netmap.h> +#include <netmap/netmap.h> +#include <netmap/netmap.api_enum.h> +#include <netmap/netmap.api_types.h> -static u32 -netmap_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, - u32 flags) -{ - /* nothing for now */ - return 0; -} +netmap_main_t netmap_main; static clib_error_t * netmap_fd_read_ready (clib_file_t * uf) @@ -88,12 +83,11 @@ int netmap_worker_thread_enable () { /* if worker threads are enabled, switch to polling mode */ - foreach_vlib_main (( - { - vlib_node_set_state (this_vlib_main, - netmap_input_node.index, - VLIB_NODE_STATE_POLLING); - })); + foreach_vlib_main () + { + vlib_node_set_state (this_vlib_main, netmap_input_node.index, + VLIB_NODE_STATE_POLLING); + } return 0; } @@ -101,12 +95,11 @@ netmap_worker_thread_enable () int netmap_worker_thread_disable () { - foreach_vlib_main (( - { - vlib_node_set_state (this_vlib_main, - netmap_input_node.index, - VLIB_NODE_STATE_INTERRUPT); - })); + foreach_vlib_main () + { + vlib_node_set_state (this_vlib_main, netmap_input_node.index, + VLIB_NODE_STATE_INTERRUPT); + } return 0; } @@ -117,9 +110,9 @@ netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set, { netmap_main_t *nm = &netmap_main; int ret = 0; + uint32_t nr_reg; netmap_if_t *nif = 0; u8 hw_addr[6]; - clib_error_t *error = 0; vnet_sw_interface_t *sw; vnet_main_t *vnm = vnet_get_main (); uword *p; @@ -179,10 +172,39 @@ netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set, reg->refcnt++; nif->nifp = NETMAP_IF (reg->mem, req->nr_offset); - nif->first_rx_ring = 0; - nif->last_rx_ring = 0; - nif->first_tx_ring = 0; - nif->last_tx_ring = 0; + nr_reg = nif->req->nr_flags & NR_REG_MASK; + + if (nr_reg == NR_REG_SW) + { /* host stack */ + nif->first_tx_ring = nif->last_tx_ring = nif->req->nr_tx_rings; + nif->first_rx_ring = nif->last_rx_ring = nif->req->nr_rx_rings; + } + else if (nr_reg == NR_REG_ALL_NIC) + { /* only nic */ + nif->first_tx_ring = 0; + nif->first_rx_ring = 0; + nif->last_tx_ring = nif->req->nr_tx_rings - 1; + nif->last_rx_ring = nif->req->nr_rx_rings - 1; + } + else if (nr_reg == NR_REG_NIC_SW) + { + nif->first_tx_ring = 0; + nif->first_rx_ring = 0; + nif->last_tx_ring = nif->req->nr_tx_rings; + nif->last_rx_ring = nif->req->nr_rx_rings; + } + else if (nr_reg == NR_REG_ONE_NIC) + { + /* XXX check validity */ + nif->first_tx_ring = nif->last_tx_ring = nif->first_rx_ring = + nif->last_rx_ring = nif->req->nr_ringid & NETMAP_RING_MASK; + } + else + { /* pipes */ + nif->first_tx_ring = nif->last_tx_ring = 0; + nif->first_rx_ring = nif->last_rx_ring = 0; + } + nif->host_if_name = if_name; nif->per_interface_next_index = ~0; @@ -213,17 +235,14 @@ netmap_create_if (vlib_main_t * vm, u8 * if_name, u8 * hw_addr_set, hw_addr[1] = 0xfe; } - error = ethernet_register_interface (vnm, netmap_device_class.index, - nif->if_index, hw_addr, - &nif->hw_if_index, - netmap_eth_flag_change); + vnet_eth_interface_registration_t eir = {}; - if (error) - { - clib_error_report (error); - ret = VNET_API_ERROR_SYSCALL_ERROR_1; - goto error; - } + eir.dev_class_index = netmap_device_class.index; + eir.dev_instance = nif->if_index; + eir.address = hw_addr; + eir.cb.set_max_frame_size = NULL; + + nif->hw_if_index = vnet_eth_register_interface (vnm, &eir); sw = vnet_get_hw_sw_interface (vnm, nif->hw_if_index); nif->sw_if_index = sw->sw_if_index; diff --git a/extras/deprecated/netmap/netmap.h b/src/plugins/netmap/netmap.h index 29f855fda8e..29f855fda8e 100644 --- a/extras/deprecated/netmap/netmap.h +++ b/src/plugins/netmap/netmap.h diff --git a/extras/deprecated/netmap/netmap_api.c b/src/plugins/netmap/netmap_api.c index ee05ec22d25..51f572a23e6 100644 --- a/extras/deprecated/netmap/netmap_api.c +++ b/src/plugins/netmap/netmap_api.c @@ -22,23 +22,11 @@ #include <vnet/interface.h> #include <vnet/api_errno.h> -#include <vnet/devices/netmap/netmap.h> +#include <netmap/netmap.h> -#include <vnet/vnet_msg_enum.h> - -#define vl_typedefs /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_typedefs - -#define vl_endianfun /* define message structures */ -#include <vnet/vnet_all_api_h.h> -#undef vl_endianfun - -/* instantiate all the print functions we know about */ -#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__) -#define vl_printfun -#include <vnet/vnet_all_api_h.h> -#undef vl_printfun +#include <vnet/format_fns.h> +#include <netmap/netmap.api_enum.h> +#include <netmap/netmap.api_types.h> #include <vlibapi/api_helper_macros.h> @@ -84,44 +72,14 @@ vl_api_netmap_delete_t_handler (vl_api_netmap_delete_t * mp) REPLY_MACRO (VL_API_NETMAP_DELETE_REPLY); } -/* - * netmap_api_hookup - * Add vpe's API message handlers to the table. - * vlib has already mapped shared memory and - * added the client registration handlers. - * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process() - */ -#define vl_msg_name_crc_list -#include <vnet/vnet_all_api_h.h> -#undef vl_msg_name_crc_list - -static void -setup_message_id_table (api_main_t * am) -{ -#define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id); - foreach_vl_msg_name_crc_netmap; -#undef _ -} - +#include <netmap/netmap.api.c> static clib_error_t * netmap_api_hookup (vlib_main_t * vm) { - api_main_t *am = vlibapi_get_main (); - -#define _(N,n) \ - vl_msg_api_set_handlers(VL_API_##N, #n, \ - vl_api_##n##_t_handler, \ - vl_noop_handler, \ - vl_api_##n##_t_endian, \ - vl_api_##n##_t_print, \ - sizeof(vl_api_##n##_t), 1); - foreach_vpe_api_msg; -#undef _ - /* * Set up the (msg_name, crc, message-id) table */ - setup_message_id_table (am); + setup_message_id_table (); return 0; } diff --git a/extras/deprecated/netmap/node.c b/src/plugins/netmap/node.c index b0a68824b9c..6169847fa79 100644 --- a/extras/deprecated/netmap/node.c +++ b/src/plugins/netmap/node.c @@ -25,8 +25,8 @@ #include <vnet/devices/devices.h> #include <vnet/feature/feature.h> -#include <vnet/devices/netmap/net_netmap.h> -#include <vnet/devices/netmap/netmap.h> +#include <netmap/net_netmap.h> +#include <netmap/netmap.h> #define foreach_netmap_input_error @@ -112,7 +112,7 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, n_free_bufs += vlib_buffer_alloc (vm, &nm->rx_buffers[thread_index][n_free_bufs], VLIB_FRAME_SIZE); - _vec_len (nm->rx_buffers[thread_index]) = n_free_bufs; + vec_set_len (nm->rx_buffers[thread_index], n_free_bufs); } cur_ring = nif->first_rx_ring; @@ -166,7 +166,8 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, prev_bi0 = bi0; bi0 = nm->rx_buffers[thread_index][last_empty_buffer]; b0 = vlib_get_buffer (vm, bi0); - _vec_len (nm->rx_buffers[thread_index]) = last_empty_buffer; + vec_set_len (nm->rx_buffers[thread_index], + last_empty_buffer); n_free_bufs--; /* copy data */ @@ -200,11 +201,12 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, /* trace */ if (PREDICT_FALSE (n_trace > 0)) { - if (PREDICT_TRUE (first_b0 != 0)) + if (PREDICT_TRUE (first_b0 != 0) && + vlib_trace_buffer (vm, node, next0, first_b0, + /* follow_chain */ 0)) { netmap_input_trace_t *tr; - vlib_trace_buffer (vm, node, next0, first_b0, - /* follow_chain */ 0); + vlib_set_trace_count (vm, node, --n_trace); tr = vlib_add_trace (vm, node, first_b0, sizeof (*tr)); tr->next_index = next0; @@ -213,10 +215,6 @@ netmap_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, } } - /* redirect if feature path enabled */ - vnet_feature_start_device_input_x1 (nif->sw_if_index, &next0, - first_b0); - /* enque and take next packet */ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, n_left_to_next, first_bi0, diff --git a/src/plugins/netmap/plugin.c b/src/plugins/netmap/plugin.c new file mode 100644 index 00000000000..1673225b683 --- /dev/null +++ b/src/plugins/netmap/plugin.c @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Tom Jones <thj@freebsd.org> + * + * This software was developed by Tom Jones <thj@freebsd.org> under sponsorship + * from the FreeBSD Foundation. + * + */ + +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vpp/app/version.h> + +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "netmap", +}; diff --git a/src/plugins/srmpls/CMakeLists.txt b/src/plugins/srmpls/CMakeLists.txt new file mode 100644 index 00000000000..25905d31e1b --- /dev/null +++ b/src/plugins/srmpls/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2024 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. + +add_vpp_plugin(srmpls + SOURCES + sr_mpls_policy.c + sr_mpls_steering.c + sr_mpls_api.c + plugin.c + + INSTALL_HEADERS + sr_mpls.h + + API_FILES + sr_mpls.api + + # This might need to be VAT_AUTO_TEST? Not documented + API_TEST_SOURCES + sr_mpls_test.c +) diff --git a/src/vnet/srmpls/FEATURE.yaml b/src/plugins/srmpls/FEATURE.yaml index c5b958224c7..c5b958224c7 100644 --- a/src/vnet/srmpls/FEATURE.yaml +++ b/src/plugins/srmpls/FEATURE.yaml diff --git a/src/vnet/srmpls/dir.dox b/src/plugins/srmpls/dir.dox index 76ec1d6a41b..76ec1d6a41b 100644 --- a/src/vnet/srmpls/dir.dox +++ b/src/plugins/srmpls/dir.dox diff --git a/extras/deprecated/netmap/dir.dox b/src/plugins/srmpls/plugin.c index 7ddbf947c29..af87607764f 100644 --- a/extras/deprecated/netmap/dir.dox +++ b/src/plugins/srmpls/plugin.c @@ -1,6 +1,7 @@ /* - * Copyright (c) 2017 Cisco and/or its affiliates. + * plugin.c: srmpls * + * Copyright (c) 2024 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: @@ -14,14 +15,12 @@ * limitations under the License. */ -/* Doxygen directory documentation */ +#include <vlib/vlib.h> +#include <vnet/plugin/plugin.h> +#include <vpp/app/version.h> -/** -@dir -@brief netmap Interface Implementation. - -This directory contains the source code for the netmap driver. - -*/ -/*? %%clicmd:group_label netmap %% ?*/ -/*? %%syscfg:group_label netmap %% ?*/ +// register a plugin +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "Segment Routing for MPLS plugin", +}; diff --git a/src/vnet/srmpls/sr_doc.rst b/src/plugins/srmpls/sr_doc.rst index ed847fa0d42..ed847fa0d42 100644 --- a/src/vnet/srmpls/sr_doc.rst +++ b/src/plugins/srmpls/sr_doc.rst diff --git a/src/vnet/srmpls/sr_mpls.api b/src/plugins/srmpls/sr_mpls.api index 742f135d493..742f135d493 100644 --- a/src/vnet/srmpls/sr_mpls.api +++ b/src/plugins/srmpls/sr_mpls.api diff --git a/src/vnet/srmpls/sr_mpls.h b/src/plugins/srmpls/sr_mpls.h index a8f9494428f..a8f9494428f 100644 --- a/src/vnet/srmpls/sr_mpls.h +++ b/src/plugins/srmpls/sr_mpls.h diff --git a/src/vnet/srmpls/sr_mpls_api.c b/src/plugins/srmpls/sr_mpls_api.c index 920856acff6..3e89017dbc1 100644 --- a/src/vnet/srmpls/sr_mpls_api.c +++ b/src/plugins/srmpls/sr_mpls_api.c @@ -17,7 +17,7 @@ */ #include <vnet/vnet.h> -#include <vnet/srmpls/sr_mpls.h> +#include "sr_mpls.h" #include <vlibmemory/api.h> #include <vnet/interface.h> @@ -26,28 +26,27 @@ #include <vnet/ip/ip_types_api.h> #include <vnet/format_fns.h> -#include <vnet/srmpls/sr_mpls.api_enum.h> -#include <vnet/srmpls/sr_mpls.api_types.h> - +#include <plugins/srmpls/sr_mpls.api_enum.h> +#include <plugins/srmpls/sr_mpls.api_types.h> #define vl_api_version(n, v) static u32 api_version = v; -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_api_version #define vl_endianfun -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_endianfun #define vl_calcsizefun -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_calcsizefun #define vl_printfun -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_printfun #define vl_msg_name_crc_list -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_msg_name_crc_list #define REPLY_MSG_ID_BASE msg_id_base diff --git a/src/vnet/srmpls/sr_mpls_policy.c b/src/plugins/srmpls/sr_mpls_policy.c index 41cb71601e9..af24acd8cf6 100644 --- a/src/vnet/srmpls/sr_mpls_policy.c +++ b/src/plugins/srmpls/sr_mpls_policy.c @@ -31,7 +31,7 @@ #include <vlib/vlib.h> #include <vnet/vnet.h> -#include <vnet/srmpls/sr_mpls.h> +#include "sr_mpls.h" #include <vnet/fib/mpls_fib.h> #include <vnet/dpo/dpo.h> #include <vnet/ip/ip.h> diff --git a/src/vnet/srmpls/sr_mpls_steering.c b/src/plugins/srmpls/sr_mpls_steering.c index e8920df542b..24c8b0e2d9f 100644 --- a/src/vnet/srmpls/sr_mpls_steering.c +++ b/src/plugins/srmpls/sr_mpls_steering.c @@ -31,7 +31,7 @@ #include <vlib/vlib.h> #include <vnet/vnet.h> -#include <vnet/srmpls/sr_mpls.h> +#include "sr_mpls.h" #include <vnet/ip/ip4_packet.h> #include <vnet/ip/ip6_packet.h> #include <vnet/fib/mpls_fib.h> diff --git a/src/vnet/srmpls/sr_mpls_test.c b/src/plugins/srmpls/sr_mpls_test.c index e5d68462443..7aff4c32b06 100644 --- a/src/vnet/srmpls/sr_mpls_test.c +++ b/src/plugins/srmpls/sr_mpls_test.c @@ -25,11 +25,11 @@ /* Declare message IDs */ #include <vnet/format_fns.h> -#include <vnet/srmpls/sr_mpls.api_enum.h> -#include <vnet/srmpls/sr_mpls.api_types.h> +#include <plugins/srmpls/sr_mpls.api_enum.h> +#include <plugins/srmpls/sr_mpls.api_types.h> #define vl_endianfun /* define message structures */ -#include <vnet/srmpls/sr_mpls.api.h> +#include <plugins/srmpls/sr_mpls.api.h> #undef vl_endianfun typedef struct @@ -163,7 +163,7 @@ api_sr_mpls_policy_del (vat_main_t *vam) return ret; } -#include <vnet/srmpls/sr_mpls.api_test.c> +#include <plugins/srmpls/sr_mpls.api_test.c> /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/tlsopenssl/tls_openssl.c b/src/plugins/tlsopenssl/tls_openssl.c index 98982439b96..5d172a0adcf 100644 --- a/src/plugins/tlsopenssl/tls_openssl.c +++ b/src/plugins/tlsopenssl/tls_openssl.c @@ -1179,18 +1179,13 @@ int tls_openssl_set_ciphers (char *ciphers) { openssl_main_t *om = &openssl_main; - int i; if (!ciphers) { return -1; } - vec_validate (om->ciphers, strlen (ciphers)); - for (i = 0; i < vec_len (om->ciphers) - 1; i++) - { - om->ciphers[i] = toupper (ciphers[i]); - } + vec_validate_init_c_string (om->ciphers, ciphers, strlen (ciphers)); return 0; diff --git a/src/plugins/unittest/gso_test.c b/src/plugins/unittest/gso_test.c index 54eb7422c87..43c614341d2 100644 --- a/src/plugins/unittest/gso_test.c +++ b/src/plugins/unittest/gso_test.c @@ -96,12 +96,94 @@ GSO_TEST_REGISTER_DATA (gso_ipv6_tcp, static) = { .is_ip6 = 1, }; +/* + * this does not support tunnel packets + */ +static void +set_hdr_offsets (vlib_buffer_t *b0, u8 is_l2) +{ + u16 ethertype = 0, l2hdr_sz = 0; + vnet_buffer_oflags_t oflags = 0; + u8 l4_proto = 0; + + if (!is_l2) + { + switch (b0->data[0] & 0xf0) + { + case 0x40: + ethertype = ETHERNET_TYPE_IP4; + break; + case 0x60: + ethertype = ETHERNET_TYPE_IP6; + break; + } + } + else + { + ethernet_header_t *eh = (ethernet_header_t *) b0->data; + ethertype = clib_net_to_host_u16 (eh->type); + l2hdr_sz = sizeof (ethernet_header_t); + + if (ethernet_frame_is_tagged (ethertype)) + { + ethernet_vlan_header_t *vlan = (ethernet_vlan_header_t *) (eh + 1); + + ethertype = clib_net_to_host_u16 (vlan->type); + l2hdr_sz += sizeof (*vlan); + if (ethertype == ETHERNET_TYPE_VLAN) + { + vlan++; + ethertype = clib_net_to_host_u16 (vlan->type); + l2hdr_sz += sizeof (*vlan); + } + } + } + + vnet_buffer (b0)->l2_hdr_offset = 0; + vnet_buffer (b0)->l3_hdr_offset = l2hdr_sz; + + if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP4)) + { + ip4_header_t *ip4 = (ip4_header_t *) (b0->data + l2hdr_sz); + vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + ip4_header_bytes (ip4); + l4_proto = ip4->protocol; + oflags |= VNET_BUFFER_OFFLOAD_F_IP_CKSUM; + b0->flags |= (VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_L2_HDR_OFFSET_VALID | + VNET_BUFFER_F_L3_HDR_OFFSET_VALID | + VNET_BUFFER_F_L4_HDR_OFFSET_VALID); + } + else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6)) + { + ip6_header_t *ip6 = (ip6_header_t *) (b0->data + l2hdr_sz); + vnet_buffer (b0)->l4_hdr_offset = l2hdr_sz + sizeof (ip6_header_t); + /* FIXME IPv6 EH traversal */ + l4_proto = ip6->protocol; + b0->flags |= (VNET_BUFFER_F_IS_IP6 | VNET_BUFFER_F_L2_HDR_OFFSET_VALID | + VNET_BUFFER_F_L3_HDR_OFFSET_VALID | + VNET_BUFFER_F_L4_HDR_OFFSET_VALID); + } + if (l4_proto == IP_PROTOCOL_TCP) + { + oflags |= VNET_BUFFER_OFFLOAD_F_TCP_CKSUM; + } + else if (l4_proto == IP_PROTOCOL_UDP) + { + oflags |= VNET_BUFFER_OFFLOAD_F_UDP_CKSUM; + } + if (oflags) + vnet_buffer_offload_flags_set (b0, oflags); +} + static u32 -fill_buffers (vlib_main_t *vm, u32 *buffer_indices, u8 *data, u32 data_size, - u32 n_buffers, u32 buffer_size, u32 packet_size, u32 gso_size, - u32 l4_hdr_len) +fill_buffers (vlib_main_t *vm, u32 *buffer_indices, + gso_test_data_t *gso_test_data, u32 n_buffers, u32 buffer_size, + u32 packet_size, u32 gso_size) { u32 i; + u8 *data = gso_test_data->data; + u32 data_size = gso_test_data->data_size; + u32 l4_hdr_len = gso_test_data->l4_hdr_len; + u8 is_l2 = gso_test_data->is_l2; for (i = 0; i < n_buffers; i++) { @@ -153,6 +235,8 @@ fill_buffers (vlib_main_t *vm, u32 *buffer_indices, u8 *data, u32 data_size, len += fill_data_size; } while (k < n_bufs); + + set_hdr_offsets (b, is_l2); b->flags |= VNET_BUFFER_F_GSO; vnet_buffer2 (b)->gso_size = gso_size; vnet_buffer2 (b)->gso_l4_hdr_sz = l4_hdr_len; @@ -165,17 +249,14 @@ fill_buffers (vlib_main_t *vm, u32 *buffer_indices, u8 *data, u32 data_size, static_always_inline u32 gso_segment_buffer_test (vlib_main_t *vm, u32 bi, - vnet_interface_per_thread_data_t *ptd, u8 is_l2, - u8 is_ip6) + vnet_interface_per_thread_data_t *ptd, u8 is_l2) { vlib_buffer_t *b = vlib_get_buffer (vm, bi); - generic_header_offset_t gho = { 0 }; u32 n_tx_bytes = 0; if (PREDICT_TRUE (b->flags & VNET_BUFFER_F_GSO)) { - vnet_generic_header_offset_parser (b, &gho, is_l2, !is_ip6, is_ip6); - n_tx_bytes = gso_segment_buffer_inline (vm, ptd, b, &gho, is_l2, is_ip6); + n_tx_bytes = gso_segment_buffer_inline (vm, ptd, b, is_l2); } return n_tx_bytes; @@ -237,19 +318,16 @@ test_gso_perf (vlib_main_t *vm, gso_test_main_t *gtm) vlib_buffer_free (vm, buffer_indices, n_alloc); goto done; } - n_filled = - fill_buffers (vm, buffer_indices, gso_test_data->data, - gso_test_data->data_size, n_buffers, buffer_size, - packet_size, gso_size, gso_test_data->l4_hdr_len); + n_filled = fill_buffers (vm, buffer_indices, gso_test_data, n_buffers, + buffer_size, packet_size, gso_size); u8 is_l2 = gso_test_data->is_l2; - u8 is_ip6 = gso_test_data->is_ip6; for (k = 0; k < warmup_rounds; k++) { for (j = 0; j < n_filled; j++) - gso_segment_buffer_test (vm, buffer_indices[j], &ptd[j], is_l2, - is_ip6); + gso_segment_buffer_test (vm, buffer_indices[j], &ptd[j], is_l2); + for (j = 0; j < n_filled; j++) { vlib_buffer_free (vm, ptd[j].split_buffers, @@ -264,8 +342,9 @@ test_gso_perf (vlib_main_t *vm, gso_test_main_t *gtm) { t0 = clib_cpu_time_now (); for (j = 0; j < n_filled; j++) - gso_segment_buffer_test (vm, buffer_indices[j], &ptd[j], is_l2, - is_ip6); + gso_segment_buffer_test (vm, buffer_indices[j], &ptd[j], + is_l2); + t1 = clib_cpu_time_now (); t2[i] += (t1 - t0); for (j = 0; j < n_filled; j++) diff --git a/src/plugins/unittest/policer_test.c b/src/plugins/unittest/policer_test.c index 2b14bf687bf..41f769960a3 100644 --- a/src/plugins/unittest/policer_test.c +++ b/src/plugins/unittest/policer_test.c @@ -21,7 +21,7 @@ policer_test (vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd_arg) { int policer_index, i; - uint rate_kbps, burst, num_pkts; + unsigned int rate_kbps, burst, num_pkts; double total_bytes, cpu_ticks_per_pkt, time = 0; double cpu_speed, cpu_ticks_per_byte; policer_result_e result, input_colour = POLICE_CONFORM; diff --git a/src/plugins/wireguard/wireguard_chachapoly.c b/src/plugins/wireguard/wireguard_chachapoly.c index 0dd7908d2e2..ad644ff6cb8 100644 --- a/src/plugins/wireguard/wireguard_chachapoly.c +++ b/src/plugins/wireguard/wireguard_chachapoly.c @@ -72,11 +72,11 @@ wg_xchacha20poly1305_encrypt (vlib_main_t *vm, u8 *src, u32 src_len, u8 *dst, u64 h_nonce; clib_memcpy (&h_nonce, nonce + 16, sizeof (h_nonce)); - h_nonce = le64toh (h_nonce); + h_nonce = clib_little_to_host_u64 (h_nonce); hchacha20 (derived_key, nonce, key); for (i = 0; i < (sizeof (derived_key) / sizeof (derived_key[0])); i++) - (derived_key[i]) = htole32 ((derived_key[i])); + (derived_key[i]) = clib_host_to_little_u32 ((derived_key[i])); uint32_t key_idx; @@ -102,11 +102,11 @@ wg_xchacha20poly1305_decrypt (vlib_main_t *vm, u8 *src, u32 src_len, u8 *dst, u64 h_nonce; clib_memcpy (&h_nonce, nonce + 16, sizeof (h_nonce)); - h_nonce = le64toh (h_nonce); + h_nonce = clib_little_to_host_u64 (h_nonce); hchacha20 (derived_key, nonce, key); for (i = 0; i < (sizeof (derived_key) / sizeof (derived_key[0])); i++) - (derived_key[i]) = htole32 ((derived_key[i])); + (derived_key[i]) = clib_host_to_little_u32 ((derived_key[i])); uint32_t key_idx; diff --git a/src/plugins/wireguard/wireguard_noise.c b/src/plugins/wireguard/wireguard_noise.c index 5fe2e44b03b..c3f28f442f5 100644 --- a/src/plugins/wireguard/wireguard_noise.c +++ b/src/plugins/wireguard/wireguard_noise.c @@ -751,8 +751,8 @@ noise_tai64n_now (uint8_t output[NOISE_TIMESTAMP_LEN]) unix_nanosec &= REJECT_INTERVAL_MASK; /* https://cr.yp.to/libtai/tai64.html */ - sec = htobe64 (0x400000000000000aULL + unix_sec); - nsec = htobe32 (unix_nanosec); + sec = clib_host_to_big_u64 (0x400000000000000aULL + unix_sec); + nsec = clib_host_to_big_u32 (unix_nanosec); /* memcpy to output buffer, assuming output could be unaligned. */ clib_memcpy (output, &sec, sizeof (sec)); diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py index fb7de0a023f..c2e1e7da7b7 100755 --- a/src/tools/vppapigen/vppapigen_c.py +++ b/src/tools/vppapigen/vppapigen_c.py @@ -365,7 +365,7 @@ class FromJSON: write(" char *p = cJSON_GetStringValue(item);\n") write(" size_t plen = strlen(p);\n") write( - " {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen, {msgsize});\n".format( + " {msgvar} = cJSON_realloc({msgvar}, {msgsize} + plen);\n".format( msgvar=msgvar, msgsize=msgsize ) ) @@ -434,7 +434,7 @@ class FromJSON: cJSON *array = cJSON_GetObjectItem(o, "{n}"); int size = cJSON_GetArraySize(array); {lfield} = size; - {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size, {msgsize}); + {realloc} = cJSON_realloc({realloc}, {msgsize} + sizeof({t}) * size); {t} *d = (void *){realloc} + {msgsize}; {msgsize} += sizeof({t}) * size; for (i = 0; i < size; i++) {{ @@ -461,12 +461,12 @@ class FromJSON: write( " {realloc} = cJSON_realloc({realloc}, {msgsize} + " - "vec_len(s), {msgsize});\n".format( + "vec_len(s));\n".format( msgvar=msgvar, msgsize=msgsize, realloc=realloc ) ) write( - " memcpy((void *){realloc} + {msgsize}, s, " + " clib_memcpy((void *){realloc} + {msgsize}, s, " "vec_len(s));\n".format(realloc=realloc, msgsize=msgsize) ) write(" {msgsize} += vec_len(s);\n".format(msgsize=msgsize)) @@ -1143,20 +1143,14 @@ ENDIAN_STRINGS = { } -def get_endian_string(o, type): +def get_endian_string(o, fieldtype): """Return proper endian string conversion function""" - try: - if o.to_network: - return ENDIAN_STRINGS[type].replace("net_to_host", "host_to_net") - except: - pass - return ENDIAN_STRINGS[type] + return ENDIAN_STRINGS[fieldtype] def endianfun_array(o): """Generate endian functions for arrays""" forloop = """\ - {comment} ASSERT((u32){length} <= (u32)VL_API_MAX_ARRAY_SIZE); for (i = 0; i < {length}; i++) {{ a->{name}[i] = {format}(a->{name}[i]); @@ -1165,31 +1159,26 @@ def endianfun_array(o): forloop_format = """\ for (i = 0; i < {length}; i++) {{ - {type}_endian(&a->{name}[i]); + {type}_endian(&a->{name}[i], to_net); }} """ - to_network_comment = "" - try: - if o.to_network: - to_network_comment = """/* - * Array fields processed first to handle variable length arrays and size - * field endian conversion in the proper order for to-network messages. - * Message fields have been sorted by type in the code generator, thus fields - * in this generated code may be converted in a different order than specified - * in the *.api file. - */""" - except: - pass - output = "" if o.fieldtype == "u8" or o.fieldtype == "string" or o.fieldtype == "bool": output += " /* a->{n} = a->{n} (no-op) */\n".format(n=o.fieldname) else: lfield = "a->" + o.lengthfield if o.lengthfield else o.length + if o.lengthfield: + output += ( + f" u32 count = to_net ? clib_host_to_net_u32(a->{o.lengthfield}) : " + f"a->{o.lengthfield};\n" + ) + lfield = "count" + else: + lfield = o.length + if o.fieldtype in ENDIAN_STRINGS: output += forloop.format( - comment=to_network_comment, length=lfield, format=get_endian_string(o, o.fieldtype), name=o.fieldname, @@ -1222,7 +1211,7 @@ def endianfun_obj(o): name=o.fieldname, format=get_endian_string(o, o.fieldtype) ) elif o.fieldtype.startswith("vl_api_"): - output += " {type}_endian(&a->{name});\n".format( + output += " {type}_endian(&a->{name}, to_net);\n".format( type=o.fieldtype, name=o.fieldname ) else: @@ -1254,19 +1243,12 @@ def endianfun(objs, modulename): output = output.format(module=modulename) signature = """\ -static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a) +static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a, bool to_net) {{ int i __attribute__((unused)); """ for t in objs: - # Outbound (to network) messages are identified by message nomenclature - # i.e. message names ending with these suffixes are 'to network' - if t.name.endswith("_reply") or t.name.endswith("_details"): - t.to_network = True - else: - t.to_network = False - if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag": output += signature.format(name=t.name) if t.enumtype in ENDIAN_STRINGS: @@ -1300,15 +1282,7 @@ static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a) output += signature.format(name=t.name) - # For outbound (to network) messages: - # some arrays have dynamic length -- iterate over - # them before changing endianness for the length field - # by making the Array types show up first - if t.to_network: - t.block.sort(key=lambda x: x.type) - for o in t.block: - o.to_network = t.to_network output += endianfun_obj(o) output += "}\n\n" @@ -1852,7 +1826,7 @@ api_{n} (cJSON *o) }} mp->_vl_msg_id = vac_get_msg_index(VL_API_{N}_CRC); - vl_api_{n}_t_endian(mp); + vl_api_{n}_t_endian(mp, 1); vac_write((char *)mp, len); cJSON_free(mp); @@ -1867,7 +1841,7 @@ api_{n} (cJSON *o) return 0; }} vl_api_{r}_t *rmp = (vl_api_{r}_t *)p; - vl_api_{r}_t_endian(rmp); + vl_api_{r}_t_endian(rmp, 0); return vl_api_{r}_t_tojson(rmp); }} @@ -1885,7 +1859,7 @@ api_{n} (cJSON *o) return 0; }} mp->_vl_msg_id = msg_id; - vl_api_{n}_t_endian(mp); + vl_api_{n}_t_endian(mp, 1); vac_write((char *)mp, len); cJSON_free(mp); @@ -1919,7 +1893,7 @@ api_{n} (cJSON *o) return 0; }} vl_api_{r}_t *rmp = (vl_api_{r}_t *)p; - vl_api_{r}_t_endian(rmp); + vl_api_{r}_t_endian(rmp, 0); cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp)); }} }} @@ -1941,7 +1915,7 @@ api_{n} (cJSON *o) }} mp->_vl_msg_id = msg_id; - vl_api_{n}_t_endian(mp); + vl_api_{n}_t_endian(mp, 1); vac_write((char *)mp, len); cJSON_free(mp); @@ -1962,14 +1936,14 @@ api_{n} (cJSON *o) u16 msg_id = ntohs(*((u16 *)p)); if (msg_id == reply_msg_id) {{ vl_api_{r}_t *rmp = (vl_api_{r}_t *)p; - vl_api_{r}_t_endian(rmp); + vl_api_{r}_t_endian(rmp, 0); cJSON_AddItemToArray(reply, vl_api_{r}_t_tojson(rmp)); break; }} if (msg_id == details_msg_id) {{ vl_api_{d}_t *rmp = (vl_api_{d}_t *)p; - vl_api_{d}_t_endian(rmp); + vl_api_{d}_t_endian(rmp, 0); cJSON_AddItemToArray(reply, vl_api_{d}_t_tojson(rmp)); }} }} diff --git a/src/vat/ip_types.c b/src/vat/ip_types.c index abcd2eaf648..248205287a4 100644 --- a/src/vat/ip_types.c +++ b/src/vat/ip_types.c @@ -205,9 +205,9 @@ ip_address_family_to_link_type (ip_address_family_t af) return (VNET_LINK_IP4); } - void -ip_address_set (ip_address_t * dst, const void *src, u8 version) +ip_address_set (ip_address_t *dst, const void *src, + ip_address_family_t version) { ip_addr_version (dst) = version; diff --git a/src/vat2/vat2_helpers.h b/src/vat2/vat2_helpers.h index 7b197608a7b..d9ce2af6b35 100644 --- a/src/vat2/vat2_helpers.h +++ b/src/vat2/vat2_helpers.h @@ -29,7 +29,7 @@ vat2_control_ping (u32 context) vl_api_control_ping_t mp = {0}; mp._vl_msg_id = vac_get_msg_index(VL_API_CONTROL_PING_CRC); mp.context = context; - vl_api_control_ping_t_endian(&mp); + vl_api_control_ping_t_endian (&mp, 1 /* to network */); vac_write((char *)&mp, sizeof(mp)); } diff --git a/src/vcl/CMakeLists.txt b/src/vcl/CMakeLists.txt index 2f738f39d1a..c8835e771c1 100644 --- a/src/vcl/CMakeLists.txt +++ b/src/vcl/CMakeLists.txt @@ -11,11 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") - message(WARNING "-- vppcom is currently only support on Linux - disabled") - return() -endif() - ############################################################################## # vppcom shared library ############################################################################## @@ -40,6 +35,9 @@ if (LDP_HAS_GNU_SOURCE) add_compile_definitions(HAVE_GNU_SOURCE) endif(LDP_HAS_GNU_SOURCE) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") + message("WARNING: vcl_ldpreload isn't supported on FreeBSD - disabled") +else() add_vpp_library(vcl_ldpreload SOURCES ldp_socket_wrapper.c @@ -48,6 +46,7 @@ add_vpp_library(vcl_ldpreload LINK_LIBRARIES vppinfra svm vlibmemoryclient rt pthread vppcom dl ) +endif() add_vpp_headers(vcl ldp.h diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c index 58f6ac0a134..a557093e897 100644 --- a/src/vcl/vppcom.c +++ b/src/vcl/vppcom.c @@ -2087,7 +2087,16 @@ read_again: ASSERT (rv >= 0); if (peek) - return rv; + { + /* Request new notifications if more data enqueued */ + if (rv < n || rv == svm_fifo_max_dequeue_cons (rx_fifo)) + { + if (is_ct) + svm_fifo_unset_event (s->rx_fifo); + svm_fifo_unset_event (rx_fifo); + } + return rv; + } n_read += rv; diff --git a/src/vlib/CMakeLists.txt b/src/vlib/CMakeLists.txt index 7ec9b2050e9..3c354b764dd 100644 --- a/src/vlib/CMakeLists.txt +++ b/src/vlib/CMakeLists.txt @@ -55,6 +55,7 @@ install( # vlib shared library ############################################################################## +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") set(PLATFORM_SOURCES linux/pci.c linux/vfio.c @@ -64,6 +65,11 @@ set(PLATFORM_SOURCES set(PLATFORM_HEADERS linux/vfio.h ) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") +set(PLATFORM_SOURCES + freebsd/pci.c +) +endif() add_vpp_library(vlib SOURCES diff --git a/src/vlib/freebsd/pci.c b/src/vlib/freebsd/pci.c new file mode 100644 index 00000000000..a4e9eb2dda6 --- /dev/null +++ b/src/vlib/freebsd/pci.c @@ -0,0 +1,380 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Tom Jones <thj@freebsd.org> + * + * This software was developed by Tom Jones <thj@freebsd.org> under sponsorship + * from the FreeBSD Foundation. + * + */ + +#include <vlib/vlib.h> +#include <vlib/pci/pci.h> +#include <vlib/unix/unix.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/eventfd.h> + +#include <sys/pciio.h> + +#include <fcntl.h> +#include <dirent.h> +#include <net/if.h> + +extern vlib_pci_main_t freebsd_pci_main; + +uword +vlib_pci_get_private_data (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return 0; +} + +void +vlib_pci_set_private_data (vlib_main_t *vm, vlib_pci_dev_handle_t h, + uword private_data) +{ +} + +vlib_pci_addr_t * +vlib_pci_get_addr (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return NULL; +} + +u32 +vlib_pci_get_numa_node (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return 0; +} + +u32 +vlib_pci_get_num_msix_interrupts (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return 0; +} + +/* Call to allocate/initialize the pci subsystem. + This is not an init function so that users can explicitly enable + pci only when it's needed. */ +clib_error_t *pci_bus_init (vlib_main_t *vm); + +vlib_pci_device_info_t * +vlib_pci_get_device_info (vlib_main_t *vm, vlib_pci_addr_t *addr, + clib_error_t **error) +{ + /* Populate a vlib_pci_device_info_t from the given address */ + clib_error_t *err = NULL; + vlib_pci_device_info_t *di = NULL; + + int fd = -1; + struct pci_conf_io pci; + struct pci_conf match; + struct pci_match_conf pattern; + bzero (&match, sizeof (match)); + bzero (&pattern, sizeof (pattern)); + + pattern.pc_sel.pc_domain = addr->domain; + pattern.pc_sel.pc_bus = addr->bus; + pattern.pc_sel.pc_dev = addr->slot; + pattern.pc_sel.pc_func = addr->function; + pattern.flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | + PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; + + pci.pat_buf_len = sizeof (pattern); + pci.num_patterns = 1; + pci.patterns = &pattern; + pci.match_buf_len = sizeof (match); + pci.num_matches = 1; + pci.matches = &match; + pci.offset = 0; + pci.generation = 0; + pci.status = 0; + + fd = open ("/dev/pci", 0); + if (fd == -1) + { + err = clib_error_return_unix (0, "open '/dev/pci'"); + goto error; + } + + if (ioctl (fd, PCIOCGETCONF, &pci) == -1) + { + err = clib_error_return_unix (0, "reading PCIOCGETCONF"); + goto error; + } + + di = clib_mem_alloc (sizeof (vlib_pci_device_info_t)); + clib_memset (di, 0, sizeof (vlib_pci_device_info_t)); + + di->addr.as_u32 = addr->as_u32; + di->numa_node = 0; /* TODO: Place holder until we have NUMA on FreeBSD */ + + di->device_class = match.pc_class; + di->vendor_id = match.pc_vendor; + di->device_id = match.pc_device; + di->revision = match.pc_revid; + + di->product_name = NULL; + di->vpd_r = 0; + di->vpd_w = 0; + di->driver_name = format (0, "%s", &match.pd_name); + di->iommu_group = -1; + + goto done; + +error: + vlib_pci_free_device_info (di); + di = NULL; +done: + if (error) + *error = err; + close (fd); + return di; +} + +clib_error_t *__attribute__ ((weak)) +vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr, vlib_pci_addr_t *root_bus) +{ + return NULL; +} + +clib_error_t * +vlib_pci_bind_to_uio (vlib_main_t *vm, vlib_pci_addr_t *addr, + char *uio_drv_name, int force) +{ + clib_error_t *error = 0; + + if (error) + { + return error; + } + + if (strncmp ("auto", uio_drv_name, 5) == 0) + { + /* TODO: We should confirm that nic_uio is loaded and return an error. */ + uio_drv_name = "nic_uio"; + } + return error; +} + +clib_error_t * +vlib_pci_register_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h, + pci_intx_handler_function_t *intx_handler) +{ + return NULL; +} + +clib_error_t * +vlib_pci_unregister_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return NULL; +} + +clib_error_t * +vlib_pci_register_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h, + u32 start, u32 count, + pci_msix_handler_function_t *msix_handler) +{ + return NULL; +} + +clib_error_t * +vlib_pci_unregister_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h, + u32 start, u32 count) +{ + return NULL; +} + +clib_error_t * +vlib_pci_enable_msix_irq (vlib_main_t *vm, vlib_pci_dev_handle_t h, u16 start, + u16 count) +{ + return NULL; +} + +uword +vlib_pci_get_msix_file_index (vlib_main_t *vm, vlib_pci_dev_handle_t h, + u16 index) +{ + return 0; +} + +clib_error_t * +vlib_pci_disable_msix_irq (vlib_main_t *vm, vlib_pci_dev_handle_t h, u16 start, + u16 count) +{ + return NULL; +} + +/* Configuration space read/write. */ +clib_error_t * +vlib_pci_read_write_config (vlib_main_t *vm, vlib_pci_dev_handle_t h, + vlib_read_or_write_t read_or_write, uword address, + void *data, u32 n_bytes) +{ + return NULL; +} + +clib_error_t * +vlib_pci_map_region (vlib_main_t *vm, vlib_pci_dev_handle_t h, u32 resource, + void **result) +{ + return NULL; +} + +clib_error_t * +vlib_pci_map_region_fixed (vlib_main_t *vm, vlib_pci_dev_handle_t h, + u32 resource, u8 *addr, void **result) +{ + return NULL; +} + +clib_error_t * +vlib_pci_io_region (vlib_main_t *vm, vlib_pci_dev_handle_t h, u32 resource) +{ + return NULL; +} + +clib_error_t * +vlib_pci_read_write_io (vlib_main_t *vm, vlib_pci_dev_handle_t h, + vlib_read_or_write_t read_or_write, uword offset, + void *data, u32 length) +{ + return NULL; +} + +clib_error_t * +vlib_pci_map_dma (vlib_main_t *vm, vlib_pci_dev_handle_t h, void *ptr) +{ + return NULL; +} + +int +vlib_pci_supports_virtual_addr_dma (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + return 0; +} + +clib_error_t * +vlib_pci_device_open (vlib_main_t *vm, vlib_pci_addr_t *addr, + pci_device_id_t ids[], vlib_pci_dev_handle_t *handle) +{ + return NULL; +} + +void +vlib_pci_device_close (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ +} + +void +init_device_from_registered (vlib_main_t *vm, vlib_pci_device_info_t *di) +{ +} + +static int +pci_addr_cmp (void *v1, void *v2) +{ + vlib_pci_addr_t *a1 = v1; + vlib_pci_addr_t *a2 = v2; + + if (a1->domain > a2->domain) + return 1; + if (a1->domain < a2->domain) + return -1; + if (a1->bus > a2->bus) + return 1; + if (a1->bus < a2->bus) + return -1; + if (a1->slot > a2->slot) + return 1; + if (a1->slot < a2->slot) + return -1; + if (a1->function > a2->function) + return 1; + if (a1->function < a2->function) + return -1; + return 0; +} + +vlib_pci_addr_t * +vlib_pci_get_all_dev_addrs () +{ + vlib_pci_addr_t *addrs = 0; + + int fd = -1; + struct pci_conf_io pci; + struct pci_conf matches[32]; + bzero (matches, sizeof (matches)); + + pci.pat_buf_len = 0; + pci.num_patterns = 0; + pci.patterns = NULL; + pci.match_buf_len = sizeof (matches); + pci.num_matches = 32; + pci.matches = (struct pci_conf *) &matches; + pci.offset = 0; + pci.generation = 0; + pci.status = 0; + + fd = open ("/dev/pci", 0); + if (fd == -1) + { + clib_error_return_unix (0, "opening /dev/pci"); + return (NULL); + } + + if (ioctl (fd, PCIOCGETCONF, &pci) == -1) + { + clib_error_return_unix (0, "reading pci config"); + close (fd); + return (NULL); + } + + for (int i = 0; i < pci.num_matches; i++) + { + struct pci_conf *m = &pci.matches[i]; + vlib_pci_addr_t addr; + + addr.domain = m->pc_sel.pc_domain; + addr.bus = m->pc_sel.pc_bus; + addr.slot = m->pc_sel.pc_dev; + addr.function = m->pc_sel.pc_func; + + vec_add1 (addrs, addr); + } + + vec_sort_with_function (addrs, pci_addr_cmp); + close (fd); + + return addrs; +} + +clib_error_t * +freebsd_pci_init (vlib_main_t *vm) +{ + vlib_pci_main_t *pm = &pci_main; + vlib_pci_addr_t *addr = 0, *addrs; + + pm->vlib_main = vm; + + ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32)); + + addrs = vlib_pci_get_all_dev_addrs (); + vec_foreach (addr, addrs) + { + vlib_pci_device_info_t *d; + if ((d = vlib_pci_get_device_info (vm, addr, 0))) + { + init_device_from_registered (vm, d); + vlib_pci_free_device_info (d); + } + } + + return 0; +} + +VLIB_INIT_FUNCTION (freebsd_pci_init) = { + .runs_after = VLIB_INITS ("unix_input_init"), +}; diff --git a/src/vlib/linux/pci.c b/src/vlib/linux/pci.c index 08923bebcdf..29ca3d97523 100644 --- a/src/vlib/linux/pci.c +++ b/src/vlib/linux/pci.c @@ -55,6 +55,7 @@ #include <linux/ethtool.h> #include <linux/sockios.h> #include <linux/vfio.h> +#include <limits.h> #include <sys/eventfd.h> #define SYSFS_DEVICES_PCI "/sys/devices/pci" @@ -1560,14 +1561,17 @@ linux_pci_init (vlib_main_t * vm) ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32)); - addrs = vlib_pci_get_all_dev_addrs (); - vec_foreach (addr, addrs) + if (pm->pci_device_registrations) { - vlib_pci_device_info_t *d; - if ((d = vlib_pci_get_device_info (vm, addr, 0))) + addrs = vlib_pci_get_all_dev_addrs (); + vec_foreach (addr, addrs) { - init_device_from_registered (vm, d); - vlib_pci_free_device_info (d); + vlib_pci_device_info_t *d; + if ((d = vlib_pci_get_device_info (vm, addr, 0))) + { + init_device_from_registered (vm, d); + vlib_pci_free_device_info (d); + } } } diff --git a/src/vlib/pci/pci.c b/src/vlib/pci/pci.c index cd580f04176..7284e6675fd 100644 --- a/src/vlib/pci/pci.c +++ b/src/vlib/pci/pci.c @@ -47,8 +47,10 @@ #include <dirent.h> #include <sys/ioctl.h> #include <net/if.h> +#ifdef __linux__ #include <linux/ethtool.h> #include <linux/sockios.h> +#endif /* __linux__ */ vlib_pci_main_t pci_main; @@ -117,7 +119,7 @@ vlib_pci_intr_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h) { const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 }; clib_error_t *err; - int already_set; + int already_set = 0; err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set); log_debug (h, "interrupt%senabled", already_set ? " " : " already "); @@ -129,7 +131,7 @@ vlib_pci_intr_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h) { const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 }; clib_error_t *err; - int already_set; + int already_set = 0; err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set); log_debug (h, "interrupt%sdisabled", already_set ? " " : " already "); @@ -141,7 +143,7 @@ vlib_pci_bus_master_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h) { const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 }; clib_error_t *err; - int already_set; + int already_set = 0; err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set); log_debug (h, "bus-master%senabled", already_set ? " " : " already "); @@ -153,7 +155,7 @@ vlib_pci_bus_master_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h) { const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 }; clib_error_t *err; - int already_set; + int already_set = 0; err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set); log_debug (h, "bus-master%sdisabled", already_set ? " " : " already "); diff --git a/src/vlib/threads.c b/src/vlib/threads.c index 3994afc2cea..87b71adc2bc 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -16,6 +16,9 @@ #include <signal.h> #include <math.h> +#ifdef __FreeBSD__ +#include <pthread_np.h> +#endif /* __FreeBSD__ */ #include <vppinfra/format.h> #include <vppinfra/time_range.h> #include <vppinfra/interrupt.h> @@ -179,9 +182,7 @@ vlib_thread_init (vlib_main_t * vm) u32 n_vlib_mains = 1; u32 first_index = 1; u32 i; - pid_t pid; - uword *avail_cpu, *affinity_cpu; - uword n_cpus; + uword *avail_cpu; u32 stats_num_worker_threads_dir_index; stats_num_worker_threads_dir_index = @@ -192,39 +193,16 @@ vlib_thread_init (vlib_main_t * vm) tm->cpu_core_bitmap = os_get_online_cpu_core_bitmap (); tm->cpu_socket_bitmap = os_get_online_cpu_node_bitmap (); - /* get bitmap of active cpu cores vpp has affinity to */ - pid = getpid (); - tm->cpu_affinity_bitmap = os_get_cpu_affinity_bitmap (pid); - - /* if fetching affinity fails, return online cpu core bmp */ - if (tm->cpu_affinity_bitmap == 0) - tm->cpu_affinity_bitmap = os_get_online_cpu_core_bitmap (); - avail_cpu = clib_bitmap_dup (tm->cpu_core_bitmap); - affinity_cpu = clib_bitmap_dup (tm->cpu_affinity_bitmap); /* skip cores */ - n_cpus = clib_bitmap_count_set_bits (avail_cpu); - if (tm->skip_cores >= n_cpus) - return clib_error_return (0, "skip-core greater than available cpus"); - n_cpus = clib_bitmap_count_set_bits (affinity_cpu); - if (tm->skip_cores >= n_cpus) - return clib_error_return (0, "skip-core greater than affinity cpus"); - for (i = 0; i < tm->skip_cores; i++) { - uword c; - c = clib_bitmap_first_set (avail_cpu); + uword c = clib_bitmap_first_set (avail_cpu); if (c == ~0) return clib_error_return (0, "no available cpus to skip"); avail_cpu = clib_bitmap_set (avail_cpu, c, 0); - - c = clib_bitmap_first_set (affinity_cpu); - if (c == ~0) - return clib_error_return (0, "no available env cpus to skip"); - - affinity_cpu = clib_bitmap_set (affinity_cpu, c, 0); } /* grab cpu for main thread */ @@ -234,17 +212,6 @@ vlib_thread_init (vlib_main_t * vm) return clib_error_return (0, "cpu %u is not available to be used" " for the main thread", tm->main_lcore); avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0); - affinity_cpu = clib_bitmap_set (affinity_cpu, tm->main_lcore, 0); - } - /* if auto enabled, grab first cpu vpp has affinity to for main thread */ - else if (tm->use_main_core_auto) - { - uword c = clib_bitmap_first_set (affinity_cpu); - if (c != ~0) - tm->main_lcore = c; - - avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0); - affinity_cpu = clib_bitmap_set (affinity_cpu, tm->main_lcore, 0); } /* assume that there is socket 0 only if there is no data from sysfs */ @@ -272,7 +239,11 @@ vlib_thread_init (vlib_main_t * vm) w->thread_mheap = clib_mem_get_heap (); w->thread_stack = vlib_thread_stacks[0]; w->cpu_id = tm->main_lcore; +#ifdef __FreeBSD__ + w->lwp = pthread_getthreadid_np (); +#else w->lwp = syscall (SYS_gettid); +#endif /* __FreeBSD__ */ w->thread_id = pthread_self (); tm->n_vlib_mains = 1; @@ -325,23 +296,13 @@ vlib_thread_init (vlib_main_t * vm) } else { - /* for automatic pinning, use cpu affinity list */ - uword n_env_cpu = 0; - n_env_cpu = clib_bitmap_count_set_bits (affinity_cpu); - - if (n_env_cpu < tr->count) - return clib_error_return (0, - "no available cpus to be used for" - " the '%s' thread #%u", - tr->name, n_env_cpu); - for (j = 0; j < tr->count; j++) { /* Do not use CPU 0 by default - leave it to the host and IRQs */ - uword avail_c0 = clib_bitmap_get (affinity_cpu, 0); - affinity_cpu = clib_bitmap_set (affinity_cpu, 0, 0); + uword avail_c0 = clib_bitmap_get (avail_cpu, 0); + avail_cpu = clib_bitmap_set (avail_cpu, 0, 0); - uword c = clib_bitmap_first_set (affinity_cpu); + uword c = clib_bitmap_first_set (avail_cpu); /* Use CPU 0 as a last resort */ if (c == ~0 && avail_c0) { @@ -355,15 +316,14 @@ vlib_thread_init (vlib_main_t * vm) " the '%s' thread #%u", tr->name, tr->count); - affinity_cpu = clib_bitmap_set (affinity_cpu, 0, avail_c0); - affinity_cpu = clib_bitmap_set (affinity_cpu, c, 0); + avail_cpu = clib_bitmap_set (avail_cpu, 0, avail_c0); + avail_cpu = clib_bitmap_set (avail_cpu, c, 0); tr->coremask = clib_bitmap_set (tr->coremask, c, 1); } } } clib_bitmap_free (avail_cpu); - clib_bitmap_free (affinity_cpu); tm->n_vlib_mains = n_vlib_mains; vlib_stats_set_gauge (stats_num_worker_threads_dir_index, n_vlib_mains - 1); @@ -448,7 +408,11 @@ vlib_worker_thread_bootstrap_fn (void *arg) { vlib_worker_thread_t *w = arg; +#ifdef __FreeBSD__ + w->lwp = pthread_getthreadid_np (); +#else w->lwp = syscall (SYS_gettid); +#endif /* __FreeBSD__ */ w->thread_id = pthread_self (); __os_thread_index = w - vlib_worker_threads; @@ -1165,7 +1129,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) tm->sched_policy = ~0; tm->sched_priority = ~0; tm->main_lcore = ~0; - tm->use_main_core_auto = 0; tr = tm->next; @@ -1181,8 +1144,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) tm->use_pthreads = 1; else if (unformat (input, "thread-prefix %v", &tm->thread_prefix)) ; - else if (unformat (input, "main-core auto")) - tm->use_main_core_auto = 1; else if (unformat (input, "main-core %u", &tm->main_lcore)) ; else if (unformat (input, "skip-cores %u", &tm->skip_cores)) @@ -1241,13 +1202,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) break; } - if (tm->main_lcore != ~0 && tm->use_main_core_auto) - { - return clib_error_return ( - 0, "cannot set both 'main-core %u' and 'main-core auto'", - tm->main_lcore); - } - if (tm->sched_priority != ~0) { if (tm->sched_policy == SCHED_FIFO || tm->sched_policy == SCHED_RR) diff --git a/src/vlib/threads.h b/src/vlib/threads.h index 3072d0e67dd..ac0c1d5d266 100644 --- a/src/vlib/threads.h +++ b/src/vlib/threads.h @@ -255,8 +255,6 @@ typedef struct int use_pthreads; - int use_main_core_auto; - /* Number of vlib_main / vnet_main clones */ u32 n_vlib_mains; @@ -284,9 +282,6 @@ typedef struct /* Bitmap of available CPU sockets (NUMA nodes) */ uword *cpu_socket_bitmap; - /* Bitmap of CPU affinity for VPP process */ - uword *cpu_affinity_bitmap; - /* Worker handoff queues */ vlib_frame_queue_main_t *frame_queue_mains; diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c index 38eef4125a9..ee28ca8f1aa 100644 --- a/src/vlib/unix/main.c +++ b/src/vlib/unix/main.c @@ -39,6 +39,7 @@ #include <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vlib/unix/plugin.h> +#include <vppinfra/unix.h> #include <limits.h> #include <signal.h> @@ -612,22 +613,23 @@ vlib_unix_main (int argc, char *argv[]) vlib_main_t *vm = vlib_get_first_main (); /* one and only time for this! */ unformat_input_t input; clib_error_t *e; - char buffer[PATH_MAX]; int i; vec_validate_aligned (vgm->vlib_mains, 0, CLIB_CACHE_LINE_BYTES); - if ((i = readlink ("/proc/self/exe", buffer, sizeof (buffer) - 1)) > 0) + vgm->exec_path = (char *) os_get_exec_path (); + + if (vgm->exec_path) { - int j; - buffer[i] = 0; - vgm->exec_path = vec_new (char, i + 1); - clib_memcpy_fast (vgm->exec_path, buffer, i + 1); - for (j = i - 1; j > 0; j--) - if (buffer[j - 1] == '/') + for (i = vec_len (vgm->exec_path) - 1; i > 0; i--) + if (vgm->exec_path[i - 1] == '/') break; - vgm->name = vec_new (char, i - j + 1); - clib_memcpy_fast (vgm->name, buffer + j, i - j + 1); + + vgm->name = 0; + + vec_add (vgm->name, vgm->exec_path + i, vec_len (vgm->exec_path) - i); + vec_add1 (vgm->exec_path, 0); + vec_add1 (vgm->name, 0); } else vgm->exec_path = vgm->name = argv[0]; diff --git a/src/vlib/unix/plugin.c b/src/vlib/unix/plugin.c index fd3a050b944..5cac9abc8fe 100644 --- a/src/vlib/unix/plugin.c +++ b/src/vlib/unix/plugin.c @@ -306,8 +306,12 @@ process_reg: } vec_free (version_required); +#if defined(RTLD_DEEPBIND) handle = dlopen ((char *) pi->filename, RTLD_LAZY | (reg->deep_bind ? RTLD_DEEPBIND : 0)); +#else + handle = dlopen ((char *) pi->filename, RTLD_LAZY); +#endif if (handle == 0) { diff --git a/src/vlibapi/api_common.h b/src/vlibapi/api_common.h index 62a8d4c62d8..c09334136c0 100644 --- a/src/vlibapi/api_common.h +++ b/src/vlibapi/api_common.h @@ -235,8 +235,8 @@ typedef struct /** Message convert function vector */ void *(*fromjson_handler) (cJSON *, int *); - /** Message endian handler vector */ - void (*endian_handler) (void *); + /** Message endian handler vector. */ + void (*endian_handler) (void *, bool to_net); /** Message calc size function vector */ uword (*calc_size_func) (void *); diff --git a/src/vlibapi/api_helper_macros.h b/src/vlibapi/api_helper_macros.h index 9c93d33934b..0380692b80e 100644 --- a/src/vlibapi/api_helper_macros.h +++ b/src/vlibapi/api_helper_macros.h @@ -29,9 +29,9 @@ #define _NATIVE_TO_NETWORK(t, rmp) \ api_main_t *am = vlibapi_get_main (); \ - void (*endian_fp) (void *); \ + void (*endian_fp) (void *, bool); \ endian_fp = am->msg_data[t + (REPLY_MSG_ID_BASE)].endian_handler; \ - (*endian_fp) (rmp); + (*endian_fp) (rmp, 1 /* to network */); #define REPLY_MACRO(msg) \ do \ diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c index 7de1906f17a..79064b292c9 100644 --- a/src/vlibapi/api_shared.c +++ b/src/vlibapi/api_shared.c @@ -230,7 +230,7 @@ vl_msg_api_trace_write_one (api_main_t *am, u8 *msg, FILE *fp) if (m && m->endian_handler) { - m->endian_handler (tmpmem); + m->endian_handler (tmpmem, 1); } if (m && m->tojson_handler) @@ -561,7 +561,7 @@ msg_handler_internal (api_main_t *am, void *the_msg, uword msg_len, } if (m->is_autoendian) - m->endian_handler (the_msg); + m->endian_handler (the_msg, 0); if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) clib_call_callbacks (am->perf_counter_cbs, am, id, diff --git a/src/vlibmemory/memclnt_api.c b/src/vlibmemory/memclnt_api.c index d4106b10559..b0b0c72eae0 100644 --- a/src/vlibmemory/memclnt_api.c +++ b/src/vlibmemory/memclnt_api.c @@ -197,6 +197,7 @@ vlib_api_init (void) cJSON_Hooks cjson_hooks = { .malloc_fn = clib_mem_alloc, .free_fn = clib_mem_free, + .realloc_fn = clib_mem_realloc, }; cJSON_InitHooks (&cjson_hooks); diff --git a/src/vlibmemory/memory_api.c b/src/vlibmemory/memory_api.c index 39c6b0fd15b..57373b91e31 100644 --- a/src/vlibmemory/memory_api.c +++ b/src/vlibmemory/memory_api.c @@ -823,9 +823,9 @@ vl_mem_api_handler_with_vm_node (api_main_t *am, svm_region_t *vlib_rp, if (m->is_autoendian) { - void (*endian_fp) (void *); + void (*endian_fp) (void *, bool); endian_fp = am->msg_data[id].endian_handler; - (*endian_fp) (the_msg); + (*endian_fp) (the_msg, 0); } if (PREDICT_FALSE (vec_len (am->perf_counter_cbs) != 0)) clib_call_callbacks (am->perf_counter_cbs, am, id, 0 /* before */); diff --git a/src/vlibmemory/socket_client.c b/src/vlibmemory/socket_client.c index 5fa19c6a9c0..ad28136dc07 100644 --- a/src/vlibmemory/socket_client.c +++ b/src/vlibmemory/socket_client.c @@ -22,6 +22,14 @@ #define _GNU_SOURCE #include <sys/socket.h> +#ifdef __FreeBSD__ +#define _WANT_UCRED +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/un.h> +#endif /* __FreeBSD__ */ + #include <svm/ssvm.h> #include <vlibmemory/socket_client.h> #include <vlibmemory/memory_client.h> @@ -278,7 +286,11 @@ vl_sock_api_recv_fd_msg_internal (socket_client_main_t * scm, int fds[], struct msghdr mh = { 0 }; struct iovec iov[1]; ssize_t size = 0; +#ifdef __linux__ struct ucred *cr = 0; +#elif __FreeBSD__ + struct cmsgcred *cr = 0; +#endif /* __linux__ */ struct cmsghdr *cmsg; pid_t pid __attribute__ ((unused)); uid_t uid __attribute__ ((unused)); @@ -318,6 +330,7 @@ vl_sock_api_recv_fd_msg_internal (socket_client_main_t * scm, int fds[], { if (cmsg->cmsg_level == SOL_SOCKET) { +#ifdef __linux__ if (cmsg->cmsg_type == SCM_CREDENTIALS) { cr = (struct ucred *) CMSG_DATA (cmsg); @@ -325,6 +338,15 @@ vl_sock_api_recv_fd_msg_internal (socket_client_main_t * scm, int fds[], gid = cr->gid; pid = cr->pid; } +#elif __FreeBSD__ + if (cmsg->cmsg_type == SCM_CREDS) + { + cr = (struct cmsgcred *) CMSG_DATA (cmsg); + uid = cr->cmcred_uid; + gid = cr->cmcred_gid; + pid = cr->cmcred_pid; + } +#endif /* __linux__ */ else if (cmsg->cmsg_type == SCM_RIGHTS) { clib_memcpy_fast (fds, CMSG_DATA (cmsg), sizeof (int) * n_fds); diff --git a/src/vlibmemory/vlib_api_cli.c b/src/vlibmemory/vlib_api_cli.c index 4492f5af980..6ae81cd13df 100644 --- a/src/vlibmemory/vlib_api_cli.c +++ b/src/vlibmemory/vlib_api_cli.c @@ -554,7 +554,7 @@ vl_msg_api_process_file (vlib_main_t * vm, u8 * filename, } if (m) { - m->endian_handler (tmpbuf + sizeof (uword)); + m->endian_handler (tmpbuf + sizeof (uword), 1 /* to network */); } } @@ -674,7 +674,7 @@ vl_msg_print_trace (u8 *msg, void *ctx) clib_memcpy_fast (tmpbuf, msg, msg_length); msg = tmpbuf; - m->endian_handler (tmpbuf); + m->endian_handler (tmpbuf, 0 /* from network */); } vlib_cli_output (a->vm, "%U\n", @@ -824,7 +824,7 @@ vl_msg_exec_json_command (vlib_main_t *vm, cJSON *o) } if (clib_arch_is_little_endian) - m->endian_handler (msg); + m->endian_handler (msg, 1 /* to network */); if (!m->handler) { diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt index fb8d294009d..ad5f44846cc 100644 --- a/src/vnet/CMakeLists.txt +++ b/src/vnet/CMakeLists.txt @@ -813,24 +813,6 @@ list(APPEND VNET_API_FILES ) ############################################################################## -# mpls segment routing -############################################################################## - -list(APPEND VNET_SOURCES - srmpls/sr_mpls_policy.c - srmpls/sr_mpls_steering.c - srmpls/sr_mpls_api.c -) - -list(APPEND VNET_HEADERS - srmpls/sr_mpls.h -) - -list(APPEND VNET_API_FILES - srmpls/sr_mpls.api -) - -############################################################################## # IPFIX / netflow v10 ############################################################################## list(APPEND VNET_SOURCES @@ -1460,7 +1442,6 @@ add_vat_test_library(vnet ip/ip_test.c arp/arp_test.c ip6-nd/ip6_nd_test.c - srmpls/sr_mpls_test.c session/session_test.c l2/l2_test.c ipsec/ipsec_test.c diff --git a/src/vnet/dev/format.c b/src/vnet/dev/format.c index ed83a0eba95..f599c0f8b85 100644 --- a/src/vnet/dev/format.c +++ b/src/vnet/dev/format.c @@ -101,7 +101,7 @@ format_vnet_dev_port_info (u8 *s, va_list *args) u32 indent = format_get_indent (s); s = format (s, "Hardware Address is %U", format_vnet_dev_hw_addr, - &port->attr.hw_addr); + &port->primary_hw_addr); s = format (s, ", %u RX queues (max %u), %u TX queues (max %u)", pool_elts (port->rx_queues), port->attr.max_rx_queues, pool_elts (port->tx_queues), port->attr.max_tx_queues); diff --git a/src/vnet/ethernet/node.c b/src/vnet/ethernet/node.c index e2558eeca41..03cbdde1c2b 100644 --- a/src/vnet/ethernet/node.c +++ b/src/vnet/ethernet/node.c @@ -982,8 +982,31 @@ eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node, else { for (int j = 0; j < 16; j++) - if (next[j] == 0) - slowpath_indices[n_slowpath++] = i + j; + { + if (next[j] == 0) + slowpath_indices[n_slowpath++] = i + j; + else if (dmac_check && main_is_l3 && dmacs_bad[i + j]) + { + next[j] = 0; + slowpath_indices[n_slowpath++] = i + j; + } + } + } + } + else + { + if (dmac_check && main_is_l3) + { + u8x16 dmac_bad = u8x16_load_unaligned (&dmacs_bad[i]); + if (!u8x16_is_all_zero (dmac_bad)) + { + for (int j = 0; j < 16; j++) + if (dmacs_bad[i + j]) + { + next[j] = 0; + slowpath_indices[n_slowpath++] = i + j; + } + } } } @@ -994,7 +1017,12 @@ eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node, continue; } #endif - if (main_is_l3 && etype[0] == et_ip4) + if (dmac_check && main_is_l3 && dmacs_bad[i]) + { + next[0] = 0; + slowpath_indices[n_slowpath++] = i; + } + else if (main_is_l3 && etype[0] == et_ip4) next[0] = next_ip4; else if (main_is_l3 && etype[0] == et_ip6) next[0] = next_ip6; @@ -1052,7 +1080,7 @@ eth_input_process_frame (vlib_main_t * vm, vlib_node_runtime_t * node, } else { - /* untagged packet with not well known etyertype */ + /* untagged packet with not well known ethertype */ if (last_unknown_etype != etype) { last_unknown_etype = etype; diff --git a/src/vnet/gso/gso.h b/src/vnet/gso/gso.h index 883a4941ee2..dee5da5c70b 100644 --- a/src/vnet/gso/gso.h +++ b/src/vnet/gso/gso.h @@ -39,13 +39,13 @@ gso_init_bufs_from_template_base (vlib_buffer_t **bufs, vlib_buffer_t *b0, u32 flags, u16 n_bufs, u16 hdr_sz) { u32 i = n_bufs; - while (i >= 4) + while (i >= 6) { /* prefetches */ CLIB_PREFETCH (bufs[2], 2 * CLIB_CACHE_LINE_BYTES, LOAD); CLIB_PREFETCH (bufs[3], 2 * CLIB_CACHE_LINE_BYTES, LOAD); - vlib_prefetch_buffer_data (bufs[2], LOAD); - vlib_prefetch_buffer_data (bufs[3], LOAD); + vlib_prefetch_buffer_data (bufs[4], LOAD); + vlib_prefetch_buffer_data (bufs[5], LOAD); /* copying objects from cacheline 0 */ bufs[0]->current_data = 0; @@ -70,10 +70,26 @@ gso_init_bufs_from_template_base (vlib_buffer_t **bufs, vlib_buffer_t *b0, bufs[0]->total_length_not_including_first_buffer = 0; bufs[1]->total_length_not_including_first_buffer = 0; + clib_memcpy_fast (&bufs[0]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); + clib_memcpy_fast (&bufs[1]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); + /* copying data */ clib_memcpy_fast (bufs[0]->data, vlib_buffer_get_current (b0), hdr_sz); clib_memcpy_fast (bufs[1]->data, vlib_buffer_get_current (b0), hdr_sz); + /* header offset fixup */ + vnet_buffer (bufs[0])->l2_hdr_offset -= b0->current_data; + vnet_buffer (bufs[0])->l3_hdr_offset -= b0->current_data; + vnet_buffer (bufs[0])->l4_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[0])->outer_l3_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[0])->outer_l4_hdr_offset -= b0->current_data; + + vnet_buffer (bufs[1])->l2_hdr_offset -= b0->current_data; + vnet_buffer (bufs[1])->l3_hdr_offset -= b0->current_data; + vnet_buffer (bufs[1])->l4_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[1])->outer_l3_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[1])->outer_l4_hdr_offset -= b0->current_data; + bufs += 2; i -= 2; } @@ -92,10 +108,18 @@ gso_init_bufs_from_template_base (vlib_buffer_t **bufs, vlib_buffer_t *b0, /* copying objects from cacheline 1 */ bufs[0]->trace_handle = b0->trace_handle; bufs[0]->total_length_not_including_first_buffer = 0; + clib_memcpy_fast (&bufs[0]->opaque2, &b0->opaque2, sizeof (b0->opaque2)); /* copying data */ clib_memcpy_fast (bufs[0]->data, vlib_buffer_get_current (b0), hdr_sz); + /* header offset fixup */ + vnet_buffer (bufs[0])->l2_hdr_offset -= b0->current_data; + vnet_buffer (bufs[0])->l3_hdr_offset -= b0->current_data; + vnet_buffer (bufs[0])->l4_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[0])->outer_l3_hdr_offset -= b0->current_data; + vnet_buffer2 (bufs[0])->outer_l4_hdr_offset -= b0->current_data; + bufs++; i--; } @@ -103,28 +127,41 @@ gso_init_bufs_from_template_base (vlib_buffer_t **bufs, vlib_buffer_t *b0, static_always_inline void gso_fixup_segmented_buf (vlib_main_t *vm, vlib_buffer_t *b0, u32 next_tcp_seq, - int is_l2, int is_ip6, generic_header_offset_t *gho, - clib_ip_csum_t *c, u8 tcp_flags) + int is_l2, u8 oflags, u16 hdr_sz, u16 l4_hdr_sz, + clib_ip_csum_t *c, u8 tcp_flags, u8 is_prefetch, + vlib_buffer_t *b1) { - ip4_header_t *ip4 = - (ip4_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset + - gho->outer_hdr_sz); - ip6_header_t *ip6 = - (ip6_header_t *) (vlib_buffer_get_current (b0) + gho->l3_hdr_offset + - gho->outer_hdr_sz); - tcp_header_t *tcp = - (tcp_header_t *) (vlib_buffer_get_current (b0) + gho->l4_hdr_offset + - gho->outer_hdr_sz); + i16 l3_hdr_offset = vnet_buffer (b0)->l3_hdr_offset; + i16 l4_hdr_offset = vnet_buffer (b0)->l4_hdr_offset; + + ip4_header_t *ip4 = (ip4_header_t *) (b0->data + l3_hdr_offset); + ip6_header_t *ip6 = (ip6_header_t *) (b0->data + l3_hdr_offset); + tcp_header_t *tcp = (tcp_header_t *) (b0->data + l4_hdr_offset); tcp->flags = tcp_flags; tcp->seq_number = clib_host_to_net_u32 (next_tcp_seq); c->odd = 0; - if (is_ip6) + if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) + { + ip4->length = + clib_host_to_net_u16 (b0->current_length - hdr_sz + + (l4_hdr_offset - l3_hdr_offset) + l4_hdr_sz); + ip4->checksum = 0; + ip4->checksum = ip4_header_checksum (ip4); + vnet_buffer_offload_flags_clear (b0, (VNET_BUFFER_OFFLOAD_F_IP_CKSUM | + VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)); + c->sum += clib_mem_unaligned (&ip4->src_address, u32); + c->sum += clib_mem_unaligned (&ip4->dst_address, u32); + c->sum += clib_host_to_net_u32 ( + (clib_net_to_host_u16 (ip4->length) - ip4_header_bytes (ip4)) + + (ip4->protocol << 16)); + } + else { - ip6->payload_length = clib_host_to_net_u16 ( - b0->current_length - gho->l4_hdr_offset - gho->outer_hdr_sz); + ip6->payload_length = + clib_host_to_net_u16 (b0->current_length - hdr_sz + l4_hdr_sz); vnet_buffer_offload_flags_clear (b0, VNET_BUFFER_OFFLOAD_F_TCP_CKSUM); ip6_psh_t psh = { 0 }; u32 *p = (u32 *) &psh; @@ -135,24 +172,15 @@ gso_fixup_segmented_buf (vlib_main_t *vm, vlib_buffer_t *b0, u32 next_tcp_seq, for (int i = 0; i < 10; i++) c->sum += p[i]; } - else - { - ip4->length = clib_host_to_net_u16 ( - b0->current_length - gho->l3_hdr_offset - gho->outer_hdr_sz); - if (gho->gho_flags & GHO_F_IP4) - ip4->checksum = ip4_header_checksum (ip4); - vnet_buffer_offload_flags_clear (b0, (VNET_BUFFER_OFFLOAD_F_IP_CKSUM | - VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)); - c->sum += clib_mem_unaligned (&ip4->src_address, u32); - c->sum += clib_mem_unaligned (&ip4->dst_address, u32); - c->sum += clib_host_to_net_u32 ( - (clib_net_to_host_u16 (ip4->length) - ip4_header_bytes (ip4)) + - (ip4->protocol << 16)); - } - clib_ip_csum_chunk (c, (u8 *) tcp, gho->l4_hdr_sz); + + if (is_prefetch) + CLIB_PREFETCH (vlib_buffer_get_current (b1) + hdr_sz, + CLIB_CACHE_LINE_BYTES, LOAD); + + clib_ip_csum_chunk (c, (u8 *) tcp, l4_hdr_sz); tcp->checksum = clib_ip_csum_fold (c); - if (!is_l2 && ((gho->gho_flags & GHO_F_TUNNEL) == 0)) + if (!is_l2 && ((oflags & VNET_BUFFER_OFFLOAD_F_TNL_MASK) == 0)) { u32 adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX]; @@ -169,16 +197,20 @@ gso_fixup_segmented_buf (vlib_main_t *vm, vlib_buffer_t *b0, u32 next_tcp_seq, static_always_inline u32 gso_segment_buffer_inline (vlib_main_t *vm, vnet_interface_per_thread_data_t *ptd, - vlib_buffer_t *b, generic_header_offset_t *gho, - int is_l2, int is_ip6) + vlib_buffer_t *b, int is_l2) { vlib_buffer_t **bufs = 0; u32 n_tx_bytes = 0; + + u8 oflags = vnet_buffer (b)->oflags; + i16 l4_hdr_offset = vnet_buffer (b)->l4_hdr_offset; u16 gso_size = vnet_buffer2 (b)->gso_size; + u16 l4_hdr_sz = vnet_buffer2 (b)->gso_l4_hdr_sz; + u8 tcp_flags = 0, tcp_flags_no_fin_psh = 0; u32 default_bflags = b->flags & ~(VNET_BUFFER_F_GSO | VLIB_BUFFER_NEXT_PRESENT); - u16 hdr_sz = gho->hdr_sz + gho->outer_hdr_sz; + u16 hdr_sz = (l4_hdr_offset - b->current_data) + l4_hdr_sz; u32 next_tcp_seq = 0, tcp_seq = 0; u32 data_size = vlib_buffer_length_in_chain (vm, b) - hdr_sz; u16 size = @@ -200,9 +232,8 @@ gso_segment_buffer_inline (vlib_main_t *vm, vec_validate (bufs, n_bufs - 1); vlib_get_buffers (vm, ptd->split_buffers, bufs, n_bufs); - tcp_header_t *tcp = - (tcp_header_t *) (vlib_buffer_get_current (b) + gho->l4_hdr_offset + - gho->outer_hdr_sz); + tcp_header_t *tcp = (tcp_header_t *) (b->data + l4_hdr_offset); + tcp_seq = next_tcp_seq = clib_net_to_host_u32 (tcp->seq_number); /* store original flags for last packet and reset FIN and PSH */ tcp_flags = tcp->flags; @@ -247,11 +278,11 @@ gso_segment_buffer_inline (vlib_main_t *vm, if (0 == dst_left && data_size) { vlib_prefetch_buffer_header (bufs[i + 1], LOAD); - vlib_prefetch_buffer_data (bufs[i + 1], LOAD); n_tx_bytes += bufs[i]->current_length; - gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, is_ip6, gho, - &c, tcp_flags_no_fin_psh); + gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, oflags, hdr_sz, + l4_hdr_sz, &c, tcp_flags_no_fin_psh, 1, + bufs[i + 1]); i++; dst_left = size; dst_ptr = vlib_buffer_get_current (bufs[i]) + hdr_sz; @@ -264,8 +295,8 @@ gso_segment_buffer_inline (vlib_main_t *vm, ASSERT ((i + 1) == n_alloc); n_tx_bytes += bufs[i]->current_length; - gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, is_ip6, gho, &c, - tcp_flags); + gso_fixup_segmented_buf (vm, bufs[i], tcp_seq, is_l2, oflags, hdr_sz, + l4_hdr_sz, &c, tcp_flags, 0, NULL); vec_free (bufs); return n_tx_bytes; diff --git a/src/vnet/gso/node.c b/src/vnet/gso/node.c index 910f1585e7f..c1d4459476e 100644 --- a/src/vnet/gso/node.c +++ b/src/vnet/gso/node.c @@ -80,113 +80,108 @@ format_gso_trace (u8 * s, va_list * args) return s; } -static_always_inline u16 -tso_segment_ipip_tunnel_fixup (vlib_main_t * vm, - vnet_interface_per_thread_data_t * ptd, - vlib_buffer_t * sb0, - generic_header_offset_t * gho) +static_always_inline void +tso_segment_ipip_tunnel_fixup (vlib_main_t *vm, + vnet_interface_per_thread_data_t *ptd, + vlib_buffer_t *sb0) { u16 n_tx_bufs = vec_len (ptd->split_buffers); - u16 i = 0, n_tx_bytes = 0; + u16 i = 0; while (i < n_tx_bufs) { vlib_buffer_t *b0 = vlib_get_buffer (vm, ptd->split_buffers[i]); + i16 outer_l3_hdr_offset = vnet_buffer2 (b0)->outer_l3_hdr_offset; + i16 l3_hdr_offset = vnet_buffer (b0)->l3_hdr_offset; - ip4_header_t *ip4 = - (ip4_header_t *) (vlib_buffer_get_current (b0) + - gho->outer_l3_hdr_offset); - ip6_header_t *ip6 = - (ip6_header_t *) (vlib_buffer_get_current (b0) + - gho->outer_l3_hdr_offset); + ip4_header_t *ip4 = (ip4_header_t *) (b0->data + outer_l3_hdr_offset); + ip6_header_t *ip6 = (ip6_header_t *) (b0->data + outer_l3_hdr_offset); - if (gho->gho_flags & GHO_F_OUTER_IP4) + if (vnet_buffer (b0)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM) { - ip4->length = - clib_host_to_net_u16 (b0->current_length - - gho->outer_l3_hdr_offset); + ip4->length = clib_host_to_net_u16 ( + b0->current_length - (outer_l3_hdr_offset - b0->current_data)); ip4->checksum = ip4_header_checksum (ip4); + vnet_buffer_offload_flags_clear ( + b0, VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM | + VNET_BUFFER_OFFLOAD_F_TNL_IPIP); } - else if (gho->gho_flags & GHO_F_OUTER_IP6) + else { - ip6->payload_length = - clib_host_to_net_u16 (b0->current_length - - gho->outer_l4_hdr_offset); + ip6->payload_length = clib_host_to_net_u16 ( + b0->current_length - (l3_hdr_offset - b0->current_data)); + vnet_buffer_offload_flags_clear (b0, VNET_BUFFER_OFFLOAD_F_TNL_IPIP); } - n_tx_bytes += gho->outer_hdr_sz; i++; } - return n_tx_bytes; } static_always_inline void -tso_segment_vxlan_tunnel_headers_fixup (vlib_main_t * vm, vlib_buffer_t * b, - generic_header_offset_t * gho) +tso_segment_vxlan_tunnel_headers_fixup (vlib_main_t *vm, vlib_buffer_t *b) { - u8 proto = 0; ip4_header_t *ip4 = 0; ip6_header_t *ip6 = 0; udp_header_t *udp = 0; + i16 outer_l3_hdr_offset = vnet_buffer2 (b)->outer_l3_hdr_offset; + i16 outer_l4_hdr_offset = vnet_buffer2 (b)->outer_l4_hdr_offset; - ip4 = - (ip4_header_t *) (vlib_buffer_get_current (b) + gho->outer_l3_hdr_offset); - ip6 = - (ip6_header_t *) (vlib_buffer_get_current (b) + gho->outer_l3_hdr_offset); - udp = - (udp_header_t *) (vlib_buffer_get_current (b) + gho->outer_l4_hdr_offset); + ip4 = (ip4_header_t *) (b->data + outer_l3_hdr_offset); + ip6 = (ip6_header_t *) (b->data + outer_l3_hdr_offset); + udp = (udp_header_t *) (b->data + outer_l4_hdr_offset); - if (gho->gho_flags & GHO_F_OUTER_IP4) + if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM) { - proto = ip4->protocol; - ip4->length = - clib_host_to_net_u16 (b->current_length - gho->outer_l3_hdr_offset); + ip4->length = clib_host_to_net_u16 ( + b->current_length - (outer_l3_hdr_offset - b->current_data)); ip4->checksum = ip4_header_checksum (ip4); + if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM) + { + udp->length = clib_host_to_net_u16 ( + b->current_length - (outer_l4_hdr_offset - b->current_data)); + // udp checksum is 0, in udp tunnel + udp->checksum = 0; + } + vnet_buffer_offload_flags_clear ( + b, VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM | + VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM | + VNET_BUFFER_OFFLOAD_F_TNL_VXLAN); } - else if (gho->gho_flags & GHO_F_OUTER_IP6) - { - proto = ip6->protocol; - ip6->payload_length = - clib_host_to_net_u16 (b->current_length - gho->outer_l4_hdr_offset); - } - if (proto == IP_PROTOCOL_UDP) + else { - int bogus; - udp->length = - clib_host_to_net_u16 (b->current_length - gho->outer_l4_hdr_offset); - udp->checksum = 0; - if (gho->gho_flags & GHO_F_OUTER_IP6) + ip6->payload_length = clib_host_to_net_u16 ( + b->current_length - (outer_l4_hdr_offset - b->current_data)); + + if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM) { + int bogus; + udp->length = ip6->payload_length; + // udp checksum is 0, in udp tunnel + udp->checksum = 0; udp->checksum = ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus); + vnet_buffer_offload_flags_clear ( + b, VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM | + VNET_BUFFER_OFFLOAD_F_TNL_VXLAN); } - else if (gho->gho_flags & GHO_F_OUTER_IP4) - { - udp->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4); - } - /* FIXME: it should be OUTER_UDP_CKSUM */ - vnet_buffer_offload_flags_clear (b, VNET_BUFFER_OFFLOAD_F_UDP_CKSUM); } } -static_always_inline u16 -tso_segment_vxlan_tunnel_fixup (vlib_main_t * vm, - vnet_interface_per_thread_data_t * ptd, - vlib_buffer_t * sb0, - generic_header_offset_t * gho) +static_always_inline void +tso_segment_vxlan_tunnel_fixup (vlib_main_t *vm, + vnet_interface_per_thread_data_t *ptd, + vlib_buffer_t *sb0) { u16 n_tx_bufs = vec_len (ptd->split_buffers); - u16 i = 0, n_tx_bytes = 0; + u16 i = 0; while (i < n_tx_bufs) { vlib_buffer_t *b0 = vlib_get_buffer (vm, ptd->split_buffers[i]); - tso_segment_vxlan_tunnel_headers_fixup (vm, b0, gho); - n_tx_bytes += gho->outer_hdr_sz; + tso_segment_vxlan_tunnel_headers_fixup (vm, b0); i++; } - return n_tx_bytes; } static_always_inline u16 @@ -682,32 +677,10 @@ vnet_gso_node_inline (vlib_main_t * vm, to_next -= 1; n_left_to_next += 1; /* undo the counting. */ - generic_header_offset_t gho = { 0 }; u32 n_tx_bytes = 0; - u32 inner_is_ip6 = is_ip6; - - vnet_generic_header_offset_parser (b[0], &gho, is_l2, - is_ip4, is_ip6); - - if (PREDICT_FALSE (gho.gho_flags & GHO_F_TUNNEL)) - { - if (PREDICT_FALSE - (gho.gho_flags & (GHO_F_GRE_TUNNEL | - GHO_F_GENEVE_TUNNEL))) - { - /* not supported yet */ - drop_one_buffer_and_count (vm, vnm, node, from - 1, - hi->sw_if_index, - GSO_ERROR_UNHANDLED_TYPE); - b += 1; - continue; - } - inner_is_ip6 = (gho.gho_flags & GHO_F_IP6) != 0; - } - - n_tx_bytes = gso_segment_buffer_inline (vm, ptd, b[0], &gho, - is_l2, inner_is_ip6); + n_tx_bytes = + gso_segment_buffer_inline (vm, ptd, b[0], is_l2); if (PREDICT_FALSE (n_tx_bytes == 0)) { @@ -718,19 +691,15 @@ vnet_gso_node_inline (vlib_main_t * vm, continue; } - - if (PREDICT_FALSE (gho.gho_flags & GHO_F_VXLAN_TUNNEL)) + if (PREDICT_FALSE (vnet_buffer (b[0])->oflags & + VNET_BUFFER_OFFLOAD_F_TNL_VXLAN)) { - n_tx_bytes += - tso_segment_vxlan_tunnel_fixup (vm, ptd, b[0], &gho); + tso_segment_vxlan_tunnel_fixup (vm, ptd, b[0]); } - else - if (PREDICT_FALSE - (gho.gho_flags & (GHO_F_IPIP_TUNNEL | - GHO_F_IPIP6_TUNNEL))) + else if (PREDICT_FALSE (vnet_buffer (b[0])->oflags & + VNET_BUFFER_OFFLOAD_F_TNL_IPIP)) { - n_tx_bytes += - tso_segment_ipip_tunnel_fixup (vm, ptd, b[0], &gho); + tso_segment_ipip_tunnel_fixup (vm, ptd, b[0]); } u16 n_tx_bufs = vec_len (ptd->split_buffers); @@ -744,7 +713,6 @@ vnet_gso_node_inline (vlib_main_t * vm, { sbi0 = to_next[0] = from_seg[0]; sb0 = vlib_get_buffer (vm, sbi0); - vnet_buffer_offload_flags_clear (sb0, 0x7F); ASSERT (sb0->current_length > 0); to_next += 1; from_seg += 1; diff --git a/src/vnet/interface_api.c b/src/vnet/interface_api.c index 2995836672d..c727e519138 100644 --- a/src/vnet/interface_api.c +++ b/src/vnet/interface_api.c @@ -1020,21 +1020,19 @@ vl_api_sw_interface_set_interface_name_t_handler ( { vl_api_sw_interface_set_interface_name_reply_t *rmp; vnet_main_t *vnm = vnet_get_main (); - u32 sw_if_index = ntohl (mp->sw_if_index); - vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); clib_error_t *error; int rv = 0; + VALIDATE_SW_IF_INDEX (mp); + + u32 sw_if_index = ntohl (mp->sw_if_index); + vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index); + if (mp->name[0] == 0) { rv = VNET_API_ERROR_INVALID_VALUE; goto out; } - if (si == 0) - { - rv = VNET_API_ERROR_INVALID_SW_IF_INDEX; - goto out; - } error = vnet_rename_interface (vnm, si->hw_if_index, (char *) mp->name); if (error) @@ -1044,6 +1042,7 @@ vl_api_sw_interface_set_interface_name_t_handler ( } out: + BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_SW_INTERFACE_SET_INTERFACE_NAME_REPLY); } diff --git a/src/vnet/ip-neighbor/ip_neighbor.c b/src/vnet/ip-neighbor/ip_neighbor.c index d340037a15d..614b78489cd 100644 --- a/src/vnet/ip-neighbor/ip_neighbor.c +++ b/src/vnet/ip-neighbor/ip_neighbor.c @@ -460,6 +460,7 @@ ip_neighbor_destroy (ip_neighbor_t * ipn) af = ip_neighbor_get_af (ipn); IP_NEIGHBOR_DBG ("free: %U", format_ip_neighbor, + vlib_time_now (vlib_get_main ()), ip_neighbor_get_index (ipn)); ip_neighbor_publish (ip_neighbor_get_index (ipn), @@ -944,20 +945,20 @@ ip_neighbor_show_sorted_i (vlib_main_t * vm, vlib_cli_command_t * cmd, ip_address_family_t af) { ip_neighbor_elt_t *elt, *head; + f64 now; head = pool_elt_at_index (ip_neighbor_elt_pool, ip_neighbor_list_head[af]); + now = vlib_time_now (vm); - - vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP", - "Flags", "Ethernet", "Interface"); + vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Age", "IP", "Flags", + "Ethernet", "Interface"); /* the list is time sorted, newest first, so start from the back * and work forwards. Stop when we get to one that is alive */ - clib_llist_foreach_reverse(ip_neighbor_elt_pool, - ipne_anchor, head, elt, - ({ - vlib_cli_output (vm, "%U", format_ip_neighbor, elt->ipne_index); - })); + clib_llist_foreach_reverse (ip_neighbor_elt_pool, ipne_anchor, head, elt, ({ + vlib_cli_output (vm, "%U", format_ip_neighbor, + now, elt->ipne_index); + })); return (NULL); } @@ -969,6 +970,7 @@ ip_neighbor_show_i (vlib_main_t * vm, { index_t *ipni, *ipnis = NULL; u32 sw_if_index; + f64 now; /* Filter entries by interface if given. */ sw_if_index = ~0; @@ -976,14 +978,15 @@ ip_neighbor_show_i (vlib_main_t * vm, &sw_if_index); ipnis = ip_neighbor_entries (sw_if_index, af); + now = vlib_time_now (vm); if (ipnis) - vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Time", "IP", - "Flags", "Ethernet", "Interface"); + vlib_cli_output (vm, "%=12s%=40s%=6s%=20s%=24s", "Age", "IP", "Flags", + "Ethernet", "Interface"); vec_foreach (ipni, ipnis) { - vlib_cli_output (vm, "%U", format_ip_neighbor, *ipni); + vlib_cli_output (vm, "%U", format_ip_neighbor, now, *ipni); } vec_free (ipnis); @@ -1573,13 +1576,12 @@ ip_neighbour_age_out (index_t ipni, f64 now, f64 * wait) if (ttl > ipndb_age) { - IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d", - format_ip_neighbor, ipni, now, - ipn->ipn_time_last_updated, ipndb_age); + IP_NEIGHBOR_DBG ("aged: %U @%f - %f > %d", format_ip_neighbor, now, ipni, + now, ipn->ipn_time_last_updated, ipndb_age); if (ipn->ipn_n_probes > 2) { /* 3 strikes and yea-re out */ - IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, ipni); + IP_NEIGHBOR_DBG ("dead: %U", format_ip_neighbor, now, ipni); *wait = 1; return (IP_NEIGHBOR_AGE_DEAD); } diff --git a/src/vnet/ip-neighbor/ip_neighbor_types.c b/src/vnet/ip-neighbor/ip_neighbor_types.c index 39039a48249..a6f3c26d42f 100644 --- a/src/vnet/ip-neighbor/ip_neighbor_types.c +++ b/src/vnet/ip-neighbor/ip_neighbor_types.c @@ -68,19 +68,18 @@ format_ip_neighbor_watcher (u8 * s, va_list * va) u8 * format_ip_neighbor (u8 * s, va_list * va) { + f64 now = va_arg (*va, f64); index_t ipni = va_arg (*va, index_t); ip_neighbor_t *ipn; ipn = ip_neighbor_get (ipni); - return (format (s, "%=12U%=40U%=6U%=20U%U", - format_vlib_time, vlib_get_main (), - ipn->ipn_time_last_updated, - format_ip_address, &ipn->ipn_key->ipnk_ip, - format_ip_neighbor_flags, ipn->ipn_flags, - format_mac_address_t, &ipn->ipn_mac, - format_vnet_sw_if_index_name, vnet_get_main (), - ipn->ipn_key->ipnk_sw_if_index)); + return ( + format (s, "%=12U%=40U%=6U%=20U%U", format_vlib_time, vlib_get_main (), + now - ipn->ipn_time_last_updated, format_ip_address, + &ipn->ipn_key->ipnk_ip, format_ip_neighbor_flags, ipn->ipn_flags, + format_mac_address_t, &ipn->ipn_mac, format_vnet_sw_if_index_name, + vnet_get_main (), ipn->ipn_key->ipnk_sw_if_index)); } static void diff --git a/src/vnet/ip/icmp4.c b/src/vnet/ip/icmp4.c index 452817dd9c1..fa4a0e12276 100644 --- a/src/vnet/ip/icmp4.c +++ b/src/vnet/ip/icmp4.c @@ -341,7 +341,7 @@ ip4_icmp_error (vlib_main_t * vm, /* Prefer a source address from "offending interface" */ if (!ip4_sas_by_sw_if_index (sw_if_index0, &out_ip0->dst_address, &out_ip0->src_address)) - { /* interface has no IP6 address - should not happen */ + { /* interface has no IP4 address - should not happen */ next0 = IP4_ICMP_ERROR_NEXT_DROP; error0 = ICMP4_ERROR_DROP; } diff --git a/src/vnet/ip/ip.c b/src/vnet/ip/ip.c index d045c2f37c1..586f7dfbc85 100644 --- a/src/vnet/ip/ip.c +++ b/src/vnet/ip/ip.c @@ -201,7 +201,8 @@ ip_feature_enable_disable (ip_address_family_t af, } int -ip_flow_hash_set (ip_address_family_t af, u32 table_id, u32 flow_hash_config) +ip_flow_hash_set (ip_address_family_t af, u32 table_id, + flow_hash_config_t flow_hash_config) { fib_protocol_t fproto; u32 fib_index; diff --git a/src/vnet/ipip/ipip_api.c b/src/vnet/ipip/ipip_api.c index dcd3ec875df..2cb7bdf8dae 100644 --- a/src/vnet/ipip/ipip_api.c +++ b/src/vnet/ipip/ipip_api.c @@ -125,22 +125,23 @@ send_ipip_tunnel_details (ipip_tunnel_t * t, vl_api_ipip_tunnel_dump_t * mp) ipip_main_t *im = &ipip_main; vl_api_ipip_tunnel_details_t *rmp; bool is_ipv6 = t->transport == IPIP_TRANSPORT_IP6 ? true : false; + ip46_type_t ip_type = is_ipv6 ? IP46_TYPE_IP6 : IP46_TYPE_IP4; fib_table_t *ft; ft = fib_table_get (t->fib_index, (is_ipv6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4)); - REPLY_MACRO_DETAILS2(VL_API_IPIP_TUNNEL_DETAILS, - ({ - ip_address_encode (&t->tunnel_src, IP46_TYPE_ANY, &rmp->tunnel.src); - ip_address_encode (&t->tunnel_dst, IP46_TYPE_ANY, &rmp->tunnel.dst); - rmp->tunnel.table_id = htonl (ft->ft_table_id); - rmp->tunnel.instance = htonl (t->user_instance); - rmp->tunnel.sw_if_index = htonl (t->sw_if_index); - rmp->tunnel.dscp = ip_dscp_encode(t->dscp); - rmp->tunnel.flags = tunnel_encap_decap_flags_encode(t->flags); - rmp->tunnel.mode = ipip_tunnel_mode_encode (t->mode); - })); + REPLY_MACRO_DETAILS2 ( + VL_API_IPIP_TUNNEL_DETAILS, ({ + ip_address_encode (&t->tunnel_src, ip_type, &rmp->tunnel.src); + ip_address_encode (&t->tunnel_dst, ip_type, &rmp->tunnel.dst); + rmp->tunnel.table_id = htonl (ft->ft_table_id); + rmp->tunnel.instance = htonl (t->user_instance); + rmp->tunnel.sw_if_index = htonl (t->sw_if_index); + rmp->tunnel.dscp = ip_dscp_encode (t->dscp); + rmp->tunnel.flags = tunnel_encap_decap_flags_encode (t->flags); + rmp->tunnel.mode = ipip_tunnel_mode_encode (t->mode); + })); } static void diff --git a/src/vnet/ipsec/ipsec_itf.c b/src/vnet/ipsec/ipsec_itf.c index 6e66d10660b..b86bf6a110c 100644 --- a/src/vnet/ipsec/ipsec_itf.c +++ b/src/vnet/ipsec/ipsec_itf.c @@ -381,6 +381,7 @@ ipsec_itf_create_cli (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; + tunnel_mode_t mode = TUNNEL_MODE_P2P; u32 instance, sw_if_index; clib_error_t *error; mac_address_t mac; @@ -396,6 +397,8 @@ ipsec_itf_create_cli (vlib_main_t * vm, { if (unformat (line_input, "instance %d", &instance)) ; + else if (unformat (line_input, "p2mp")) + mode = TUNNEL_MODE_MP; else { error = clib_error_return (0, "unknown input: %U", @@ -410,7 +413,7 @@ ipsec_itf_create_cli (vlib_main_t * vm, return error; } - rv = ipsec_itf_create (instance, TUNNEL_MODE_P2P, &sw_if_index); + rv = ipsec_itf_create (instance, mode, &sw_if_index); if (rv) return clib_error_return (0, "iPSec interface create failed"); @@ -425,13 +428,13 @@ ipsec_itf_create_cli (vlib_main_t * vm, * * @cliexpar * The following two command syntaxes are equivalent: - * @cliexcmd{ipsec itf create [instance <instance>]} + * @cliexcmd{ipsec itf create [instance <instance>] [p2mp]} * Example of how to create a ipsec interface: * @cliexcmd{ipsec itf create} ?*/ VLIB_CLI_COMMAND (ipsec_itf_create_command, static) = { .path = "ipsec itf create", - .short_help = "ipsec itf create [instance <instance>]", + .short_help = "ipsec itf create [instance <instance>] [p2mp]", .function = ipsec_itf_create_cli, }; diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index f81485de65f..321472c4d85 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -1578,7 +1578,7 @@ fill_buffer_offload_flags (vlib_main_t *vm, u32 *buffers, u32 n_buffers, (VNET_BUFFER_F_IS_IP4 | VNET_BUFFER_F_L2_HDR_OFFSET_VALID | VNET_BUFFER_F_L3_HDR_OFFSET_VALID | VNET_BUFFER_F_L4_HDR_OFFSET_VALID); - if (buffer_oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM) + if (buffer_oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM || gso_enabled) oflags |= VNET_BUFFER_OFFLOAD_F_IP_CKSUM; } else if (PREDICT_TRUE (ethertype == ETHERNET_TYPE_IP6)) @@ -1596,7 +1596,7 @@ fill_buffer_offload_flags (vlib_main_t *vm, u32 *buffers, u32 n_buffers, if (l4_proto == IP_PROTOCOL_TCP) { - if (buffer_oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM) + if (buffer_oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM || gso_enabled) oflags |= VNET_BUFFER_OFFLOAD_F_TCP_CKSUM; /* only set GSO flag for chained buffers */ diff --git a/src/vnet/session/application.h b/src/vnet/session/application.h index 5fea61bdab4..c68a911230f 100644 --- a/src/vnet/session/application.h +++ b/src/vnet/session/application.h @@ -342,7 +342,7 @@ session_error_t app_worker_start_listen (app_worker_t *app_wrk, int app_worker_stop_listen (app_worker_t * app_wrk, app_listener_t * al); int app_worker_init_accepted (session_t * s); int app_worker_listened_notify (app_worker_t *app_wrk, session_handle_t alsh, - u32 opaque, int err); + u32 opaque, session_error_t err); int app_worker_unlisten_reply (app_worker_t *app_wrk, session_handle_t sh, u32 opaque, session_error_t err); int app_worker_accept_notify (app_worker_t * app_wrk, session_t * s); diff --git a/src/vnet/session/application_interface.c b/src/vnet/session/application_interface.c index 86f3dcdece6..a62f914d43a 100644 --- a/src/vnet/session/application_interface.c +++ b/src/vnet/session/application_interface.c @@ -106,8 +106,8 @@ parse_uri (char *uri, session_endpoint_cfg_t *sep) return 0; } -int -vnet_bind_uri (vnet_listen_args_t * a) +session_error_t +vnet_bind_uri (vnet_listen_args_t *a) { session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL; int rv; diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index e1a93a6e250..67e7ee39001 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -273,7 +273,7 @@ session_cleanup_notify (session_t * s, session_cleanup_ntf_t ntf) app_worker_t *app_wrk; app_wrk = app_worker_get_if_valid (s->app_wrk_index); - if (!app_wrk) + if (PREDICT_FALSE (!app_wrk)) { if (ntf == SESSION_CLEANUP_TRANSPORT) return; @@ -1600,11 +1600,28 @@ void session_detach_app (session_t *s) { if (s->session_state < SESSION_STATE_TRANSPORT_CLOSING) - session_close (s); - else if (s->session_state < SESSION_STATE_TRANSPORT_CLOSED) - session_set_state (s, SESSION_STATE_APP_CLOSED); - else if (s->session_state < SESSION_STATE_CLOSED) - session_set_state (s, SESSION_STATE_CLOSED); + { + session_close (s); + } + else if (s->session_state < SESSION_STATE_TRANSPORT_DELETED) + { + transport_connection_t *tc; + + /* Transport is closing but it's not yet deleted. Confirm close and + * subsequently detach transport from session and enqueue a session + * cleanup notification. Transport closed and cleanup notifications are + * going to be dropped by session layer apis */ + transport_close (session_get_transport_proto (s), s->connection_index, + s->thread_index); + tc = session_get_transport (s); + tc->s_index = SESSION_INVALID_INDEX; + session_set_state (s, SESSION_STATE_TRANSPORT_DELETED); + session_cleanup_notify (s, SESSION_CLEANUP_SESSION); + } + else + { + session_cleanup_notify (s, SESSION_CLEANUP_SESSION); + } s->flags |= SESSION_F_APP_CLOSED; s->app_wrk_index = APP_INVALID_INDEX; diff --git a/src/vnet/srv6/sr_api.c b/src/vnet/srv6/sr_api.c index da774c4325f..a44c3098112 100644 --- a/src/vnet/srv6/sr_api.c +++ b/src/vnet/srv6/sr_api.c @@ -163,7 +163,7 @@ vl_api_sr_policy_add_v2_t_handler (vl_api_sr_policy_add_v2_t *mp) mp->type, ntohl (mp->fib_table), mp->is_encap, 0, NULL); vec_free (segments); - REPLY_MACRO (VL_API_SR_POLICY_ADD_REPLY); + REPLY_MACRO (VL_API_SR_POLICY_ADD_V2_REPLY); } static void diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c index 71434a9c065..c57efd59a62 100644 --- a/src/vpp/vnet/main.c +++ b/src/vpp/vnet/main.c @@ -22,6 +22,8 @@ #include <vppinfra/clib.h> #include <vppinfra/cpu.h> +#include <vppinfra/bitmap.h> +#include <vppinfra/unix.h> #include <vlib/vlib.h> #include <vlib/unix/unix.h> #include <vlib/threads.h> @@ -43,25 +45,26 @@ static void vpp_find_plugin_path () { extern char *vat_plugin_path; - char *p, path[PATH_MAX]; - int rv; - u8 *s; + char *p; + u8 *s, *path; /* find executable path */ - if ((rv = readlink ("/proc/self/exe", path, PATH_MAX - 1)) == -1) + path = os_get_exec_path (); + + if (!path) return; - /* readlink doesn't provide null termination */ - path[rv] = 0; + /* add null termination */ + vec_add1 (path, 0); /* strip filename */ - if ((p = strrchr (path, '/')) == 0) - return; + if ((p = strrchr ((char *) path, '/')) == 0) + goto done; *p = 0; /* strip bin/ */ - if ((p = strrchr (path, '/')) == 0) - return; + if ((p = strrchr ((char *) path, '/')) == 0) + goto done; *p = 0; s = format (0, "%s/" CLIB_LIB_DIR "/vpp_plugins", path, path); @@ -71,6 +74,9 @@ vpp_find_plugin_path () s = format (0, "%s/" CLIB_LIB_DIR "/vpp_api_test_plugins", path, path); vec_add1 (s, 0); vat_plugin_path = (char *) s; + +done: + vec_free (path); } static void diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt index f34ceed9d15..154e3a77cb1 100644 --- a/src/vppinfra/CMakeLists.txt +++ b/src/vppinfra/CMakeLists.txt @@ -229,7 +229,12 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") ) endif() -option(VPP_USE_EXTERNAL_LIBEXECINFO "Use external libexecinfo (useful for non-glibc targets)." OFF) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") + option(VPP_USE_EXTERNAL_LIBEXECINFO "Use external libexecinfo (useful for non-glibc targets)." ON) +else() + option(VPP_USE_EXTERNAL_LIBEXECINFO "Use external libexecinfo (useful for non-glibc targets)." OFF) +endif() + if(VPP_USE_EXTERNAL_LIBEXECINFO) set(EXECINFO_LIB execinfo) endif() @@ -260,6 +265,7 @@ if(VPP_BUILD_VPPINFRA_TESTS) longjmp macros maplog + mhash pmalloc pool_alloc pool_iterate diff --git a/src/vppinfra/cJSON.c b/src/vppinfra/cJSON.c index 448435de4dc..24e0110ed08 100644 --- a/src/vppinfra/cJSON.c +++ b/src/vppinfra/cJSON.c @@ -20,6 +20,7 @@ THE SOFTWARE. */ /* clang-format off */ + /* cJSON */ /* JSON parser in C. */ @@ -96,9 +97,9 @@ CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) return (const char*) (global_error.json + global_error.position); } -CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) +CJSON_PUBLIC (char *) cJSON_GetStringValue (const cJSON *const item) { - if (!cJSON_IsString(item)) + if (!cJSON_IsString (item)) { return NULL; } @@ -106,9 +107,9 @@ CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) return item->valuestring; } -CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) +CJSON_PUBLIC (double) cJSON_GetNumberValue (const cJSON *const item) { - if (!cJSON_IsNumber(item)) + if (!cJSON_IsNumber (item)) { return (double) NAN; } @@ -117,8 +118,9 @@ CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) } /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || \ + (CJSON_VERSION_PATCH != 17) +#error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif CJSON_PUBLIC(const char*) cJSON_Version(void) @@ -157,7 +159,7 @@ typedef struct internal_hooks { void *(CJSON_CDECL *allocate)(size_t size); void (CJSON_CDECL *deallocate)(void *pointer); - void *(CJSON_CDECL *reallocate)(void *pointer, size_t new_size, size_t old_size); + void *(CJSON_CDECL *reallocate) (void *pointer, size_t size); } internal_hooks; #if defined(_MSC_VER) @@ -170,20 +172,17 @@ static void CJSON_CDECL internal_free(void *pointer) { free(pointer); } +static void *CJSON_CDECL +internal_realloc (void *pointer, size_t size) +{ + return realloc (pointer, size); +} #else #define internal_malloc malloc #define internal_free free +#define internal_realloc realloc #endif -static void * CJSON_CDECL internal_realloc(void *pointer, size_t new_size, - size_t old_size) -{ - return realloc(pointer, new_size); -} - -static void * -cjson_realloc_internal (void *ptr, size_t new_size, size_t old_size); - /* strlen of character literals resolved at compile time */ #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) @@ -217,8 +216,8 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) /* Reset hooks */ global_hooks.allocate = malloc; global_hooks.deallocate = free; - global_hooks.reallocate = internal_realloc; - return; + global_hooks.reallocate = realloc; + return; } global_hooks.allocate = malloc; @@ -233,16 +232,11 @@ CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) global_hooks.deallocate = hooks->free_fn; } - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = internal_realloc; - } - else - { - global_hooks.reallocate = cjson_realloc_internal; - } + global_hooks.reallocate = realloc; + if (hooks->realloc_fn != NULL) + { + global_hooks.reallocate = hooks->realloc_fn; + } } /* Internal constructor. */ @@ -405,14 +399,22 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) return object->valuedouble = number; } +/* Note: when passing a NULL valuestring, cJSON_SetValuestring treats this as + * an error and return NULL */ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) { char *copy = NULL; /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ - if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) - { - return NULL; - } + if ((object == NULL) || !(object->type & cJSON_String) || + (object->type & cJSON_IsReference)) + { + return NULL; + } + /* return NULL if the object is corrupted or valuestring is NULL */ + if (object->valuestring == NULL || valuestring == NULL) + { + return NULL; + } if (strlen(valuestring) <= strlen(object->valuestring)) { strcpy(object->valuestring, valuestring); @@ -443,27 +445,6 @@ typedef struct internal_hooks hooks; } printbuffer; -static void * -cjson_realloc_internal (void *ptr, size_t new_size, size_t old_size) -{ - size_t copy_size; - if (old_size < new_size) - copy_size = old_size; - else - copy_size = new_size; - - unsigned char *newbuffer = global_hooks.allocate(new_size); - if (!newbuffer) - { - global_hooks.deallocate(ptr); - return NULL; - } - - memcpy (newbuffer, ptr, copy_size); - global_hooks.deallocate (ptr); - return newbuffer; -} - /* realloc printbuffer if necessary to have at least "needed" bytes more */ static unsigned char* ensure(printbuffer * const p, size_t needed) { @@ -515,14 +496,35 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) newsize = needed * 2; } - newbuffer = p->hooks.reallocate (p->buffer, newsize, p->length); - if (newbuffer == NULL) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - return NULL; - } + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char *) p->hooks.reallocate (p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate (p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char *) p->hooks.allocate (newsize); + if (!newbuffer) + { + p->hooks.deallocate (p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + + memcpy (newbuffer, p->buffer, p->offset + 1); + p->hooks.deallocate (p->buffer); + } p->length = newsize; p->buffer = newbuffer; @@ -570,6 +572,10 @@ static cJSON_bool print_number(const cJSON * const item, printbuffer * const out { length = sprintf((char*)number_buffer, "null"); } + else if (d == (double) item->valueint) + { + length = sprintf ((char *) number_buffer, "%d", item->valueint); + } else { /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ @@ -1111,7 +1117,7 @@ CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer } buffer.content = (const unsigned char*)value; - buffer.length = buffer_length; + buffer.length = buffer_length; buffer.offset = 0; buffer.hooks = global_hooks; @@ -1216,11 +1222,13 @@ static unsigned char *print(const cJSON * const item, cJSON_bool format, const i /* check if reallocate is available */ if (hooks->reallocate != NULL) { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1, default_buffer_size); - if (printed == NULL) { - goto fail; - } - buffer->buffer = NULL; + printed = (unsigned char *) hooks->reallocate (buffer->buffer, + buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + buffer->buffer = NULL; } else /* otherwise copy the JSON over to a new buffer */ { @@ -1658,8 +1666,13 @@ static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_bu current_item = new_item; } - /* parse the name of the child */ - input_buffer->offset++; + if (cannot_access_at_index (input_buffer, 1)) + { + goto fail; /* nothing comes after the comma */ + } + + /* parse the name of the child */ + input_buffer->offset++; buffer_skip_whitespace(input_buffer); if (!parse_string(current_item, input_buffer)) { @@ -2268,10 +2281,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON { cJSON *after_inserted = NULL; - if (which < 0) - { - return false; - } + if (which < 0 || newitem == NULL) + { + return false; + } after_inserted = get_array_item(array, (size_t)which); if (after_inserted == NULL) @@ -2279,6 +2292,12 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON return add_item_to_array(array, newitem); } + if (after_inserted != array->child && after_inserted->prev == NULL) + { + /* return false if after_inserted is a corrupted array item */ + return false; + } + newitem->next = after_inserted; newitem->prev = after_inserted->prev; after_inserted->prev = newitem; @@ -2295,7 +2314,8 @@ CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) { - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || + (item == NULL)) { return false; } @@ -2365,6 +2385,11 @@ static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSO cJSON_free(replacement->string); } replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if (replacement->string == NULL) + { + return false; + } + replacement->type &= ~cJSON_StringIsConst; return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); @@ -2639,9 +2664,9 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) for (i = 0; a && (i < (size_t) count); i++) { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { + n = cJSON_CreateNumber (numbers[i]); + if (!n) + { cJSON_Delete(a); return NULL; } @@ -2988,7 +3013,7 @@ CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) { return false; } @@ -3121,7 +3146,7 @@ CJSON_PUBLIC(void) cJSON_free(void *object) global_hooks.deallocate(object); } -CJSON_PUBLIC(void *) cJSON_realloc(void *object, size_t new_size, size_t old_size) +CJSON_PUBLIC (void *) cJSON_realloc (void *object, size_t size) { - return global_hooks.reallocate(object, new_size, old_size); + return global_hooks.reallocate (object, size); } diff --git a/src/vppinfra/cJSON.h b/src/vppinfra/cJSON.h index 1474c4e5c49..1c98dfac70e 100644 --- a/src/vppinfra/cJSON.h +++ b/src/vppinfra/cJSON.h @@ -81,7 +81,7 @@ then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJ /* project version */ #define CJSON_VERSION_MAJOR 1 #define CJSON_VERSION_MINOR 7 -#define CJSON_VERSION_PATCH 14 +#define CJSON_VERSION_PATCH 17 #include <stddef.h> @@ -127,8 +127,7 @@ typedef struct cJSON_Hooks /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ void *(CJSON_CDECL *malloc_fn)(size_t sz); void (CJSON_CDECL *free_fn)(void *ptr); - void *(CJSON_CDECL *realloc_fn) (void *ptr, size_t new_size, - size_t old_size); + void *(CJSON_CDECL *realloc_fn) (void *ptr, size_t sz); } cJSON_Hooks; typedef int cJSON_bool; @@ -256,9 +255,10 @@ CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); -/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. - * The input pointer json cannot point to a read-only address area, such as a string constant, - * but should point to a readable and writable adress area. */ +/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') + * from strings. The input pointer json cannot point to a read-only address + * area, such as a string constant, + * but should point to a readable and writable address area. */ CJSON_PUBLIC(void) cJSON_Minify(char *json); /* Helper functions for creating and adding items to an object at the same time. @@ -281,14 +281,21 @@ CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); +/* If the object is not a boolean type this does nothing and returns + * cJSON_Invalid else it returns the new type*/ +#define cJSON_SetBoolValue(object, boolValue) \ + ((object != NULL && ((object)->type & (cJSON_False | cJSON_True))) ? \ + (object)->type = ((object)->type & (~(cJSON_False | cJSON_True))) | \ + ((boolValue) ? cJSON_True : cJSON_False) : \ + cJSON_Invalid) + /* Macro for iterating over an array or object */ #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ CJSON_PUBLIC(void *) cJSON_malloc(size_t size); CJSON_PUBLIC(void) cJSON_free(void *object); -CJSON_PUBLIC (void *) -cJSON_realloc (void *object, size_t new_size, size_t old_size); +CJSON_PUBLIC (void *) cJSON_realloc (void *object, size_t size); #ifdef __cplusplus } diff --git a/src/vppinfra/heap.c b/src/vppinfra/heap.c index 7db814200f8..9920528732d 100644 --- a/src/vppinfra/heap.c +++ b/src/vppinfra/heap.c @@ -680,6 +680,7 @@ debug_elt (u8 * s, void *v, word i, word n) i = -n / 2; for (e = e0; 1; e = heap_next (e)) { + s = format (s, " "); if (heap_is_free (e)) s = format (s, "index %4d, free\n", e - h->elts); else if (h->format_elt) diff --git a/src/vppinfra/mhash.c b/src/vppinfra/mhash.c index f0f1aa470d7..babaaeec726 100644 --- a/src/vppinfra/mhash.c +++ b/src/vppinfra/mhash.c @@ -164,6 +164,8 @@ mhash_sanitize_hash_user (mhash_t * mh) h->user = pointer_to_uword (mh); } +static u8 *mhash_format_pair_default (u8 *s, va_list *args); + __clib_export void mhash_init (mhash_t * h, uword n_value_bytes, uword n_key_bytes) { @@ -208,12 +210,12 @@ mhash_init (mhash_t * h, uword n_value_bytes, uword n_key_bytes) vec_validate (h->key_tmps, os_get_nthreads () - 1); ASSERT (n_key_bytes < ARRAY_LEN (t)); - h->hash = hash_create2 ( /* elts */ 0, + h->hash = hash_create2 (/* elts */ 0, /* user */ pointer_to_uword (h), /* value_bytes */ n_value_bytes, t[n_key_bytes].key_sum, t[n_key_bytes].key_equal, /* format pair/arg */ - 0, 0); + mhash_format_pair_default, 0); } static uword @@ -331,8 +333,8 @@ mhash_set_mem (mhash_t * h, void *key, uword * new_value, uword * old_value) { if (key_alloc_from_free_list) { - h->key_vector_free_indices[l] = i; - vec_set_len (h->key_vector_free_indices, l + 1); + vec_set_len (h->key_vector_free_indices, l); + h->key_vector_free_indices[l - 1] = i; } else vec_dec_len (h->key_vector_or_heap, h->n_key_bytes); @@ -371,8 +373,8 @@ mhash_unset (mhash_t * h, void *key, uword * old_value) return 1; } -u8 * -format_mhash_key (u8 * s, va_list * va) +__clib_export u8 * +format_mhash_key (u8 *s, va_list *va) { mhash_t *h = va_arg (*va, mhash_t *); u32 ki = va_arg (*va, u32); @@ -387,7 +389,43 @@ format_mhash_key (u8 * s, va_list * va) else if (h->format_key) s = format (s, "%U", h->format_key, k); else - s = format (s, "%U", format_hex_bytes, k, h->n_key_bytes); + s = format (s, "0x%U", format_hex_bytes, k, h->n_key_bytes); + + return s; +} + +static u8 * +mhash_format_pair_default (u8 *s, va_list *args) +{ + void *CLIB_UNUSED (user_arg) = va_arg (*args, void *); + void *v = va_arg (*args, void *); + hash_pair_t *p = va_arg (*args, hash_pair_t *); + hash_t *h = hash_header (v); + mhash_t *mh = uword_to_pointer (h->user, mhash_t *); + + s = format (s, "%U", format_mhash_key, mh, (u32) p->key); + if (hash_value_bytes (h) > 0) + s = format (s, " -> 0x%8U", format_hex_bytes, &p->value[0], + hash_value_bytes (h)); + return s; +} + +__clib_export u8 * +format_mhash (u8 *s, va_list *va) +{ + mhash_t *h = va_arg (*va, mhash_t *); + int verbose = va_arg (*va, int); + + s = format (s, "mhash %p, %wd elts, \n", h, mhash_elts (h)); + if (mhash_key_vector_is_heap (h)) + s = format (s, " %U", format_heap, h->key_vector_or_heap, verbose); + else + s = format (s, " keys %wd elts, %wd size, %wd free, %wd bytes used\n", + vec_len (h->key_vector_or_heap) / h->n_key_bytes, + h->n_key_bytes, vec_len (h->key_vector_free_indices), + vec_bytes (h->key_vector_or_heap) + + vec_bytes (h->key_vector_free_indices)); + s = format (s, " %U", format_hash, h->hash, verbose); return s; } diff --git a/src/vppinfra/mhash.h b/src/vppinfra/mhash.h index 7eb1918384e..62aee365fa3 100644 --- a/src/vppinfra/mhash.h +++ b/src/vppinfra/mhash.h @@ -166,8 +166,13 @@ do { \ })); \ } while (0) +u8 *format_mhash (u8 *s, va_list *va); + format_function_t format_mhash_key; +/* Main test routine. */ +int test_mhash_main (unformat_input_t *input); + #endif /* included_clib_mhash_h */ /* diff --git a/src/vppinfra/pmalloc.c b/src/vppinfra/pmalloc.c index 2a27379b573..85b9db9d56c 100644 --- a/src/vppinfra/pmalloc.c +++ b/src/vppinfra/pmalloc.c @@ -17,6 +17,9 @@ #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> +#ifdef __FreeBSD__ +#include <sys/memrange.h> +#endif /* __FreeBSD__ */ #include <fcntl.h> #include <unistd.h> #include <sched.h> @@ -184,8 +187,9 @@ next_chunk: } static void -pmalloc_update_lookup_table (clib_pmalloc_main_t * pm, u32 first, u32 count) +pmalloc_update_lookup_table (clib_pmalloc_main_t *pm, u32 first, u32 count) { +#ifdef __linux uword seek, va, pa, p; int fd; u32 elts_per_page = 1U << (pm->def_log2_page_sz - pm->lookup_log2_page_sz); @@ -223,6 +227,45 @@ pmalloc_update_lookup_table (clib_pmalloc_main_t * pm, u32 first, u32 count) if (fd != -1) close (fd); +#elif defined(__FreeBSD__) + struct mem_extract meme; + uword p; + int fd; + u32 elts_per_page = 1U << (pm->def_log2_page_sz - pm->lookup_log2_page_sz); + + vec_validate_aligned (pm->lookup_table, + vec_len (pm->pages) * elts_per_page - 1, + CLIB_CACHE_LINE_BYTES); + + p = (uword) first * elts_per_page; + if (pm->flags & CLIB_PMALLOC_F_NO_PAGEMAP) + { + while (p < (uword) elts_per_page * count) + { + pm->lookup_table[p] = + pointer_to_uword (pm->base) + (p << pm->lookup_log2_page_sz); + p++; + } + return; + } + + fd = open ((char *) "/dev/mem", O_RDONLY); + if (fd == -1) + return; + + while (p < (uword) elts_per_page * count) + { + meme.me_vaddr = + pointer_to_uword (pm->base) + (p << pm->lookup_log2_page_sz); + if (ioctl (fd, MEM_EXTRACT_PADDR, &meme) == -1) + continue; + pm->lookup_table[p] = meme.me_vaddr - meme.me_paddr; + p++; + } + return; +#else +#error "Unsupported OS" +#endif } static inline clib_pmalloc_page_t * diff --git a/src/vppinfra/test_mhash.c b/src/vppinfra/test_mhash.c new file mode 100644 index 00000000000..70be2b9b382 --- /dev/null +++ b/src/vppinfra/test_mhash.c @@ -0,0 +1,403 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright(c) 2023 Yandex LLC. + */ + +#ifdef CLIB_LINUX_KERNEL +#include <linux/unistd.h> +#endif + +#ifdef CLIB_UNIX +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <vppinfra/time.h> +#endif + +#include <vppinfra/random.h> +#include <vppinfra/mem.h> +#include <vppinfra/hash.h> +#include <vppinfra/mhash.h> +#include <vppinfra/error.h> +#include <vppinfra/format.h> +#include <vppinfra/bitmap.h> + +static int verbose; +#define if_verbose(format, args...) \ + if (verbose) \ + { \ + clib_warning (format, ##args); \ + } + +typedef struct +{ + int n_iterations; + + int n_iterations_per_print; + + /* Number of pairs to insert into mhash. */ + int n_pairs; + + /* True to validate correctness of mhash functions. */ + int n_iterations_per_validate; + + /* Verbosity level for mhash formats. */ + int verbose; + + /* Random number seed. */ + u32 seed; +} mhash_test_t; + +static clib_error_t * +mhash_next_test (mhash_t *h) +{ + hash_next_t hn = { 0 }; + hash_pair_t *p0, *p1; + clib_error_t *error = 0; + + hash_foreach_pair (p0, h->hash, { + p1 = hash_next (h->hash, &hn); + error = CLIB_ERROR_ASSERT (p0 == p1); + if (error) + break; + }); + + if (!error) + error = CLIB_ERROR_ASSERT (!hash_next (h->hash, &hn)); + + return error; +} + +static clib_error_t * +test_word_key (mhash_test_t *ht) +{ + mhash_t _h = { 0 }, *h = &_h; + word i, j; + + word *keys = 0, *vals = 0; + uword *is_inserted = 0; + + clib_error_t *error = 0; + + vec_resize (keys, ht->n_pairs); + vec_resize (vals, vec_len (keys)); + + mhash_init (h, sizeof (vals[0]), sizeof (keys[0])); + /* borrow 0 elt to make index keys non-zero */ + vec_validate (h->key_vector_or_heap, 0); + + { + uword *unique = 0; + u32 k; + + for (i = 0; i < vec_len (keys); i++) + { + do + { + k = random_u32 (&ht->seed) & 0xfffff; + } + while (clib_bitmap_get (unique, k)); + unique = clib_bitmap_ori (unique, k); + keys[i] = k; + vals[i] = i; + } + + clib_bitmap_free (unique); + } + + for (i = 0; i < ht->n_iterations; i++) + { + u32 vi = random_u32 (&ht->seed) % vec_len (keys); + + if (clib_bitmap_get (is_inserted, vi)) + { + mhash_unset (h, &keys[vi], 0); + mhash_unset (h, &keys[vi], 0); + } + else + { + mhash_set (h, &keys[vi], vals[vi], 0); + mhash_set (h, &keys[vi], vals[vi], 0); + } + + is_inserted = clib_bitmap_xori (is_inserted, vi); + + if (ht->n_iterations_per_print > 0 && + ((i + 1) % ht->n_iterations_per_print) == 0) + if_verbose ("iteration %d\n %U", i + 1, format_mhash, h, ht->verbose); + + if (ht->n_iterations_per_validate == 0 || + (i + 1) % ht->n_iterations_per_validate) + continue; + + { + uword ki, *k, *v; + + mhash_foreach (k, v, h, { + ki = v[0]; + ASSERT (keys[ki] == k[0]); + }); + } + + if ((error = hash_validate (h->hash))) + goto done; + + for (j = 0; j < vec_len (keys); j++) + { + uword *v; + v = mhash_get (h, &keys[j]); + if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) == + (v != 0)))) + goto done; + if (v) + { + if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j]))) + goto done; + } + } + } + + if ((error = mhash_next_test (h))) + goto done; + + if_verbose ("%U", format_mhash, h, ht->verbose); + + for (i = 0; i < vec_len (keys); i++) + { + if (!clib_bitmap_get (is_inserted, i)) + continue; + + mhash_unset (h, &keys[i], 0); + mhash_unset (h, &keys[i], 0); + is_inserted = clib_bitmap_xori (is_inserted, i); + + if (ht->n_iterations_per_validate == 0 || + (i + 1) % ht->n_iterations_per_validate) + continue; + + if ((error = hash_validate (h->hash))) + goto done; + + for (j = 0; j < vec_len (keys); j++) + { + uword *v; + v = mhash_get (h, &keys[j]); + if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) == + (v != 0)))) + goto done; + if (v) + { + if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j]))) + goto done; + } + } + } + +done: + mhash_free (h); + vec_free (keys); + vec_free (vals); + clib_bitmap_free (is_inserted); + + if (verbose) + fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0); + + return error; +} + +static u8 * +test2_format (u8 *s, va_list *args) +{ + void *CLIB_UNUSED (user_arg) = va_arg (*args, void *); + void *v = va_arg (*args, void *); + hash_pair_t *p = va_arg (*args, hash_pair_t *); + hash_t *h = hash_header (v); + mhash_t *mh = uword_to_pointer (h->user, mhash_t *); + + return format (s, "0x%8U <- %U", format_hex_bytes, &p->value[0], + hash_value_bytes (h), format_mhash_key, mh, (u32) p->key); +} + +static clib_error_t * +test_string_key (mhash_test_t *ht, uword is_c_string) +{ + mhash_t _h = { 0 }, *h = &_h; + word i, j; + + u8 **keys = 0; + word *vals = 0; + uword *is_inserted = 0; + + clib_error_t *error = 0; + + vec_resize (keys, ht->n_pairs); + vec_resize (vals, vec_len (keys)); + + if (is_c_string) + mhash_init_c_string (h, sizeof (vals[0])); + else + mhash_init_vec_string (h, sizeof (vals[0])); + hash_set_pair_format (h->hash, test2_format, 0); + + for (i = 0; i < vec_len (keys); i++) + { + keys[i] = random_string (&ht->seed, 5 + (random_u32 (&ht->seed) & 0xf)); + keys[i] = format (keys[i], "%x", i); + if (is_c_string) + vec_terminate_c_string (keys[i]); + vals[i] = random_u32 (&ht->seed); + } + + for (i = 0; i < ht->n_iterations; i++) + { + u32 vi = random_u32 (&ht->seed) % vec_len (keys); + + if (clib_bitmap_get (is_inserted, vi)) + { + mhash_unset (h, keys[vi], 0); + mhash_unset (h, keys[vi], 0); + } + else + { + mhash_set (h, keys[vi], vals[vi], 0); + mhash_set (h, keys[vi], vals[vi], 0); + } + + is_inserted = clib_bitmap_xori (is_inserted, vi); + + if (ht->n_iterations_per_print > 0 && + ((i + 1) % ht->n_iterations_per_print) == 0) + if_verbose ("iteration %d\n %U", i + 1, format_mhash, h, ht->verbose); + + if (ht->n_iterations_per_validate == 0 || + (i + 1) % ht->n_iterations_per_validate) + continue; + + if ((error = hash_validate (h->hash))) + goto done; + + for (j = 0; j < vec_len (keys); j++) + { + uword *v; + v = mhash_get (h, keys[j]); + if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) == + (v != 0)))) + goto done; + if (v) + { + if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j]))) + goto done; + } + } + } + + if ((error = mhash_next_test (h))) + goto done; + + if_verbose ("%U", format_mhash, h, ht->verbose); + + for (i = 0; i < vec_len (keys); i++) + { + if (!clib_bitmap_get (is_inserted, i)) + continue; + + mhash_unset (h, keys[i], 0); + mhash_unset (h, keys[i], 0); + is_inserted = clib_bitmap_xori (is_inserted, i); + + if (ht->n_iterations_per_validate == 0 || + (i + 1) % ht->n_iterations_per_validate) + continue; + + if ((error = hash_validate (h->hash))) + goto done; + + for (j = 0; j < vec_len (keys); j++) + { + uword *v; + v = mhash_get (h, keys[j]); + if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) == + (v != 0)))) + goto done; + if (v) + { + if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j]))) + goto done; + } + } + } + +done: + mhash_free (h); + vec_free (vals); + clib_bitmap_free (is_inserted); + + for (i = 0; i < vec_len (keys); i++) + vec_free (keys[i]); + vec_free (keys); + + if (verbose) + fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0); + + return error; +} + +int +test_mhash_main (unformat_input_t *input) +{ + mhash_test_t _ht = { 0 }, *ht = &_ht; + clib_error_t *error; + + ht->n_iterations = 100; + ht->n_pairs = 10; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (0 == unformat (input, "iter %d", &ht->n_iterations) && + 0 == unformat (input, "print %d", &ht->n_iterations_per_print) && + 0 == unformat (input, "elts %d", &ht->n_pairs) && + 0 == unformat (input, "seed %d", &ht->seed) && + 0 == unformat (input, "verbose %=", &ht->verbose, 1) && + 0 == unformat (input, "valid %d", &ht->n_iterations_per_validate)) + { + clib_warning ("unknown input `%U'", format_unformat_error, input); + return 1; + } + } + + if (!ht->seed) + ht->seed = random_default_seed (); + + if_verbose ("testing %d iterations, seed %d", ht->n_iterations, ht->seed); + + error = test_word_key (ht); + if (error) + clib_error_report (error); + + error = test_string_key (ht, 0); + if (error) + clib_error_report (error); + + error = test_string_key (ht, 1); + if (error) + clib_error_report (error); + + return 0; +} + +#ifdef CLIB_UNIX +int +main (int argc, char *argv[]) +{ + unformat_input_t i; + int ret; + + clib_mem_init (0, 3ULL << 30); + + verbose = (argc > 1); + unformat_init_command_line (&i, argv); + ret = test_mhash_main (&i); + unformat_free (&i); + + return ret; +} +#endif /* CLIB_UNIX */ diff --git a/src/vppinfra/unix-misc.c b/src/vppinfra/unix-misc.c index 4dbc5ce98ce..31c0a489e8d 100644 --- a/src/vppinfra/unix-misc.c +++ b/src/vppinfra/unix-misc.c @@ -35,6 +35,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include <vppinfra/error.h> #include <vppinfra/os.h> #include <vppinfra/bitmap.h> @@ -42,11 +46,19 @@ #include <vppinfra/format.h> #ifdef __linux__ #include <vppinfra/linux/sysfs.h> +#include <sched.h> +#elif defined(__FreeBSD__) +#define _WANT_FREEBSD_BITSET +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/cpuset.h> +#include <sys/domainset.h> +#include <sys/sysctl.h> #endif #include <sys/stat.h> #include <sys/types.h> -#include <sys/syscall.h> #include <sys/uio.h> /* writev */ #include <fcntl.h> #include <stdio.h> /* for sprintf */ @@ -288,7 +300,7 @@ os_get_cpu_affinity_bitmap (int pid) __CPU_ZERO_S (sizeof (cpu_set_t), &cpuset); - ret = syscall (SYS_sched_getaffinity, 0, sizeof (cpu_set_t), &cpuset); + ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset); if (ret < 0) { @@ -300,8 +312,23 @@ os_get_cpu_affinity_bitmap (int pid) if (__CPU_ISSET_S (index, sizeof (cpu_set_t), &cpuset)) clib_bitmap_set (affinity_cpus, index, 1); return affinity_cpus; +#elif defined(__FreeBSD__) + cpuset_t mask; + uword *r = NULL; + + if (cpuset_getaffinity (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1, + sizeof (mask), &mask) != 0) + { + clib_bitmap_free (r); + return NULL; + } + + for (int bit = 0; bit < CPU_SETSIZE; bit++) + clib_bitmap_set (r, bit, CPU_ISSET (bit, &mask)); + + return r; #else - return 0; + return NULL; #endif } @@ -310,6 +337,21 @@ os_get_online_cpu_node_bitmap () { #if __linux__ return clib_sysfs_read_bitmap ("/sys/devices/system/node/online"); +#elif defined(__FreeBSD__) + domainset_t domain; + uword *r = NULL; + int policy; + + if (cpuset_getdomain (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1, + sizeof (domain), &domain, &policy) != 0) + { + clib_bitmap_free (r); + return NULL; + } + + for (int bit = 0; bit < CPU_SETSIZE; bit++) + clib_bitmap_set (r, bit, CPU_ISSET (bit, &domain)); + return r; #else return 0; #endif @@ -358,6 +400,28 @@ os_get_cpu_phys_core_id (int cpu_id) #endif } +__clib_export u8 * +os_get_exec_path () +{ + u8 *rv = 0; +#ifdef __linux__ + char tmp[PATH_MAX]; + ssize_t sz = readlink ("/proc/self/exe", tmp, sizeof (tmp)); + + if (sz <= 0) + return 0; +#else + char tmp[MAXPATHLEN]; + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t sz = MAXPATHLEN; + + if (sysctl (mib, 4, tmp, &sz, NULL, 0) == -1) + return 0; +#endif + vec_add (rv, tmp, sz); + return rv; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vppinfra/unix.h b/src/vppinfra/unix.h index 3ad57b05e72..d0ddb93a46f 100644 --- a/src/vppinfra/unix.h +++ b/src/vppinfra/unix.h @@ -56,9 +56,6 @@ clib_error_t *unix_proc_file_contents (char *file, u8 ** result); /* Retrieve bitmap of online cpu cures */ clib_bitmap_t *os_get_online_cpu_core_bitmap (); -/* Retrieve bitmap of cpus vpp has affinity to */ -clib_bitmap_t *os_get_cpu_affinity_bitmap (int pid); - /* Retrieve bitmap of online cpu nodes (sockets) */ clib_bitmap_t *os_get_online_cpu_node_bitmap (); @@ -71,6 +68,10 @@ clib_bitmap_t *os_get_cpu_on_node_bitmap (int node); /* Retrieve physical core id of specific cpu, -1 if not available */ int os_get_cpu_phys_core_id (int cpu); +/* Retrieve the path of the current executable as a vector (not + * null-terminated). */ +u8 *os_get_exec_path (); + #endif /* included_clib_unix_h */ /* diff --git a/test/scripts/core_pinning.sh b/test/scripts/core_pinning.sh deleted file mode 100755 index 941d53871e5..00000000000 --- a/test/scripts/core_pinning.sh +++ /dev/null @@ -1,328 +0,0 @@ -#!/bin/bash -# -# core_pinning_auto.sh -- script to test vpp (debug-build) core-pinning -# -- in bare-metal, containers (docker, lxc) -# -DOCKER_CONTAINER_NAME="vpp_core_pinning" -VPP_SOCK_PATH=/run/vpp -CONTAINER_CPU_RANGE="4-7" -TEST_SUCCESS=0 -TEST_FAIL=0 -if [ ! $WS_ROOT ] -then - if [ ! -d "../../../vpp" ]; then - echo "VPP workspace path invalid" - echo "Please execute script from vpp/test/scripts folder.." - exit 1 - fi - WS_ROOT="$(dirname $(readlink -e "../../../vpp"))/$(basename "../../../vpp")" -fi -# Get available CPU count on host machine -host_cpulist=$(cat /sys/devices/system/cpu/online) -startcpu="${host_cpulist%-*}" -endcpu="${host_cpulist#*\-}" -cpucount="$(($endcpu - $startcpu + 1))" -if [ $cpucount -lt 8 ] -then - echo "Current host machine has $cpucount CPUs" - echo "A minimum of 8 CPUs is required to run testcases, exiting.." - exit 1 -fi -# Check that container 'vpp_core_pinning' does not already exist -count=$(docker ps -a | grep -c "$DOCKER_CONTAINER_NAME") -if [ $count -ne 0 ] -then - echo "Error: docker container $DOCKER_CONTAINER_NAME already exists" - echo "Remove it using 'docker stop/docker rm', then re-run test" - exit 1 -fi -# Check that there is no vpp instance currently running on the machine -count=$(pgrep vpp | wc -l) -if [ $count -ne 0 ] -then - echo "Error: a vpp instance is currently running on this machine" - echo "Please stop the running instance, then re-run test" - exit 1 -fi -mkdir -p $VPP_SOCK_PATH - -# Function to parse main core -parse_maincore () { - main_core_args=$1 - main_core_parsed=$main_core_args - if [ $main_core_args = "auto" ]; - then - main_core_parsed="0" - if [ -n "$SKIP_CORE" ] - then - main_core_parsed=$(($main_core_parsed + $SKIP_CORE)) - fi - if [ -n "$CONTAINER_RESTRAIN_CPUSET" ] - then - main_core_parsed=(${container_cpus[ $main_core_parsed ]}) - fi - fi - echo $main_core_parsed -} - -# Function to parse n workers range to an array -# e.g. "4" is parsed to ('0','1','2','3') -parse_workers_n () { - workers_n_args=$1 - workers_n_parsed=() - main_core_increment="0" - skip_core_increment="0" - if [ -n "$SKIP_CORE" ] - then - skip_core_increment=$(($SKIP_CORE)) - fi - - for ((i=0;i<$workers_n_args;i++)); do - - if [ -n "$CONTAINER_RESTRAIN_CPUSET" ] - then - if [ $(( ${container_cpus[ $(($i + $skip_core_increment)) ]})) -eq $(("$parsed_main_core")) ] - then - main_core_increment=$(($main_core_increment + 1)) - fi - workers_n_parsed+=" ${container_cpus[ $(($i + $main_core_increment + $skip_core_increment)) ]}" - else - if [ $(( $skip_core_increment + $i)) -eq $(("$parsed_main_core")) ] - then - main_core_increment=$(($main_core_increment + 1)) - fi - workers_n_parsed+=" $(($i + $main_core_increment + $skip_core_increment))" - fi - done - echo $workers_n_parsed -} - -# Function to parse corelist range to an array -# e.g. "0,3-5,7" is parsed to ('0','3','4','5','7') -parse_corelist () { - corelist_args=$1 - corelist_args=$(echo $corelist_args | grep -Po '[0-9]+-[0-9]+|[0-9]+') - corelist_parsed=() - for corelist_elt in ${corelist_args[@]};do - if [ $(echo $corelist_elt | grep -Po '[0-9]+-[0-9]+') ] - then - startcpu="${corelist_elt%-*}" - endcpu="${corelist_elt#*\-}" - cpucount="$(($endcpu - $startcpu))" - for ((i=0;i<=$cpucount;i++)); do - corelist_parsed+=" $(($i+$startcpu))" - done - elif [ $(echo $corelist_elt | grep -Po '[0-9]+') ] - then - corelist_parsed+=" ${corelist_elt}" - fi - done - echo $corelist_parsed -} -# Test VPP core pinning configuration -test_pinning_conf () { - VPP_CPU_EXTRA_OPTIONS="" - if [ -n "$CORELIST_WORKERS" ]; - then - VPP_CPU_EXTRA_OPTIONS=" corelist-workers ${CORELIST_WORKERS}" - fi - if [ -n "$WORKERS_AUTO" ]; - then - VPP_CPU_EXTRA_OPTIONS=" workers ${WORKERS_AUTO}" - fi - if [ -n "$SKIP_CORE" ]; - then - VPP_CPU_EXTRA_OPTIONS="${VPP_CPU_EXTRA_OPTIONS} skip-cores ${SKIP_CORE}" - fi - echo "TEST - conf 'cpu {main-core ${MAIN_CORE} ${VPP_CPU_EXTRA_OPTIONS}}'" - if [ -z "$CONTAINER_RESTRAIN_CPUSET" ]; - then - VPP_CONTAINER_CPUSET="" - echo "(Running vpp in container with full host cpuset $host_cpulist)" - else - VPP_CONTAINER_CPUSET="--cpuset-cpus $CONTAINER_CPU_RANGE" - echo "(Running vpp in container with limited cpuset $CONTAINER_CPU_RANGE)" - fi - (docker run -d ${VPP_CONTAINER_CPUSET} --name="$DOCKER_CONTAINER_NAME" \ - -e LD_LIBRARY_PATH="/vpp/build-root/build-vpp_debug-native/vpp/lib/x86_64-linux-gnu/" -v $VPP_SOCK_PATH:$VPP_SOCK_PATH \ - -v $WS_ROOT:/vpp ubuntu:22.04 sh -c "/vpp/build-root/build-vpp_debug-native/vpp/bin/vpp unix {interactive \ - nodaemon cli-listen $VPP_SOCK_PATH/cli.sock} cpu {main-core ${MAIN_CORE} ${VPP_CPU_EXTRA_OPTIONS} } plugins \ - { plugin dpdk_plugin.so {disable } }" > /dev/null ) - sleep 3 # wait for VPP to initialize socket - # Change access permissions on vpp cli socket - # docker exec -it "$DOCKER_CONTAINER_NAME" /bin/bash -c "chmod 777 $VPP_SOCK_PATH/cli.sock" > /dev/null - # check if vppctl can connect to vpp container instance - $WS_ROOT/build-root/build-vpp_debug-native/vpp/bin/vppctl -s $VPP_SOCK_PATH/cli.sock show threads 1> /dev/null - # get CPUs vpp instance in container is running on - taskset_vpp_cpus=($( taskset --all-tasks -pc $(pgrep vpp) | grep -e ".$" -o)) - rc=$? - # parse list of user requested CPUs for vpp - requested_cpus=() - parsed_main_core=$(parse_maincore ${MAIN_CORE}) - requested_cpus+=($parsed_main_core) - if [ -n "$CORELIST_WORKERS" ]; - then - requested_cpus+=($(parse_corelist ${CORELIST_WORKERS})) - fi - if [ -n "$WORKERS_AUTO" ]; - then - requested_cpus+=($(parse_workers_n ${WORKERS_AUTO})) - fi - - # parse list of expected CPUs used by vpp - expected_cpu_mapping=() - expected_cpu_mapping=("${requested_cpus[@]}") - echo "CPUs requested by user: [${requested_cpus[@]}]" - echo "--------------------" - echo "Expected CPU Mapping: [${expected_cpu_mapping[@]}]" - echo "VPP pinning (taskset): [${taskset_vpp_cpus[@]}]" - #check if expected CPU mapping matches CPUs vpp instance in container is running on - failure_cond="" - for index in ${!taskset_vpp_cpus[@]}; do - if [ ${taskset_vpp_cpus[$index]} -ne ${expected_cpu_mapping[ $index ]} ] - then - failure_cond="t" - fi - done - if [ $rc -eq 0 ] && [ -z "$failure_cond" ] - then - echo "Test Successful" - TEST_SUCCESS=$(($TEST_SUCCESS+1)) - else - echo "Test Failed" - TEST_FAIL=$(($TEST_FAIL+1)) - fi - echo "==============================================" - echo " " - # Stop & destroy container instance - docker stop $DOCKER_CONTAINER_NAME &> /dev/null - docker rm -f $DOCKER_CONTAINER_NAME &> /dev/null -} -test_invalid_conf () { - if [ -n "$CORELIST_WORKERS" ]; - then - VPP_CPU_EXTRA_OPTIONS=" corelist-workers ${CORELIST_WORKERS}" - fi - if [ -n "$WORKERS_AUTO" ]; - then - VPP_CPU_EXTRA_OPTIONS=" workers ${WORKERS_AUTO}" - fi - if [ -n "$SKIP_CORE" ]; - then - VPP_CPU_EXTRA_OPTIONS="${VPP_CPU_EXTRA_OPTIONS} skip-cores ${SKIP_CORE}" - fi - echo "TEST - conf 'cpu {main-core ${MAIN_CORE} ${VPP_CPU_EXTRA_OPTIONS}}'" - if [ -z "$CONTAINER_RESTRAIN_CPUSET" ]; - then - VPP_CONTAINER_CPUSET="" - echo "(Running vpp in container with full host cpuset $host_cpulist)" - else - VPP_CONTAINER_CPUSET="--cpuset-cpus $CONTAINER_CPU_RANGE" - echo "(Running vpp in container with limited cpuset $CONTAINER_CPU_RANGE)" - fi - (docker run -d --cpuset-cpus $CONTAINER_CPU_RANGE --name="$DOCKER_CONTAINER_NAME" \ - -e LD_LIBRARY_PATH="/vpp/build-root/build-vpp_debug-native/vpp/lib/x86_64-linux-gnu/" -v $VPP_SOCK_PATH:$VPP_SOCK_PATH \ - -v $WS_ROOT:/vpp ubuntu:22.04 sh -c "/vpp/build-root/build-vpp_debug-native/vpp/bin/vpp unix {interactive \ - nodaemon cli-listen $VPP_SOCK_PATH/cli.sock} cpu {main-core ${MAIN_CORE} ${VPP_CPU_EXTRA_OPTIONS}} plugins \ - { plugin dpdk_plugin.so {disable } }" > /dev/null) - sleep 3 # wait for vpp to initialize socket - # check if vpp launched with invalid configuration - taskset --all-tasks -pc $(pgrep vpp) &> /dev/null - rc=$? - if [ $rc -eq 1 ] - then - echo " " - echo "OK... VPP did not launch with invalid configuration" - TEST_SUCCESS=$(($TEST_SUCCESS+1)) - else - echo " " - echo "Failure... VPP launched with wrong configuration" - TEST_FAIL=$(($TEST_FAIL+1)) - fi - echo "==============================================" - echo " " - # Stop & destroy container instance - docker stop $DOCKER_CONTAINER_NAME &> /dev/null - docker rm -f $DOCKER_CONTAINER_NAME &> /dev/null -} -run_tests () { - container_cpus=($(parse_corelist ${CONTAINER_CPU_RANGE})) - echo "TESTING VALID CORE PINNING CONFIGURATIONS" - echo " " - WORKERS_AUTO="" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="" - CORELIST_WORKERS="1-3" - MAIN_CORE="0" - test_pinning_conf - WORKERS_AUTO="" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="" - CORELIST_WORKERS="0,2-3" - MAIN_CORE="1" - test_pinning_conf - WORKERS_AUTO="" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="" - CORELIST_WORKERS="0-2" - MAIN_CORE="3" - test_pinning_conf - WORKERS_AUTO="2" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_pinning_conf - WORKERS_AUTO="3" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_pinning_conf - WORKERS_AUTO="2" - SKIP_CORE="1" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_pinning_conf - WORKERS_AUTO="2" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="5" - test_pinning_conf - echo "TESTING NON-VALID CORE PINNING CONFIGURATIONS" - echo " " - WORKERS_AUTO="" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="1-3" - MAIN_CORE="0" - test_invalid_conf - WORKERS_AUTO="3" - SKIP_CORE="1" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_invalid_conf - WORKERS_AUTO="5" - SKIP_CORE="" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_invalid_conf - WORKERS_AUTO="" - SKIP_CORE="4" - CONTAINER_RESTRAIN_CPUSET="t" - CORELIST_WORKERS="" - MAIN_CORE="auto" - test_invalid_conf - echo " " - echo "========================" - echo "RESULTS:" - echo "SUCCESS: $TEST_SUCCESS" - echo "FAILURE: $TEST_FAIL" - echo "========================" - echo " " -} -run_tests
\ No newline at end of file diff --git a/test/test_abf.py b/test/test_abf.py index 3baec9f9e9b..ec329a0ec9b 100644 --- a/test/test_abf.py +++ b/test/test_abf.py @@ -391,7 +391,7 @@ class TestAbf(VppTestCase): # a packet matching the deny rule # p_deny = ( - Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg3.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100) @@ -402,7 +402,7 @@ class TestAbf(VppTestCase): # a packet matching the permit rule # p_permit = ( - Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100) @@ -454,7 +454,7 @@ class TestAbf(VppTestCase): # a packet matching the deny rule # p_deny = ( - Ether(src=self.pg0.remote_mac, dst=self.pg3.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg3.remote_ip6) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100) @@ -465,7 +465,7 @@ class TestAbf(VppTestCase): # a packet matching the permit rule # p_permit = ( - Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg2.remote_ip6) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100) diff --git a/test/test_flowprobe.py b/test/test_flowprobe.py index ac0433abc00..8e3fecfd7b4 100644 --- a/test/test_flowprobe.py +++ b/test/test_flowprobe.py @@ -559,7 +559,7 @@ class Flowprobe(MethodHolder): # make a tcp packet self.pkts = [ ( - Ether(src=self.pg3.remote_mac, dst=self.pg4.local_mac) + Ether(src=self.pg3.remote_mac, dst=self.pg3.local_mac) / IP(src=self.pg3.remote_ip4, dst=self.pg4.remote_ip4) / TCP(sport=1234, dport=4321) / Raw(b"\xa5" * 50) diff --git a/test/test_gso.py b/test/test_gso.py index 78c5c734660..3d9ce5fb4ee 100644 --- a/test/test_gso.py +++ b/test/test_gso.py @@ -405,7 +405,7 @@ class TestGSO(VppTestCase): # IPv4/IPv4 - VXLAN # p45 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -419,12 +419,12 @@ class TestGSO(VppTestCase): self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) - self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False) + self.assert_udp_checksum_valid(rx, ignore_zero_checksum=True) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) - self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") + self.assertEqual(inner[Ether].dst, self.pg2.local_mac) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.3.3") self.assert_ip_checksum_valid(inner) @@ -438,7 +438,7 @@ class TestGSO(VppTestCase): # IPv4/IPv6 - VXLAN # p65 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -452,12 +452,12 @@ class TestGSO(VppTestCase): self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) - self.assert_udp_checksum_valid(rx, ignore_zero_checksum=False) + self.assert_udp_checksum_valid(rx, ignore_zero_checksum=True) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) - self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") + self.assertEqual(inner[Ether].dst, self.pg2.local_mac) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:3::3") self.assert_tcp_checksum_valid(inner) @@ -483,7 +483,7 @@ class TestGSO(VppTestCase): # IPv6/IPv4 - VXLAN # p46 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -501,7 +501,7 @@ class TestGSO(VppTestCase): inner = rx[VXLAN].payload self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) - self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") + self.assertEqual(inner[Ether].dst, self.pg2.local_mac) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.3.3") self.assert_ip_checksum_valid(inner) @@ -515,7 +515,7 @@ class TestGSO(VppTestCase): # IPv6/IPv6 - VXLAN # p66 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -533,7 +533,7 @@ class TestGSO(VppTestCase): inner = rx[VXLAN].payload self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) - self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") + self.assertEqual(inner[Ether].dst, self.pg2.local_mac) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:3::3") self.assert_tcp_checksum_valid(inner) @@ -590,7 +590,7 @@ class TestGSO(VppTestCase): # IPv4/IPv4 - IPIP # p47 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -633,7 +633,7 @@ class TestGSO(VppTestCase): # IPv4/IPv6 - IPIP # p67 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -731,7 +731,7 @@ class TestGSO(VppTestCase): # IPv6/IPv4 - IPIP # p48 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -774,7 +774,7 @@ class TestGSO(VppTestCase): # IPv6/IPv6 - IPIP # p68 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -842,7 +842,7 @@ class TestGSO(VppTestCase): self.ip4_via_gre4_tunnel.add_vpp_config() pgre4 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -952,7 +952,7 @@ class TestGSO(VppTestCase): # Create IPv6 packet # pgre6 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -1078,7 +1078,7 @@ class TestGSO(VppTestCase): # IPv4/IPv4 - IPSEC # ipsec44 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -1116,7 +1116,7 @@ class TestGSO(VppTestCase): # IPv4/IPv6 - IPSEC # ipsec46 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -1213,7 +1213,7 @@ class TestGSO(VppTestCase): # IPv6/IPv4 - IPSEC # ipsec64 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags="DF") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) @@ -1252,7 +1252,7 @@ class TestGSO(VppTestCase): # IPv6/IPv6 - IPSEC # ipsec66 = ( - Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b"\xa5" * 65200) diff --git a/test/test_gtpu.py b/test/test_gtpu.py index fd97205ac63..5fe4f36ccb3 100644 --- a/test/test_gtpu.py +++ b/test/test_gtpu.py @@ -36,7 +36,7 @@ class TestGtpuUDP(VppTestCase): def _check_udp_port_ip4(self, enabled=True): pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=self.dport, dport=self.dport, chksum=0) ) @@ -55,7 +55,7 @@ class TestGtpuUDP(VppTestCase): def _check_udp_port_ip6(self, enabled=True): pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / UDP(sport=self.dport, dport=self.dport, chksum=0) ) diff --git a/test/test_ip6.py b/test/test_ip6.py index a1cd943570c..84b060aa7a3 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -3409,9 +3409,11 @@ class TestIP6LinkLocal(VppTestCase): # Use the specific link-local API on pg1 # VppIp6LinkLocalAddress(self, self.pg1, ll1).add_vpp_config() + p_echo_request_1.dst = self.pg1.local_mac self.send_and_expect(self.pg1, [p_echo_request_1], self.pg1) VppIp6LinkLocalAddress(self, self.pg1, ll3).add_vpp_config() + p_echo_request_3.dst = self.pg1.local_mac self.send_and_expect(self.pg1, [p_echo_request_3], self.pg1) def test_ip6_ll_p2p(self): diff --git a/test/test_ip6_nd_mirror_proxy.py b/test/test_ip6_nd_mirror_proxy.py index 65209925e87..10dc77e1a86 100644 --- a/test/test_ip6_nd_mirror_proxy.py +++ b/test/test_ip6_nd_mirror_proxy.py @@ -161,7 +161,7 @@ class TestNDPROXY(VppTestCase): redirect.add_vpp_config() echo_reply = ( - Ether(dst=self.pg0.remote_mac, src=self.pg0.local_mac) + Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / ICMPv6EchoReply(seq=1, id=id) ) diff --git a/test/test_ipip.py b/test/test_ipip.py index 2817d5a17ba..9574c2c299c 100644 --- a/test/test_ipip.py +++ b/test/test_ipip.py @@ -677,7 +677,7 @@ class TestIPIP(VppTestCase): / Raw(b"0x44" * 100) ) tx_e = [ - (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner) + (Ether(dst=self.pg2.local_mac, src=self.pg0.remote_mac) / inner) for x in range(63) ] @@ -1454,7 +1454,7 @@ class TestIPIPMPLS(VppTestCase): # Tunnel Decap # p4 = ( - self.p_ether + Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / MPLS(label=44, ttl=4) / IP(src="1.1.1.1", dst="2.2.2.2") @@ -1468,7 +1468,7 @@ class TestIPIPMPLS(VppTestCase): self.assertEqual(rx[IP].dst, "2.2.2.2") p6 = ( - self.p_ether + Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) / MPLS(label=66, ttl=4) / IPv6(src="1::1", dst="2::2") diff --git a/test/test_l3xc.py b/test/test_l3xc.py index 351c599051c..69267b35817 100644 --- a/test/test_l3xc.py +++ b/test/test_l3xc.py @@ -126,7 +126,7 @@ class TestL3xc(VppTestCase): p_2 = [] for ii in range(NUM_PKTS): p_2.append( - Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) + Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1000 + ii, dport=1234) / Raw(b"\xa5" * 100) diff --git a/test/test_linux_cp.py b/test/test_linux_cp.py index a9ff242e215..95a9f1aca1f 100644 --- a/test/test_linux_cp.py +++ b/test/test_linux_cp.py @@ -126,7 +126,7 @@ class TestLinuxCP(VppTestCase): for phy, host in zip(phys, hosts): for j in range(N_HOSTS): p = ( - Ether(src=phy.local_mac, dst=phy.remote_hosts[j].mac) + Ether(src=phy.local_mac, dst=host.local_mac) / IP(src=phy.local_ip4, dst=phy.remote_hosts[j].ip4) / UDP(sport=1234, dport=1234) / Raw() diff --git a/test/test_map.py b/test/test_map.py index 565f7da6491..c65c5df7cda 100644 --- a/test/test_map.py +++ b/test/test_map.py @@ -494,7 +494,7 @@ class TestMAP(VppTestCase): # # Send a v4 packet that will be encapped. # - p_ether = Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) + p_ether = Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst="192.168.1.1") p_tcp = TCP(sport=20000, dport=30000, flags="S", options=[("MSS", 1455)]) p4 = p_ether / p_ip4 / p_tcp diff --git a/test/test_map_br.py b/test/test_map_br.py index 0de0e31520c..a2c00d8d8ea 100644 --- a/test/test_map_br.py +++ b/test/test_map_br.py @@ -280,7 +280,7 @@ class TestMAPBR(VppTestCase): def test_map_t_echo_request_ip4_to_ip6(self): """MAP-T echo request IPv4 -> IPv6""" - eth = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) + eth = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) ip = IP(src=self.pg0.remote_ip4, dst=self.ipv4_map_address) icmp = ICMP(type="echo-request", id=self.ipv6_udp_or_tcp_map_port) payload = "H" * 10 @@ -306,7 +306,7 @@ class TestMAPBR(VppTestCase): def test_map_t_echo_reply_ip4_to_ip6(self): """MAP-T echo reply IPv4 -> IPv6""" - eth = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) + eth = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) ip = IP(src=self.pg0.remote_ip4, dst=self.ipv4_map_address) icmp = ICMP(type="echo-reply", id=self.ipv6_udp_or_tcp_map_port) payload = "H" * 10 diff --git a/test/test_mpls.py b/test/test_mpls.py index 9c07251a481..0e747ec7cd0 100644 --- a/test/test_mpls.py +++ b/test/test_mpls.py @@ -2018,7 +2018,7 @@ class TestMPLS(VppTestCase): binding.add_vpp_config() tx = ( - Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=44, ttl=64) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=1234, dport=1234) diff --git a/test/test_nat44_ed_output.py b/test/test_nat44_ed_output.py index ad1c5611418..dbf1dc40a75 100644 --- a/test/test_nat44_ed_output.py +++ b/test/test_nat44_ed_output.py @@ -216,7 +216,7 @@ class TestNAT44EDOutput(VppTestCase): # send FIN+ACK packet in->out - will cause session to be wiped # but won't create a new session p = ( - Ether(src=pg0.remote_mac, dst=pg0.local_mac) + Ether(src=pg1.remote_mac, dst=pg1.local_mac) / IP(src=local_host, dst=remote_host) / TCP(sport=local_sport, dport=remote_dport, flags="FA", seq=300, ack=101) ) diff --git a/test/test_neighbor.py b/test/test_neighbor.py index 6fcf13f8261..d11d4abac14 100644 --- a/test/test_neighbor.py +++ b/test/test_neighbor.py @@ -2176,6 +2176,7 @@ class ARPTestCase(VppTestCase): table_id=1, ).add_vpp_config() + p2.dst = self.pg3.local_mac rxs = self.send_and_expect(self.pg3, [p2], self.pg1) for rx in rxs: self.verify_arp_req(rx, self.pg1.local_mac, "10.0.1.2", "10.0.1.128") diff --git a/test/test_pcap.py b/test/test_pcap.py index ae3a298f76a..72d215cea06 100644 --- a/test/test_pcap.py +++ b/test/test_pcap.py @@ -135,7 +135,7 @@ class TestPcap(VppTestCase): self.vapi.cli("classify filter pcap del mask l3 ip4 src") pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) # wrong destination address / IP(src=self.pg0.local_ip4, dst=self.pg0.local_ip4, ttl=2) / UDP(sport=1234, dport=2345) diff --git a/test/test_reassembly.py b/test/test_reassembly.py index e407252d380..98c50f9bb61 100644 --- a/test/test_reassembly.py +++ b/test/test_reassembly.py @@ -1604,16 +1604,6 @@ class TestIPv6Reassembly(VppTestCase): self.assertIn(ICMPv6ParamProblem, icmp) self.assert_equal(icmp[ICMPv6ParamProblem].code, 3, "ICMP code") - def test_truncated_fragment(self): - """truncated fragment""" - pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) - / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=2) - / IPv6ExtHdrFragment(nh=6) - ) - - self.send_and_assert_no_replies(self.pg0, [pkt], self.pg0) - def test_invalid_frag_size(self): """fragment size not a multiple of 8""" p = ( @@ -1657,7 +1647,7 @@ class TestIPv6Reassembly(VppTestCase): def test_atomic_fragment(self): """IPv6 atomic fragment""" pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44, plen=65535) / IPv6ExtHdrFragment( offset=8191, m=1, res1=0xFF, res2=0xFF, nh=255, id=0xFFFF @@ -1679,7 +1669,7 @@ class TestIPv6Reassembly(VppTestCase): self.send_and_assert_no_replies(self.pg0, [pkt]) pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.remote_ip6) / ICMPv6EchoRequest() ) @@ -1688,7 +1678,7 @@ class TestIPv6Reassembly(VppTestCase): def test_one_fragment(self): """whole packet in one fragment processed independently""" pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / ICMPv6EchoRequest() / Raw("X" * 1600) @@ -1700,7 +1690,7 @@ class TestIPv6Reassembly(VppTestCase): # send an atomic fragment with same id - should be reassembled pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / IPv6ExtHdrFragment(id=1) / ICMPv6EchoRequest() @@ -1715,7 +1705,7 @@ class TestIPv6Reassembly(VppTestCase): def test_bunch_of_fragments(self): """valid fragments followed by rogue fragments and atomic fragment""" pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / ICMPv6EchoRequest() / Raw("X" * 1600) @@ -1733,7 +1723,7 @@ class TestIPv6Reassembly(VppTestCase): self.send_and_assert_no_replies(self.pg0, inc_frag * 604) pkt = ( - Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) + Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / IPv6ExtHdrFragment(id=1) / ICMPv6EchoRequest() @@ -1748,7 +1738,7 @@ class TestIPv6Reassembly(VppTestCase): ) self.vapi.ip_local_reass_enable_disable(enable_ip6=True) pkt = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.src_if.local_ip6) / ICMPv6EchoRequest(id=1234) / Raw("X" * 1600) @@ -2194,7 +2184,7 @@ class TestIPv6SVReassembly(VppTestCase): def test_one_fragment(self): """whole packet in one fragment processed independently""" pkt = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / ICMPv6EchoRequest() / Raw("X" * 1600) @@ -2206,7 +2196,7 @@ class TestIPv6SVReassembly(VppTestCase): # send an atomic fragment with same id - should be reassembled pkt = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / IPv6ExtHdrFragment(id=1) / ICMPv6EchoRequest() @@ -2219,7 +2209,7 @@ class TestIPv6SVReassembly(VppTestCase): def test_bunch_of_fragments(self): """valid fragments followed by rogue fragments and atomic fragment""" pkt = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / ICMPv6EchoRequest() / Raw("X" * 1600) @@ -2228,7 +2218,7 @@ class TestIPv6SVReassembly(VppTestCase): rx = self.send_and_expect(self.src_if, frags, self.dst_if) rogue = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / IPv6ExtHdrFragment(id=1, nh=58, offset=608) / Raw("X" * 308) @@ -2237,7 +2227,7 @@ class TestIPv6SVReassembly(VppTestCase): self.send_and_expect(self.src_if, rogue * 604, self.dst_if) pkt = ( - Ether(src=self.src_if.local_mac, dst=self.src_if.remote_mac) + Ether(src=self.src_if.remote_mac, dst=self.src_if.local_mac) / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / IPv6ExtHdrFragment(id=1) / ICMPv6EchoRequest() diff --git a/test/test_srv6_mobile.py b/test/test_srv6_mobile.py index 9d39f194015..314dfc114e2 100644 --- a/test/test_srv6_mobile.py +++ b/test/test_srv6_mobile.py @@ -60,7 +60,7 @@ class TestSRv6EndMGTP4E(VppTestCase): pkts = list() for d, s in inner: pkt = ( - Ether() + Ether(dst=self.pg0.local_mac) / IPv6(dst=str(ip6_dst), src=str(ip6_src)) / IPv6ExtHdrSegmentRouting() / IPv6(dst=d, src=s) @@ -149,7 +149,7 @@ class TestSRv6TMGTP4D(VppTestCase): pkts = list() for d, s in inner: pkt = ( - Ether() + Ether(dst=self.pg0.local_mac) / IP(dst=str(ip4_dst), src=str(ip4_src)) / UDP(sport=2152, dport=2152) / GTP_U_Header(gtp_type="g_pdu", teid=200) @@ -254,7 +254,7 @@ class TestSRv6EndMGTP6E(VppTestCase): pkts = list() for d, s in inner: pkt = ( - Ether() + Ether(dst=self.pg0.local_mac) / IPv6(dst=str(ip6_dst), src=str(ip6_src)) / IPv6ExtHdrSegmentRouting( segleft=1, lastentry=0, tag=0, addresses=["a1::1"] @@ -344,7 +344,7 @@ class TestSRv6EndMGTP6D(VppTestCase): pkts = list() for d, s in inner: pkt = ( - Ether() + Ether(dst=self.pg0.local_mac) / IPv6(dst=str(ip6_dst), src=str(ip6_src)) / UDP(sport=2152, dport=2152) / GTP_U_Header(gtp_type="g_pdu", teid=200) diff --git a/test/test_trace_filter.py b/test/test_trace_filter.py index 58494cd7ad9..c188631c200 100644 --- a/test/test_trace_filter.py +++ b/test/test_trace_filter.py @@ -386,7 +386,7 @@ class TestTraceFilterInner(TemplateTraceFilter): def __gen_encrypt_pkt(self, scapy_sa, pkt): return Ether( - src=self.pg0.local_mac, dst=self.pg0.remote_mac + src=self.pg0.remote_mac, dst=self.pg0.local_mac ) / scapy_sa.encrypt(pkt) def test_encrypted_encap(self): diff --git a/test/test_vxlan.py b/test/test_vxlan.py index 6128d1070d3..284e1359116 100644 --- a/test/test_vxlan.py +++ b/test/test_vxlan.py @@ -580,6 +580,7 @@ class TestVxlanL2Mode(VppTestCase): # Send packets NUM_PKTS = 128 + p.dst = self.pg1.local_mac rx = self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg0) self.assertEqual(NUM_PKTS, len(rx)) diff --git a/test/vpp_ip_route.py b/test/vpp_ip_route.py index 9b3a138a81c..d36c56761e3 100644 --- a/test/vpp_ip_route.py +++ b/test/vpp_ip_route.py @@ -169,15 +169,17 @@ def fib_interface_ip_prefix(test, addr, len, sw_if_index): class VppIpTable(VppObject): - def __init__(self, test, table_id, is_ip6=0, register=True): + def __init__(self, test, table_id, is_ip6=0, register=True, name=""): self._test = test + self.name = name self.table_id = table_id self.is_ip6 = is_ip6 self.register = register def add_vpp_config(self): self._test.vapi.ip_table_add_del( - is_add=1, table={"is_ip6": self.is_ip6, "table_id": self.table_id} + is_add=1, + table={"is_ip6": self.is_ip6, "table_id": self.table_id, "name": self.name}, ) if self.register: self._test.registry.register(self, self._test.logger) |