diff options
156 files changed, 2713 insertions, 3579 deletions
diff --git a/.clang-format b/.clang-format index 617c5db417f..798a8c39a35 100644 --- a/.clang-format +++ b/.clang-format @@ -27,6 +27,7 @@ ForEachMacros: - 'foreach_vlib_frame_bitmap_set_bit_index' - 'FOREACH_ARRAY_ELT' - 'RTE_ETH_FOREACH_DEV' + - 'foreach_clib_stack_frame' - 'foreach_vnet_dev_rx_queue_runtime' - 'foreach_vnet_dev_counter' - 'foreach_vnet_dev_port_rx_queue' diff --git a/.gitignore b/.gitignore index 5c707a8364a..a1550566b42 100644 --- a/.gitignore +++ b/.gitignore @@ -123,6 +123,8 @@ compile_commands.json /extras/hs-test/hs-test /extras/hs-test/http_server /extras/hs-test/.build.ok +/extras/hs-test/.build.cov.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/ @@ -72,7 +72,7 @@ DEB_DEPENDS += debhelper dkms git libtool libapr1-dev dh-python DEB_DEPENDS += libconfuse-dev git-review exuberant-ctags cscope pkg-config DEB_DEPENDS += gcovr lcov chrpath autoconf libnuma-dev DEB_DEPENDS += python3-all python3-setuptools check -DEB_DEPENDS += libffi-dev python3-ply +DEB_DEPENDS += libffi-dev python3-ply libunwind-dev DEB_DEPENDS += cmake ninja-build python3-jsonschema python3-yaml DEB_DEPENDS += python3-venv # ensurepip DEB_DEPENDS += python3-dev python3-pip @@ -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 @@ -244,6 +245,7 @@ help: @echo " build - build debug binaries" @echo " build-release - build release binaries" @echo " build-coverity - build coverity artifacts" + @echo " build-vpp-gcov - build gcov vpp only" @echo " rebuild - wipe and build debug binaries" @echo " rebuild-release - wipe and build release binaries" @echo " run - run debug binary" @@ -251,6 +253,8 @@ help: @echo " debug - run debug binary with debugger" @echo " debug-release - run release binary with debugger" @echo " test - build and run tests" + @echo " test-cov-hs - build and run host stack tests with coverage" + @echo " test-cov-both - build and run python and host stack tests, merge coverage data" @echo " test-help - show help on test framework" @echo " run-vat - run vpp-api-test tool" @echo " pkg-deb - build DEB packages" @@ -439,6 +443,10 @@ rebuild: wipe build build-release: $(BR)/.deps.ok $(call make,$(PLATFORM),$(addsuffix -install,$(TARGETS))) +.PHONY: build-vpp-gcov +build-vpp-gcov: + $(call test,vpp_gcov) + .PHONY: wipe-release wipe-release: test-wipe $(BR)/.deps.ok $(call make,$(PLATFORM),$(addsuffix -wipe,$(TARGETS))) @@ -485,6 +493,20 @@ test-cov: $(eval TEST_GCOV=1) $(call test,vpp_gcov,cov) +.PHONY: test-cov-hs +test-cov-hs: + @make -C extras/hs-test build-cov + @make -C extras/hs-test test-cov + +.PHONY: test-cov-both +test-cov-both: + @echo "Running Python, Golang tests and merging coverage reports." + find $(BR) -name '*.gcda' -delete + @make test-cov + find $(BR) -name '*.gcda' -delete + @make test-cov-hs + @make cov-merge + .PHONY: test-cov-build test-cov-build: $(eval CC=gcc) @@ -501,6 +523,14 @@ test-cov-post: $(eval CC=gcc) $(call test,vpp_gcov,cov-post) +.PHONY: cov-merge +cov-merge: + @lcov --add-tracefile $(BR)/test-coverage-merged/coverage-filtered.info \ + -a $(BR)/test-coverage-merged/coverage-filtered1.info -o $(BR)/test-coverage-merged/coverage-merged.info + @genhtml $(BR)/test-coverage-merged/coverage-merged.info \ + --output-directory $(BR)/test-coverage-merged/html + @echo "Code coverage report is in $(BR)/test-coverage-merged/html/index.html" + .PHONY: test-all test-all: $(eval EXTENDED_TESTS=1) diff --git a/build/external/packages/octeon-roc.mk b/build/external/packages/octeon-roc.mk index 62f5d823bdf..98eb29b95aa 100644 --- a/build/external/packages/octeon-roc.mk +++ b/build/external/packages/octeon-roc.mk @@ -2,12 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 # https://spdx.org/licenses/Apache-2.0.html -octeon-roc_version := 0.3 -octeon-roc_tarball := octeon-roc-v$(octeon-roc_version).tar.gz -octeon-roc_tarball_md5sum := e4a16beb76a6c63af1600dd4d1d752b8 +octeon-roc_version := 0.5 +octeon-roc_tarball := v$(octeon-roc_version).tar.gz +octeon-roc_tarball_md5sum := 76bc56c84935da944bbf340fe5283ef0 octeon-roc_tarball_strip_dirs := 1 -octeon-roc_url := https://github.com/MarvellEmbeddedProcessors/marvell-vpp/archive/refs/tags/$(octeon-roc_tarball) +octeon-roc_url := https://github.com/MarvellEmbeddedProcessors/marvell-octeon-roc/archive/refs/tags/$(octeon-roc_tarball) define octeon-roc_config_cmds @true diff --git a/docs/aboutvpp/releasenotes/index.rst b/docs/aboutvpp/releasenotes/index.rst index adbe8401d27..6fda5152a58 100644 --- a/docs/aboutvpp/releasenotes/index.rst +++ b/docs/aboutvpp/releasenotes/index.rst @@ -9,6 +9,4 @@ Release notes v24.02 v23.10 v23.06 - v23.02 - v22.10.1 past diff --git a/docs/aboutvpp/releasenotes/past.rst b/docs/aboutvpp/releasenotes/past.rst index 87285828eef..8f15bd4da3e 100644 --- a/docs/aboutvpp/releasenotes/past.rst +++ b/docs/aboutvpp/releasenotes/past.rst @@ -6,6 +6,8 @@ Past releases .. toctree:: :maxdepth: 1 + v23.02 + v22.10.1 v22.10 v22.06.1 v22.06 diff --git a/docs/configuration/reference.rst b/docs/configuration/reference.rst index 598e195af13..d288a6d7788 100644 --- a/docs/configuration/reference.rst +++ b/docs/configuration/reference.rst @@ -497,6 +497,9 @@ The buffers Section buffers-per-numa 128000 default data-size 2048 page-size default-hugepage + numa 1 { + buffers 64000 + } } buffers-per-numa number @@ -532,6 +535,31 @@ Set the page size for buffer allocation page-size default page-size default-hugepage +numa <numa index> { .. } +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Settings specific to a single NUMA domain. + +.. code-block:: console + + buffers { + numa 0 { + buffers 32768 + } + } + +buffers <n> +^^^^^^^^^^^^^^^ + +The number of buffers allocated for this specific NUMA domain. +Default is 0, which falls back to the value configured in **buffers-per-numa**. + +.. code-block:: console + + numa 0 { + buffers 32768 + } + The dpdk Section ---------------- 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 d4e699940d1..dc34e5332ea 100644 --- a/extras/hs-test/Makefile +++ b/extras/hs-test/Makefile @@ -1,3 +1,4 @@ +export HS_ROOT=$(CURDIR) ifeq ($(VERBOSE),) VERBOSE=false @@ -15,6 +16,10 @@ ifeq ($(TEST),) TEST=all endif +ifeq ($(TEST-HS),) +TEST-HS=all +endif + ifeq ($(DEBUG),) DEBUG=false endif @@ -50,7 +55,9 @@ list_tests = @go run github.com/onsi/ginkgo/v2/ginkgo --dry-run -v --no-color -- help: @echo "Make targets:" @echo " test - run tests" + @echo " test-debug - run tests (vpp debug image)" @echo " build - build test infra" + @echo " build-cov - coverage build of VPP and Docker images" @echo " build-debug - build test infra (vpp debug image)" @echo " build-go - just build golang files" @echo " fixstyle - format .go source files" @@ -66,7 +73,7 @@ help: @echo " UNCONFIGURE=[true|false] - unconfigure selected test" @echo " DEBUG=[true|false] - attach VPP to GDB" @echo " TEST=[test-name] - specific test to run" - @echo " CPUS=[n-cpus] - number of cpus to run with vpp" + @echo " CPUS=[n-cpus] - number of cpus to allocate to VPP and containers" @echo " VPPSRC=[path-to-vpp-src] - path to vpp source files (for gdb)" @echo " PARALLEL=[n-cpus] - number of test processes to spawn to run in parallel" @echo " REPEAT=[n] - repeat tests up to N times or until a failure occurs" @@ -86,14 +93,44 @@ build-vpp-release: build-vpp-debug: @make -C ../.. build +.PHONY: build-vpp-gcov +build-vpp-gcov: + @make -C ../.. build-vpp-gcov + .build.ok: build @touch .build.ok +.build.cov.ok: build-vpp-gcov + @touch .build.cov.ok + +.build_debug.ok: build-debug + @touch .build.ok + .PHONY: test test: .deps.ok .build.ok - @bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ + # '-' ignores the exit status, it is set in compress.sh + # necessary so gmake won't skip executing the bash script + -bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) + @bash ./script/compress.sh + +.PHONY: test-debug +test-debug: .deps.ok .build_debug.ok + # '-' ignores the exit status, it is set in compress.sh + # necessary so gmake won't skip executing the bash script + -bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ + --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ + --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) + @bash ./script/compress.sh + +.PHONY: test-cov +test-cov: .deps.ok .build.cov.ok + -bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \ + --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST-HS) --cpus=$(CPUS) \ + --vppsrc=$(VPPSRC) + @make -C ../.. test-cov-post HS_TEST=1 + @bash ./script/compress.sh .PHONY: build-go build-go: @@ -105,6 +142,12 @@ build: .deps.ok build-vpp-release build-go bash ./script/build_hst.sh release @touch .build.ok +.PHONY: build-cov +build-cov: .deps.ok build-vpp-gcov build-go + @rm -f .build.cov.ok + bash ./script/build_hst.sh gcov + @touch .build.cov.ok + .PHONY: build-debug build-debug: .deps.ok build-vpp-debug build-go @rm -f .build.ok diff --git a/extras/hs-test/container.go b/extras/hs-test/container.go index c82f1fc03a7..080eb736ad4 100644 --- a/extras/hs-test/container.go +++ b/extras/hs-test/container.go @@ -37,6 +37,7 @@ type Container struct { volumes map[string]Volume envVars map[string]string vppInstance *VppInstance + allocatedCpus []int } func newContainer(suite *HstSuite, yamlInput ContainerConfig) (*Container, error) { @@ -77,7 +78,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig) (*Container, error } if _, ok := yamlInput["volumes"]; ok { - workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + container.suite.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{}) { @@ -160,6 +161,12 @@ func (c *Container) create() error { return exechelper.Run(cmd) } +func (c *Container) allocateCpus() { + c.suite.startedContainers = append(c.suite.startedContainers, c) + c.allocatedCpus = c.suite.AllocateCpus() + c.suite.log("Allocated CPUs " + fmt.Sprint(c.allocatedCpus) + " to container " + c.name) +} + func (c *Container) start() error { cmd := "docker start " + c.name c.suite.log(cmd) @@ -173,8 +180,11 @@ func (c *Container) prepareCommand() (string, error) { cmd := "docker run " if c.runDetached { - cmd += " -d" + cmd += " -dt" } + + c.allocateCpus() + cmd += fmt.Sprintf(" --cpuset-cpus=\"%d-%d\"", c.allocatedCpus[0], c.allocatedCpus[len(c.allocatedCpus)-1]) cmd += " " + c.getContainerArguments() c.suite.log(cmd) @@ -286,7 +296,7 @@ func (c *Container) exec(command string, arguments ...any) string { GinkgoHelper() c.suite.log(containerExecCommand) byteOutput, err := exechelper.CombinedOutput(containerExecCommand) - c.suite.assertNil(err, err) + c.suite.assertNil(err, fmt.Sprint(err)) return string(byteOutput) } @@ -340,7 +350,7 @@ func (c *Container) log(maxLines int) (string, error) { } func (c *Container) stop() error { - if c.vppInstance != nil && c.vppInstance.apiChannel != nil { + if c.vppInstance != nil && c.vppInstance.apiStream != nil { c.vppInstance.saveLogs() c.vppInstance.disconnect() } diff --git a/extras/hs-test/cpu.go b/extras/hs-test/cpu.go index a976f47d8a5..49a7dfb02f8 100644 --- a/extras/hs-test/cpu.go +++ b/extras/hs-test/cpu.go @@ -4,6 +4,7 @@ import ( "bufio" "errors" "fmt" + . "github.com/onsi/ginkgo/v2" "os" "os/exec" "strings" @@ -16,26 +17,35 @@ type CpuContext struct { cpus []int } -func (c *CpuContext) Release() { - c.cpuAllocator.cpus = append(c.cpuAllocator.cpus, c.cpus...) - c.cpus = c.cpus[:0] // empty the list -} - type CpuAllocatorT struct { cpus []int } var cpuAllocator *CpuAllocatorT = nil -func (c *CpuAllocatorT) Allocate(nCpus int) (*CpuContext, error) { +func (c *CpuAllocatorT) Allocate(containerCount int, nCpus int) (*CpuContext, error) { var cpuCtx CpuContext - if len(c.cpus) < nCpus { - return nil, fmt.Errorf("could not allocate %d CPUs; available: %d", nCpus, len(c.cpus)) + // splitting cpus into equal parts; this will over-allocate cores but it's good enough for now + maxContainerCount := 4 + // skip CPU 0 + minCpu := ((GinkgoParallelProcess() - 1) * maxContainerCount * nCpus) + 1 + maxCpu := (GinkgoParallelProcess() * maxContainerCount * nCpus) + + if len(c.cpus)-1 < maxCpu { + err := fmt.Errorf("could not allocate %d CPUs; available: %d; attempted to allocate cores %d-%d", + nCpus*containerCount, len(c.cpus)-1, minCpu, maxCpu) + return nil, err } - cpuCtx.cpus = c.cpus[0:nCpus] + if containerCount == 1 { + cpuCtx.cpus = c.cpus[minCpu : minCpu+nCpus] + } else if containerCount > 1 && containerCount <= maxContainerCount { + cpuCtx.cpus = c.cpus[minCpu+(nCpus*(containerCount-1)) : minCpu+(nCpus*containerCount)] + } else { + return nil, fmt.Errorf("too many containers; CPU allocation for >%d containers is not implemented", maxContainerCount) + } + cpuCtx.cpuAllocator = c - c.cpus = c.cpus[nCpus:] return &cpuCtx, nil } diff --git a/extras/hs-test/docker/Dockerfile.nginx b/extras/hs-test/docker/Dockerfile.nginx index 11ec6af156d..386f8e90016 100644 --- a/extras/hs-test/docker/Dockerfile.nginx +++ b/extras/hs-test/docker/Dockerfile.nginx @@ -3,7 +3,7 @@ ARG UBUNTU_VERSION FROM ubuntu:${UBUNTU_VERSION} RUN apt-get update \ - && apt-get install -y nginx gdb less \ + && apt-get install -y nginx gdb less libunwind-dev \ && rm -rf /var/lib/apt/lists/* COPY vpp-data/lib/* /usr/lib/ diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp index ace83c593c6..9d900e86772 100644 --- a/extras/hs-test/docker/Dockerfile.vpp +++ b/extras/hs-test/docker/Dockerfile.vpp @@ -5,7 +5,7 @@ FROM ubuntu:${UBUNTU_VERSION} RUN apt-get update \ && apt-get install -y openssl libapr1 libnuma1 libsubunit0 \ iproute2 libnl-3-dev libnl-route-3-dev python3 iputils-ping \ - vim gdb \ + vim gdb libunwind-dev \ && rm -rf /var/lib/apt/lists/* ENV DIR=vpp-data/lib/vpp_plugins diff --git a/extras/hs-test/echo_test.go b/extras/hs-test/echo_test.go index 0515b5e0411..ce852bea3e0 100644 --- a/extras/hs-test/echo_test.go +++ b/extras/hs-test/echo_test.go @@ -21,7 +21,9 @@ func EchoBuiltinTest(s *VethsSuite) { s.assertNotContains(o, "failed:") } +// unstable with multiple workers func TcpWithLossTest(s *VethsSuite) { + s.SkipIfMultiWorker() serverVpp := s.getContainerByName("server-vpp").vppInstance serverVeth := s.getInterfaceByName(serverInterfaceName) @@ -45,5 +47,5 @@ func TcpWithLossTest(s *VethsSuite) { serverVeth.ip4AddressString()) s.log(output) s.assertNotEqual(len(output), 0) - s.assertNotContains(output, "failed: timeout", output) + s.assertNotContains(output, "failed", output) } diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go index 8773fa2417d..8cbf936f026 100644 --- a/extras/hs-test/framework_test.go +++ b/extras/hs-test/framework_test.go @@ -2,12 +2,21 @@ package main import ( "testing" + "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) +var suiteTimeout time.Duration + func TestHst(t *testing.T) { + if *isVppDebug { + // 30 minute timeout so that the framework won't timeout while debugging + suiteTimeout = time.Minute * 30 + } else { + suiteTimeout = time.Minute * 5 + } RegisterFailHandler(Fail) RunSpecs(t, "HST") } diff --git a/extras/hs-test/go.mod b/extras/hs-test/go.mod index 0f3854d2148..3be9ba20a86 100644 --- a/extras/hs-test/go.mod +++ b/extras/hs-test/go.mod @@ -26,7 +26,7 @@ require ( 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/sirupsen/logrus v1.9.3 // indirect + github.com/sirupsen/logrus v1.9.3 github.com/vishvananda/netns v0.0.4 // indirect golang.org/x/sys v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/extras/hs-test/hst_suite.go b/extras/hs-test/hst_suite.go index bb499246bf9..26dcf4e5a2b 100644 --- a/extras/hs-test/hst_suite.go +++ b/extras/hs-test/hst_suite.go @@ -5,7 +5,8 @@ import ( "errors" "flag" "fmt" - "log/slog" + "io" + "log" "os" "os/exec" "strings" @@ -29,19 +30,28 @@ var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp") var vppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory") type HstSuite struct { - containers map[string]*Container - volumes []string - netConfigs []NetConfig - netInterfaces map[string]*NetInterface - ip4AddrAllocator *Ip4AddressAllocator - testIds map[string]string - cpuAllocator *CpuAllocatorT - cpuContexts []*CpuContext - cpuPerVpp int - pid string + containers map[string]*Container + startedContainers []*Container + volumes []string + netConfigs []NetConfig + netInterfaces map[string]*NetInterface + ip4AddrAllocator *Ip4AddressAllocator + testIds map[string]string + cpuAllocator *CpuAllocatorT + cpuContexts []*CpuContext + cpuPerVpp int + 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() @@ -52,7 +62,7 @@ func (s *HstSuite) SetupSuite() { } func (s *HstSuite) AllocateCpus() []int { - cpuCtx, err := s.cpuAllocator.Allocate(s.cpuPerVpp) + cpuCtx, err := s.cpuAllocator.Allocate(len(s.startedContainers), s.cpuPerVpp) s.assertNil(err) s.AddCpuContext(cpuCtx) return cpuCtx.cpus @@ -63,16 +73,16 @@ 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 } - for _, c := range s.cpuContexts { - c.Release() - } s.resetContainers() s.removeVolumes() s.ip4AddrAllocator.deleteIpAddresses() @@ -85,10 +95,8 @@ func (s *HstSuite) skipIfUnconfiguring() { } func (s *HstSuite) SetupTest() { - RegisterFailHandler(func(message string, callerSkip ...int) { - s.hstFail() - Fail(message, callerSkip...) - }) + s.log("Test Setup") + s.startedContainers = s.startedContainers[:0] s.skipIfUnconfiguring() s.setupVolumes() s.setupContainers() @@ -110,7 +118,7 @@ func (s *HstSuite) setupContainers() { } } -func logVppInstance(container *Container, maxLines int) { +func (s *HstSuite) logVppInstance(container *Container, maxLines int) { if container.vppInstance == nil { return } @@ -136,26 +144,26 @@ func logVppInstance(container *Container, maxLines int) { } } - fmt.Println("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:") + s.log("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:") for _, line := range lines { - fmt.Println(line) + 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 { + for _, container := range s.startedContainers { out, err := container.log(20) if err != nil { - fmt.Printf("An error occured while obtaining '%s' container logs: %s\n", container.name, fmt.Sprint(err)) + s.log("An error occured while obtaining '" + container.name + "' container logs: " + fmt.Sprint(err)) + s.log("The container might not be running - check logs in " + container.getLogDirPath()) continue } - fmt.Printf("\nvvvvvvvvvvvvvvv " + + s.log("\nvvvvvvvvvvvvvvv " + container.name + ":\n" + out + "^^^^^^^^^^^^^^^\n\n") - logVppInstance(container, 20) + s.logVppInstance(container, 20) } } @@ -187,9 +195,25 @@ func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) 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) +} + +// 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 { - slog.Info(fmt.Sprint(arg)) + GinkgoWriter.Println(arg) } } @@ -266,7 +290,7 @@ func (s *HstSuite) loadContainerTopology(topologyName string) { for _, elem := range yamlTopo.Volumes { volumeMap := elem["volume"].(VolumeConfig) hostDir := volumeMap["host-dir"].(string) - workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + 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) @@ -450,7 +474,7 @@ func (s *HstSuite) startHttpServer(running chan struct{}, done chan struct{}, ad err := cmd.Start() s.log(cmd) if err != nil { - fmt.Println("Failed to start http server: " + fmt.Sprint(err)) + s.log("Failed to start http server: " + fmt.Sprint(err)) return } running <- struct{}{} diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index fe12f5a2f65..f7a160c8764 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "net/http" "os" "strings" "time" @@ -11,12 +12,16 @@ import ( func init() { registerNsTests(HttpTpsTest) - registerVethTests(HttpCliTest) + registerVethTests(HttpCliTest, HttpCliConnectErrorTest) registerNoTopoTests(NginxHttp3Test, NginxAsServerTest, - NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, HeaderServerTest) + NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, HeaderServerTest, + HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest, + HttpCliBadRequestTest, HttpStaticPathTraversalTest) registerNoTopoSoloTests(HttpStaticPromTest) } +const wwwRootPath = "/tmp/www_root" + func HttpTpsTest(s *NsSuite) { iface := s.getInterfaceByName(clientInterface) client_ip := iface.ip4AddressString() @@ -55,6 +60,20 @@ func HttpCliTest(s *VethsSuite) { s.assertContains(o, "<html>", "<html> not found in the result!") } +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() @@ -71,6 +90,7 @@ func NginxHttp3Test(s *NoTopoSuite) { 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.log(o) s.assertNil(err, fmt.Sprint(err)) s.assertContains(o, "<http>", "<http> not found in the result!") } @@ -91,19 +111,97 @@ func HttpStaticPromTest(s *NoTopoSuite) { s.assertNil(err) } +func HttpStaticPathTraversalTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + vpp.container.exec("mkdir -p " + wwwRootPath) + vpp.container.exec("mkdir -p " + "/tmp/secret_folder") + vpp.container.createFile("/tmp/secret_folder/secret_file.txt", "secret") + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + s.log(vpp.vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) + + client := newHttpClient() + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/../secret_folder/secret_file.txt", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := client.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(404, resp.StatusCode) +} + +func HttpStaticMovedTest(s *NoTopoSuite) { + vpp := s.getContainerByName("vpp").vppInstance + vpp.container.exec("mkdir -p " + wwwRootPath + "/tmp.aaa") + vpp.container.createFile(wwwRootPath+"/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 " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) + + client := newHttpClient() + 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 + vpp.container.exec("mkdir -p " + wwwRootPath) + serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() + s.log(vpp.vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) + + client := newHttpClient() + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/notfound.html", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := client.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") + + client := newHttpClient() + req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := client.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") + + client := newHttpClient() + req, err := http.NewRequest("GET", "http://"+serverAddress+":80", nil) + s.assertNil(err, fmt.Sprint(err)) + resp, err := client.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual(400, resp.StatusCode) +} + func HeaderServerTest(s *NoTopoSuite) { - query := "show/version" vpp := s.getContainerByName("vpp").vppInstance serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString() vpp.vppctl("http cli server") - curlCont := s.getContainerByName("curl") - args := fmt.Sprintf("curl -i -s http://%s:80/%s", serverAddress, query) - curlCont.extraRunningArgs = args - o, err := curlCont.combinedOutput() + client := newHttpClient() + req, err := http.NewRequest("GET", "http://"+serverAddress+":80/show/version", nil) s.assertNil(err, fmt.Sprint(err)) - s.log(o) - s.assertContains(o, "Server: http_cli_server") + resp, err := client.Do(req) + s.assertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.assertEqual("http_cli_server", resp.Header.Get("Server")) } func NginxAsServerTest(s *NoTopoSuite) { @@ -150,6 +248,7 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { if ab_or_wrk == "ab" { abCont := s.getContainerByName("ab") + abCont.runDetached = true args := fmt.Sprintf("-n %d -c %d", nRequests, nClients) if mode == "rps" { args += " -k" @@ -160,7 +259,6 @@ 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) @@ -168,6 +266,7 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { s.assertNil(err, "err: '%s', output: '%s'", err, o) } else { wrkCont := s.getContainerByName("wrk") + wrkCont.runDetached = true args := fmt.Sprintf("-c %d -t 2 -d 30 http://%s:80/64B.json", nClients, serverAddress) wrkCont.extraRunningArgs = args @@ -180,7 +279,9 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { return nil } +// unstable with multiple workers func NginxPerfCpsTest(s *NoTopoSuite) { + s.SkipIfMultiWorker() s.assertNil(runNginxPerf(s, "cps", "ab")) } diff --git a/extras/hs-test/mirroring_test.go b/extras/hs-test/mirroring_test.go index 6c5a860b01c..1fd15dde2f4 100644 --- a/extras/hs-test/mirroring_test.go +++ b/extras/hs-test/mirroring_test.go @@ -8,7 +8,9 @@ func init() { registerNginxTests(MirroringTest) } +// broken when CPUS > 1 func MirroringTest(s *NginxSuite) { + s.SkipIfMultiWorker() proxyAddress := s.getInterfaceByName(mirroringClientInterfaceName).peer.ip4AddressString() path := "/64B.json" diff --git a/extras/hs-test/raw_session_test.go b/extras/hs-test/raw_session_test.go index cf74c62cd3e..5c66df0b1ce 100644 --- a/extras/hs-test/raw_session_test.go +++ b/extras/hs-test/raw_session_test.go @@ -1,16 +1,15 @@ package main func init() { - registerVethTests(VppEchoQuicTest, VppEchoTcpTest, VppEchoUdpTest) + registerVethTests(VppEchoQuicTest, VppEchoTcpTest) } func VppEchoQuicTest(s *VethsSuite) { s.testVppEcho("quic") } -// udp echo currently broken in vpp, skipping +// TODO: udp echo currently broken in vpp func VppEchoUdpTest(s *VethsSuite) { - s.skip("Broken") s.testVppEcho("udp") } diff --git a/extras/hs-test/script/build_hst.sh b/extras/hs-test/script/build_hst.sh index 33a8393b8b5..3b4bc28e275 100755 --- a/extras/hs-test/script/build_hst.sh +++ b/extras/hs-test/script/build_hst.sh @@ -21,6 +21,8 @@ export VPP_WS=../.. if [ "$1" == "debug" ]; then VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp_debug-native/vpp +elif [ "$1" == "gcov" ]; then + VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp_gcov-native/vpp else VPP_BUILD_ROOT=${VPP_WS}/build-root/build-vpp-native/vpp fi @@ -67,9 +69,9 @@ docker_build hs-test/vpp vpp docker_build hs-test/nginx-ldp nginx docker_build hs-test/nginx-server nginx-server docker_build hs-test/build build -docker_build hs-test/curl curl if [ "$HST_EXTENDED_TESTS" = true ] ; then docker_build hs-test/nginx-http3 nginx-http3 + docker_build hs-test/curl curl fi # cleanup detached images diff --git a/extras/hs-test/script/compress.sh b/extras/hs-test/script/compress.sh new file mode 100644 index 00000000000..1f0205c1efb --- /dev/null +++ b/extras/hs-test/script/compress.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# if failed-summary.log is not empty, exit status = 1 +if [ -s "${HS_ROOT}/summary/failed-summary.log" ] +then + if [ -n "${WORKSPACE}" ] + then + echo -n "Copying docker logs..." + dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText' ${HS_ROOT}/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." + + echo -n "Copying failed test logs into build log archive directory (${WORKSPACE}/archives)... " + mkdir -p ${WORKSPACE}/archives/summary + cp -a ${HS_ROOT}/summary/* ${WORKSPACE}/archives/summary + echo "Done." + + 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." + fi + exit 1 +fi diff --git a/extras/hs-test/script/nginx_ldp.sh b/extras/hs-test/script/nginx_ldp.sh index 4a22e14aaf7..a6b0a20e47b 100755 --- a/extras/hs-test/script/nginx_ldp.sh +++ b/extras/hs-test/script/nginx_ldp.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -LD_PRELOAD=$LDP $@ 2>&1 > /proc/1/fd/1 +$1 -v && LD_PRELOAD=$LDP $@ 2>&1 > /proc/1/fd/1 diff --git a/extras/hs-test/suite_nginx_test.go b/extras/hs-test/suite_nginx_test.go index 2d1caf152f4..4c6e9dbb309 100644 --- a/extras/hs-test/suite_nginx_test.go +++ b/extras/hs-test/suite_nginx_test.go @@ -4,7 +4,6 @@ import ( "reflect" "runtime" "strings" - "time" . "github.com/onsi/ginkgo/v2" ) @@ -48,10 +47,9 @@ func (s *NginxSuite) SetupTest() { append("enable"). append("use-app-socket-api").close() - cpus := s.AllocateCpus() // ... for proxy vppProxyContainer := s.getContainerByName(vppProxyContainerName) - proxyVpp, _ := vppProxyContainer.newVppInstance(cpus, sessionConfig) + proxyVpp, _ := vppProxyContainer.newVppInstance(vppProxyContainer.allocatedCpus, sessionConfig) s.assertNil(proxyVpp.start()) clientInterface := s.getInterfaceByName(mirroringClientInterfaceName) @@ -98,9 +96,11 @@ var _ = Describe("NginxSuite", Ordered, ContinueOnFailure, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) @@ -118,12 +118,15 @@ var _ = Describe("NginxSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { AfterEach(func() { s.TearDownTest() }) + for _, test := range nginxSoloTests { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) diff --git a/extras/hs-test/suite_no_topo_test.go b/extras/hs-test/suite_no_topo_test.go index 6df06c7e60e..260fc1d681d 100644 --- a/extras/hs-test/suite_no_topo_test.go +++ b/extras/hs-test/suite_no_topo_test.go @@ -4,7 +4,6 @@ import ( "reflect" "runtime" "strings" - "time" . "github.com/onsi/ginkgo/v2" ) @@ -45,9 +44,8 @@ func (s *NoTopoSuite) SetupTest() { append("enable"). append("use-app-socket-api").close() - cpus := s.AllocateCpus() container := s.getContainerByName(singleTopoContainerVpp) - vpp, _ := container.newVppInstance(cpus, sessionConfig) + vpp, _ := container.newVppInstance(container.allocatedCpus, sessionConfig) s.assertNil(vpp.start()) tapInterface := s.getInterfaceByName(tapInterfaceName) @@ -74,9 +72,11 @@ var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) @@ -99,8 +99,10 @@ var _ = Describe("NoTopoSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) diff --git a/extras/hs-test/suite_ns_test.go b/extras/hs-test/suite_ns_test.go index 86d9b78a010..7bdb90b42ae 100644 --- a/extras/hs-test/suite_ns_test.go +++ b/extras/hs-test/suite_ns_test.go @@ -5,7 +5,6 @@ import ( "reflect" "runtime" "strings" - "time" . "github.com/onsi/ginkgo/v2" ) @@ -48,9 +47,8 @@ func (s *NsSuite) SetupTest() { append("evt_qs_memfd_seg"). append("event-queue-length 100000").close() - cpus := s.AllocateCpus() container := s.getContainerByName("vpp") - vpp, _ := container.newVppInstance(cpus, sessionConfig) + vpp, _ := container.newVppInstance(container.allocatedCpus, sessionConfig) s.assertNil(vpp.start()) idx, err := vpp.createAfPacket(s.getInterfaceByName(serverInterface)) @@ -83,9 +81,11 @@ var _ = Describe("NsSuite", Ordered, ContinueOnFailure, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) @@ -108,8 +108,10 @@ var _ = Describe("NsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) diff --git a/extras/hs-test/suite_tap_test.go b/extras/hs-test/suite_tap_test.go index 25c1e25a215..cb0653304c3 100644 --- a/extras/hs-test/suite_tap_test.go +++ b/extras/hs-test/suite_tap_test.go @@ -48,9 +48,11 @@ var _ = Describe("TapSuite", Ordered, ContinueOnFailure, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) @@ -73,8 +75,10 @@ var _ = Describe("TapSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) diff --git a/extras/hs-test/suite_veth_test.go b/extras/hs-test/suite_veth_test.go index f4c3684f031..13ef5ef268d 100644 --- a/extras/hs-test/suite_veth_test.go +++ b/extras/hs-test/suite_veth_test.go @@ -50,8 +50,7 @@ func (s *VethsSuite) SetupTest() { // ... For server serverContainer := s.getContainerByName("server-vpp") - cpus := s.AllocateCpus() - serverVpp, err := serverContainer.newVppInstance(cpus, sessionConfig) + serverVpp, err := serverContainer.newVppInstance(serverContainer.allocatedCpus, sessionConfig) s.assertNotNil(serverVpp, fmt.Sprint(err)) s.setupServerVpp() @@ -59,8 +58,7 @@ func (s *VethsSuite) SetupTest() { // ... For client clientContainer := s.getContainerByName("client-vpp") - cpus = s.AllocateCpus() - clientVpp, err := clientContainer.newVppInstance(cpus, sessionConfig) + clientVpp, err := clientContainer.newVppInstance(clientContainer.allocatedCpus, sessionConfig) s.assertNotNil(clientVpp, fmt.Sprint(err)) s.setupClientVpp() @@ -107,9 +105,11 @@ var _ = Describe("VethsSuite", Ordered, ContinueOnFailure, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) @@ -123,7 +123,6 @@ var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { }) AfterAll(func() { s.TearDownSuite() - }) AfterEach(func() { s.TearDownTest() @@ -134,8 +133,10 @@ var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { test := test pc := reflect.ValueOf(test).Pointer() funcValue := runtime.FuncForPC(pc) - It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { + testName := strings.Split(funcValue.Name(), ".")[2] + It(testName, Label("SOLO"), func(ctx SpecContext) { + s.log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(suiteTimeout)) } }) diff --git a/extras/hs-test/test b/extras/hs-test/test index 94162b87759..398e2b39edb 100755..100644 --- a/extras/hs-test/test +++ b/extras/hs-test/test @@ -86,4 +86,9 @@ if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then exit 1 fi -sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --no-color --trace $ginkgo_args -- $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 + +jq -r '.[0] | .SpecReports[] | select((.State == "failed") or (.State == "timedout") or (.State == "panicked")) | select(.Failure != null) | "TestName: \(.LeafNodeText)\nSuite:\n\(.Failure.Location.FileName)\nMessage:\n\(.Failure.Message)\n Full Stack Trace:\n\(.Failure.Location.FullStackTrace)\n"' summary/report.json > summary/failed-summary.log \ + && echo "Summary generated -> summary/failed-summary.log"
\ No newline at end of file diff --git a/extras/hs-test/utils.go b/extras/hs-test/utils.go index 304dd4c241b..d250dc64519 100644 --- a/extras/hs-test/utils.go +++ b/extras/hs-test/utils.go @@ -3,8 +3,10 @@ package main import ( "fmt" "io" + "net/http" "os" "strings" + "time" ) const networkTopologyDir string = "topo-network/" @@ -78,3 +80,17 @@ func (s *Stanza) saveToFile(fileName string) error { _, err = io.Copy(fo, strings.NewReader(s.content)) return err } + +// newHttpClient creates [http.Client] with disabled proxy and redirects, it also sets timeout to 30seconds. +func newHttpClient() *http.Client { + transport := http.DefaultTransport + transport.(*http.Transport).Proxy = nil + transport.(*http.Transport).DisableKeepAlives = true + client := &http.Client{ + Transport: transport, + Timeout: time.Second * 30, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }} + return client +} diff --git a/extras/hs-test/vppinstance.go b/extras/hs-test/vppinstance.go index 7ddec7e0ed4..8a92776894c 100644 --- a/extras/hs-test/vppinstance.go +++ b/extras/hs-test/vppinstance.go @@ -1,7 +1,9 @@ package main import ( + "context" "fmt" + "io" "os" "os/exec" "os/signal" @@ -12,6 +14,7 @@ import ( "github.com/edwarnicke/exechelper" . "github.com/onsi/ginkgo/v2" + "github.com/sirupsen/logrus" "go.fd.io/govpp" "go.fd.io/govpp/api" @@ -20,7 +23,6 @@ import ( "go.fd.io/govpp/binapi/interface_types" "go.fd.io/govpp/binapi/session" "go.fd.io/govpp/binapi/tapv2" - "go.fd.io/govpp/binapi/vpe" "go.fd.io/govpp/core" ) @@ -81,7 +83,7 @@ type VppInstance struct { container *Container additionalConfig []Stanza connection *core.Connection - apiChannel api.Channel + apiStream api.Stream cpus []int } @@ -106,6 +108,11 @@ func (vpp *VppInstance) getEtcDir() string { } func (vpp *VppInstance) start() error { + maxReconnectAttempts := 3 + // 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() @@ -136,6 +143,8 @@ func (vpp *VppInstance) start() error { vpp.getSuite().log("starting vpp") if *isVppDebug { + // default = 3; VPP will timeout while debugging if there are not enough attempts + maxReconnectAttempts = 5000 sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGQUIT) cont := make(chan bool, 1) @@ -160,10 +169,10 @@ func (vpp *VppInstance) start() error { sockAddress := vpp.container.getHostWorkDir() + defaultApiSocketFilePath conn, connEv, err := govpp.AsyncConnect( sockAddress, - core.DefaultMaxReconnectAttempts, + maxReconnectAttempts, core.DefaultReconnectInterval) if err != nil { - fmt.Println("async connect error: ", err) + vpp.getSuite().log("async connect error: " + fmt.Sprint(err)) return err } vpp.connection = conn @@ -171,24 +180,19 @@ func (vpp *VppInstance) start() error { // ... wait for Connected event e := <-connEv if e.State != core.Connected { - fmt.Println("connecting to VPP failed: ", e.Error) + vpp.getSuite().log("connecting to VPP failed: " + fmt.Sprint(e.Error)) } - // ... check compatibility of used messages - ch, err := conn.NewAPIChannel() + ch, err := conn.NewStream( + context.Background(), + core.WithRequestSize(50), + core.WithReplySize(50), + core.WithReplyTimeout(time.Second*5)) if err != nil { - fmt.Println("creating channel failed: ", err) + vpp.getSuite().log("creating stream failed: " + fmt.Sprint(err)) return err } - if err := ch.CheckCompatiblity(vpe.AllMessages()...); err != nil { - fmt.Println("compatibility error: ", err) - return err - } - if err := ch.CheckCompatiblity(interfaces.AllMessages()...); err != nil { - fmt.Println("compatibility error: ", err) - return err - } - vpp.apiChannel = ch + vpp.apiStream = ch return nil } @@ -236,31 +240,50 @@ func (vpp *VppInstance) waitForApp(appName string, timeout int) { func (vpp *VppInstance) createAfPacket( veth *NetInterface, ) (interface_types.InterfaceIndex, error) { - createReq := &af_packet.AfPacketCreateV2{ + createReq := &af_packet.AfPacketCreateV3{ + Mode: 1, UseRandomHwAddr: true, HostIfName: veth.Name(), + Flags: af_packet.AfPacketFlags(11), } if veth.hwAddress != (MacAddress{}) { createReq.UseRandomHwAddr = false createReq.HwAddr = veth.hwAddress } - createReply := &af_packet.AfPacketCreateV2Reply{} vpp.getSuite().log("create af-packet interface " + veth.Name()) - if err := vpp.apiChannel.SendRequest(createReq).ReceiveReply(createReply); err != nil { + if err := vpp.apiStream.SendMsg(createReq); err != nil { + vpp.getSuite().hstFail() + return 0, err + } + replymsg, err := vpp.apiStream.RecvMsg() + if err != nil { + return 0, err + } + reply := replymsg.(*af_packet.AfPacketCreateV3Reply) + err = api.RetvalToVPPApiError(reply.Retval) + if err != nil { return 0, err } - veth.index = createReply.SwIfIndex + + veth.index = reply.SwIfIndex // Set to up upReq := &interfaces.SwInterfaceSetFlags{ SwIfIndex: veth.index, Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP, } - upReply := &interfaces.SwInterfaceSetFlagsReply{} vpp.getSuite().log("set af-packet interface " + veth.Name() + " up") - if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil { + if err := vpp.apiStream.SendMsg(upReq); err != nil { + return 0, err + } + replymsg, err = vpp.apiStream.RecvMsg() + if err != nil { + return 0, err + } + reply2 := replymsg.(*interfaces.SwInterfaceSetFlagsReply) + if err = api.RetvalToVPPApiError(reply2.Retval); err != nil { return 0, err } @@ -279,10 +302,18 @@ func (vpp *VppInstance) createAfPacket( SwIfIndex: veth.index, Prefix: veth.addressWithPrefix(), } - 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 { + if err := vpp.apiStream.SendMsg(addressReq); err != nil { + return 0, err + } + replymsg, err = vpp.apiStream.RecvMsg() + if err != nil { + return 0, err + } + reply3 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply) + err = api.RetvalToVPPApiError(reply3.Retval) + if err != nil { return 0, err } @@ -294,25 +325,41 @@ func (vpp *VppInstance) addAppNamespace( ifx interface_types.InterfaceIndex, namespaceId string, ) error { - req := &session.AppNamespaceAddDelV2{ + req := &session.AppNamespaceAddDelV4{ + IsAdd: true, Secret: secret, SwIfIndex: ifx, NamespaceID: namespaceId, + SockName: defaultApiSocketFilePath, } - reply := &session.AppNamespaceAddDelV2Reply{} vpp.getSuite().log("add app namespace " + namespaceId) - if err := vpp.apiChannel.SendRequest(req).ReceiveReply(reply); err != nil { + if err := vpp.apiStream.SendMsg(req); err != nil { + return err + } + replymsg, err := vpp.apiStream.RecvMsg() + if err != nil { + return err + } + reply := replymsg.(*session.AppNamespaceAddDelV4Reply) + if err = api.RetvalToVPPApiError(reply.Retval); err != nil { return err } sessionReq := &session.SessionEnableDisable{ IsEnable: true, } - sessionReply := &session.SessionEnableDisableReply{} vpp.getSuite().log("enable app namespace " + namespaceId) - if err := vpp.apiChannel.SendRequest(sessionReq).ReceiveReply(sessionReply); err != nil { + if err := vpp.apiStream.SendMsg(sessionReq); err != nil { + return err + } + replymsg, err = vpp.apiStream.RecvMsg() + if err != nil { + return err + } + reply2 := replymsg.(*session.SessionEnableDisableReply) + if err = api.RetvalToVPPApiError(reply2.Retval); err != nil { return err } @@ -327,43 +374,64 @@ func (vpp *VppInstance) createTap( if len(tapId) > 0 { id = tapId[0] } - createTapReq := &tapv2.TapCreateV2{ + createTapReq := &tapv2.TapCreateV3{ ID: id, HostIfNameSet: true, HostIfName: tap.Name(), HostIP4PrefixSet: true, HostIP4Prefix: tap.ip4AddressWithPrefix(), } - createTapReply := &tapv2.TapCreateV2Reply{} vpp.getSuite().log("create tap interface " + tap.Name()) // Create tap interface - if err := vpp.apiChannel.SendRequest(createTapReq).ReceiveReply(createTapReply); err != nil { + if err := vpp.apiStream.SendMsg(createTapReq); err != nil { + return err + } + replymsg, err := vpp.apiStream.RecvMsg() + if err != nil { + return err + } + reply := replymsg.(*tapv2.TapCreateV3Reply) + if err = api.RetvalToVPPApiError(reply.Retval); err != nil { return err } // Add address addAddressReq := &interfaces.SwInterfaceAddDelAddress{ IsAdd: true, - SwIfIndex: createTapReply.SwIfIndex, + SwIfIndex: reply.SwIfIndex, Prefix: tap.peer.addressWithPrefix(), } - 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 { + if err := vpp.apiStream.SendMsg(addAddressReq); err != nil { + return err + } + replymsg, err = vpp.apiStream.RecvMsg() + if err != nil { + return err + } + reply2 := replymsg.(*interfaces.SwInterfaceAddDelAddressReply) + if err = api.RetvalToVPPApiError(reply2.Retval); err != nil { return err } // Set interface to up upReq := &interfaces.SwInterfaceSetFlags{ - SwIfIndex: createTapReply.SwIfIndex, + SwIfIndex: reply.SwIfIndex, Flags: interface_types.IF_STATUS_API_FLAG_ADMIN_UP, } - upReply := &interfaces.SwInterfaceSetFlagsReply{} vpp.getSuite().log("set tap interface " + tap.Name() + " up") - if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil { + if err := vpp.apiStream.SendMsg(upReq); err != nil { + return err + } + replymsg, err = vpp.apiStream.RecvMsg() + if err != nil { + return err + } + reply3 := replymsg.(*interfaces.SwInterfaceSetFlagsReply) + if err = api.RetvalToVPPApiError(reply3.Retval); err != nil { return err } @@ -380,7 +448,7 @@ func (vpp *VppInstance) saveLogs() { func (vpp *VppInstance) disconnect() { vpp.connection.Disconnect() - vpp.apiChannel.Close() + vpp.apiStream.Close() } func (vpp *VppInstance) generateCpuConfig() string { @@ -391,6 +459,7 @@ func (vpp *VppInstance) generateCpuConfig() string { } c.newStanza("cpu"). append(fmt.Sprintf("main-core %d", vpp.cpus[0])) + vpp.getSuite().log(fmt.Sprintf("main-core %d", vpp.cpus[0])) workers := vpp.cpus[1:] if len(workers) > 0 { @@ -401,6 +470,7 @@ func (vpp *VppInstance) generateCpuConfig() string { s = s + fmt.Sprintf("%d", workers[i]) } c.append(fmt.Sprintf("corelist-workers %s", s)) + vpp.getSuite().log("corelist-workers " + s) } return c.close().toString() } diff --git a/src/cmake/platform/octeon9.cmake b/src/cmake/platform/octeon9.cmake new file mode 100644 index 00000000000..46ca7dfa64a --- /dev/null +++ b/src/cmake/platform/octeon9.cmake @@ -0,0 +1,4 @@ + +set(VPP_PLATFORM_CACHE_LINE_SIZE 128) +set(VPP_PLATFORM_MARCH_FLAGS -march=armv8.2-a+crc+crypto) +set(VPP_PLATFORM_BUFFER_ALIGN 128) diff --git a/src/plugins/acl/acl_test.c b/src/plugins/acl/acl_test.c index 8404689dc06..98803a916cb 100644 --- a/src/plugins/acl/acl_test.c +++ b/src/plugins/acl/acl_test.c @@ -114,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++) { @@ -141,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++) { @@ -173,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); } @@ -191,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]); @@ -225,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/builtinurl/builtinurl.api b/src/plugins/builtinurl/builtinurl.api index f292fd77a8e..80efa73c725 100644 --- a/src/plugins/builtinurl/builtinurl.api +++ b/src/plugins/builtinurl/builtinurl.api @@ -35,6 +35,7 @@ option version = "1.0.0"; */ autoreply define builtinurl_enable { + option deprecated="incorporated in http_static plugin"; /* Client identifier, set from api_main.my_client_index */ u32 client_index; diff --git a/src/plugins/dev_octeon/CMakeLists.txt b/src/plugins/dev_octeon/CMakeLists.txt index e8abf1a3389..0f6b32bbecd 100644 --- a/src/plugins/dev_octeon/CMakeLists.txt +++ b/src/plugins/dev_octeon/CMakeLists.txt @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright(c) 2022 Cisco Systems, Inc. -if (NOT VPP_PLATFORM_NAME STREQUAL "octeon10") +if (NOT VPP_PLATFORM_NAME STREQUAL "octeon10" AND NOT VPP_PLATFORM_NAME STREQUAL "octeon9") return() endif() @@ -21,6 +21,10 @@ endif() include_directories (${OCTEON_ROC_DIR}/) +if (VPP_PLATFORM_NAME STREQUAL "octeon9") + add_compile_definitions(PLATFORM_OCTEON9) +endif() + add_vpp_plugin(dev_octeon SOURCES init.c diff --git a/src/plugins/dev_octeon/format.c b/src/plugins/dev_octeon/format.c index e624b84f54e..d0f53013d99 100644 --- a/src/plugins/dev_octeon/format.c +++ b/src/plugins/dev_octeon/format.c @@ -25,7 +25,7 @@ format_oct_nix_rx_cqe_desc (u8 *s, va_list *args) typeof (d->sg0) *sg0 = &d->sg0; typeof (d->sg0) *sg1 = &d->sg1; - s = format (s, "hdr: cqe_type %u nude %u q %u tag 0x%x", h->cqe_type, + s = format (s, "hdr: cqe_type %u nude %u qid %u tag 0x%x", h->cqe_type, h->node, h->q, h->tag); s = format (s, "\n%Uparse:", format_white_space, indent); #define _(n, f) s = format (s, " " #n " " f, p->n) diff --git a/src/plugins/dev_octeon/init.c b/src/plugins/dev_octeon/init.c index 97a11e0d0d7..aacc18415c2 100644 --- a/src/plugins/dev_octeon/init.c +++ b/src/plugins/dev_octeon/init.c @@ -245,6 +245,7 @@ oct_init (vlib_main_t *vm, vnet_dev_t *dev) { case OCT_DEVICE_TYPE_RVU_PF: case OCT_DEVICE_TYPE_RVU_VF: + case OCT_DEVICE_TYPE_LBK_VF: case OCT_DEVICE_TYPE_SDP_VF: return oct_init_nix (vm, dev); diff --git a/src/plugins/dev_octeon/port.c b/src/plugins/dev_octeon/port.c index d5f78301adf..0bbada8ecc1 100644 --- a/src/plugins/dev_octeon/port.c +++ b/src/plugins/dev_octeon/port.c @@ -203,7 +203,8 @@ oct_port_poll (vlib_main_t *vm, vnet_dev_port_t *port) if (cd->speed != link_info.speed) { changes.change.link_speed = 1; - changes.link_speed = link_info.speed; + /* Convert to Kbps */ + changes.link_speed = link_info.speed * 1000; cd->speed = link_info.speed; } @@ -385,7 +386,7 @@ oct_validate_config_promisc_mode (vnet_dev_port_t *port, int enable) oct_device_t *cd = vnet_dev_get_data (dev); struct roc_nix *nix = cd->nix; - if (roc_nix_is_vf_or_sdp (nix)) + if (roc_nix_is_sdp (nix) || roc_nix_is_lbk (nix)) return VNET_DEV_ERR_UNSUPPORTED_DEVICE; return VNET_DEV_OK; @@ -405,6 +406,9 @@ oct_op_config_promisc_mode (vlib_main_t *vm, vnet_dev_port_t *port, int enable) return oct_roc_err (dev, rv, "roc_nix_npc_promisc_ena_dis failed"); } + if (!roc_nix_is_pf (nix)) + return VNET_DEV_OK; + rv = roc_nix_mac_promisc_mode_enable (nix, enable); if (rv) { @@ -416,6 +420,44 @@ oct_op_config_promisc_mode (vlib_main_t *vm, vnet_dev_port_t *port, int enable) 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) @@ -465,6 +507,9 @@ oct_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port, 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/roc_helper.c b/src/plugins/dev_octeon/roc_helper.c index f10c2cb578b..16e0a871a9d 100644 --- a/src/plugins/dev_octeon/roc_helper.c +++ b/src/plugins/dev_octeon/roc_helper.c @@ -49,6 +49,12 @@ oct_plt_get_thread_index (void) return __os_thread_index; } +static u64 +oct_plt_get_cache_line_size (void) +{ + return CLIB_CACHE_LINE_BYTES; +} + static void oct_drv_physmem_free (vlib_main_t *vm, void *mem) { @@ -178,4 +184,5 @@ oct_plt_init_param_t oct_plt_init_param = { .oct_plt_spinlock_unlock = oct_plt_spinlock_unlock, .oct_plt_spinlock_trylock = oct_plt_spinlock_trylock, .oct_plt_get_thread_index = oct_plt_get_thread_index, + .oct_plt_get_cache_line_size = oct_plt_get_cache_line_size, }; diff --git a/src/plugins/dev_octeon/rx_node.c b/src/plugins/dev_octeon/rx_node.c index 997f1356199..1f8d5d93fa3 100644 --- a/src/plugins/dev_octeon/rx_node.c +++ b/src/plugins/dev_octeon/rx_node.c @@ -165,6 +165,38 @@ oct_rx_batch (vlib_main_t *vm, oct_rx_node_ctx_t *ctx, return n; } +#ifdef PLATFORM_OCTEON9 +static_always_inline u32 +oct_rxq_refill (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq, u16 n_refill) +{ + u32 n_alloc, n_free; + u32 buffer_indices[n_refill]; + vlib_buffer_t *buffers[n_refill]; + u8 bpi = vnet_dev_get_rx_queue_buffer_pool_index (rxq); + oct_rxq_t *crq = vnet_dev_get_rx_queue_data (rxq); + u64 aura = roc_npa_aura_handle_to_aura (crq->aura_handle); + const uint64_t addr = + roc_npa_aura_handle_to_base (crq->aura_handle) + NPA_LF_AURA_OP_FREE0; + + if (n_refill < 256) + return 0; + + n_alloc = vlib_buffer_alloc (vm, buffer_indices, n_refill); + if (PREDICT_FALSE (n_alloc < n_refill)) + goto alloc_fail; + + vlib_get_buffers (vm, buffer_indices, (vlib_buffer_t **) buffers, n_alloc); + + for (n_free = 0; n_free < n_alloc; n_free++) + roc_store_pair ((u64) buffers[n_free], aura, addr); + + return n_alloc; + +alloc_fail: + vlib_buffer_unalloc_to_pool (vm, buffer_indices, n_alloc, bpi); + return 0; +} +#else static_always_inline void oct_rxq_refill_batch (vlib_main_t *vm, u64 lmt_id, u64 addr, oct_npa_lf_aura_batch_free_line_t *lines, u32 *bi, @@ -260,6 +292,7 @@ oct_rxq_refill (vlib_main_t *vm, vnet_dev_rx_queue_t *rxq, u16 n_refill) return n_enq; } +#endif static_always_inline void oct_rx_trace (vlib_main_t *vm, vlib_node_runtime_t *node, diff --git a/src/plugins/dev_octeon/tx_node.c b/src/plugins/dev_octeon/tx_node.c index a2e4b07de8a..0907493814d 100644 --- a/src/plugins/dev_octeon/tx_node.c +++ b/src/plugins/dev_octeon/tx_node.c @@ -32,6 +32,44 @@ typedef struct lmt_line_t *lmt_lines; } oct_tx_ctx_t; +#ifdef PLATFORM_OCTEON9 +static_always_inline u32 +oct_batch_free (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq) +{ + oct_txq_t *ctq = vnet_dev_get_tx_queue_data (txq); + u16 off = ctq->hdr_off; + u64 ah = ctq->aura_handle; + u32 n_freed = 0, n; + + ah = ctq->aura_handle; + + if ((n = roc_npa_aura_op_available (ah)) >= 32) + { + u64 buffers[n]; + u32 bi[n]; + + n_freed = roc_npa_aura_op_bulk_alloc (ah, buffers, n, 0, 1); + vlib_get_buffer_indices_with_offset (vm, (void **) &buffers, bi, n_freed, + off); + vlib_buffer_free_no_next (vm, bi, n_freed); + } + + return n_freed; +} + +static_always_inline void +oct_lmt_copy (void *lmt_addr, u64 io_addr, void *desc, u64 dwords) +{ + u64 lmt_status; + + do + { + roc_lmt_mov_seg (lmt_addr, desc, dwords); + lmt_status = roc_lmt_submit_ldeor (io_addr); + } + while (lmt_status == 0); +} +#else static_always_inline u32 oct_batch_free (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq) { @@ -133,6 +171,7 @@ oct_batch_free (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq) return n_freed; } +#endif static_always_inline u8 oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, @@ -158,6 +197,11 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, return 0; } +#ifdef PLATFORM_OCTEON9 + /* Override line for Octeon9 */ + line = ctx->lmt_lines; +#endif + if (!simple && flags & VLIB_BUFFER_NEXT_PRESENT) { u8 n_tail_segs = 0; @@ -238,8 +282,12 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b, t->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_TX]; } +#ifdef PLATFORM_OCTEON9 + oct_lmt_copy (line, ctx->lmt_ioaddr, &d, n_dwords); +#else for (u32 i = 0; i < n_dwords; i++) line->dwords[i] = d.as_u128[i]; +#endif *dpl = n_dwords; *n = *n + 1; @@ -252,7 +300,7 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, vlib_buffer_t **b, u32 n_pkts, int trace) { u8 dwords_per_line[16], *dpl = dwords_per_line; - u64 lmt_arg, ioaddr, n_lines; + u64 __attribute__ ((unused)) lmt_arg, ioaddr, n_lines; u32 n_left, or_flags_16 = 0, n = 0; const u32 not_simple_flags = VLIB_BUFFER_NEXT_PRESENT | VNET_BUFFER_F_OFFLOAD; @@ -331,6 +379,7 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, if (PREDICT_FALSE (!n_lines)) return n_pkts; +#ifndef PLATFORM_OCTEON9 if (PREDICT_FALSE (or_flags_16 & VLIB_BUFFER_NEXT_PRESENT)) { dpl = dwords_per_line; @@ -359,6 +408,7 @@ oct_tx_enq16 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vnet_dev_tx_queue_t *txq, } roc_lmt_submit_steorl (lmt_arg, ioaddr); +#endif return n_pkts; } @@ -375,7 +425,11 @@ VNET_DEV_NODE_FN (oct_tx_node) u32 *from = vlib_frame_vector_args (frame); u32 n, n_enq, n_left, n_pkts = frame->n_vectors; vlib_buffer_t *buffers[VLIB_FRAME_SIZE + 8], **b = buffers; +#ifdef PLATFORM_OCTEON9 + u64 lmt_id = 0; +#else u64 lmt_id = vm->thread_index << ROC_LMT_LINES_PER_CORE_LOG2; +#endif oct_tx_ctx_t ctx = { .node = node, diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c index 421f662efa2..e416efe2e4d 100644 --- a/src/plugins/dpdk/device/init.c +++ b/src/plugins/dpdk/device/init.c @@ -1045,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; @@ -1258,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) @@ -1272,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 */ 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 085a2b69bf7..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 * @@ -411,6 +425,12 @@ hcc_run (vlib_main_t *vm, int 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: err = clib_error_return (0, "unexpected event %d", event_type); break; diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 37a6de71bc7..893dd877c29 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -267,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)); @@ -378,7 +382,7 @@ static const char *http_response_template = "HTTP/1.1 %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 @@ -521,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; } @@ -547,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; @@ -592,17 +596,14 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp) } 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; } 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; } @@ -743,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], @@ -763,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; } @@ -818,11 +824,18 @@ http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) goto error; } + /* 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)) { @@ -838,7 +851,9 @@ http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) return HTTP_SM_STOP; error: + 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_ERROR; } @@ -897,6 +912,13 @@ http_state_client_io_more_data (http_conn_t *hc, transport_send_params_t *sp) hc->to_recv -= rv; HTTP_DBG (1, "drained %d from ts; remains %d", rv, hc->to_recv); + if (hc->to_recv == 0) + { + hc->rx_buf_offset = 0; + vec_reset_length (hc->rx_buf); + http_state_change (hc, HTTP_STATE_WAIT_APP_METHOD); + } + app_wrk = app_worker_get_if_valid (as->app_wrk_index); if (app_wrk) app_worker_rx_notify (app_wrk, as); @@ -1151,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))) @@ -1248,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 c9912dd6db8..7fbefd667f4 100644 --- a/src/plugins/http/http.h +++ b/src/plugins/http/http.h @@ -277,6 +277,74 @@ http_state_is_tx_valid (http_conn_t *hc) state == HTTP_STATE_WAIT_APP_METHOD); } +/** + * Remove dot segments from path (RFC3986 section 5.2.4) + * + * @param path Path to sanitize. + * + * @return New vector with sanitized path. + * + * The caller is always responsible to free the returned vector. + */ +always_inline u8 * +http_path_remove_dot_segments (u8 *path) +{ + u32 *segments = 0, *segments_len = 0, segment_len; + u8 *new_path = 0; + int i, ii; + + if (!path) + return vec_new (u8, 0); + + segments = vec_new (u32, 1); + /* first segment */ + segments[0] = 0; + /* find all segments */ + for (i = 1; i < (vec_len (path) - 1); i++) + { + if (path[i] == '/') + vec_add1 (segments, i + 1); + } + /* dummy tail */ + vec_add1 (segments, vec_len (path)); + + /* scan all segments for "." and ".." */ + segments_len = vec_new (u32, vec_len (segments) - 1); + for (i = 0; i < vec_len (segments_len); i++) + { + segment_len = segments[i + 1] - segments[i]; + if (segment_len == 2 && path[segments[i]] == '.') + segment_len = 0; + else if (segment_len == 3 && path[segments[i]] == '.' && + path[segments[i] + 1] == '.') + { + segment_len = 0; + /* remove parent (if any) */ + for (ii = i - 1; ii >= 0; ii--) + { + if (segments_len[ii]) + { + segments_len[ii] = 0; + break; + } + } + } + segments_len[i] = segment_len; + } + + /* we might end with empty path, so return at least empty vector */ + new_path = vec_new (u8, 0); + /* append all valid segments */ + for (i = 0; i < vec_len (segments_len); i++) + { + if (segments_len[i]) + vec_add (new_path, path + segments[i], segments_len[i]); + } + vec_free (segments); + vec_free (segments_len); + return new_path; +} + #endif /* SRC_PLUGINS_HTTP_HTTP_H_ */ /* diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 040cdca9d7a..f433238dcb1 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -357,7 +357,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, u8 *request) { http_status_code_t sc = HTTP_STATUS_OK; - u8 *path; + u8 *path, *sanitized_path; u32 ce_index; http_content_type_t type; @@ -367,6 +367,9 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, type = content_type_from_request (request); + /* Remove dot segments to prevent path traversal */ + sanitized_path = http_path_remove_dot_segments (request); + /* * Construct the file to open * Browsers are capable of sporadically including a leading '/' @@ -374,9 +377,9 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, if (!request) path = format (0, "%s%c", hsm->www_root, 0); else if (request[0] == '/') - path = format (0, "%s%s%c", hsm->www_root, request, 0); + path = format (0, "%s%s%c", hsm->www_root, sanitized_path, 0); else - path = format (0, "%s/%s%c", hsm->www_root, request, 0); + path = format (0, "%s/%s%c", hsm->www_root, sanitized_path, 0); if (hsm->debug_level > 0) clib_warning ("%s '%s'", (rt == HTTP_REQ_GET) ? "GET" : "POST", path); @@ -419,7 +422,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, hs->cache_pool_index = ce_index; done: - + vec_free (sanitized_path); hs->content_type = type; start_send_data (hs, sc); if (!hs->data) diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index a3e71668126..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 */); }); } @@ -476,7 +476,7 @@ send_sa_v3 (ikev2_sa_t *sa, vl_api_ikev2_sa_v3_dump_t *mp, u32 api_sa_index) ikev2_copy_stats (&rsa->stats, &sa->stats); - vl_api_ikev2_sa_v3_t_endian (rsa); + vl_api_ikev2_sa_v3_t_endian (rsa, 1 /* to network */); }); } @@ -549,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 */); }); } @@ -628,7 +628,7 @@ send_child_sa_v2 (ikev2_child_sa_t *child, vl_api_ikev2_child_sa_v2_dump_t *mp, clib_memcpy (&k->sk_ar, child->sk_ar, k->sk_ar_len); } - vl_api_ikev2_child_sa_v2_t_endian (&rmp->child_sa); + vl_api_ikev2_child_sa_v2_t_endian (&rmp->child_sa, 1 /* to network */); }); } @@ -700,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_test.c b/src/plugins/ikev2/ikev2_test.c index 5682d7058f6..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); @@ -533,7 +533,7 @@ vl_api_ikev2_sa_v3_details_t_handler (vl_api_ikev2_sa_v3_details_t *mp) ip_address_t iaddr; ip_address_t raddr; vl_api_ikev2_keys_t *k = &sa->keys; - vl_api_ikev2_sa_v3_t_endian (sa); + vl_api_ikev2_sa_v3_t_endian (sa, 0 /* from network */); ip_address_decode2 (&sa->iaddr, &iaddr); ip_address_decode2 (&sa->raddr, &raddr); @@ -619,7 +619,7 @@ 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); @@ -696,7 +696,7 @@ vl_api_ikev2_child_sa_v2_details_t_handler ( 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); @@ -784,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/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-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/urpf/CMakeLists.txt b/src/plugins/urpf/CMakeLists.txt index 2f44e3b2344..f665d30b0bb 100644 --- a/src/plugins/urpf/CMakeLists.txt +++ b/src/plugins/urpf/CMakeLists.txt @@ -22,6 +22,10 @@ add_vpp_plugin(urpf ip4_urpf.c ip6_urpf.c + INSTALL_HEADERS + urpf_dp.h + urpf.h + API_FILES urpf.api ) diff --git a/src/plugins/urpf/urpf.c b/src/plugins/urpf/urpf.c index e5209caafb4..1e7d6c0fb91 100644 --- a/src/plugins/urpf/urpf.c +++ b/src/plugins/urpf/urpf.c @@ -60,7 +60,17 @@ static const char *urpf_feats[N_AF][VLIB_N_DIR][URPF_N_MODES] = urpf_data_t *urpf_cfgs[N_AF][VLIB_N_DIR]; u8 * -format_urpf_mode (u8 * s, va_list * a) +format_urpf_trace (u8 *s, va_list *va) +{ + CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *); + CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *); + urpf_trace_t *t = va_arg (*va, urpf_trace_t *); + + return format (s, "uRPF:%d fib:%d", t->urpf, t->fib_index); +} + +__clib_export u8 * +format_urpf_mode (u8 *s, va_list *a) { urpf_mode_t mode = va_arg (*a, int); @@ -76,8 +86,8 @@ format_urpf_mode (u8 * s, va_list * a) return (format (s, "unknown")); } -static uword -unformat_urpf_mode (unformat_input_t * input, va_list * args) +__clib_export uword +unformat_urpf_mode (unformat_input_t *input, va_list *args) { urpf_mode_t *mode = va_arg (*args, urpf_mode_t *); @@ -94,7 +104,16 @@ unformat_urpf_mode (unformat_input_t * input, va_list * args) return 0; } -int +__clib_export int +urpf_feature_enable_disable (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, u32 sw_if_index, int enable) +{ + return vnet_feature_enable_disable (urpf_feat_arcs[af][dir], + urpf_feats[af][dir][mode], sw_if_index, + enable, 0, 0); +} + +__clib_export int urpf_update (urpf_mode_t mode, u32 sw_if_index, ip_address_family_t af, vlib_dir_t dir, u32 table_id) { diff --git a/src/plugins/urpf/urpf.h b/src/plugins/urpf/urpf.h index 6983a2b440c..a40a25df16b 100644 --- a/src/plugins/urpf/urpf.h +++ b/src/plugins/urpf/urpf.h @@ -32,7 +32,15 @@ typedef enum urpf_mode_t_ #define URPF_N_MODES (URPF_MODE_STRICT+1) -extern u8 *format_urpf_mode (u8 * s, va_list * a); +typedef struct +{ + index_t urpf; + u32 fib_index; +} urpf_trace_t; + +u8 *format_urpf_trace (u8 *s, va_list *va); +u8 *format_urpf_mode (u8 *s, va_list *a); +uword unformat_urpf_mode (unformat_input_t *input, va_list *args); typedef struct { @@ -43,8 +51,8 @@ typedef struct extern urpf_data_t *urpf_cfgs[N_AF][VLIB_N_DIR]; -extern int urpf_update (urpf_mode_t mode, u32 sw_if_index, - ip_address_family_t af, vlib_dir_t dir, u32 table_id); +int urpf_update (urpf_mode_t mode, u32 sw_if_index, ip_address_family_t af, + vlib_dir_t dir, u32 table_id); #endif diff --git a/src/plugins/urpf/urpf_dp.h b/src/plugins/urpf/urpf_dp.h index 816d8b70b90..b17fed7e04b 100644 --- a/src/plugins/urpf/urpf_dp.h +++ b/src/plugins/urpf/urpf_dp.h @@ -53,22 +53,6 @@ * * This file contains the interface unicast source check. */ -typedef struct -{ - index_t urpf; -} urpf_trace_t; - -static u8 * -format_urpf_trace (u8 * s, va_list * va) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *); - urpf_trace_t *t = va_arg (*va, urpf_trace_t *); - - s = format (s, "uRPF:%d", t->urpf); - - return s; -} #define foreach_urpf_error \ _(DROP, "uRPF Drop") \ @@ -87,10 +71,157 @@ typedef enum URPF_N_NEXT, } urpf_next_t; +static_always_inline u32 +urpf_get_fib_index (vlib_buffer_t *b, ip_address_family_t af, vlib_dir_t dir) +{ + u32 sw_if_index = vnet_buffer (b)->sw_if_index[dir]; + return vec_elt (urpf_cfgs[af][dir], sw_if_index).fib_index; +} + +static_always_inline void +urpf_perform_check_x1 (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, vlib_buffer_t *b, const u8 *h, + u32 fib_index, load_balance_t **lb, u32 *pass) +{ + load_balance_t *llb; + u32 lpass; + u32 lb_index; + + ASSERT (fib_index != ~0); + + if (AF_IP4 == af) + { + const ip4_header_t *ip; + + ip = (ip4_header_t *) h; + + lb_index = ip4_fib_forwarding_lookup (fib_index, &ip->src_address); + + /* Pass multicast. */ + lpass = (ip4_address_is_multicast (&ip->src_address) || + ip4_address_is_global_broadcast (&ip->src_address)); + } + else + { + const ip6_header_t *ip; + + ip = (ip6_header_t *) h; + + lb_index = ip6_fib_table_fwding_lookup (fib_index, &ip->src_address); + lpass = ip6_address_is_multicast (&ip->src_address); + } + + llb = load_balance_get (lb_index); + + if (URPF_MODE_STRICT == mode) + { + int res; + + res = fib_urpf_check (llb->lb_urpf, vnet_buffer (b)->sw_if_index[dir]); + if (VLIB_RX == dir) + lpass |= res; + else + { + lpass |= !res && fib_urpf_check_size (llb->lb_urpf); + lpass |= b->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + } + } + else + lpass |= fib_urpf_check_size (llb->lb_urpf); + + *lb = llb; + *pass = lpass; +} + +static_always_inline void +urpf_perform_check_x2 (ip_address_family_t af, vlib_dir_t dir, + urpf_mode_t mode, vlib_buffer_t *b0, vlib_buffer_t *b1, + const u8 *h0, const u8 *h1, u32 fib_index0, + u32 fib_index1, load_balance_t **lb0, + load_balance_t **lb1, u32 *pass0, u32 *pass1) +{ + load_balance_t *llb0, *llb1; + u32 lpass0, lpass1; + u32 lb_index0, lb_index1; + + ASSERT (fib_index0 != ~0); + ASSERT (fib_index1 != ~0); + + if (AF_IP4 == af) + { + const ip4_header_t *ip0, *ip1; + + ip0 = (ip4_header_t *) h0; + ip1 = (ip4_header_t *) h1; + + ip4_fib_forwarding_lookup_x2 (fib_index0, fib_index1, &ip0->src_address, + &ip1->src_address, &lb_index0, &lb_index1); + /* Pass multicast. */ + lpass0 = (ip4_address_is_multicast (&ip0->src_address) || + ip4_address_is_global_broadcast (&ip0->src_address)); + lpass1 = (ip4_address_is_multicast (&ip1->src_address) || + ip4_address_is_global_broadcast (&ip1->src_address)); + } + else + { + const ip6_header_t *ip0, *ip1; + + ip0 = (ip6_header_t *) h0; + ip1 = (ip6_header_t *) h1; + + lb_index0 = ip6_fib_table_fwding_lookup (fib_index0, &ip0->src_address); + lb_index1 = ip6_fib_table_fwding_lookup (fib_index1, &ip1->src_address); + lpass0 = ip6_address_is_multicast (&ip0->src_address); + lpass1 = ip6_address_is_multicast (&ip1->src_address); + } + + llb0 = load_balance_get (lb_index0); + llb1 = load_balance_get (lb_index1); + + if (URPF_MODE_STRICT == mode) + { + /* for RX the check is: would this source adddress be + * forwarded out of the interface on which it was recieved, + * if yes allow. For TX it's; would this source address be + * forwarded out of the interface through which it is being + * sent, if yes drop. + */ + int res0, res1; + + res0 = + fib_urpf_check (llb0->lb_urpf, vnet_buffer (b0)->sw_if_index[dir]); + res1 = + fib_urpf_check (llb1->lb_urpf, vnet_buffer (b1)->sw_if_index[dir]); + + if (VLIB_RX == dir) + { + lpass0 |= res0; + lpass1 |= res1; + } + else + { + lpass0 |= !res0 && fib_urpf_check_size (llb0->lb_urpf); + lpass1 |= !res1 && fib_urpf_check_size (llb1->lb_urpf); + + /* allow locally generated */ + lpass0 |= b0->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + lpass1 |= b1->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; + } + } + else + { + lpass0 |= fib_urpf_check_size (llb0->lb_urpf); + lpass1 |= fib_urpf_check_size (llb1->lb_urpf); + } + + *lb0 = llb0; + *lb1 = llb1; + *pass0 = lpass0; + *pass1 = lpass1; +} + static_always_inline uword -urpf_inline (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * frame, +urpf_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, ip_address_family_t af, vlib_dir_t dir, urpf_mode_t mode) { vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; @@ -106,8 +237,8 @@ urpf_inline (vlib_main_t * vm, while (n_left >= 4) { - u32 pass0, lb_index0, pass1, lb_index1; - const load_balance_t *lb0, *lb1; + u32 pass0, pass1; + load_balance_t *lb0 = 0, *lb1 = 0; u32 fib_index0, fib_index1; const u8 *h0, *h1; @@ -121,87 +252,32 @@ urpf_inline (vlib_main_t * vm, h0 = (u8 *) vlib_buffer_get_current (b[0]); h1 = (u8 *) vlib_buffer_get_current (b[1]); - if (VLIB_TX == dir) { h0 += vnet_buffer (b[0])->ip.save_rewrite_length; h1 += vnet_buffer (b[1])->ip.save_rewrite_length; } - fib_index0 = - urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index; - fib_index1 = - urpf_cfgs[af][dir][vnet_buffer (b[1])->sw_if_index[dir]].fib_index; + fib_index0 = urpf_get_fib_index (b[0], af, dir); + fib_index1 = urpf_get_fib_index (b[1], af, dir); + urpf_perform_check_x2 (af, dir, mode, b[0], b[1], h0, h1, fib_index0, + fib_index1, &lb0, &lb1, &pass0, &pass1); - if (AF_IP4 == af) - { - const ip4_header_t *ip0, *ip1; - - ip0 = (ip4_header_t *) h0; - ip1 = (ip4_header_t *) h1; - - ip4_fib_forwarding_lookup_x2 (fib_index0, - fib_index1, - &ip0->src_address, - &ip1->src_address, - &lb_index0, &lb_index1); - /* Pass multicast. */ - pass0 = (ip4_address_is_multicast (&ip0->src_address) || - ip4_address_is_global_broadcast (&ip0->src_address)); - pass1 = (ip4_address_is_multicast (&ip1->src_address) || - ip4_address_is_global_broadcast (&ip1->src_address)); - } - else + if (b[0]->flags & VLIB_BUFFER_IS_TRACED) { - const ip6_header_t *ip0, *ip1; - - ip0 = (ip6_header_t *) h0; - ip1 = (ip6_header_t *) h1; - - lb_index0 = ip6_fib_table_fwding_lookup (fib_index0, - &ip0->src_address); - lb_index1 = ip6_fib_table_fwding_lookup (fib_index1, - &ip1->src_address); - pass0 = ip6_address_is_multicast (&ip0->src_address); - pass1 = ip6_address_is_multicast (&ip1->src_address); - } - - lb0 = load_balance_get (lb_index0); - lb1 = load_balance_get (lb_index1); + urpf_trace_t *t; - if (URPF_MODE_STRICT == mode) - { - /* for RX the check is: would this source adddress be forwarded - * out of the interface on which it was recieved, if yes allow. - * For TX it's; would this source address be forwarded out of the - * interface through which it is being sent, if yes drop. - */ - int res0, res1; - - res0 = fib_urpf_check (lb0->lb_urpf, - vnet_buffer (b[0])->sw_if_index[dir]); - res1 = fib_urpf_check (lb1->lb_urpf, - vnet_buffer (b[1])->sw_if_index[dir]); - - if (VLIB_RX == dir) - { - pass0 |= res0; - pass1 |= res1; - } - else - { - pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf); - pass1 |= !res1 && fib_urpf_check_size (lb1->lb_urpf); - - /* allow locally generated */ - pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - pass1 |= b[1]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + t = vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->urpf = lb0 ? lb0->lb_urpf : ~0; + t->fib_index = fib_index0; } - else + if (b[1]->flags & VLIB_BUFFER_IS_TRACED) { - pass0 |= fib_urpf_check_size (lb0->lb_urpf); - pass1 |= fib_urpf_check_size (lb1->lb_urpf); + urpf_trace_t *t; + + t = vlib_add_trace (vm, node, b[1], sizeof (*t)); + t->urpf = lb1 ? lb1->lb_urpf : ~0; + t->fib_index = fib_index1; } if (PREDICT_TRUE (pass0)) @@ -218,22 +294,6 @@ urpf_inline (vlib_main_t * vm, next[1] = URPF_NEXT_DROP; b[1]->error = node->errors[URPF_ERROR_DROP]; } - - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[0], sizeof (*t)); - t->urpf = lb0->lb_urpf; - } - if (b[1]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[1], sizeof (*t)); - t->urpf = lb1->lb_urpf; - } - b += 2; next += 2; n_left -= 2; @@ -241,8 +301,8 @@ urpf_inline (vlib_main_t * vm, while (n_left) { - u32 pass0, lb_index0, fib_index0; - const load_balance_t *lb0; + u32 pass0, fib_index0; + load_balance_t *lb0 = 0; const u8 *h0; h0 = (u8 *) vlib_buffer_get_current (b[0]); @@ -250,51 +310,18 @@ urpf_inline (vlib_main_t * vm, if (VLIB_TX == dir) h0 += vnet_buffer (b[0])->ip.save_rewrite_length; - fib_index0 = - urpf_cfgs[af][dir][vnet_buffer (b[0])->sw_if_index[dir]].fib_index; - - if (AF_IP4 == af) - { - const ip4_header_t *ip0; - - ip0 = (ip4_header_t *) h0; - - lb_index0 = ip4_fib_forwarding_lookup (fib_index0, - &ip0->src_address); + fib_index0 = urpf_get_fib_index (b[0], af, dir); + urpf_perform_check_x1 (af, dir, mode, b[0], h0, fib_index0, &lb0, + &pass0); - /* Pass multicast. */ - pass0 = (ip4_address_is_multicast (&ip0->src_address) || - ip4_address_is_global_broadcast (&ip0->src_address)); - } - else + if (b[0]->flags & VLIB_BUFFER_IS_TRACED) { - const ip6_header_t *ip0; - - ip0 = (ip6_header_t *) h0; - - lb_index0 = ip6_fib_table_fwding_lookup (fib_index0, - &ip0->src_address); - pass0 = ip6_address_is_multicast (&ip0->src_address); - } - - lb0 = load_balance_get (lb_index0); + urpf_trace_t *t; - if (URPF_MODE_STRICT == mode) - { - int res0; - - res0 = fib_urpf_check (lb0->lb_urpf, - vnet_buffer (b[0])->sw_if_index[dir]); - if (VLIB_RX == dir) - pass0 |= res0; - else - { - pass0 |= !res0 && fib_urpf_check_size (lb0->lb_urpf); - pass0 |= b[0]->flags & VNET_BUFFER_F_LOCALLY_ORIGINATED; - } + t = vlib_add_trace (vm, node, b[0], sizeof (*t)); + t->urpf = lb0 ? lb0->lb_urpf : ~0; + t->fib_index = fib_index0; } - else - pass0 |= fib_urpf_check_size (lb0->lb_urpf); if (PREDICT_TRUE (pass0)) vnet_feature_next_u16 (&next[0], b[0]); @@ -303,14 +330,6 @@ urpf_inline (vlib_main_t * vm, next[0] = URPF_NEXT_DROP; b[0]->error = node->errors[URPF_ERROR_DROP]; } - - if (b[0]->flags & VLIB_BUFFER_IS_TRACED) - { - urpf_trace_t *t; - - t = vlib_add_trace (vm, node, b[0], sizeof (*t)); - t->urpf = lb0->lb_urpf; - } b++; next++; n_left--; 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/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/vlib/buffer.c b/src/vlib/buffer.c index 674f15d5dc6..5ba42270b1a 100644 --- a/src/vlib/buffer.c +++ b/src/vlib/buffer.c @@ -663,7 +663,7 @@ vlib_buffer_main_init_numa_alloc (struct vlib_main_t *vm, u32 numa_node, u8 unpriv) { vlib_buffer_main_t *bm = vm->buffer_main; - u32 buffers_per_numa = bm->buffers_per_numa; + u32 buffers_per_numa = bm->buffers_per_numa[numa_node]; clib_error_t *error; u32 buffer_size; uword n_pages, pagesize; @@ -680,6 +680,9 @@ vlib_buffer_main_init_numa_alloc (struct vlib_main_t *vm, u32 numa_node, "size (%llu)", buffer_size, pagesize); if (buffers_per_numa == 0) + buffers_per_numa = bm->default_buffers_per_numa; + + if (buffers_per_numa == 0) buffers_per_numa = unpriv ? VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA_UNPRIV : VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA; @@ -906,18 +909,48 @@ done: } static clib_error_t * +vlib_buffers_numa_configure (vlib_buffer_main_t *bm, u32 numa_node, + unformat_input_t *input) +{ + u32 buffers = 0; + + if (numa_node >= VLIB_BUFFER_MAX_NUMA_NODES) + return clib_error_return (0, "invalid numa node"); + + if (!input) + return 0; + + unformat_skip_white_space (input); + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "buffers %u", &buffers)) + ; + else + return unformat_parse_error (input); + } + + bm->buffers_per_numa[numa_node] = buffers; + return 0; +} + +static clib_error_t * vlib_buffers_configure (vlib_main_t * vm, unformat_input_t * input) { vlib_buffer_main_t *bm; + u32 numa_node; + unformat_input_t sub_input; + clib_error_t *error = 0; vlib_buffer_main_alloc (vm); bm = vm->buffer_main; bm->log2_page_size = CLIB_MEM_PAGE_SZ_UNKNOWN; + memset (bm->buffers_per_numa, 0, sizeof (bm->buffers_per_numa)); while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - if (unformat (input, "buffers-per-numa %u", &bm->buffers_per_numa)) + if (unformat (input, "buffers-per-numa %u", + &bm->default_buffers_per_numa)) ; else if (unformat (input, "page-size %U", unformat_log2_page_size, &bm->log2_page_size)) @@ -925,6 +958,15 @@ vlib_buffers_configure (vlib_main_t * vm, unformat_input_t * input) else if (unformat (input, "default data-size %u", &bm->default_data_size)) ; + else if (unformat (input, "numa %u %U", &numa_node, + unformat_vlib_cli_sub_input, &sub_input)) + { + error = vlib_buffers_numa_configure (bm, numa_node, &sub_input); + unformat_free (&sub_input); + + if (error) + return error; + } else return unformat_parse_error (input); } diff --git a/src/vlib/buffer.h b/src/vlib/buffer.h index 7d45689ed19..aad9701080e 100644 --- a/src/vlib/buffer.h +++ b/src/vlib/buffer.h @@ -508,7 +508,8 @@ typedef struct u8 default_buffer_pool_index_for_numa[VLIB_BUFFER_MAX_NUMA_NODES]; /* config */ - u32 buffers_per_numa; + u32 default_buffers_per_numa; + u32 buffers_per_numa[VLIB_BUFFER_MAX_NUMA_NODES]; u16 ext_hdr_size; u32 default_data_size; clib_mem_page_sz_t log2_page_size; diff --git a/src/vlib/linux/pci.c b/src/vlib/linux/pci.c index f7c63bc3607..29ca3d97523 100644 --- a/src/vlib/linux/pci.c +++ b/src/vlib/linux/pci.c @@ -1561,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/threads.c b/src/vlib/threads.c index 87b71adc2bc..ef2c5616f21 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -205,6 +205,10 @@ vlib_thread_init (vlib_main_t * vm) avail_cpu = clib_bitmap_set (avail_cpu, c, 0); } + /* if main thread affinity is unspecified, set to current running cpu */ + if (tm->main_lcore == ~0) + tm->main_lcore = sched_getcpu (); + /* grab cpu for main thread */ if (tm->main_lcore != ~0) { @@ -370,6 +374,8 @@ void vlib_worker_thread_init (vlib_worker_thread_t * w) { vlib_thread_main_t *tm = vlib_get_thread_main (); + sigset_t signals; + int rv; /* * Note: disabling signals in worker threads as follows @@ -379,7 +385,17 @@ vlib_worker_thread_init (vlib_worker_thread_t * w) * sigfillset (&s); * pthread_sigmask (SIG_SETMASK, &s, 0); * } + * We can still disable signals for SIGINT,SIGHUP and SIGTERM as they don't + * trigger post-dump handlers anyway. */ + sigemptyset (&signals); + sigaddset (&signals, SIGINT); + sigaddset (&signals, SIGHUP); + sigaddset (&signals, SIGTERM); + rv = pthread_sigmask (SIG_BLOCK, &signals, NULL); + + if (rv) + clib_warning ("Failed to set the worker signal mask"); clib_mem_set_heap (w->thread_mheap); @@ -1122,6 +1138,7 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) u8 *name; uword *bitmap; u32 count; + int use_corelist = 0; tm->thread_registrations_by_name = hash_create_string (0, sizeof (uword)); @@ -1173,6 +1190,7 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) tr->coremask = bitmap; tr->count = clib_bitmap_count_set_bits (tr->coremask); + use_corelist = 1; } else if (unformat @@ -1202,6 +1220,9 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) break; } + if (use_corelist && tm->main_lcore == ~0) + return clib_error_return (0, "main-core must be specified when using " + "corelist-* or coremask-* attribute"); if (tm->sched_priority != ~0) { if (tm->sched_policy == SCHED_FIFO || tm->sched_policy == SCHED_RR) diff --git a/src/vlib/unix/main.c b/src/vlib/unix/main.c index ee28ca8f1aa..11d0cb1160c 100644 --- a/src/vlib/unix/main.c +++ b/src/vlib/unix/main.c @@ -40,6 +40,8 @@ #include <vlib/unix/unix.h> #include <vlib/unix/plugin.h> #include <vppinfra/unix.h> +#include <vppinfra/stack.h> +#include <vppinfra/format_ansi.h> #include <limits.h> #include <signal.h> @@ -97,20 +99,42 @@ int vlib_last_signum = 0; uword vlib_last_faulting_address = 0; static void +log_one_line () +{ + vec_terminate_c_string (syslog_msg); + if (unix_main.flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG)) + fprintf (stderr, "%s\n", syslog_msg); + else + syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg); + vec_reset_length (syslog_msg); +} + +static void unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) { uword fatal = 0; + int color = + (unix_main.flags & (UNIX_FLAG_INTERACTIVE | UNIX_FLAG_NOSYSLOG)) && + (unix_main.flags & UNIX_FLAG_NOCOLOR) == 0; /* These come in handy when looking at core files from optimized images */ vlib_last_signum = signum; vlib_last_faulting_address = (uword) si->si_addr; + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_BR_RED); + syslog_msg = format (syslog_msg, "received signal %U, PC %U", format_signal, signum, format_ucontext_pc, uc); - if (signum == SIGSEGV) + if (signum == SIGSEGV || signum == SIGBUS) syslog_msg = format (syslog_msg, ", faulting address %p", si->si_addr); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT); + + log_one_line (); + switch (signum) { /* these (caught) signals cause the application to exit */ @@ -120,11 +144,17 @@ unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) */ if (unix_main.vlib_main && unix_main.vlib_main->main_loop_exit_set) { - syslog (LOG_ERR | LOG_DAEMON, "received SIGTERM, exiting..."); + syslog_msg = format ( + syslog_msg, "received SIGTERM from PID %d UID %d, exiting...", + si->si_pid, si->si_uid); + log_one_line (); unix_main.vlib_main->main_loop_exit_now = 1; } else - syslog (LOG_ERR | LOG_DAEMON, "IGNORE early SIGTERM..."); + { + syslog_msg = format (syslog_msg, "IGNORE early SIGTERM..."); + log_one_line (); + } break; /* fall through */ case SIGQUIT: @@ -144,26 +174,75 @@ unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) break; } - /* Null terminate. */ - vec_add1 (syslog_msg, 0); if (fatal) { - syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg); + int skip = 1, index = 0; - /* Address of callers: outer first, inner last. */ - uword callers[15]; - uword n_callers = clib_backtrace (callers, ARRAY_LEN (callers), 0); - int i; - for (i = 0; i < n_callers; i++) + foreach_clib_stack_frame (sf) { - vec_reset_length (syslog_msg); + if (sf->is_signal_frame) + { + int pipefd[2]; + const int n_bytes = 20; + u8 *ip = (void *) sf->ip; + + if (pipe (pipefd) == 0) + { + /* check PC points to valid memory */ + if (write (pipefd[1], ip, n_bytes) == n_bytes) + { + syslog_msg = format (syslog_msg, "Code: "); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_CYAN); + for (int i = 0; i < n_bytes; i++) + syslog_msg = format (syslog_msg, " %02x", ip[i]); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT); + } + else + { + syslog_msg = format ( + syslog_msg, "PC contains invalid memory address"); + } + log_one_line (); + foreach_int (i, 0, 1) + close (pipefd[i]); + } + skip = 0; + } + + if (skip) + continue; + + syslog_msg = format (syslog_msg, "#%-2d ", index++); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_BLUE); + syslog_msg = format (syslog_msg, "0x%016lx", sf->ip); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT); + + if (sf->name[0]) + { + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_YELLOW); + syslog_msg = + format (syslog_msg, " %s + 0x%x", sf->name, sf->offset); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT); + } - syslog_msg = - format (syslog_msg, "#%-2d 0x%016lx %U%c", i, callers[i], - format_clib_elf_symbol_with_address, callers[i], 0); + log_one_line (); - syslog (LOG_ERR | LOG_DAEMON, "%s", syslog_msg); + if (sf->file_name) + { + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_GREEN); + syslog_msg = format (syslog_msg, " from %s", sf->file_name); + if (color) + syslog_msg = format (syslog_msg, ANSI_FG_DEFAULT); + log_one_line (); + } } /* have to remove SIGABRT to avoid recursive - os_exit calling abort() */ @@ -175,9 +254,6 @@ unix_signal_handler (int signum, siginfo_t * si, ucontext_t * uc) else os_exit (1); } - else - clib_warning ("%s", syslog_msg); - } static clib_error_t * diff --git a/src/vlib/unix/plugin.c b/src/vlib/unix/plugin.c index fd3a050b944..77e4633e14a 100644 --- a/src/vlib/unix/plugin.c +++ b/src/vlib/unix/plugin.c @@ -88,19 +88,14 @@ extract (u8 * sp, u8 * ep) */ static clib_error_t * -r2_to_reg (elf_main_t * em, vlib_plugin_r2_t * r2, - vlib_plugin_registration_t * reg) +r2_to_reg (elf_main_t *em, vlib_plugin_r2_t *r2, + vlib_plugin_registration_t *reg, elf_section_t *data_section) { - clib_error_t *error; - elf_section_t *section; uword data_segment_offset; u8 *data; /* It turns out that the strings land in the ".data" section */ - error = elf_get_section_by_name (em, ".data", §ion); - if (error) - return error; - data = elf_get_section_contents (em, section->index, 1); + data = elf_get_section_contents (em, data_section->index, 1); /* * Offsets in the ".vlib_plugin_r2" section @@ -177,13 +172,52 @@ load_one_plugin (plugin_main_t * pm, plugin_info_t * pi, int from_early_init) error = elf_get_section_by_name (&em, ".vlib_plugin_r2", §ion); if (error == 0) { + elf_section_t *data_section; + elf_relocation_table_t *rt; + elf_relocation_with_addend_t *r; + elf_symbol_table_t *st; + elf64_symbol_t *sym, *symok = 0; + data = elf_get_section_contents (&em, section->index, 1); r2 = (vlib_plugin_r2_t *) data; + + elf_get_section_by_name (&em, ".data", &data_section); + + // Find first symbol in .vlib_plugin_r2 section. + vec_foreach (st, em.symbol_tables) + { + vec_foreach (sym, st->symbols) + { + if (sym->section_index == section->index) + { + symok = sym; + break; + } + } + } + + // Relocate section data as per relocation tables. + if (symok != 0) + { + vec_foreach (rt, em.relocation_tables) + { + vec_foreach (r, rt->relocations) + { + if (r->address >= symok->value && + r->address < symok->value + symok->size) + { + *(uword *) ((void *) data + r->address - symok->value) += + r->addend - data_section->header.exec_address; + } + } + } + } + reg = clib_mem_alloc (sizeof (*reg)); memset (reg, 0, sizeof (*reg)); reg->default_disabled = r2->default_disabled != 0; - error = r2_to_reg (&em, r2, reg); + error = r2_to_reg (&em, r2, reg, data_section); if (error) { PLUGIN_LOG_ERR ("Bad r2 registration: %s\n", (char *) pi->name); @@ -306,8 +340,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/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..eb74f5de84c 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 @@ -1162,6 +1144,7 @@ list(APPEND VNET_HEADERS fib/fib_path_list.h fib/fib_sas.h fib/fib_source.h + fib/fib_urpf_list.h ) list(APPEND VNET_API_FILES @@ -1460,7 +1443,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/devices/virtio/node.c b/src/vnet/devices/virtio/node.c index 8c837575cf8..027e1ed4e74 100644 --- a/src/vnet/devices/virtio/node.c +++ b/src/vnet/devices/virtio/node.c @@ -282,6 +282,16 @@ virtio_device_input_gso_inline (vlib_main_t *vm, vlib_node_runtime_t *node, if (n_left == 0) return 0; + if (PREDICT_FALSE (n_left == vring->queue_size)) + { + /* + * Informational error logging when VPP is not pulling packets fast + * enough. + */ + vlib_error_count (vm, node->node_index, VIRTIO_INPUT_ERROR_FULL_RX_QUEUE, + 1); + } + if (type == VIRTIO_IF_TYPE_TUN) { next_index = VNET_DEVICE_INPUT_NEXT_IP4_INPUT; diff --git a/src/vnet/devices/virtio/virtio_inline.h b/src/vnet/devices/virtio/virtio_inline.h index 179f319aa4c..41bba755934 100644 --- a/src/vnet/devices/virtio/virtio_inline.h +++ b/src/vnet/devices/virtio/virtio_inline.h @@ -17,6 +17,7 @@ #define foreach_virtio_input_error \ _ (BUFFER_ALLOC, "buffer alloc error") \ + _ (FULL_RX_QUEUE, "full rx queue (driver tx drop)") \ _ (UNKNOWN, "unknown") typedef enum 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/fib/fib_api.c b/src/vnet/fib/fib_api.c index 07d6699d87a..1b1c0d113c0 100644 --- a/src/vnet/fib/fib_api.c +++ b/src/vnet/fib/fib_api.c @@ -190,6 +190,7 @@ fib_api_path_decode (vl_api_fib_path_t *in, break; case FIB_API_PATH_TYPE_DROP: out->frp_flags |= FIB_ROUTE_PATH_DROP; + out->frp_sw_if_index = ntohl(in->sw_if_index); break; case FIB_API_PATH_TYPE_LOCAL: out->frp_flags |= FIB_ROUTE_PATH_LOCAL; diff --git a/src/vnet/fib/fib_types.c b/src/vnet/fib/fib_types.c index c4472c7122d..9abb89bc6a0 100644 --- a/src/vnet/fib/fib_types.c +++ b/src/vnet/fib/fib_types.c @@ -715,6 +715,10 @@ unformat_fib_route_path (unformat_input_t * input, va_list * args) rpath->frp_proto = DPO_PROTO_IP6; rpath->frp_flags = FIB_ROUTE_PATH_INTF_RX; } + else if (unformat (input, "drop")) + { + rpath->frp_flags = FIB_ROUTE_PATH_DROP; + } else if (unformat (input, "local")) { clib_memset (&rpath->frp_addr, 0, sizeof (rpath->frp_addr)); 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/icmp6.c b/src/vnet/ip/icmp6.c index b095f679cc8..f93ebce4bf1 100644 --- a/src/vnet/ip/icmp6.c +++ b/src/vnet/ip/icmp6.c @@ -338,7 +338,7 @@ ip6_icmp_error (vlib_main_t * vm, if (throttle_check (&icmp_throttle, thread_index, r0, seed)) { - vlib_error_count (vm, node->node_index, ICMP4_ERROR_DROP, 1); + vlib_error_count (vm, node->node_index, ICMP6_ERROR_DROP, 1); from += 1; n_left_from -= 1; continue; diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c index c225c222a38..c0fa430e0aa 100644 --- a/src/vnet/ip/lookup.c +++ b/src/vnet/ip/lookup.c @@ -603,6 +603,8 @@ VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = { * @cliexcmd{ip route add 7.0.0.1/32 via 6.0.0.2 GigabitEthernet2/0/0 weight 3} * To add a route to a particular FIB table (VRF), use: * @cliexcmd{ip route add 172.16.24.0/24 table 7 via GigabitEthernet2/0/0} + * To add a route to drop the traffic: + * @cliexcmd{ip route add 172.16.24.0/24 table 100 via 127.0.0.1 drop} ?*/ VLIB_CLI_COMMAND (ip_route_command, static) = { .path = "ip route", @@ -612,7 +614,7 @@ VLIB_CLI_COMMAND (ip_route_command, static) = { "<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] " "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] " "[resolve-via-host] [resolve-via-connected] [rx-ip4|rx-ip6 " - "<interface>] [out-labels <value value value>]", + "<interface>] [out-labels <value value value>] [drop]", .function = vnet_ip_route_cmd, .is_mp_safe = 1, }; diff --git a/src/vnet/ipsec/ipsec_input.c b/src/vnet/ipsec/ipsec_input.c index 6ccc0be2622..9cec7dd15d1 100644 --- a/src/vnet/ipsec/ipsec_input.c +++ b/src/vnet/ipsec/ipsec_input.c @@ -299,10 +299,11 @@ ipsec_esp_packet_process (vlib_main_t *vm, ipsec_main_t *im, ip4_header_t *ip0, search_flow_cache = im->input_flow_cache_flag; udp_or_esp: - /* SPI ID field in the ESP header MUST NOT be a zero value */ if (esp0->spi == 0) { - /* Drop the packet if SPI ID is zero */ + /* RFC 4303, section 2.1: The SPI value of zero (0 is reserved for + * local, implementation-specific use and MUST NOT be sent on the wire. + */ *ipsec_unprocessed += 1; next[0] = IPSEC_INPUT_NEXT_DROP; return; @@ -552,12 +553,10 @@ VLIB_NODE_FN (ipsec4_input_node) (vlib_main_t * vm, udp_header_t *udp0 = NULL; udp0 = (udp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0)); - /* As per rfc3948 in UDP Encapsulated Header, UDP checksum must be - * Zero, and receivers must not depen upon UPD checksum. - * inside ESP header , SPI ID value MUST NOT be a zero value - * */ - - if (udp0->checksum == 0) + /* RFC5996 Section 2.23 "Port 4500 is reserved for + * UDP-encapsulated ESP and IKE." + */ + if (clib_host_to_net_u16 (4500) == udp0->dst_port) { esp0 = (esp_header_t *) ((u8 *) udp0 + sizeof (udp_header_t)); diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c index 9d028dbb28c..ff20bc2d835 100644 --- a/src/vnet/session/session_lookup.c +++ b/src/vnet/session/session_lookup.c @@ -1184,7 +1184,6 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl, rv = clib_bihash_search_inline_48_8 (&st->v6_session_hash, &kv6); if (rv == 0) { - ASSERT ((u32) (kv6.value >> 32) == thread_index); if (PREDICT_FALSE ((u32) (kv6.value >> 32) != thread_index)) { *result = SESSION_LOOKUP_RESULT_WRONG_THREAD; diff --git a/src/vnet/udp/udp.c b/src/vnet/udp/udp.c index b3c02510232..9c1121f7cfb 100644 --- a/src/vnet/udp/udp.c +++ b/src/vnet/udp/udp.c @@ -232,18 +232,43 @@ udp_session_get_listener (u32 listener_index) return &us->connection; } +always_inline u16 +udp_compute_checksum (vlib_main_t *vm, vlib_buffer_t *b, u8 csum_offload, + u8 is_ip4) +{ + u16 csum = 0; + + if (csum_offload) + vnet_buffer_offload_flags_set (b, VNET_BUFFER_OFFLOAD_F_UDP_CKSUM); + else + { + if (is_ip4) + csum = + ip4_tcp_udp_compute_checksum (vm, b, vlib_buffer_get_current (b)); + else + { + int bogus = 0; + csum = ip6_tcp_udp_icmp_compute_checksum ( + vm, b, vlib_buffer_get_current (b), &bogus); + } + } + + return csum; +} + always_inline u32 udp_push_one_header (vlib_main_t *vm, udp_connection_t *uc, vlib_buffer_t *b, u8 is_cless) { + udp_header_t *uh; + b->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED; /* reuse tcp medatada for now */ vnet_buffer (b)->tcp.connection_index = uc->c_c_index; if (!is_cless) { - vlib_buffer_push_udp (b, uc->c_lcl_port, uc->c_rmt_port, - udp_csum_offload (uc)); + uh = vlib_buffer_push_udp (b, uc->c_lcl_port, uc->c_rmt_port); if (uc->c_is_ip4) vlib_buffer_push_ip4_custom (vm, b, &uc->c_lcl_ip4, &uc->c_rmt_ip4, @@ -263,8 +288,7 @@ udp_push_one_header (vlib_main_t *vm, udp_connection_t *uc, vlib_buffer_t *b, hdr = *(session_dgram_hdr_t *) (data - sizeof (hdr)); /* Local port assumed to be bound, not overwriting it */ - vlib_buffer_push_udp (b, uc->c_lcl_port, hdr.rmt_port, - udp_csum_offload (uc)); + uh = vlib_buffer_push_udp (b, uc->c_lcl_port, hdr.rmt_port); if (uc->c_is_ip4) vlib_buffer_push_ip4_custom (vm, b, &hdr.lcl_ip.ip4, &hdr.rmt_ip.ip4, @@ -279,6 +303,9 @@ udp_push_one_header (vlib_main_t *vm, udp_connection_t *uc, vlib_buffer_t *b, vnet_buffer (b)->tcp.flags |= UDP_CONN_F_LISTEN; } + uh->checksum = + udp_compute_checksum (vm, b, udp_csum_offload (uc), uc->c_is_ip4); + return 0; } diff --git a/src/vnet/udp/udp_inlines.h b/src/vnet/udp/udp_inlines.h index f0dd44f48b5..ceec0b191b1 100644 --- a/src/vnet/udp/udp_inlines.h +++ b/src/vnet/udp/udp_inlines.h @@ -26,7 +26,7 @@ #include <vnet/udp/udp_encap.h> always_inline void * -vlib_buffer_push_udp (vlib_buffer_t * b, u16 sp, u16 dp, u8 offload_csum) +vlib_buffer_push_udp (vlib_buffer_t *b, u16 sp, u16 dp) { udp_header_t *uh; u16 udp_len = sizeof (udp_header_t) + b->current_length; @@ -38,8 +38,6 @@ vlib_buffer_push_udp (vlib_buffer_t * b, u16 sp, u16 dp, u8 offload_csum) uh->dst_port = dp; uh->checksum = 0; uh->length = clib_host_to_net_u16 (udp_len); - if (offload_csum) - vnet_buffer_offload_flags_set (b, VNET_BUFFER_OFFLOAD_F_UDP_CKSUM); vnet_buffer (b)->l4_hdr_offset = (u8 *) uh - b->data; b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID; return uh; diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c index c57efd59a62..dd4f4cc3353 100644 --- a/src/vpp/vnet/main.c +++ b/src/vpp/vnet/main.c @@ -329,6 +329,10 @@ defaulted: unformat_free (&input); + /* if main thread affinity is unspecified, set to current running cpu */ + if (main_core == ~0) + main_core = sched_getcpu (); + /* set process affinity for main thread */ if (main_core != ~0) { diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt index 5878f0612f0..233e75d6e2a 100644 --- a/src/vppinfra/CMakeLists.txt +++ b/src/vppinfra/CMakeLists.txt @@ -14,6 +14,34 @@ enable_language(ASM) ############################################################################## +# find libdl +############################################################################## +vpp_find_path(LIBDL_INCLUDE_DIR dlfcn.h) +vpp_find_library(LIBDL_LIB NAMES dl) + +if (LIBDL_INCLUDE_DIR AND LIBDL_LIB) + message(STATUS "libdl found at ${LIBDL_LIB}") + list(APPEND VPPINFRA_LIBS ${LIBDL_LIB}) +else() + message(FATAL_ERROR "libdl not found") +endif() + +############################################################################## +# find libunwind +############################################################################## +vpp_find_path(LIBUNWIND_INCLUDE_DIR unwind.h) +vpp_find_library(LIBUNWIND_LIB NAMES unwind libunwind) + +if (LIBUNWIND_INCLUDE_DIR AND LIBUNWIND_LIB) + message(STATUS "libunwind found at ${LIBUNWIND_LIB}") + list(APPEND VPPINFRA_LIBS ${LIBUNWIND_LIB}) + add_definitions(-DHAVE_LIBUNWIND=1) +else() + message(WARNING "libunwind not found - stack traces disabled") + add_definitions(-DHAVE_LIBUNWIND=0) +endif() + +############################################################################## # Generate vppinfra/config.h ############################################################################## set(LOG2_CACHE_LINE_BYTES ${VPP_LOG2_CACHE_LINE_SIZE}) @@ -42,12 +70,10 @@ add_definitions(-fvisibility=hidden) set_source_files_properties( cJSON.c jsonformat.c PROPERTIES COMPILE_DEFINITIONS " CJSON_API_VISIBILITY " ) - ############################################################################## # vppinfra sources ############################################################################## set(VPPINFRA_SRCS - backtrace.c bitmap.c bihash_all_vector.c cpu.c @@ -80,6 +106,7 @@ set(VPPINFRA_SRCS rbtree.c serialize.c socket.c + stack.c std-formats.c string.c time.c @@ -142,6 +169,7 @@ set(VPPINFRA_HEADERS fifo.h file.h format.h + format_ansi.h format_table.h hash.h heap.h @@ -175,6 +203,7 @@ set(VPPINFRA_HEADERS smp.h socket.h sparse_vec.h + stack.h string.h time.h time_range.h @@ -229,18 +258,9 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD") ) endif() -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() add_vpp_library(vppinfra SOURCES ${VPPINFRA_SRCS} - LINK_LIBRARIES m ${EXECINFO_LIB} + LINK_LIBRARIES m ${VPPINFRA_LIBS} INSTALL_HEADERS ${VPPINFRA_HEADERS} COMPONENT libvppinfra LTO @@ -265,6 +285,7 @@ if(VPP_BUILD_VPPINFRA_TESTS) longjmp macros maplog + mhash pmalloc pool_alloc pool_iterate diff --git a/src/vppinfra/asm_mips.h b/src/vppinfra/asm_mips.h deleted file mode 100644 index 7c9e69586f4..00000000000 --- a/src/vppinfra/asm_mips.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Copyright (c) 2004 Eliot Dresselhaus - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef included_asm_mips_h -#define included_asm_mips_h - -/* Encoding of MIPS instructions. */ -/* Encoding of opcode field (op). */ -#define mips_foreach_opcode \ - _(SPECIAL) _(REGIMM) _(j) _(jal) _(beq) _(bne) _(blez) _(bgtz) \ - _(addi) _(addiu) _(slti) _(sltiu) _(andi) _(ori) _(xori) _(lui) \ - _(COP0) _(COP1) _(COP2) _(COP1X) _(beql) _(bnel) _(blezl) _(bgtzl) \ - _(daddi) _(daddiu) _(ldl) _(ldr) _(SPECIAL2) _(jalx) _(MDMX) _(O37) \ - _(lb) _(lh) _(lwl) _(lw) _(lbu) _(lhu) _(lwr) _(lwu) \ - _(sb) _(sh) _(swl) _(sw) _(sdl) _(sdr) _(swr) _(cache) \ - _(ll) _(lwc1) _(lwc2) _(pref) _(lld) _(ldc1) _(ldc2) _(ld) \ - _(sc) _(swc1) _(swc2) _(o73) _(scd) _(sdc1) _(sdc2) _(sd) - -/* Encoding of funct field. */ -#define mips_foreach_special_funct \ - _(sll) _(MOVCI) _(srl) _(sra) _(sllv) _(o05) _(srlv) _(srav) \ - _(jr) _(jalr) _(movz) _(movn) _(syscall) _(break) _(o16) _(sync) \ - _(mfhi) _(mthi) _(mflo) _(mtlo) _(dsllv) _(o25) _(dsrlv) _(dsrav) \ - _(mult) _(multu) _(div) _(divu) _(dmult) _(dmultu) _(ddiv) _(ddivu) \ - _(add) _(addu) _(sub) _(subu) _(and) _(or) _(xor) _(nor) \ - _(o50) _(o51) _(slt) _(sltu) _(dadd) _(daddu) _(dsub) _(dsubu) \ - _(tge) _(tgeu) _(tlt) _(tltu) _(teq) _(o65) _(tne) _(o67) \ - _(dsll) _(o71) _(dsrl) _(dsra) _(dsll32) _(o75) _(dsrl32) _(dsra32) - -/* SPECIAL2 encoding of funct field. */ -#define mips_foreach_special2_funct \ - _(madd) _(maddu) _(mul) _(o03) _(msub) _(msubu) _(o06) _(o07) \ - _(o10) _(o11) _(o12) _(o13) _(o14) _(o15) _(o16) _(o17) \ - _(o20) _(o21) _(o22) _(o23) _(o24) _(o25) _(o26) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) \ - _(clz) _(clo) _(o42) _(o43) _(dclz) _(dclo) _(o46) _(o47) \ - _(o50) _(o51) _(o52) _(o53) _(o54) _(o55) _(o56) _(o57) \ - _(o60) _(o61) _(o62) _(o63) _(o64) _(o65) _(o66) _(o67) \ - _(o70) _(o71) _(o72) _(o73) _(o74) _(o75) _(o76) _(sdbbp) - -/* REGIMM encoding of rt field. */ -#define mips_foreach_regimm_rt \ - _(bltz) _(bgez) _(bltzl) _(bgezl) _(o04) _(o05) _(o06) _(o07) \ - _(tgei) _(tgeiu) _(tltiu) _(teqi) _(o14) _(tnei) _(o16) _(o17) \ - _(bltzal) _(bgezal) _(bltzall) _(bgezall) _(o24) _(o25) _(o26) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) - -/* COP0 encoding of rs field. */ -#define mips_foreach_cop0_rs \ - _(mfc0) _(dmfc0) _(o02) _(o03) _(mtc0) _(dmtc0) _(o06) _(o07) \ - _(o10) _(o11) _(o12) _(o13) _(o14) _(o15) _(o16) _(o17) \ - _(C0) _(o21) _(o22) _(o23) _(o24) _(o25) _(o26) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) - -/* COP0 encoding of funct when rs == RS_CO */ -#define mips_foreach_cop0_funct \ - _(o00) _(tlbr) _(tlbwi) _(o03) _(o04) _(o05) _(tlbwr) _(o07) \ - _(tlbp) _(o11) _(o12) _(o13) _(o14) _(o15) _(o16) _(o17) \ - _(o20) _(o21) _(o22) _(o23) _(o24) _(o25) _(o26) _(o27) \ - _(eret) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(deret) \ - _(wait) _(o41) _(o42) _(o43) _(o44) _(o45) _(o46) _(o47) \ - _(o50) _(o51) _(o52) _(o53) _(o54) _(o55) _(o56) _(o57) \ - _(o60) _(o61) _(o62) _(o63) _(o64) _(o65) _(o66) _(o67) \ - _(o70) _(o71) _(o72) _(o73) _(o74) _(o75) _(o76) _(o77) - -/* COP1 encoding of rs field. */ -#define mips_foreach_cop1_rs \ - _(mfc1) _(dmfc1) _(cfc1) _(o03) _(mtc1) _(dmtc1) _(ctc1) _(o07) \ - _(BC1) _(o11) _(o12) _(o13) _(o14) _(o15) _(o16) _(o17) \ - _(S) _(D) _(o22) _(o23) _(W) _(L) _(o26) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) - -/* COP1 encoding of funct for S and D */ -#define mips_foreach_cop1_funct \ - _(add) _(sub) _(mul) _(div) _(sqrt) _(abs) _(mov) _(neg) \ - _(roundl) _(truncl) _(ceill) _(floorl) _(roundw) _(truncw) _(ceilw) _(floorw) \ - _(o20) _(MOVCF) _(movz) _(movn) _(o24) _(recip) _(rsqrt) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) \ - _(cvts) _(cvtd) _(o42) _(o43) _(cvtw) _(cvtl) _(o46) _(o47) \ - _(o50) _(o51) _(o52) _(o53) _(o54) _(o55) _(o56) _(o57) \ - _(cf) _(cun) _(ceq) _(cueq) _(colt) _(cult) _(cole) _(cule) \ - _(csf) _(cngle) _(cseq) _(cngl) _(clt) _(cnge) _(cle) _(cngt) - -/* COP1X encoding of funct */ -#define mips_foreach_cop1x_funct \ - _(lwxc1) _(ldxc1) _(o02) _(o03) _(o04) _(luxc1) _(o06) _(o07) \ - _(swxc1) _(sdxc1) _(o12) _(o13) _(o14) _(suxc1) _(o16) _(prefx) \ - _(o20) _(o21) _(o22) _(o23) _(o24) _(o25) _(o26) _(o27) \ - _(o30) _(o31) _(o32) _(o33) _(o34) _(o35) _(o36) _(o37) \ - _(madds) _(maddd) _(o42) _(o43) _(o44) _(o45) _(o46) _(o47) \ - _(msubs) _(msubd) _(o52) _(o53) _(o54) _(o55) _(o56) _(o57) \ - _(nmadds) _(nmaddd) _(o62) _(o63) _(o64) _(o65) _(o66) _(o67) \ - _(nmsubs) _(nmsubd) _(o72) _(o73) _(o74) _(o75) _(o76) _(o77) - -#define mips_foreach_mdmx_funct \ - _(msgn) _(ceq) _(pickf) _(pickt) _(clt) _(cle) _(min) _(max) \ - _(o10) _(o11) _(sub) _(add) _(and) _(xor) _(or) _(nor) \ - _(sll) _(o21) _(srl) _(sra) _(o24) _(o25) _(o26) _(o27) \ - _(alniob) _(alnvob) _(alniqh) _(alnvqh) _(o34) _(o35) _(o36) _(shfl) \ - _(rzu) _(rnau) _(rneu) _(o43) _(rzs) _(rnas) _(rnes) _(o47) \ - _(o50) _(o51) _(o52) _(o53) _(o54) _(o55) _(o56) _(o57) \ - _(mul) _(o61) _(muls) _(mula) _(o64) _(o65) _(suba) _(adda) \ - _(o70) _(o71) _(o72) _(o73) _(o74) _(o75) _(wac) _(rac) - -#define _(f) MIPS_OPCODE_##f, -typedef enum -{ - mips_foreach_opcode -} mips_insn_opcode_t; -#undef _ - -#define _(f) MIPS_SPECIAL_FUNCT_##f, -typedef enum -{ - mips_foreach_special_funct -} mips_insn_special_funct_t; -#undef _ - -#define _(f) MIPS_SPECIAL2_FUNCT_##f, -typedef enum -{ - mips_foreach_special2_funct -} mips_insn_special2_funct_t; -#undef _ - -#define _(f) MIPS_REGIMM_RT_##f, -typedef enum -{ - mips_foreach_regimm_rt -} mips_insn_regimm_rt_t; -#undef _ - -#define _(f) MIPS_COP0_RS_##f, -typedef enum -{ - mips_foreach_cop0_rs -} mips_insn_cop0_rs_t; -#undef _ - -#define _(f) MIPS_COP0_FUNCT_##f, -typedef enum -{ - mips_foreach_cop0_funct -} mips_insn_cop0_funct_t; -#undef _ - -#define _(f) MIPS_COP1_RS_##f, -typedef enum -{ - mips_foreach_cop1_rs -} mips_insn_cop1_rs_t; -#undef _ - -#define _(f) MIPS_COP1_FUNCT_##f, -typedef enum -{ - mips_foreach_cop1_funct -} mips_insn_cop1_funct_t; -#undef _ - -#define _(f) MIPS_COP1X_FUNCT_##f, -typedef enum -{ - mips_foreach_cop1x_funct -} mips_insn_cop1x_funct_t; -#undef _ - -#define _(f) MIPS_MDMX_FUNCT_##f, -typedef enum -{ - mips_foreach_mdmx_funct -} mips_insn_mdmx_funct_t; -#undef _ - -always_inline mips_insn_opcode_t -mips_insn_get_op (u32 insn) -{ - return (insn >> 26) & 0x3f; -} - -always_inline u32 -mips_insn_get_rs (u32 insn) -{ - return (insn >> 21) & 0x1f; -} - -always_inline u32 -mips_insn_get_rt (u32 insn) -{ - return (insn >> 16) & 0x1f; -} - -always_inline u32 -mips_insn_get_rd (u32 insn) -{ - return (insn >> 11) & 0x1f; -} - -always_inline u32 -mips_insn_get_sa (u32 insn) -{ - return (insn >> 6) & 0x1f; -} - -always_inline u32 -mips_insn_get_funct (u32 insn) -{ - return (insn >> 0) & 0x3f; -} - -always_inline i32 -mips_insn_get_immediate (u32 insn) -{ - return (((i32) insn) << 16) >> 16; -} - -always_inline u32 -mips_insn_encode_i_type (int op, int rs, int rt, int immediate) -{ - u32 insn; - insn = immediate; - insn |= rt << 16; - insn |= rs << 21; - insn |= op << 26; - - ASSERT (mips_insn_get_immediate (insn) == immediate); - ASSERT (mips_insn_get_rt (insn) == rt); - ASSERT (mips_insn_get_rs (insn) == rt); - ASSERT (mips_insn_get_op (insn) == op); - - return insn; -} - -always_inline u32 -mips_insn_encode_j_type (int op, u32 addr) -{ - u32 insn; - - insn = (addr & ((1 << 28) - 1)) / 4; - insn |= op << 26; - - return insn; -} - -always_inline u32 -mips_insn_encode_r_type (int op, int rs, int rt, int rd, int sa, int funct) -{ - u32 insn; - insn = funct; - insn |= sa << 6; - insn |= rd << 11; - insn |= rt << 16; - insn |= rs << 21; - insn |= op << 26; - - ASSERT (mips_insn_get_funct (insn) == funct); - ASSERT (mips_insn_get_sa (insn) == sa); - ASSERT (mips_insn_get_rd (insn) == rd); - ASSERT (mips_insn_get_rt (insn) == rt); - ASSERT (mips_insn_get_rs (insn) == rt); - ASSERT (mips_insn_get_op (insn) == op); - - return insn; -} - -#define mips_insn_r(op,funct,rd,rs,rt,sa) \ - mips_insn_encode_r_type (MIPS_OPCODE_##op, \ - (rs), (rt), (rd), (sa), \ - MIPS_##op##_FUNCT_##funct) - -#define mips_insn_i(op,rs,rt,imm) \ - mips_insn_encode_i_type (MIPS_OPCODE_##op, (rs), (rt), (imm)) - -#define mips_insn_j(op,target) \ - mips_insn_encode_i_type (MIPS_OPCODE_##op, (rs), (rt), (imm)) - -/* Generate unsigned load instructions of data of various sizes. */ -always_inline u32 -mips_insn_load (u32 rd, i32 offset, u32 base, u32 log2_bytes) -{ - int op; - - ASSERT (log2_bytes < 4); - switch (log2_bytes) - { - case 0: - op = MIPS_OPCODE_lbu; - break; - case 1: - op = MIPS_OPCODE_lhu; - break; - case 2: - op = MIPS_OPCODE_lwu; - break; - case 3: - op = MIPS_OPCODE_ld; - break; - } - - return mips_insn_encode_i_type (op, base, rd, offset); -} - -typedef enum -{ - MIPS_REG_SP = 29, - MIPS_REG_RA = 31, -} mips_reg_t; - -#endif /* included_asm_mips_h */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vppinfra/asm_x86.c b/src/vppinfra/asm_x86.c deleted file mode 100644 index e6e00ce5543..00000000000 --- a/src/vppinfra/asm_x86.c +++ /dev/null @@ -1,1947 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* FIXME - opcode name remove to save table space; enum - x87 - 3dnow - cbw naming -*/ - -#include <vppinfra/error.h> -#include <vppinfra/byte_order.h> -#include <vppinfra/asm_x86.h> - -#define foreach_x86_gp_register \ - _ (AX) _ (CX) _ (DX) _ (BX) \ - _ (SP) _ (BP) _ (SI) _ (DI) - -typedef enum { -#define _(r) X86_INSN_GP_REG_##r, - foreach_x86_gp_register -#undef _ -} x86_insn_gp_register_t; - -typedef union { - struct { - u8 rm : 3; - u8 reg : 3; - u8 mode : 2; - }; - u8 byte; -} x86_insn_modrm_byte_t; - -typedef union { - struct { - u8 base : 3; - u8 index : 3; - u8 log2_scale : 2; - }; - u8 byte; -} x86_insn_sib_byte_t; - -always_inline uword -x86_insn_has_modrm_byte (x86_insn_t * insn) -{ - int i; - for (i = 0; i < ARRAY_LEN (insn->operands); i++) - switch (insn->operands[i].code) - { - case 'G': case 'E': case 'M': case 'R': - return 1; - } - return 0; -} - -always_inline uword -x86_insn_immediate_type (x86_insn_t * insn) -{ - int i; - for (i = 0; i < ARRAY_LEN (insn->operands); i++) - switch (insn->operands[i].code) - { - case 'J': - case 'I': - case 'O': - return insn->operands[i].type; - } - return 0; -} - -/* Opcode extension in modrm byte reg field. */ -#define foreach_x86_insn_modrm_reg_group \ - _ (1) _ (1a) _ (2) _ (3) _ (4) _ (5) _ (6) _ (7) \ - _ (8) _ (9) _ (10) _ (11) _ (12) _ (13) _ (14) \ - _ (15) _ (16) _ (p) - -#define foreach_x86_insn_sse_group \ - _ (10) _ (28) _ (50) _ (58) _ (60) _ (68) _ (70) _ (78) \ - _ (c0) _ (d0) _ (d8) _ (e0) _ (e8) _ (f0) _ (f8) - -enum { -#define _(x) X86_INSN_MODRM_REG_GROUP_##x, - foreach_x86_insn_modrm_reg_group -#undef _ -#define _(x) X86_INSN_SSE_GROUP_##x, - foreach_x86_insn_sse_group -#undef _ -}; - -enum { -#define _(x) \ - X86_INSN_FLAG_MODRM_REG_GROUP_##x \ - = X86_INSN_FLAG_SET_MODRM_REG_GROUP (1 + X86_INSN_MODRM_REG_GROUP_##x), - foreach_x86_insn_modrm_reg_group -#undef _ - -#define _(x) \ - X86_INSN_FLAG_SSE_GROUP_##x \ - = X86_INSN_FLAG_SET_SSE_GROUP (1 + X86_INSN_SSE_GROUP_##x), - foreach_x86_insn_sse_group -#undef _ -}; - -#define foreach_x86_gp_reg \ - _ (AX) _ (CX) _ (DX) _ (BX) \ - _ (SP) _ (BP) _ (SI) _ (DI) - -#define foreach_x86_condition \ - _ (o) _ (no) _ (b) _ (nb) \ - _ (z) _ (nz) _ (be) _ (nbe) \ - _ (s) _ (ns) _ (p) _ (np) \ - _ (l) _ (nl) _ (le) _ (nle) - -#define _3f(x,f,o0,o1,o2) \ -{ \ - .name = #x, \ - .flags = (f), \ - .operands[0] = { .data = #o0 }, \ - .operands[1] = { .data = #o1 }, \ - .operands[2] = { .data = #o2 }, \ -} - -#define _2f(x,f,o0,o1) _3f(x,f,o0,o1,__) -#define _1f(x,f,o0) _2f(x,f,o0,__) -#define _0f(x,f) _1f(x,f,__) - -#define _3(x,o0,o1,o2) _3f(x,0,o0,o1,o2) -#define _2(x,o0,o1) _2f(x,0,o0,o1) -#define _1(x,o0) _1f(x,0,o0) -#define _0(x) _0f(x,0) - -static x86_insn_t x86_insns_one_byte[256] = { - -#define _(x) \ - _2 (x, Eb, Gb), \ - _2 (x, Ev, Gv), \ - _2 (x, Gb, Eb), \ - _2 (x, Gv, Ev), \ - _2 (x, AL, Ib), \ - _2 (x, AX, Iz) - - /* 0x00 */ - _ (add), - _0 (push_es), - _0 (pop_es), - _ (or), - _0 (push_cs), - _0 (escape_two_byte), - - /* 0x10 */ - _ (adc), - _0 (push_ss), - _0 (pop_ss), - _ (sbb), - _0 (push_ds), - _0 (pop_ds), - - /* 0x20 */ - _ (and), - _0 (segment_es), - _0 (daa), - _ (sub), - _0 (segment_cs), - _0 (das), - - /* 0x30 */ - _ (xor), - _0 (segment_ss), - _0 (aaa), - _ (cmp), - _0 (segment_ds), - _0 (aas), - -#undef _ - - /* 0x40 */ -#define _(r) _1 (inc, r), - foreach_x86_gp_reg -#undef _ -#define _(r) _1 (dec, r), - foreach_x86_gp_reg -#undef _ - - /* 0x50 */ -#define _(r) _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, r), - foreach_x86_gp_reg -#undef _ -#define _(r) _1f (pop, X86_INSN_FLAG_DEFAULT_64_BIT, r), - foreach_x86_gp_reg -#undef _ - - /* 0x60 */ - _0 (pusha), - _0 (popa), - _2 (bound, Gv, Ma), - _2 (movsxd, Gv, Ed), - _0 (segment_fs), - _0 (segment_gs), - _0 (operand_type), - _0 (address_size), - _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Iz), - _3 (imul, Gv, Ev, Iz), - _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Ib), - _3 (imul, Gv, Ev, Ib), - _1 (insb, DX), - _1 (insw, DX), - _1 (outsb, DX), - _1 (outsw, DX), - - /* 0x70 */ -#define _(x) _1 (j##x, Jb), - foreach_x86_condition -#undef _ - - /* 0x80 */ - _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), - _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Iz), - _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Eb, Ib), - _2f (modrm_group_1, X86_INSN_FLAG_MODRM_REG_GROUP_1, Ev, Ib), - _2 (test, Eb, Gb), - _2 (test, Ev, Gv), - _2 (xchg, Eb, Gb), - _2 (xchg, Ev, Gv), - _2 (mov, Eb, Gb), - _2 (mov, Ev, Gv), - _2 (mov, Gb, Eb), - _2 (mov, Gv, Ev), - _2 (mov, Ev, Sw), - _2 (lea, Gv, Ev), - _2 (mov, Sw, Ew), - _1f (modrm_group_1a, X86_INSN_FLAG_MODRM_REG_GROUP_1a, Ev), - - /* 0x90 */ - _0 (nop), - _1 (xchg, CX), - _1 (xchg, DX), - _1 (xchg, BX), - _1 (xchg, SP), - _1 (xchg, BP), - _1 (xchg, SI), - _1 (xchg, DI), - _0 (cbw), - _0 (cwd), - _1 (call, Ap), - _0 (wait), - _0 (pushf), - _0 (popf), - _0 (sahf), - _0 (lahf), - - /* 0xa0 */ - _2 (mov, AL, Ob), - _2 (mov, AX, Ov), - _2 (mov, Ob, AL), - _2 (mov, Ov, AX), - _0 (movsb), - _0 (movsw), - _0 (cmpsb), - _0 (cmpsw), - _2 (test, AL, Ib), - _2 (test, AX, Iz), - _1 (stosb, AL), - _1 (stosw, AX), - _1 (lodsb, AL), - _1 (lodsw, AX), - _1 (scasb, AL), - _1 (scasw, AX), - - /* 0xb0 */ - _2 (mov, AL, Ib), - _2 (mov, CL, Ib), - _2 (mov, DL, Ib), - _2 (mov, BL, Ib), - _2 (mov, AH, Ib), - _2 (mov, CH, Ib), - _2 (mov, DH, Ib), - _2 (mov, BH, Ib), -#define _(r) _2 (mov, r, Iv), - foreach_x86_gp_reg -#undef _ - - /* 0xc0 */ - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, Ib), - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, Ib), - _1 (ret, Iw), - _0 (ret), - _2 (les, Gz, Mp), - _2 (lds, Gz, Mp), - _2f (modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Eb, Ib), - _2f (modrm_group_11, X86_INSN_FLAG_MODRM_REG_GROUP_11, Ev, Iz), - _2 (enter, Iw, Ib), - _0 (leave), - _1 (ret, Iw), - _0 (ret), - _0 (int3), - _1 (int, Ib), - _0 (into), - _0 (iret), - - /* 0xd0 */ - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, 1b), - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, 1b), - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Eb, CL), - _2f (modrm_group_2, X86_INSN_FLAG_MODRM_REG_GROUP_2, Ev, CL), - _0 (aam), - _0 (aad), - _0 (salc), - _0 (xlat), - /* FIXME x87 */ - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - - /* 0xe0 */ - _1 (loopnz, Jb), - _1 (loopz, Jb), - _1 (loop, Jb), - _1 (jcxz, Jb), - _2 (in, AL, Ib), - _2 (in, AX, Ib), - _2 (out, Ib, AL), - _2 (out, Ib, AX), - _1f (call, X86_INSN_FLAG_DEFAULT_64_BIT, Jz), - _1f ( jmp, X86_INSN_FLAG_DEFAULT_64_BIT, Jz), - _1 (jmp, Ap), - _1 (jmp, Jb), - _2 (in, AL, DX), - _2 (in, AX, DX), - _2 (out, DX, AL), - _2 (out, DX, AX), - - /* 0xf0 */ - _0 (lock), - _0 (int1), - _0 (repne), - _0 (rep), - _0 (hlt), - _0 (cmc), - _0f (modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), - _0f (modrm_group_3, X86_INSN_FLAG_MODRM_REG_GROUP_3), - _0 (clc), - _0 (stc), - _0 (cli), - _0 (sti), - _0 (cld), - _0 (std), - _1f (modrm_group_4, X86_INSN_FLAG_MODRM_REG_GROUP_4, Eb), - _0f (modrm_group_5, X86_INSN_FLAG_MODRM_REG_GROUP_5), -}; - -static x86_insn_t x86_insns_two_byte[256] = { - /* 0x00 */ - _0f (modrm_group_6, X86_INSN_FLAG_MODRM_REG_GROUP_6), - _0f (modrm_group_7, X86_INSN_FLAG_MODRM_REG_GROUP_7), - _2 (lar, Gv, Ew), - _2 (lsl, Gv, Ew), - _0 (bad), - _0 (syscall), - _0 (clts), - _0 (sysret), - _0 (invd), - _0 (wbinvd), - _0 (bad), - _0 (ud2), - _0 (bad), - _0f (modrm_group_p, X86_INSN_FLAG_MODRM_REG_GROUP_p), - _0 (femms), - _0 (escape_3dnow), - - /* 0x10 */ - _2f (movups, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), - _2f (movups, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), - _2f (movlps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), - _2f (movlps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), - _2f (unpcklps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), - _2f (unpckhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), - _2f (movhps, X86_INSN_FLAG_SSE_GROUP_10, Ex, Gx), - _2f (movhps, X86_INSN_FLAG_SSE_GROUP_10, Gx, Ex), - _0f (modrm_group_16, X86_INSN_FLAG_MODRM_REG_GROUP_16), - _0 (nop), - _0 (nop), - _0 (nop), - _0 (nop), - _0 (nop), - _0 (nop), - _0 (nop), - - /* 0x20 */ - _2 (mov, Rv, Cv), - _2 (mov, Rv, Dv), - _2 (mov, Cv, Rv), - _2 (mov, Dv, Rv), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2f (movaps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - _2f (movaps, X86_INSN_FLAG_SSE_GROUP_28, Ex, Gx), - _2f (cvtpi2ps, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - _2f (movntps, X86_INSN_FLAG_SSE_GROUP_28, Mx, Gx), - _2f (cvttps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - _2f (cvtps2pi, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - _2f (ucomiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - _2f (comiss, X86_INSN_FLAG_SSE_GROUP_28, Gx, Ex), - - /* 0x30 */ - _0 (wrmsr), - _0 (rdtsc), - _0 (rdmsr), - _0 (rdpmc), - _0 (sysenter), - _0 (sysexit), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - - /* 0x40 */ -#define _(x) _2 (cmov##x, Gv, Ev), - foreach_x86_condition -#undef _ - - /* 0x50 */ - _2f (movmskps, X86_INSN_FLAG_SSE_GROUP_50, Gd, Rx), - _2f (sqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (rsqrtps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (rcpps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (andps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (andnps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (orps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (xorps, X86_INSN_FLAG_SSE_GROUP_50, Gx, Ex), - _2f (addps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (mulps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (cvtps2pd, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (cvtdq2ps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (subps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (minps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (divps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - _2f (maxps, X86_INSN_FLAG_SSE_GROUP_58, Gx, Ex), - - /* 0x60 */ - _2f (punpcklbw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (punpcklwd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (punpckldq, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (packsswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (pcmpgtb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (pcmpgtw, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (pcmpgtd, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (packuswb, X86_INSN_FLAG_SSE_GROUP_60, Gm, Em), - _2f (punpckhbw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - _2f (punpckhwd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - _2f (punpckhdq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - _2f (packssdw, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_68), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_68), - _2f (movd, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - _2f (movq, X86_INSN_FLAG_SSE_GROUP_68, Gm, Em), - - /* 0x70 */ - _3f (pshufw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em, Ib), - _0f (modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), - _0f (modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), - _0f (modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), - _2f (pcmpeqb, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), - _2f (pcmpeqw, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), - _2f (pcmpeqd, X86_INSN_FLAG_SSE_GROUP_70, Gm, Em), - _0f (emms, X86_INSN_FLAG_SSE_GROUP_70), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_78), - _2f (movd, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), - _2f (movq, X86_INSN_FLAG_SSE_GROUP_78, Em, Gm), - - /* 0x80 */ -#define _(x) _1 (jmp##x, Jz), - foreach_x86_condition -#undef _ - - /* 0x90 */ -#define _(x) _1 (set##x, Eb), - foreach_x86_condition -#undef _ - - /* 0xa0 */ - _0 (push_fs), - _0 (pop_fs), - _0 (cpuid), - _2 (bt, Ev, Gv), - _3 (shld, Ev, Gv, Ib), - _3 (shld, Ev, Gv, CL), - _0 (bad), - _0 (bad), - _0 (push_gs), - _0 (pop_gs), - _0 (rsm), - _2 (bts, Ev, Gv), - _3 (shrd, Ev, Gv, Ib), - _3 (shrd, Ev, Gv, CL), - _0f (modrm_group_15, X86_INSN_FLAG_MODRM_REG_GROUP_15), - _2 (imul, Gv, Ev), - - /* 0xb0 */ - _2 (cmpxchg, Eb, Gb), - _2 (cmpxchg, Ev, Gv), - _2 (lss, Gz, Mp), - _2 (btr, Ev, Gv), - _2 (lfs, Gz, Mp), - _2 (lgs, Gz, Mp), - _2 (movzbl, Gv, Eb), - _2 (movzwl, Gv, Ew), - _0 (bad), - _0f (modrm_group_10, X86_INSN_FLAG_MODRM_REG_GROUP_10), - _2f (modrm_group_8, X86_INSN_FLAG_MODRM_REG_GROUP_8, Ev, Ib), - _2 (btc, Ev, Gv), - _2 (bsf, Gv, Ev), - _2 (bsr, Gv, Ev), - _2 (movsx, Gv, Eb), - _2 (movsx, Gv, Ew), - - /* 0xc0 */ - _2 (xadd, Eb, Gb), - _2 (xadd, Ev, Gv), - _3f (cmpps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), - _2 (movnti, Mv, Gv), - _3f (pinsrw, X86_INSN_FLAG_SSE_GROUP_c0, Gm, Ew, Ib), - _3f (pextrw, X86_INSN_FLAG_SSE_GROUP_c0, Gd, Rm, Ib), - _3f (shufps, X86_INSN_FLAG_SSE_GROUP_c0, Gx, Ex, Ib), - _1f (modrm_group_9, X86_INSN_FLAG_MODRM_REG_GROUP_9, Mx), -#define _(r) _1 (bswap, r), - foreach_x86_gp_reg -#undef _ - - /* 0xd0 */ - _0f (bad, X86_INSN_FLAG_SSE_GROUP_d0), - _2f (psrlw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), - _2f (psrld, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), - _2f (psrlq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), - _2f (paddq, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), - _2f (pmullw, X86_INSN_FLAG_SSE_GROUP_d0, Gm, Em), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_d0), - _2f (pmovmskb, X86_INSN_FLAG_SSE_GROUP_d0, Gd, Rm), - _2f (psubusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (psubusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (pminub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (pand, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (paddusb, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (paddusw, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (pmaxub, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - _2f (pandn, X86_INSN_FLAG_SSE_GROUP_d8, Gm, Em), - - /* 0xe0 */ - _2f (pavgb, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (psraw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (psrad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (pavgw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (pmulhuw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (pmulhw, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (bad, X86_INSN_FLAG_SSE_GROUP_e0, Gm, Em), - _2f (movntq, X86_INSN_FLAG_SSE_GROUP_e0, Mm, Gm), - _2f (psubsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (psubsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (pminsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (por, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (paddsb, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (paddsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (pmaxsw, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - _2f (pxor, X86_INSN_FLAG_SSE_GROUP_e8, Gm, Em), - - /* 0xf0 */ - _0f (bad, X86_INSN_FLAG_SSE_GROUP_f0), - _2f (psllw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (pslld, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (psllq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (pmuludq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (pmaddwd, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (psadbw, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (maskmovq, X86_INSN_FLAG_SSE_GROUP_f0, Gm, Em), - _2f (psubb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (psubw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (psubd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (psubq, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (paddb, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (paddw, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _2f (paddd, X86_INSN_FLAG_SSE_GROUP_f8, Gm, Em), - _0f (bad, X86_INSN_FLAG_SSE_GROUP_f8), -}; - -typedef struct { - x86_insn_t insns[8]; -} x86_insn_group8_t; - -/* Escape groups are indexed by modrm reg field. */ -static x86_insn_group8_t x86_insn_modrm_reg_groups[] = { - [X86_INSN_MODRM_REG_GROUP_1].insns = { - _0 (add), _0 ( or), _0 (adc), _0 (sbb), - _0 (and), _0 (sub), _0 (xor), _0 (cmp), - }, - - [X86_INSN_MODRM_REG_GROUP_1a].insns = { - _0f (pop, X86_INSN_FLAG_DEFAULT_64_BIT), - _0 (bad), _0 (bad), _0 (bad), - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_2].insns = { - _0 (rol), _0 (ror), _0 (rcl), _0 (rcr), - _0 (shl), _0 (shr), _0 (sal), _0 (sar), - }, - - [X86_INSN_MODRM_REG_GROUP_3].insns = { - _0 (test), _0 (test), _0 (not), _0 (neg), - _0 (mul), _0 (imul), _0 (div), _0 (idiv), - }, - - [X86_INSN_MODRM_REG_GROUP_4].insns = { - _0 (inc), _0 (dec), _0 (bad), _0 (bad), - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_5].insns = { - _1 (inc, Ev), - _1 (dec, Ev), - _1f (call, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), - _1 (call, Mp), - _1f (jmp, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), - _1 (jmp, Mp), - _1f (push, X86_INSN_FLAG_DEFAULT_64_BIT, Ev), - _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_6].insns = { - _1 (sldt, Ev), - _1 (str, Ev), - _1 (lldt, Ev), - _1 (ltr, Ev), - _1 (verr, Ev), - _1 (verw, Ev), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_7].insns = { - _1 (sgdt, Mv), - _1 (sidt, Mv), - _1 (lgdt, Mv), - _1 (lidt, Mv), - _1 (smsw, Ev), - _0 (bad), - _1 (lmsw, Ew), - _1 (invlpg, Mv), - }, - - [X86_INSN_MODRM_REG_GROUP_8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (bt, Ev, Ib), - _2 (bts, Ev, Ib), - _2 (btr, Ev, Ib), - _2 (btc, Ev, Ib), - }, - - [X86_INSN_MODRM_REG_GROUP_9].insns = { - _0 (bad), - _1 (cmpxchg, Mx), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_10].insns = { - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_11].insns = { - _0 (mov), _0 (bad), _0 (bad), _0 (bad), - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_12].insns = { - _0 (bad), - _0 (bad), - _2 (psrlw, Rm, Ib), - _0 (bad), - _2 (psraw, Rm, Ib), - _0 (bad), - _2 (psllw, Rm, Ib), - _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_13].insns = { - _0 (bad), - _0 (bad), - _2 (psrld, Rm, Ib), - _0 (bad), - _2 (psrad, Rm, Ib), - _0 (bad), - _2 (pslld, Rm, Ib), - _0 (bad), - }, - - [X86_INSN_MODRM_REG_GROUP_14].insns = { - _0 (bad), - _0 (bad), - _2 (psrlq, Rm, Ib), - _0f (bad, 0), - _0 (bad), - _0 (bad), - _2 (psllq, Rm, Ib), - _0f (bad, 0), - }, - - [X86_INSN_MODRM_REG_GROUP_15].insns = { - _1 (fxsave, Mv), - _1 (fxrstor, Mv), - _1 (ldmxcsr, Mv), - _1 (stmxcsr, Mv), - _0 (bad), - _1 (lfence, Mv), - _1 (mfence, Mv), - _1 (sfence, Mv), - }, - - [X86_INSN_MODRM_REG_GROUP_16].insns = { - _1 (prefetch_nta, Mv), - _1 (prefetch_t0, Mv), - _1 (prefetch_t1, Mv), - _1 (prefetch_t2, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - }, - - [X86_INSN_MODRM_REG_GROUP_p].insns = { - _1 (prefetch_exclusive, Mv), - _1 (prefetch_modified, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_modified, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - _1 (prefetch_nop, Mv), - }, -}; - -static x86_insn_group8_t x86_insn_sse_groups_repz[] = { - [X86_INSN_SSE_GROUP_10].insns = { - _2 (movss, Gx, Ex), - _2 (movss, Ex, Gx), - _2 (movsldup, Gx, Ex), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (movshdup, Gx, Ex), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_28].insns = { - _0 (bad), - _0 (bad), - _2 (cvtsi2ss, Gx, Ev), - _0 (bad), - _2 (cvttss2si, Gv, Ex), - _2 (cvtss2si, Gv, Ex), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_50].insns = { - _0 (bad), - _2 (sqrtss, Gx, Ex), - _2 (rsqrtps, Gx, Ex), - _2 (rcpss, Gx, Ex), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_58].insns = { - _2 (addss, Gx, Ex), - _2 (mulss, Gx, Ex), - _2 (cvtss2sd, Gx, Ex), - _2 (cvttps2dq, Gx, Ex), - _2 (subss, Gx, Ex), - _2 (minss, Gx, Ex), - _2 (divss, Gx, Ex), - _2 (maxss, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_60].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_68].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (movdqu, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_70].insns = { - _3 (pshufhw, Gx, Ex, Ib), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_78].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (movq, Gx, Ex), - _2 (movdqu, Ex, Gx), - }, - - [X86_INSN_SSE_GROUP_c0].insns = { - _0 (bad), - _0 (bad), - _3 (cmpss, Gx, Ex, Ib), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_d0].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (movq2dq, Gx, Em), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_d8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_e0].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (cvtdq2pd, Gx, Ex), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_e8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_f0].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_f8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, -}; - -static x86_insn_group8_t x86_insn_sse_groups_operand_size[] = { - [X86_INSN_SSE_GROUP_10].insns = { - _2 (movupd, Gx, Ex), - _2 (movupd, Ex, Gx), - _2 (movlpd, Gx, Ex), - _2 (movlpd, Ex, Gx), - _2 (unpcklpd, Gx, Ex), - _2 (unpckhpd, Gx, Ex), - _2 (movhpd, Gx, Mx), - _2 (movhpd, Mx, Gx), - }, - - [X86_INSN_SSE_GROUP_28].insns = { - _2 (movapd, Gx, Ex), - _2 (movapd, Ex, Gx), - _2 (cvtpi2pd, Gx, Ex), - _2 (movntpd, Mx, Gx), - _2 (cvttpd2pi, Gx, Mx), - _2 (cvtpd2pi, Gx, Mx), - _2 (ucomisd, Gx, Ex), - _2 (comisd, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_50].insns = { - _2 (movmskpd, Gd, Rx), - _2 (sqrtpd, Gx, Ex), - _0 (bad), - _0 (bad), - _2 (andpd, Gx, Ex), - _2 (andnpd, Gx, Ex), - _2 (orpd, Gx, Ex), - _2 (xorpd, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_58].insns = { - _2 (addpd, Gx, Ex), - _2 (mulpd, Gx, Ex), - _2 (cvtpd2ps, Gx, Ex), - _2 (cvtps2dq, Gx, Ex), - _2 (subpd, Gx, Ex), - _2 (minpd, Gx, Ex), - _2 (divpd, Gx, Ex), - _2 (maxpd, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_60].insns = { - _2 (punpcklbw, Gx, Ex), - _2 (punpcklwd, Gx, Ex), - _2 (punpckldq, Gx, Ex), - _2 (packsswb, Gx, Ex), - _2 (pcmpgtb, Gx, Ex), - _2 (pcmpgtw, Gx, Ex), - _2 (pcmpgtd, Gx, Ex), - _2 (packuswb, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_68].insns = { - _2 (punpckhbw, Gx, Ex), - _2 (punpckhwd, Gx, Ex), - _2 (punpckhdq, Gx, Ex), - _2 (packssdw, Gx, Ex), - _2 (punpcklqdq, Gx, Ex), - _2 (punpckhqdq, Gx, Ex), - _2 (movd, Gx, Ev), - _2 (movdqa, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_70].insns = { - _3 (pshufd, Gx, Ex, Ib), - _0f (modrm_group_12, X86_INSN_FLAG_MODRM_REG_GROUP_12), - _0f (modrm_group_13, X86_INSN_FLAG_MODRM_REG_GROUP_13), - _0f (modrm_group_14, X86_INSN_FLAG_MODRM_REG_GROUP_14), - _2 (pcmpeqb, Gx, Ex), - _2 (pcmpeqw, Gx, Ex), - _2 (pcmpeqd, Gx, Ex), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_78].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (haddpd, Gx, Ex), - _2 (hsubpd, Gx, Ex), - _2 (movd, Ev, Gx), - _2 (movdqa, Ex, Gx), - }, - - [X86_INSN_SSE_GROUP_c0].insns = { - _0 (bad), - _0 (bad), - _3 (cmppd, Gx, Ex, Ib), - _0 (bad), - _3 (pinsrw, Gx, Ew, Ib), - _3 (pextrw, Gd, Gx, Ib), - _3 (shufpd, Gx, Ex, Ib), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_d0].insns = { - _2 (addsubpd, Gx, Ex), - _2 (psrlw, Gx, Ex), - _2 (psrld, Gx, Ex), - _2 (psrlq, Gx, Ex), - _2 (paddq, Gx, Ex), - _2 (pmullw, Gx, Ex), - _2 (movq, Ex, Gx), - _2 (pmovmskb, Gd, Rx), - }, - - [X86_INSN_SSE_GROUP_d8].insns = { - _2 (psubusb, Gx, Ex), - _2 (psubusw, Gx, Ex), - _2 (pminub, Gx, Ex), - _2 (pand, Gx, Ex), - _2 (paddusb, Gx, Ex), - _2 (paddusw, Gx, Ex), - _2 (pmaxub, Gx, Ex), - _2 (pandn, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_e0].insns = { - _2 (pavgb, Gx, Ex), - _2 (psraw, Gx, Ex), - _2 (psrad, Gx, Ex), - _2 (pavgw, Gx, Ex), - _2 (pmulhuw, Gx, Ex), - _2 (pmulhw, Gx, Ex), - _2 (cvttpd2dq, Gx, Ex), - _2 (movntdq, Mx, Gx), - }, - - [X86_INSN_SSE_GROUP_e8].insns = { - _2 (psubsb, Gx, Ex), - _2 (psubsw, Gx, Ex), - _2 (pminsw, Gx, Ex), - _2 (por, Gx, Ex), - _2 (paddsb, Gx, Ex), - _2 (paddsw, Gx, Ex), - _2 (pmaxsw, Gx, Ex), - _2 (pxor, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_f0].insns = { - _0 (bad), - _2 (psllw, Gx, Ex), - _2 (pslld, Gx, Ex), - _2 (psllq, Gx, Ex), - _2 (pmuludq, Gx, Ex), - _2 (pmaddwd, Gx, Ex), - _2 (psadbw, Gx, Ex), - _2 (maskmovdqu, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_f8].insns = { - _2 (psubb, Gx, Ex), - _2 (psubw, Gx, Ex), - _2 (psubd, Gx, Ex), - _2 (psubq, Gx, Ex), - _2 (paddb, Gx, Ex), - _2 (paddw, Gx, Ex), - _2 (paddd, Gx, Ex), - _0 (bad), - }, -}; - -static x86_insn_group8_t x86_insn_sse_groups_repnz[] = { - [X86_INSN_SSE_GROUP_10].insns = { - _2 (movsd, Gx, Ex), - _2 (movsd, Ex, Gx), - _2 (movddup, Gx, Ex), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_28].insns = { - _0 (bad), - _0 (bad), - _2 (cvtsi2sd, Gx, Ev), - _0 (bad), - _2 (cvttsd2si, Gv, Ex), - _2 (cvtsd2si, Gv, Ex), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_50].insns = { - _0 (bad), - _2 (sqrtsd, Gx, Ex), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_58].insns = { - _2 (addsd, Gx, Ex), - _2 (mulsd, Gx, Ex), - _2 (cvtsd2ss, Gx, Ex), - _0 (bad), - _2 (subsd, Gx, Ex), - _2 (minsd, Gx, Ex), - _2 (divsd, Gx, Ex), - _2 (maxsd, Gx, Ex), - }, - - [X86_INSN_SSE_GROUP_60].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_68].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_70].insns = { - _3 (pshuflw, Gx, Ex, Ib), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_78].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (haddps, Gx, Ex), - _2 (hsubps, Gx, Ex), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_c0].insns = { - _0 (bad), - _0 (bad), - _3 (cmpsd, Gx, Ex, Ib), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_d0].insns = { - _2 (addsubps, Gx, Ex), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (movdq2q, Gm, Ex), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_d8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_e0].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _2 (cvtpd2dq, Gx, Ex), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_e8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_f0].insns = { - _2 (lddqu, Gx, Mx), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, - - [X86_INSN_SSE_GROUP_f8].insns = { - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - _0 (bad), - }, -}; - -#undef _ - -/* Parses memory displacements and immediates. */ -static u8 * x86_insn_parse_number (u32 log2_n_bytes, - u8 * code, u8 * code_end, - i64 * result) -{ - i64 x = 0; - - if (code + (1 << log2_n_bytes) > code_end) - return 0; - - switch (log2_n_bytes) - { - case 3: - x = clib_little_to_host_unaligned_mem_u64 ((u64 *) code); - break; - - case 2: - x = (i32) clib_little_to_host_unaligned_mem_u32 ((u32 *) code); - break; - - case 1: - x = (i16) clib_little_to_host_unaligned_mem_u16 ((u16 *) code); - break; - - case 0: - x = (i8) code[0]; - break; - - default: - ASSERT (0); - } - - *result = x; - return code + (1 << log2_n_bytes); -} - -static u32 -x86_insn_log2_immediate_bytes (x86_insn_parse_t * p, x86_insn_t * insn) -{ - u32 i = ~0; - switch (x86_insn_immediate_type (insn)) - { - case 'b': i = 0; break; - case 'w': i = 1; break; - case 'd': i = 2; break; - case 'q': i = 3; break; - - case 'z': - i = p->log2_effective_operand_bytes; - if (i > 2) i = 2; - break; - - case 'v': - i = p->log2_effective_operand_bytes; - break; - - default: - i = ~0; - break; - } - - return i; -} - -static u8 * -x86_insn_parse_modrm_byte (x86_insn_parse_t * x, - x86_insn_modrm_byte_t modrm, - u32 parse_flags, - u8 * code, - u8 * code_end) -{ - u8 effective_address_bits; - - if (parse_flags & X86_INSN_PARSE_64_BIT) - effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 32 : 64; - else if (parse_flags & X86_INSN_PARSE_32_BIT) - effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 16 : 32; - else - effective_address_bits = (x->flags & X86_INSN_ADDRESS_SIZE) ? 32 : 16; - - x->log2_effective_address_bytes = 1; - x->log2_effective_address_bytes += effective_address_bits > 16; - x->log2_effective_address_bytes += effective_address_bits > 32; - - x->regs[0] |= modrm.reg; - if (modrm.mode == 3) - x->regs[1] |= modrm.rm; - else - { - u32 log2_disp_bytes = ~0; - - x->flags |= X86_INSN_IS_ADDRESS; - - if (effective_address_bits != 16) - { - u8 has_sib_byte = 0; - - switch (modrm.mode) - { - case 0: - /* When base is bp displacement is present for mode 0. */ - if (modrm.rm == X86_INSN_GP_REG_BP) - { - log2_disp_bytes = x->log2_effective_address_bytes; - break; - } - else if (modrm.rm == X86_INSN_GP_REG_SP - && effective_address_bits != 16) - { - has_sib_byte = 1; - break; - } - /* fall through */ - case 1: - case 2: - x->regs[1] |= modrm.rm; - x->flags |= X86_INSN_HAS_BASE; - if (modrm.mode != 0) - { - log2_disp_bytes = (modrm.mode == 1 - ? 0 - : x->log2_effective_address_bytes); - if (log2_disp_bytes > 2) - log2_disp_bytes = 2; - } - break; - } - - if (has_sib_byte) - { - x86_insn_sib_byte_t sib; - - if (code >= code_end) - return 0; - sib.byte = *code++; - - x->log2_index_scale = 1 << sib.log2_scale; - x->regs[1] |= sib.base; - x->flags |= X86_INSN_HAS_BASE; - - if (sib.index != X86_INSN_GP_REG_SP) - { - x->regs[2] |= sib.index; - x->flags |= X86_INSN_HAS_INDEX; - } - } - } - else - { - /* effective_address_bits == 16 */ - switch (modrm.mode) - { - case 0: - if (modrm.rm == 6) - { - /* [disp16] */ - log2_disp_bytes = 1; - break; - } - /* fall through */ - case 1: - case 2: - switch (modrm.rm) - { - case 0: /* [bx + si/di] */ - case 1: - x->regs[1] = X86_INSN_GP_REG_BX; - x->regs[2] = X86_INSN_GP_REG_SI + (modrm.rm & 1); - x->flags |= X86_INSN_HAS_BASE | X86_INSN_HAS_INDEX; - break; - - case 2: /* [bp + si/di] */ - case 3: - x->regs[1] = X86_INSN_GP_REG_BP; - x->regs[2] = X86_INSN_GP_REG_SI + (modrm.rm & 1); - x->flags |= X86_INSN_HAS_BASE | X86_INSN_HAS_INDEX; - break; - - case 4: /* [si/di] */ - case 5: - x->regs[1] = X86_INSN_GP_REG_SI + (modrm.rm & 1); - x->flags |= X86_INSN_HAS_BASE; - break; - - case 6: /* [bp + disp] */ - x->regs[1] = X86_INSN_GP_REG_BP; - x->flags |= X86_INSN_HAS_BASE; - break; - - case 7: /* [bx + disp] */ - x->regs[1] = X86_INSN_GP_REG_BX; - x->flags |= X86_INSN_HAS_BASE; - break; - } - - if (modrm.mode != 0) - log2_disp_bytes = modrm.mode == 1 ? 0 : 1; - break; - } - } - - if (log2_disp_bytes != ~0) - { - i64 disp; - code = x86_insn_parse_number (log2_disp_bytes, code, code_end, - &disp); - if (code) - x->displacement = disp; - } - } - - return code; -} - -u8 * x86_insn_parse (x86_insn_parse_t * p, u8 * code_start) -{ - u8 i, * code, * code_end; - x86_insn_t * insn, * group_insn; - u8 default_operand_bits, effective_operand_bits; - u32 opcode, parse_flags; - - /* Preserve global parse flags. */ - parse_flags = p->flags & (X86_INSN_PARSE_32_BIT | X86_INSN_PARSE_64_BIT); - clib_memset (p, 0, sizeof (p[0])); - p->flags = parse_flags; - - /* 64 implies 32 bit parsing. */ - if (parse_flags & X86_INSN_PARSE_64_BIT) - parse_flags |= X86_INSN_PARSE_32_BIT; - - /* Instruction must be <= 15 bytes. */ - code = code_start; - code_end = code + 15; - - /* Parse legacy prefixes. */ - while (1) - { - if (code >= code_end) - goto insn_too_long; - i = code[0]; - code++; - switch (i) - { - default: goto prefix_done; - - /* Set flags based on prefix. */ -#define _(x,o) case o: p->flags |= X86_INSN_##x; break; - foreach_x86_legacy_prefix; -#undef _ - } - } - prefix_done: - - /* REX prefix. */ - if ((parse_flags & X86_INSN_PARSE_64_BIT) && i >= 0x40 && i <= 0x4f) - { - p->regs[0] |= ((i & (1 << 2)) != 0) << 3; /* r bit */ - p->regs[1] |= ((i & (1 << 0)) != 0) << 3; /* b bit */ - p->regs[2] |= ((i & (1 << 1)) != 0) << 3; /* x bit */ - p->flags |= ((i & (1 << 3)) /* w bit */ - ? X86_INSN_OPERAND_SIZE_64 : 0); - if (code >= code_end) - goto insn_too_long; - i = *code++; - } - - opcode = i; - if (opcode == 0x0f) - { - /* two byte opcode. */; - if (code >= code_end) - goto insn_too_long; - i = *code++; - opcode = (opcode << 8) | i; - insn = x86_insns_two_byte + i; - } - else - { - static x86_insn_t arpl = { - .name = "arpl", - .operands[0].data = "Ew", - .operands[1].data = "Gw", - }; - - if (PREDICT_FALSE (i == 0x63 - && ! (parse_flags & X86_INSN_PARSE_64_BIT))) - insn = &arpl; - else - insn = x86_insns_one_byte + i; - } - - if ((i = X86_INSN_FLAG_GET_SSE_GROUP (insn->flags)) != 0) - { - x86_insn_group8_t * g8; - - if (p->flags & X86_INSN_OPERAND_SIZE) - g8 = x86_insn_sse_groups_operand_size; - else if (p->flags & X86_INSN_REPZ) - g8 = x86_insn_sse_groups_repz; - else if (p->flags & X86_INSN_REPNZ) - g8 = x86_insn_sse_groups_repnz; - else - g8 = 0; - - /* insn flags have 1 + group so != 0 test above can work. */ - ASSERT ((i - 1) < ARRAY_LEN (x86_insn_sse_groups_operand_size)); - if (g8) - insn = g8[i - 1].insns + (opcode & 7); - } - - /* Parse modrm and displacement if present. */ - if (x86_insn_has_modrm_byte (insn)) - { - x86_insn_modrm_byte_t modrm; - - if (code >= code_end) - goto insn_too_long; - modrm.byte = *code++; - - /* Handle special 0x0f01 and 0x0fae encodings. */ - if (PREDICT_FALSE (modrm.mode == 3 - && (opcode == 0x0f01 - || opcode == 0x0fae))) - { - static x86_insn_t x86_insns_0f01_special[] = { - _0 (swapgs), _0 (rdtscp), _0 (bad), _0 (bad), - _0 (bad), _0 (bad), _0 (bad), _0 (bad), - }; - static x86_insn_t x86_insns_0fae_special[] = { - _0 (vmrun), _0 (vmmcall), _0 (vmload), _0 (vmsave), - _0 (stgi), _0 (clgi), _0 (skinit), _0 (invlpga), - }; - - if (opcode == 0x0f01) - insn = x86_insns_0f01_special; - else - insn = x86_insns_0fae_special; - insn += modrm.rm; - opcode = (opcode << 8) | modrm.byte; - } - else - { - code = x86_insn_parse_modrm_byte (p, modrm, parse_flags, - code, code_end); - if (! code) - goto insn_too_long; - } - } - - group_insn = 0; - if ((i = X86_INSN_FLAG_GET_MODRM_REG_GROUP (insn->flags)) != 0) - { - u32 g = i - 1; - ASSERT (g < ARRAY_LEN (x86_insn_modrm_reg_groups)); - group_insn = x86_insn_modrm_reg_groups[g].insns + (p->regs[0] & 7); - } - - p->insn = insn[0]; - if (group_insn) - { - u32 k; - p->insn.name = group_insn->name; - p->insn.flags |= group_insn->flags; - for (k = 0; k < ARRAY_LEN (group_insn->operands); k++) - if (x86_insn_operand_is_valid (group_insn, k)) - p->insn.operands[k] = group_insn->operands[k]; - } - - default_operand_bits - = ((((parse_flags & X86_INSN_PARSE_32_BIT) != 0) - ^ ((p->flags & X86_INSN_OPERAND_SIZE) != 0)) - ? BITS (u32) : BITS (u16)); - - if ((parse_flags & X86_INSN_PARSE_64_BIT) - && (p->insn.flags & X86_INSN_FLAG_DEFAULT_64_BIT)) - default_operand_bits = BITS (u64); - - effective_operand_bits = default_operand_bits; - if (p->flags & X86_INSN_OPERAND_SIZE_64) - effective_operand_bits = BITS (u64); - - p->log2_effective_operand_bytes = 1; - p->log2_effective_operand_bytes += effective_operand_bits > 16; - p->log2_effective_operand_bytes += effective_operand_bits > 32; - - /* Parse immediate if present. */ - { - u32 l = x86_insn_log2_immediate_bytes (p, insn); - if (l <= 3) - { - code = x86_insn_parse_number (l, code, code_end, &p->immediate); - if (! code) - goto insn_too_long; - } - } - - return code; - - insn_too_long: - return 0; -} - -static u8 * format_x86_gp_reg_operand (u8 * s, va_list * va) -{ - u32 r = va_arg (*va, u32); - u32 log2_n_bytes = va_arg (*va, u32); - - const char names8[8] = "acdbsbsd"; - const char names16[8] = "xxxxppii"; - - ASSERT (r < 16); - - /* Add % register prefix. */ - vec_add1 (s, '%'); - - switch (log2_n_bytes) - { - case 0: - { - - if (r < 8) - s = format (s, "%c%c", names8[r & 3], (r >> 2) ? 'l' : 'h'); - else - s = format (s, "r%db", r); - } - break; - - case 2: - case 3: - s = format (s, "%c", log2_n_bytes == 2 ? 'e' : 'r'); - /* fall through */ - case 1: - if (r < 8) - s = format (s, "%c%c", names8[r], names16[r]); - else - { - s = format (s, "%d", r); - if (log2_n_bytes != 3) - s = format (s, "%c", log2_n_bytes == 1 ? 'w' : 'd'); - } - break; - - default: - ASSERT (0); - } - - return s; -} - -static u8 * format_x86_reg_operand (u8 * s, va_list * va) -{ - u32 reg = va_arg (*va, u32); - u32 log2_n_bytes = va_arg (*va, u32); - u32 type = va_arg (*va, u32); - - switch (type) - { - default: - ASSERT (0); - break; - - case 'x': - ASSERT (reg < 16); - return format (s, "%%xmm%d", reg); - - case 'm': - ASSERT (reg < 8); - return format (s, "%%mm%d", reg); - - /* Explicit byte/word/double-word/quad-word */ - case 'b': log2_n_bytes = 0; break; - case 'w': log2_n_bytes = 1; break; - case 'd': log2_n_bytes = 2; break; - case 'q': log2_n_bytes = 3; break; - - /* Use effective operand size. */ - case 'v': break; - - /* word or double-word depending on effective operand size. */ - case 'z': - log2_n_bytes = clib_min (log2_n_bytes, 2); - break; - } - - s = format (s, "%U", format_x86_gp_reg_operand, reg, log2_n_bytes); - return s; -} - -static u8 * format_x86_mem_operand (u8 * s, va_list * va) -{ - x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); - - if (p->displacement != 0) - s = format (s, "0x%x", p->displacement); - - if (p->flags & X86_INSN_HAS_BASE) - { - s = format (s, "(%U", - format_x86_gp_reg_operand, p->regs[1], - p->log2_effective_address_bytes); - if (p->flags & X86_INSN_HAS_INDEX) - { - s = format (s, ",%U", - format_x86_gp_reg_operand, p->regs[2], - p->log2_effective_address_bytes); - if (p->log2_index_scale != 0) - s = format (s, ",%d", 1 << p->log2_index_scale); - } - s = format (s, ")"); - } - - /* [RIP+disp] PC relative addressing in 64 bit mode. */ - else if (p->flags & X86_INSN_PARSE_64_BIT) - s = format (s, "(%%rip)"); - - return s; -} - -static u8 * format_x86_insn_operand (u8 * s, va_list * va) -{ - x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); - x86_insn_t * insn = &p->insn; - u32 o = va_arg (*va, u32); - u8 c, t; - - ASSERT (o < ARRAY_LEN (insn->operands)); - c = insn->operands[o].code; - t = insn->operands[o].type; - - /* Register encoded in instruction. */ - if (c < 8) - return format (s, "%U", - format_x86_gp_reg_operand, c, - p->log2_effective_operand_bytes); - - switch (c) - { - /* Memory or reg field from modrm byte. */ - case 'M': - ASSERT (p->flags & X86_INSN_IS_ADDRESS); - /* FALLTHROUGH */ - case 'E': - if (p->flags & X86_INSN_IS_ADDRESS) - s = format (s, "%U", format_x86_mem_operand, p); - else - s = format (s, "%U", - format_x86_reg_operand, p->regs[1], - p->log2_effective_operand_bytes, t); - break; - - /* reg field from modrm byte. */ - case 'R': - case 'G': - s = format (s, "%U", - format_x86_reg_operand, p->regs[0], - p->log2_effective_operand_bytes, t); - break; - - case 'I': - { - u32 l = x86_insn_log2_immediate_bytes (p, insn); - i64 mask = pow2_mask (8ULL << l); - s = format (s, "$0x%Lx", p->immediate & mask); - } - break; - - case 'J': - if (p->immediate < 0) - s = format (s, "- 0x%Lx", -p->immediate); - else - s = format (s, "+ 0x%Lx", p->immediate); - break; - - case 'O': - s = format (s, "0x%Lx", p->immediate); - break; - - case 'A': - /* AX/AL */ - s = format (s, "%U", - format_x86_gp_reg_operand, X86_INSN_GP_REG_AX, - t == 'L' ? 0 : p->log2_effective_operand_bytes); - break; - - case 'B': - /* BX/BL/BP */ - s = format (s, "%U", - format_x86_gp_reg_operand, - t == 'P' ? X86_INSN_GP_REG_BP : X86_INSN_GP_REG_BX, - t == 'L' ? 0 : p->log2_effective_operand_bytes); - break; - - case 'C': - /* CX/CL */ - s = format (s, "%U", - format_x86_gp_reg_operand, X86_INSN_GP_REG_CX, - t == 'L' ? 0 : p->log2_effective_operand_bytes); - break; - - case 'D': - /* DX/DL/DI */ - s = format (s, "%U", - format_x86_gp_reg_operand, - t == 'I' ? X86_INSN_GP_REG_DI : X86_INSN_GP_REG_DX, - t == 'L' ? 0 : p->log2_effective_operand_bytes); - break; - - case 'S': - /* SI/SP */ - s = format (s, "%U", - format_x86_gp_reg_operand, - t == 'I' ? X86_INSN_GP_REG_SI : X86_INSN_GP_REG_SP, - p->log2_effective_operand_bytes); - break; - - case '1': - s = format (s, "1"); - break; - - default: - ASSERT (0); - } - - return s; -} - -u8 * format_x86_insn_parse (u8 * s, va_list * va) -{ - x86_insn_parse_t * p = va_arg (*va, x86_insn_parse_t *); - x86_insn_t * insn = &p->insn; - u32 o, i, is_src_dst; - - s = format (s, "%s", insn->name); - - if (! x86_insn_operand_is_valid (insn, 0)) - goto done; - - is_src_dst = x86_insn_operand_is_valid (insn, 1); - - /* If instruction has immediate add suffix to opcode to - indicate operand size. */ - if (is_src_dst) - { - u32 b; - - b = x86_insn_log2_immediate_bytes (p, insn); - if (b < p->log2_effective_operand_bytes - && (p->flags & X86_INSN_IS_ADDRESS)) - s = format (s, "%c", "bwlq"[b]); - } - - for (i = 0; i < ARRAY_LEN (insn->operands); i++) - { - o = is_src_dst + i; - if (! x86_insn_operand_is_valid (insn, o)) - break; - s = format (s, "%s%U", - i == 0 ? " " : ", ", - format_x86_insn_operand, p, o); - } - - if (is_src_dst) - s = format (s, ", %U", - format_x86_insn_operand, p, 0); - - done: - return s; -} diff --git a/src/vppinfra/asm_x86.h b/src/vppinfra/asm_x86.h deleted file mode 100644 index dacef61755c..00000000000 --- a/src/vppinfra/asm_x86.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef included_asm_x86_h -#define included_asm_x86_h - -#include <vppinfra/format.h> - -typedef union -{ - struct - { - u8 code; - u8 type; - }; - u8 data[2]; -} x86_insn_operand_t; - -typedef struct -{ - /* Instruction name. */ - char *name; - - /* X86 instructions may have up to 3 operands. */ - x86_insn_operand_t operands[3]; - - u16 flags; -#define X86_INSN_FLAG_DEFAULT_64_BIT (1 << 0) -#define X86_INSN_FLAG_SET_SSE_GROUP(n) ((n) << 5) -#define X86_INSN_FLAG_GET_SSE_GROUP(f) (((f) >> 5) & 0x1f) -#define X86_INSN_FLAG_SET_MODRM_REG_GROUP(n) (((n) & 0x3f) << 10) -#define X86_INSN_FLAG_GET_MODRM_REG_GROUP(f) (((f) >> 10) & 0x3f) -} x86_insn_t; - -always_inline uword -x86_insn_operand_is_valid (x86_insn_t * i, uword o) -{ - ASSERT (o < ARRAY_LEN (i->operands)); - return i->operands[o].code != '_'; -} - -#define foreach_x86_legacy_prefix \ - _ (OPERAND_SIZE, 0x66) \ - _ (ADDRESS_SIZE, 0x67) \ - _ (SEGMENT_CS, 0x2e) \ - _ (SEGMENT_DS, 0x3e) \ - _ (SEGMENT_ES, 0x26) \ - _ (SEGMENT_FS, 0x64) \ - _ (SEGMENT_GS, 0x65) \ - _ (SEGMENT_SS, 0x36) \ - _ (LOCK, 0xf0) \ - _ (REPZ, 0xf3) \ - _ (REPNZ, 0xf2) - -#define foreach_x86_insn_parse_flag \ - /* Parse in 32/64-bit mode. */ \ - _ (PARSE_32_BIT, 0) \ - _ (PARSE_64_BIT, 0) \ - _ (IS_ADDRESS, 0) \ - /* regs[1/2] is a valid base/index register */ \ - _ (HAS_BASE, 0) \ - _ (HAS_INDEX, 0) \ - /* rex w bit */ \ - _ (OPERAND_SIZE_64, 0) - -typedef enum -{ -#define _(f,o) X86_INSN_FLAG_BIT_##f, - foreach_x86_insn_parse_flag foreach_x86_legacy_prefix -#undef _ -} x86_insn_parse_flag_bit_t; - -typedef enum -{ -#define _(f,o) X86_INSN_##f = 1 << X86_INSN_FLAG_BIT_##f, - foreach_x86_insn_parse_flag foreach_x86_legacy_prefix -#undef _ -} x86_insn_parse_flag_t; - -typedef struct -{ - /* Registers in instruction. - [0] is modrm reg field - [1] is base reg - [2] is index reg. */ - u8 regs[3]; - - /* Scale for index register. */ - u8 log2_index_scale:2; - u8 log2_effective_operand_bytes:3; - u8 log2_effective_address_bytes:3; - - i32 displacement; - - /* Parser flags: set of x86_insn_parse_flag_t enums. */ - u32 flags; - - i64 immediate; - - x86_insn_t insn; -} x86_insn_parse_t; - -u8 *x86_insn_parse (x86_insn_parse_t * p, u8 * code_start); -format_function_t format_x86_insn_parse; - -#endif /* included_asm_x86_h */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ diff --git a/src/vppinfra/backtrace.c b/src/vppinfra/backtrace.c deleted file mode 100644 index e713bae6876..00000000000 --- a/src/vppinfra/backtrace.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Copyright (c) 2004 Eliot Dresselhaus - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include <vppinfra/clib.h> -#include <vppinfra/error.h> - -#ifdef __mips__ - -/* Let code below know we've defined _clib_backtrace */ -#define clib_backtrace_defined - -#include <vppinfra/asm_mips.h> - -__clib_export uword -clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip) -{ - u32 *pc; - void *sp; - uword i, saved_pc; - - /* Figure current PC, saved PC and stack pointer. */ - asm volatile (".set push\n" - ".set noat\n" "move %[saved_pc], $31\n" "move %[sp], $29\n" - /* Fetches current PC. */ - "la $at, 1f\n" - "jalr %[pc], $at\n" - "nop\n" - "1:\n" - ".set pop\n":[pc] "=r" (pc), - [saved_pc] "=r" (saved_pc),[sp] "=r" (sp)); - - /* Also skip current frame. */ - n_frames_to_skip += 1; - - for (i = 0; i < max_callers + n_frames_to_skip; i++) - { - mips_insn_opcode_t op; - mips_insn_special_funct_t funct; - i32 insn, rs, rt, rd, immediate, found_saved_pc; - u32 *start_pc; - - /* Parse instructions until we reach prologue for this - stack frame. We'll need to figure out where saved - PC is and where previous stack frame lives. */ - start_pc = pc; - found_saved_pc = 0; - while (1) - { - insn = *--pc; - op = mips_insn_get_op (insn); - funct = mips_insn_get_funct (insn); - rs = mips_insn_get_rs (insn); - rt = mips_insn_get_rt (insn); - rd = mips_insn_get_rd (insn); - immediate = mips_insn_get_immediate (insn); - - switch (op) - { - default: - break; - - case MIPS_OPCODE_sd: - case MIPS_OPCODE_sw: - /* Trace stores of return address. */ - if (rt == MIPS_REG_RA) - { - void *addr = sp + immediate; - - /* If RA is stored somewhere other than in the - stack frame, give up. */ - if (rs != MIPS_REG_SP) - goto backtrace_done; - - ASSERT (immediate % 4 == 0); - if (op == MIPS_OPCODE_sw) - saved_pc = ((u32 *) addr)[0]; - else - saved_pc = ((u64 *) addr)[0]; - found_saved_pc = 1; - } - break; - - case MIPS_OPCODE_addiu: - case MIPS_OPCODE_daddiu: - case MIPS_OPCODE_addi: - case MIPS_OPCODE_daddi: - if (rt == MIPS_REG_SP) - { - if (rs != MIPS_REG_SP) - goto backtrace_done; - - ASSERT (immediate % 4 == 0); - - /* Assume positive offset is part of the epilogue. - E.g. - jr ra - add sp,sp,100 - */ - if (immediate > 0) - continue; - - /* Negative offset means allocate stack space. - This could either be the prologue or could be due to - alloca. */ - sp -= immediate; - - /* This frame will not save RA. */ - if (i == 0) - goto found_prologue; - - /* Assume that addiu sp,sp,-N without store of ra means - that we have not found the prologue yet. */ - if (found_saved_pc) - goto found_prologue; - } - break; - - case MIPS_OPCODE_slti: - case MIPS_OPCODE_sltiu: - case MIPS_OPCODE_andi: - case MIPS_OPCODE_ori: - case MIPS_OPCODE_xori: - case MIPS_OPCODE_lui: - case MIPS_OPCODE_ldl: - case MIPS_OPCODE_ldr: - case MIPS_OPCODE_lb: - case MIPS_OPCODE_lh: - case MIPS_OPCODE_lwl: - case MIPS_OPCODE_lw: - case MIPS_OPCODE_lbu: - case MIPS_OPCODE_lhu: - case MIPS_OPCODE_lwr: - case MIPS_OPCODE_lwu: - case MIPS_OPCODE_ld: - /* Give up when we find anyone setting the stack pointer. */ - if (rt == MIPS_REG_SP) - goto backtrace_done; - break; - - case MIPS_OPCODE_SPECIAL: - if (rd == MIPS_REG_SP) - switch (funct) - { - default: - /* Give up when we find anyone setting the stack pointer. */ - goto backtrace_done; - - case MIPS_SPECIAL_FUNCT_break: - case MIPS_SPECIAL_FUNCT_jr: - case MIPS_SPECIAL_FUNCT_sync: - case MIPS_SPECIAL_FUNCT_syscall: - case MIPS_SPECIAL_FUNCT_tge: - case MIPS_SPECIAL_FUNCT_tgeu: - case MIPS_SPECIAL_FUNCT_tlt: - case MIPS_SPECIAL_FUNCT_tltu: - case MIPS_SPECIAL_FUNCT_teq: - case MIPS_SPECIAL_FUNCT_tne: - /* These instructions can validly have rd == MIPS_REG_SP */ - break; - } - break; - } - } - - found_prologue: - /* Check sanity of saved pc. */ - if (saved_pc & 3) - goto backtrace_done; - if (saved_pc == 0) - goto backtrace_done; - - if (i >= n_frames_to_skip) - callers[i - n_frames_to_skip] = saved_pc; - pc = uword_to_pointer (saved_pc, u32 *); - } - -backtrace_done: - if (i < n_frames_to_skip) - return 0; - else - return i - n_frames_to_skip; -} -#endif /* __mips__ */ - -#ifndef clib_backtrace_defined -#define clib_backtrace_defined - -/* use glibc backtrace for stack trace */ -#include <execinfo.h> - -__clib_export uword -clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip) -{ - int size; - void *array[20]; - /* Also skip current frame. */ - n_frames_to_skip += 1; - - size = clib_min (ARRAY_LEN (array), max_callers + n_frames_to_skip); - - size = backtrace (array, size); - - uword i; - - for (i = 0; i < max_callers + n_frames_to_skip && i < size; i++) - { - if (i >= n_frames_to_skip) - callers[i - n_frames_to_skip] = pointer_to_uword (array[i]); - } - - if (i < n_frames_to_skip) - return 0; - else - return i - n_frames_to_skip; -} - - -#endif /* clib_backtrace_defined */ - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ 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/clib.h b/src/vppinfra/clib.h index d14582492d6..75cebc65672 100644 --- a/src/vppinfra/clib.h +++ b/src/vppinfra/clib.h @@ -385,10 +385,6 @@ void qsort (void *base, uword n, uword size, int (*)(const void *, const void *)); #endif -/* Stack backtrace. */ -uword -clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip); - #include <vppinfra/byte_order.h> #endif /* included_clib_h */ diff --git a/src/vppinfra/format_ansi.h b/src/vppinfra/format_ansi.h new file mode 100644 index 00000000000..c35406aacf7 --- /dev/null +++ b/src/vppinfra/format_ansi.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Cisco Systems, Inc. + */ + +#ifndef __FORMAT_ANSI_H__ +#define __FORMAT_ANSI_H__ + +#define ANSI_RESET "\x1b[0m" +#define ANSI_BOLD "\x1b[1m" +#define ANSI_ITALIC "\x1b[3m" +#define ANSI_UNDERLINE "\x1b[4m" +#define ANSI_BLINK "\x1b[5m" +#define ANSI_FG_BLACK "\x1b[30m" +#define ANSI_FG_RED "\x1b[31m" +#define ANSI_FG_GREEN "\x1b[32m" +#define ANSI_FG_YELLOW "\x1b[33m" +#define ANSI_FG_BLUE "\x1b[34m" +#define ANSI_FG_MAGENTA "\x1b[35m" +#define ANSI_FG_CYAN "\x1b[36m" +#define ANSI_FG_WHITE "\x1b[37m" +#define ANSI_FG_DEFAULT "\x1b[39m" +#define ANSI_BG_BLACK "\x1b[40m" +#define ANSI_BG_RED "\x1b[41m" +#define ANSI_BG_GREEN "\x1b[42m" +#define ANSI_BG_YELLOW "\x1b[43m" +#define ANSI_BG_BLUE "\x1b[44m" +#define ANSI_BG_MAGENTA "\x1b[45m" +#define ANSI_BG_CYAN "\x1b[46m" +#define ANSI_BG_WHITE "\x1b[47m" +#define ANSI_BG_DEFAULT "\x1b[49m" +#define ANSI_FG_BR_BLACK "\x1b[90m" +#define ANSI_FG_BR_RED "\x1b[91m" +#define ANSI_FG_BR_GREEN "\x1b[92m" +#define ANSI_FG_BR_YELLOW "\x1b[93m" +#define ANSI_FG_BR_BLUE "\x1b[94m" +#define ANSI_FG_BR_MAGENTA "\x1b[95m" +#define ANSI_FG_BR_CYAN "\x1b[96m" +#define ANSI_FG_BR_WHITE "\x1b[97m" +#define ANSI_BG_BR_BLACK "\x1b[100m" +#define ANSI_BG_BR_RED "\x1b[101m" +#define ANSI_BG_BR_GREEN "\x1b[102m" +#define ANSI_BG_BR_YELLOW "\x1b[103m" +#define ANSI_BG_BR_BLUE "\x1b[104m" +#define ANSI_BG_BR_MAGENTA "\x1b[105m" +#define ANSI_BG_BR_CYAN "\x1b[106m" +#define ANSI_BG_BR_WHITE "\x1b[107m" + +#endif /* __FORMAT_ANSI_H__ */ 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/mem_dlmalloc.c b/src/vppinfra/mem_dlmalloc.c index a188164a7ba..e98687fff2a 100644 --- a/src/vppinfra/mem_dlmalloc.c +++ b/src/vppinfra/mem_dlmalloc.c @@ -19,6 +19,7 @@ #include <vppinfra/lock.h> #include <vppinfra/hash.h> #include <vppinfra/elf_clib.h> +#include <vppinfra/stack.h> typedef struct { @@ -65,15 +66,13 @@ mheap_get_trace_internal (const clib_mem_heap_t *heap, uword offset, { mheap_trace_main_t *tm = &mheap_trace_main; mheap_trace_t *t; - uword i, n_callers, trace_index, *p; - mheap_trace_t trace; + uword i, trace_index, *p; + mheap_trace_t trace = {}; + int index; if (heap != tm->current_traced_mheap || mheap_trace_thread_disable) return; - /* Spurious Coverity warnings be gone. */ - clib_memset (&trace, 0, sizeof (trace)); - clib_spinlock_lock (&tm->lock); /* heap could have changed while we were waiting on the lock */ @@ -83,9 +82,19 @@ mheap_get_trace_internal (const clib_mem_heap_t *heap, uword offset, /* Turn off tracing for this thread to avoid embarrassment... */ mheap_trace_thread_disable = 1; - /* Skip our frame and mspace_get_aligned's frame */ - n_callers = clib_backtrace (trace.callers, ARRAY_LEN (trace.callers), 2); - if (n_callers == 0) + index = -2; /* skip first 2 stack frames */ + foreach_clib_stack_frame (sf) + { + if (index >= 0) + { + if (index == ARRAY_LEN (trace.callers)) + break; + trace.callers[index] = sf->ip; + } + index++; + } + + if (index < 1) goto out; if (!tm->trace_by_callers) 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/stack.c b/src/vppinfra/stack.c new file mode 100644 index 00000000000..190e880c228 --- /dev/null +++ b/src/vppinfra/stack.c @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Cisco Systems, Inc. + */ + +#define _GNU_SOURCE +#include <dlfcn.h> + +#include <vppinfra/clib.h> +#include <vppinfra/stack.h> +#include <vppinfra/error.h> + +#if HAVE_LIBUNWIND == 1 + +#define UNW_LOCAL_ONLY +#include <libunwind.h> + +static __thread unw_cursor_t cursor; +static __thread unw_context_t context; + +#endif + +__clib_export clib_stack_frame_t * +clib_stack_frame_get (clib_stack_frame_t *sf) +{ +#if HAVE_LIBUNWIND == 1 + Dl_info info = {}; + + if (sf->index == 0) + { + if (unw_getcontext (&context) < 0) + { + clib_warning ("libunwind: cannot get local machine state\n"); + return 0; + } + if (unw_init_local (&cursor, &context) < 0) + { + clib_warning ( + "libunwind: cannot initialize cursor for local unwinding\n"); + return 0; + } + if (unw_step (&cursor) < 1) + return 0; + } + else if (unw_step (&cursor) < 1) + return 0; + + if (unw_get_reg (&cursor, UNW_REG_IP, &sf->ip)) + { + clib_warning ("libunwind: cannot read IP\n"); + return 0; + } + + if (unw_get_reg (&cursor, UNW_REG_SP, &sf->sp)) + { + clib_warning ("libunwind: cannot read SP\n"); + return 0; + } + + if (unw_get_proc_name (&cursor, sf->name, sizeof (sf->name), &sf->offset) < + 0) + sf->name[0] = sf->offset = 0; + + sf->is_signal_frame = unw_is_signal_frame (&cursor) ? 1 : 0; + + if (dladdr ((void *) sf->ip, &info)) + sf->file_name = info.dli_fname; + else + sf->file_name = 0; + + sf->index++; + return sf; +#else + return 0; +#endif +} diff --git a/src/vppinfra/stack.h b/src/vppinfra/stack.h new file mode 100644 index 00000000000..98a621d4176 --- /dev/null +++ b/src/vppinfra/stack.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright (c) 2024 Cisco Systems, Inc. + */ + +#ifndef __STACK_H__ +#define __STACK_H__ + +#include <vppinfra/clib.h> + +typedef struct +{ + uword ip, sp; + uword offset; + char name[64]; + const char *file_name; + u32 index; + u8 is_signal_frame; +} clib_stack_frame_t; + +clib_stack_frame_t *clib_stack_frame_get (clib_stack_frame_t *); + +#define foreach_clib_stack_frame(sf) \ + for (clib_stack_frame_t _sf = {}, *sf = clib_stack_frame_get (&_sf); sf; \ + sf = clib_stack_frame_get (sf)) + +#endif /* __STACK_H__ */ 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 5008f82c493..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,9 +46,15 @@ #include <vppinfra/format.h> #ifdef __linux__ #include <vppinfra/linux/sysfs.h> +#include <sched.h> #elif defined(__FreeBSD__) -#include <sys/sysctl.h> +#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> @@ -278,10 +288,70 @@ os_get_online_cpu_core_bitmap () } __clib_export clib_bitmap_t * +os_get_cpu_affinity_bitmap (int pid) +{ +#if __linux + int index, ret; + cpu_set_t cpuset; + uword *affinity_cpus; + + clib_bitmap_alloc (affinity_cpus, sizeof (cpu_set_t)); + clib_bitmap_zero (affinity_cpus); + + __CPU_ZERO_S (sizeof (cpu_set_t), &cpuset); + + ret = sched_getaffinity (0, sizeof (cpu_set_t), &cpuset); + + if (ret < 0) + { + clib_bitmap_free (affinity_cpus); + return 0; + } + + for (index = 0; index < sizeof (cpu_set_t); index++) + 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 NULL; +#endif +} + +__clib_export clib_bitmap_t * 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 diff --git a/test/Makefile b/test/Makefile index 9b9cc178cf6..cabb3526c8c 100644 --- a/test/Makefile +++ b/test/Makefile @@ -350,32 +350,72 @@ cov-prep: test-dep @lcov --zerocounters --directory $(VPP_BUILD_DIR) @test -z "$(EXTERN_COV_DIR)" || lcov --zerocounters --directory $(EXTERN_COV_DIR) +COV_REM_NOT_CODE="/usr/include/*" "*/build-root/*" "/opt/*" "/usr/lib/*" \ + "*_test.*" "*test_*" "*vat*" "*/vnet/unix/gdb_funcs.c" \ + "*pg.c" + +COV_REM_DRIVERS="*rdma*" "*/plugins/af_packet/*" "*/plugins/af_xdp/*" \ + "*/plugins/avf/*" "*/plugins/dma_intel/*" "*/vlib/pci/*" \ + "*/vnet/devices/*" "*/vlib/dma/*" "*/plugins/vmxnet3/*" \ + "*/vnet/devices/virtio/*" "*/plugins/perfmon/arm*" \ + "*/plugins/perfmon/intel/*" "*/vlib/vmbus/*" \ + "*/vnet/dev/*" "*/plugins/dev_ena/*" "*/plugins/dev_iavf/*" + +COV_REM_UNUSED_FEAT="*/plugins/ioam/analyse/*" "*/plugins/ioam/lib-*/*" \ + "*/plugins/ioam/export-common/*" "*/vnet/srp/*" \ + "*/lawful-intercept/*" "*/lisp/*" "*/vnet/osi/*" \ + "*/plugins/nsh/*" + +COV_REM_TODO_NO_TEST="*/vpp-api/client/*" "*/plugins/prom/*" \ + "*/plugins/tlspicotls/*" "*/plugins/tlsmbedtls/*" \ + "*/vppinfra/perfmon/*" "*/plugins/ila/*" \ + "*/vlib/linux/*" "*/vnet/util/radix.c" "*/vapi/vapi.hpp" \ + "*/vpp/api/types.c" "*/vpp/api/json_format.c" \ + "*/plugins/ioam/*/*.h" "*/linux/netns.c" "*/vnet/flow/*" \ + "*/vppinfra/random.c" "*/vppinfra/ring.h" \ + "*/vppinfra/bihash_vec8_8.h" "*/vppinfra/maplog.c" \ + "*/vppinfra/format_table.c" "*/vppinfra/timing_wheel.c" \ + "*/vppinfra/macros.c" "*/vppinfra/valloc.c" \ + "*/vppinfra/jsonformat.c" "*/vppinfra/vector/array_mask.h" \ + "*/vppinfra/vector/toeplitz.c" "*/plugins/vrrp/vrrp_packet.h" \ + "*/vnet/srv6/sr.h" "*/vlibapi/api_format.c" \ + "*/vlibapi/node_serialize.c" "*/plugins/quic/error.c" \ + "*/vnet/ipfix-export/flow_report_classify.h" \ + "*/vnet/ip/ip6_ll_types.c" "*/vnet/ip/ip_psh_cksum.h" \ + "*/vnet/ip/ip6_hop_by_hop.h" "*/vnet/ip/ip_format_fns.h" \ + "*/vnet/dpo/classify_dpo.h" "*/vnet/dpo/l3_proxy_dpo.h" \ + "*/vnet/ipsec/esp_format.c" "*/vnet/ethernet/sfp.c" \ + "*/vnet/ethernet/ethernet_format_fns.h" \ + "*/plugins/ikev2/ikev2_format.c" "*/vnet/bier/bier_types.c" + +COV_REM_ALT_TEST="*/plugins/hs_apps/*" "*/plugins/builtinurl/*" \ + "*/plugins/http/*.h" .PHONY: cov-post cov-post: wipe-cov $(BUILD_COV_DIR) @lcov --capture \ --directory $(VPP_BUILD_DIR) \ - --output-file $(BUILD_COV_DIR)/coverage.info + --output-file $(BUILD_COV_DIR)/coverage$(HS_TEST).info @test -z "$(EXTERN_COV_DIR)" || \ lcov --capture \ --directory $(EXTERN_COV_DIR) \ - --output-file $(BUILD_COV_DIR)/extern-coverage.info - @lcov --remove $(BUILD_COV_DIR)/coverage.info \ - "/usr/include/*" "*/build-root/*" "/opt/*" "/usr/lib/*" \ - "*_test.*" "*vat*" "*rdma*" "*/vpp-api/client/*" "*/plugins/af_packet/*" \ - "*/plugins/af_xdp/*" "*/plugins/avf/*" "*/plugins/dma_intel/*" \ - "*/plugins/hs_apps/*" "*/plugins/vmxnet3/*" "*/vnet/devices/virtio/*" \ - "*/plugins/perfmon/arm*" "*/plugins/perfmon/intel/*" "*/vlib/vmbus/*" \ - "*/vnet/dev/*" "*/plugins/dev_ena/*" "*/plugins/builtinurl/*" "*/vnet/flow/*" \ - "*/plugins/http_static/builtinurl/*" "*/plugins/dev_iavf/*" \ - -o $(BUILD_COV_DIR)/coverage-filtered.info - @genhtml $(BUILD_COV_DIR)/coverage-filtered.info \ + --output-file $(BUILD_COV_DIR)/extern-coverage$(HS_TEST).info + @lcov --remove $(BUILD_COV_DIR)/coverage$(HS_TEST).info \ + $(COV_REM_NOT_CODE) \ + $(COV_REM_DRIVERS) \ + $(COV_REM_TODO_NO_TEST) \ + $(COV_REM_UNUSED_FEAT) \ + $(COV_REM_ALT_TEST) \ + -o $(BUILD_COV_DIR)/coverage-filtered$(HS_TEST).info + @genhtml $(BUILD_COV_DIR)/coverage-filtered$(HS_TEST).info \ --output-directory $(BUILD_COV_DIR)/html @test -z "$(EXTERN_COV_DIR)" || \ - genhtml $(BUILD_COV_DIR)/extern-coverage.info \ + genhtml $(BUILD_COV_DIR)/extern-coverage$(HS_TEST).info \ --output-directory $(BUILD_COV_DIR)/extern-html @echo @echo "Build finished. Code coverage report is in $(BUILD_COV_DIR)/html/index.html" @test -z "$(EXTERN_COV_DIR)" || echo "Code coverage report for out-of-tree objects is in $(BUILD_COV_DIR)/extern-html/index.html" + @mkdir -p $(BR)/test-coverage-merged + @cp -f $(BUILD_COV_DIR)/coverage-filtered$(HS_TEST).info $(BR)/test-coverage-merged .PHONY: cov cov: @@ -434,6 +474,7 @@ help: @echo " test-cov-prep - coverage phase #1 : prepare lcov" @echo " test-cov-build - coverage phase #2 : build gcov image & run tests against it (use TEST=)" @echo " test-cov-post - coverage phase #3 : generate lcov html report" + @echo " test-cov-both - generate and merge code coverage report for Python and Golang tests" @echo " test-all - build and run functional and extended tests" @echo " test-all-debug - build and run functional and extended tests (debug build)" @echo " test-all-cov - generate code coverage report for functional and extended tests" diff --git a/test/template_ipsec.py b/test/template_ipsec.py index b5cd922f127..7953f603287 100644 --- a/test/template_ipsec.py +++ b/test/template_ipsec.py @@ -3022,7 +3022,7 @@ class SpdFlowCacheTemplate(IPSecIPv4Fwd): return False def create_stream( - cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=5678, proto="UDP-ESP" + cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP" ): packets = [] packets = super(SpdFlowCacheTemplate, cls).create_stream( @@ -3031,7 +3031,7 @@ class SpdFlowCacheTemplate(IPSecIPv4Fwd): return packets def verify_capture( - self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=5678 + self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500 ): super(SpdFlowCacheTemplate, self).verify_l3_l4_capture( src_if, dst_if, capture, tcp_port_in, udp_port_in @@ -3056,7 +3056,7 @@ class SpdFastPathTemplate(IPSecIPv4Fwd): super(SpdFastPathTemplate, self).tearDown() def create_stream( - cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=5678, proto="UDP-ESP" + cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP" ): packets = [] packets = super(SpdFastPathTemplate, cls).create_stream( @@ -3065,7 +3065,7 @@ class SpdFastPathTemplate(IPSecIPv4Fwd): return packets def verify_capture( - self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=5678 + self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500 ): super(SpdFastPathTemplate, self).verify_l3_l4_capture( src_if, dst_if, capture, tcp_port_in, udp_port_in @@ -3084,7 +3084,7 @@ class IpsecDefaultTemplate(IPSecIPv4Fwd): super(IpsecDefaultTemplate, self).tearDown() def create_stream( - cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=5678, proto="UDP-ESP" + cls, src_if, dst_if, pkt_count, src_prt=1234, dst_prt=4500, proto="UDP-ESP" ): packets = [] packets = super(IpsecDefaultTemplate, cls).create_stream( @@ -3093,7 +3093,7 @@ class IpsecDefaultTemplate(IPSecIPv4Fwd): return packets def verify_capture( - self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=5678 + self, src_if, dst_if, capture, tcp_port_in=1234, udp_port_in=4500 ): super(IpsecDefaultTemplate, self).verify_l3_l4_capture( src_if, dst_if, capture, tcp_port_in, udp_port_in 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 1db83be50a8..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) @@ -424,7 +424,7 @@ class TestGSO(VppTestCase): 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) @@ -457,7 +457,7 @@ class TestGSO(VppTestCase): 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_ip4.py b/test/test_ip4.py index 926ca77a5f8..a183b0ca0ba 100644 --- a/test/test_ip4.py +++ b/test/test_ip4.py @@ -244,12 +244,13 @@ class TestIPv4RouteLookup(VppTestCase): """IPv4 Route Lookup Test Case""" routes = [] + tables = [] - def route_lookup(self, prefix, exact): + def route_lookup(self, prefix, exact, table_id=0): return self.vapi.api( self.vapi.papi.ip_route_lookup, { - "table_id": 0, + "table_id": table_id, "exact": exact, "prefix": prefix, }, @@ -283,11 +284,30 @@ class TestIPv4RouteLookup(VppTestCase): r.add_vpp_config() self.routes.append(r) + custom_vrf = VppIpTable(self, 200) + custom_vrf.add_vpp_config() + self.tables.append(custom_vrf) + + r = VppIpRoute(self, "2.2.0.0", 16, [drop_nh], 200) + r.add_vpp_config() + self.routes.append(r) + + r = VppIpRoute(self, "2.2.2.0", 24, [drop_nh], 200) + r.add_vpp_config() + self.routes.append(r) + + r = VppIpRoute(self, "2.2.2.2", 32, [drop_nh], 200) + r.add_vpp_config() + self.routes.append(r) + def tearDown(self): # Remove the routes we added for r in self.routes: r.remove_vpp_config() + for vrf in self.tables: + vrf.remove_vpp_config() + super(TestIPv4RouteLookup, self).tearDown() def test_exact_match(self): @@ -305,6 +325,20 @@ class TestIPv4RouteLookup(VppTestCase): with self.vapi.assert_negative_api_retval(): self.route_lookup("1.1.1.2/32", True) + # Verify we find the host route + prefix = "2.2.2.2/32" + result = self.route_lookup(prefix, True, 200) + assert prefix == str(result.route.prefix) + + # Verify we find a middle prefix route + prefix = "2.2.2.0/24" + result = self.route_lookup(prefix, True, 200) + assert prefix == str(result.route.prefix) + + # Verify we do not find an available LPM. + with self.vapi.assert_negative_api_retval(): + self.route_lookup("2.2.2.1/32", True, 200) + def test_longest_prefix_match(self): # verify we find lpm lpm_prefix = "1.1.1.0/24" @@ -315,6 +349,15 @@ class TestIPv4RouteLookup(VppTestCase): result = self.route_lookup(lpm_prefix, False) assert lpm_prefix == str(result.route.prefix) + # verify we find lpm + lpm_prefix = "2.2.2.0/24" + result = self.route_lookup("2.2.2.1/32", False, 200) + assert lpm_prefix == str(result.route.prefix) + + # Verify we find the exact when not requested + result = self.route_lookup(lpm_prefix, False, 200) + assert lpm_prefix == str(result.route.prefix) + # Can't seem to delete the default route so no negative LPM test. 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_ipsec_spd_flow_cache_input.py b/test/test_ipsec_spd_flow_cache_input.py index 283f345be18..b913a980599 100644 --- a/test/test_ipsec_spd_flow_cache_input.py +++ b/test/test_ipsec_spd_flow_cache_input.py @@ -785,9 +785,9 @@ class IPSec4SpdTestCaseCollisionInbound(SpdFlowCacheInbound): # create the packet streams # packet hashes to: # ad727628 - packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1) + packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 4500) # b5512898 - packets2 = self.create_stream(self.pg0, self.pg3, pkt_count, 1, 1) + packets2 = self.create_stream(self.pg0, self.pg3, pkt_count, 1, 4500) # add the streams to the source interfaces self.pg2.add_stream(packets1) self.pg0.add_stream(packets2) @@ -821,9 +821,9 @@ class IPSec4SpdTestCaseCollisionInbound(SpdFlowCacheInbound): # create the packet streams # 2f8f90f557eef12c - packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 1) + packets1 = self.create_stream(self.pg2, self.pg1, pkt_count, 1, 4500) # 6b7f9987719ffc1c - packets2 = self.create_stream(self.pg3, self.pg2, pkt_count, 1, 1) + packets2 = self.create_stream(self.pg3, self.pg2, pkt_count, 1, 4500) # add the streams to the source interfaces self.pg2.add_stream(packets1) self.pg3.add_stream(packets2) 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 6b6745f221c..98c50f9bb61 100644 --- a/test/test_reassembly.py +++ b/test/test_reassembly.py @@ -1647,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 @@ -1669,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() ) @@ -1678,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) @@ -1690,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() @@ -1705,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) @@ -1723,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() @@ -1738,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) @@ -2184,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) @@ -2196,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() @@ -2209,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) @@ -2218,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) @@ -2227,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)) |