aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS11
-rw-r--r--Makefile24
-rw-r--r--docs/configuration/reference.rst4
l---------docs/developer/plugins/dev_armada.rst1
-rw-r--r--docs/developer/plugins/index.rst2
l---------docs/developer/plugins/marvell.rst1
-rw-r--r--docs/spelling_wordlist.txt2
-rw-r--r--docs/usecases/webapp.rst19
-rw-r--r--extras/configs/http/setup.http3
-rw-r--r--extras/hs-test/Makefile29
-rw-r--r--extras/hs-test/README.rst46
-rw-r--r--extras/hs-test/docker/Dockerfile.build8
-rw-r--r--extras/hs-test/docker/Dockerfile.curl9
-rw-r--r--extras/hs-test/docker/Dockerfile.nginx-http38
-rw-r--r--extras/hs-test/docker/Dockerfile.nginx-server6
-rw-r--r--extras/hs-test/docker/Dockerfile.vpp2
-rw-r--r--extras/hs-test/go.mod59
-rw-r--r--extras/hs-test/go.sum175
-rw-r--r--extras/hs-test/hs_test.sh46
-rw-r--r--extras/hs-test/http_test.go749
-rw-r--r--extras/hs-test/infra/container.go77
-rw-r--r--extras/hs-test/infra/hst_suite.go251
-rw-r--r--extras/hs-test/infra/suite_envoy_proxy.go201
-rw-r--r--extras/hs-test/infra/suite_ldp.go203
-rw-r--r--extras/hs-test/infra/suite_nginx.go144
-rw-r--r--extras/hs-test/infra/suite_nginx_proxy.go181
-rw-r--r--extras/hs-test/infra/suite_no_topo.go12
-rw-r--r--extras/hs-test/infra/suite_vpp_proxy.go198
-rw-r--r--extras/hs-test/infra/utils.go197
-rw-r--r--extras/hs-test/infra/vppinstance.go96
-rw-r--r--extras/hs-test/ldp_test.go104
-rw-r--r--extras/hs-test/linux_iperf_test.go4
-rw-r--r--extras/hs-test/mem_leak_test.go24
-rw-r--r--extras/hs-test/nginx_test.go25
-rw-r--r--extras/hs-test/proxy_test.go138
-rw-r--r--extras/hs-test/resources/envoy/proxy.yaml16
-rw-r--r--extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf5
-rw-r--r--extras/hs-test/resources/nginx/nginx_server.conf40
-rw-r--r--extras/hs-test/resources/nginx/nginx_server_mirroring.conf13
-rwxr-xr-xextras/hs-test/script/build_hst.sh3
-rwxr-xr-xextras/hs-test/script/compress.sh6
-rwxr-xr-xextras/hs-test/script/nginx_server_entrypoint.sh3
-rw-r--r--extras/hs-test/topo-containers/2peerVethLdp.yaml18
-rw-r--r--extras/hs-test/topo-containers/envoyProxy.yaml40
-rw-r--r--extras/hs-test/topo-containers/nginxProxy.yaml32
-rw-r--r--extras/hs-test/topo-containers/ns.yaml2
-rw-r--r--extras/hs-test/topo-containers/vppProxy.yaml (renamed from extras/hs-test/topo-containers/nginxProxyAndServer.yaml)21
-rwxr-xr-xextras/scripts/checkstyle.sh19
-rw-r--r--src/cmake/platform/cn913x.cmake3
-rw-r--r--src/plugins/avf/avf.h3
-rw-r--r--src/plugins/avf/device.c4
-rw-r--r--src/plugins/avf/format.c17
-rw-r--r--src/plugins/avf/input.c2
-rw-r--r--src/plugins/avf/output.c2
-rw-r--r--src/plugins/builtinurl/FEATURE.yaml13
-rw-r--r--src/plugins/builtinurl/builtins.c194
-rw-r--r--src/plugins/builtinurl/builtinurl.api44
-rw-r--r--src/plugins/builtinurl/builtinurl.c137
-rw-r--r--src/plugins/builtinurl/builtinurl.h57
-rw-r--r--src/plugins/builtinurl/builtinurl_test.c66
-rw-r--r--src/plugins/crypto_native/aes_cbc.c199
-rw-r--r--src/plugins/dev_armada/CMakeLists.txt30
-rw-r--r--src/plugins/dev_armada/README.rst61
-rw-r--r--src/plugins/dev_armada/musdk.h22
-rw-r--r--src/plugins/dev_armada/plugin.c12
-rw-r--r--src/plugins/dev_armada/pp2/format.c176
-rw-r--r--src/plugins/dev_armada/pp2/init.c343
-rw-r--r--src/plugins/dev_armada/pp2/port.c280
-rw-r--r--src/plugins/dev_armada/pp2/pp2.h144
-rw-r--r--src/plugins/dev_armada/pp2/queue.c48
-rw-r--r--src/plugins/dev_armada/pp2/rx.c158
-rw-r--r--src/plugins/dev_armada/pp2/tx.c83
-rw-r--r--src/plugins/dev_iavf/port.c13
-rw-r--r--src/plugins/dev_iavf/virtchnl_funcs.h4
-rw-r--r--src/plugins/dev_octeon/flow.c102
-rw-r--r--src/plugins/dev_octeon/init.c3
-rw-r--r--src/plugins/dev_octeon/port.c49
-rw-r--r--src/plugins/dev_octeon/tx_node.c9
-rw-r--r--src/plugins/dpdk/device/dpdk.h1
-rw-r--r--src/plugins/dpdk/device/init.c11
-rw-r--r--src/plugins/flowprobe/flowprobe.c4
-rw-r--r--src/plugins/hs_apps/CMakeLists.txt2
-rw-r--r--src/plugins/hs_apps/echo_client.c5
-rw-r--r--src/plugins/hs_apps/echo_server.c5
-rw-r--r--src/plugins/hs_apps/http_cli.c70
-rw-r--r--src/plugins/hs_apps/http_client_cli.c113
-rw-r--r--src/plugins/hs_apps/http_simple_post.c581
-rw-r--r--src/plugins/hs_apps/http_tps.c183
-rw-r--r--src/plugins/hs_apps/proxy.c31
-rw-r--r--src/plugins/hs_apps/test_builtins.c179
-rw-r--r--src/plugins/hs_apps/vcl/vcl_test.h33
-rw-r--r--src/plugins/hs_apps/vcl/vcl_test_server.c6
-rw-r--r--src/plugins/http/CMakeLists.txt1
-rw-r--r--src/plugins/http/http.c786
-rw-r--r--src/plugins/http/http.h439
-rw-r--r--src/plugins/http/http_buffer.c2
-rw-r--r--src/plugins/http/http_content_types.h19
-rw-r--r--src/plugins/http/http_header_names.h21
-rw-r--r--src/plugins/http/http_plugin.rst369
-rw-r--r--src/plugins/http/http_status_codes.h27
-rw-r--r--src/plugins/http/http_test.c34
-rw-r--r--src/plugins/http_static/builtinurl/json_urls.c3
-rw-r--r--src/plugins/http_static/http_cache.c28
-rw-r--r--src/plugins/http_static/http_cache.h7
-rw-r--r--src/plugins/http_static/http_static.api37
-rw-r--r--src/plugins/http_static/http_static.c35
-rw-r--r--src/plugins/http_static/http_static.h15
-rw-r--r--src/plugins/http_static/http_static_test.c91
-rw-r--r--src/plugins/http_static/static_server.c156
-rw-r--r--src/plugins/ikev2/CMakeLists.txt1
-rw-r--r--src/plugins/ikev2/ikev2.api6
-rw-r--r--src/plugins/ikev2/ikev2.c53
-rw-r--r--src/plugins/ikev2/ikev2_api.c1
-rw-r--r--src/plugins/ikev2/ikev2_crypto.c5
-rw-r--r--src/plugins/ikev2/ikev2_handoff.c165
-rw-r--r--src/plugins/ikev2/ikev2_priv.h6
-rw-r--r--src/plugins/linux-cp/lcp_interface.c3
-rw-r--r--src/plugins/mactime/builtins.c1
-rw-r--r--src/plugins/marvell/CMakeLists.txt47
-rw-r--r--src/plugins/marvell/README.rst85
-rw-r--r--src/plugins/marvell/pp2/cli.c135
-rw-r--r--src/plugins/marvell/pp2/format.c200
-rw-r--r--src/plugins/marvell/pp2/input.c392
-rw-r--r--src/plugins/marvell/pp2/output.c121
-rw-r--r--src/plugins/marvell/pp2/pp2.c403
-rw-r--r--src/plugins/marvell/pp2/pp2.h147
-rw-r--r--src/plugins/marvell/pp2/pp2_api.c100
-rw-r--r--src/plugins/marvell/pp2/pp2_test.c144
-rw-r--r--src/plugins/npt66/npt66.api13
-rw-r--r--src/plugins/npt66/npt66_node.c71
-rw-r--r--src/plugins/osi/CMakeLists.txt (renamed from src/plugins/builtinurl/CMakeLists.txt)20
-rw-r--r--src/plugins/osi/FEATURE.yaml11
-rw-r--r--src/plugins/osi/node.c (renamed from src/vnet/osi/node.c)2
-rw-r--r--src/plugins/osi/osi.c (renamed from src/vnet/osi/osi.c)14
-rw-r--r--src/plugins/osi/osi.h (renamed from src/vnet/osi/osi.h)0
-rw-r--r--src/plugins/osi/pg.c (renamed from src/vnet/osi/pg.c)2
-rw-r--r--src/plugins/osi/plugin.c (renamed from src/plugins/marvell/plugin.c)20
-rw-r--r--src/plugins/prom/prom.c12
-rw-r--r--src/plugins/tlsopenssl/tls_openssl.c5
-rw-r--r--src/plugins/unittest/segment_manager_test.c5
-rw-r--r--src/plugins/unittest/session_test.c365
-rw-r--r--src/plugins/unittest/tcp_test.c5
-rw-r--r--src/plugins/unittest/util_test.c30
-rw-r--r--src/svm/svmdb.c2
-rwxr-xr-xsrc/tools/vppapigen/vppapigen_c.py58
-rw-r--r--src/vat/api_format.c2
-rw-r--r--src/vcl/vcl_locked.c8
-rw-r--r--src/vcl/vppcom.c117
-rw-r--r--src/vcl/vppcom.h3
-rw-r--r--src/vlib/buffer.c22
-rw-r--r--src/vlib/cli.c106
-rw-r--r--src/vlib/format.c2
-rw-r--r--src/vlib/main.c5
-rw-r--r--src/vlib/node.c49
-rw-r--r--src/vlib/node.h1
-rw-r--r--src/vlib/node_funcs.h4
-rw-r--r--src/vlib/unix/cli.c6
-rw-r--r--src/vlibapi/api_shared.c2
-rw-r--r--src/vnet/CMakeLists.txt21
-rw-r--r--src/vnet/dev/bus/platform.c172
-rw-r--r--src/vnet/dev/bus/platform.h27
-rw-r--r--src/vnet/dev/errors.h3
-rw-r--r--src/vnet/dev/port.c3
-rw-r--r--src/vnet/devices/tap/tap.c5
-rw-r--r--src/vnet/devices/tap/tap.h1
-rw-r--r--src/vnet/devices/virtio/FEATURE.yaml1
-rw-r--r--src/vnet/devices/virtio/cli.c4
-rw-r--r--src/vnet/devices/virtio/pci.c52
-rw-r--r--src/vnet/devices/virtio/pci.h82
-rw-r--r--src/vnet/devices/virtio/virtio.api1
-rw-r--r--src/vnet/devices/virtio/virtio.c1
-rw-r--r--src/vnet/devices/virtio/virtio.h1
-rw-r--r--src/vnet/devices/virtio/virtio_api.c8
-rw-r--r--src/vnet/devices/virtio/virtio_std.h96
-rw-r--r--src/vnet/error.c4
-rw-r--r--src/vnet/interface/runtime.c3
-rw-r--r--src/vnet/ip/ip6_input.h66
-rw-r--r--src/vnet/ip/ip_sas.c2
-rw-r--r--src/vnet/ipsec/ipsec_sa.h2
-rw-r--r--src/vnet/ipsec/ipsec_tun_in.c4
-rw-r--r--src/vnet/llc/llc.c4
-rw-r--r--src/vnet/llc/node.c4
-rw-r--r--src/vnet/pg/output.c8
-rw-r--r--src/vnet/pg/pg.h9
-rw-r--r--src/vnet/session/application_namespace.c77
-rw-r--r--src/vnet/session/application_namespace.h4
-rw-r--r--src/vnet/session/session.api60
-rw-r--r--src/vnet/session/session.c48
-rw-r--r--src/vnet/session/session.h50
-rw-r--r--src/vnet/session/session_api.c253
-rw-r--r--src/vnet/session/session_cli.c326
-rw-r--r--src/vnet/session/session_lookup.c356
-rw-r--r--src/vnet/session/session_lookup.h16
-rw-r--r--src/vnet/session/session_rules_table.c313
-rw-r--r--src/vnet/session/session_rules_table.h216
-rw-r--r--src/vnet/session/session_sdl.c768
-rw-r--r--src/vnet/session/session_sdl.h36
-rw-r--r--src/vnet/session/session_table.c15
-rw-r--r--src/vnet/session/session_table.h5
-rw-r--r--src/vnet/session/session_test.c23
-rw-r--r--src/vnet/snap/snap.c5
-rw-r--r--src/vnet/srv6/sr_localsid.c2
-rw-r--r--src/vnet/tcp/tcp.c2
-rw-r--r--src/vnet/tcp/tcp.h29
-rw-r--r--src/vnet/tcp/tcp_cli.c83
-rw-r--r--src/vnet/tcp/tcp_output.c4
-rw-r--r--src/vnet/tls/tls_record.c279
-rw-r--r--src/vnet/tls/tls_record.h250
-rw-r--r--src/vpp-api/python/pyproject.toml3
-rw-r--r--src/vpp/conf/startup.conf5
-rw-r--r--src/vppinfra/CMakeLists.txt12
-rw-r--r--src/vppinfra/cpu.h1
-rw-r--r--src/vppinfra/crypto/aes_cbc.h203
-rw-r--r--src/vppinfra/devicetree.c347
-rw-r--r--src/vppinfra/devicetree.h72
-rw-r--r--src/vppinfra/format.c10
-rw-r--r--src/vppinfra/format.h2
-rw-r--r--src/vppinfra/jsonformat.c13
-rw-r--r--src/vppinfra/linux/mem.c25
-rw-r--r--src/vppinfra/mem.h17
-rw-r--r--src/vppinfra/mem_dlmalloc.c32
-rw-r--r--src/vppinfra/time.c7
-rw-r--r--src/vppinfra/time_range.c9
-rw-r--r--src/vppinfra/unix-misc.c22
-rw-r--r--test/Makefile11
-rw-r--r--test/asf/asfframework.py29
-rw-r--r--test/asf/test_api_trace.py2
-rw-r--r--test/asf/test_http_static.py2
-rw-r--r--test/asf/test_prom.py1
-rw-r--r--test/asf/test_session_sdl.py297
-rw-r--r--test/asf/test_vcl.py34
-rw-r--r--test/asf/vpp_session_sdl.py75
-rw-r--r--test/framework.py3
-rw-r--r--test/patches/scapy-2.4.5/cdp.patch14
-rw-r--r--test/patches/scapy-2.4.5/ikev2.patch22
-rw-r--r--test/patches/scapy-2.4.5/ipsec.patch230
-rw-r--r--test/patches/scapy-2.4.5/ppp.patch45
-rw-r--r--test/patches/scapy-2.4.5/scapy-python312.patch590
-rw-r--r--test/requirements-3.txt463
-rw-r--r--test/requirements.txt4
-rw-r--r--test/template_ipsec.py14
-rw-r--r--test/test_dhcp.py16
-rw-r--r--test/test_dhcp6.py4
-rw-r--r--test/test_ikev2.py75
-rw-r--r--test/test_ip4.py2
-rw-r--r--test/test_ip6_nd_mirror_proxy.py6
-rw-r--r--test/test_ipip.py4
-rw-r--r--test/test_ipsec_tun_if_esp.py2
-rw-r--r--test/test_linux_cp.py11
-rw-r--r--test/test_mtu.py6
-rw-r--r--test/test_nat44_ed_output.py2
-rw-r--r--test/test_pg.py4
-rw-r--r--test/test_pnat.py2
-rw-r--r--test/test_pppoe.py1
-rw-r--r--test/test_span.py3
-rw-r--r--test/test_udp.py14
-rw-r--r--test/test_vlib.py4
-rw-r--r--test/test_vxlan6.py2
-rw-r--r--test/test_wireguard.py14
-rw-r--r--test/vpp_pg_interface.py2
260 files changed, 13520 insertions, 4900 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index fd456c04a6c..c6dbd8bc903 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -460,11 +460,6 @@ M: Dave Barach <vpp@barachs.net>
M: Florin Coras <fcoras@cisco.com>
F: src/plugins/http_static/
-Plugin - builtinurl
-I: builtinurl
-M: Dave Barach <vpp@barachs.net>
-F: src/plugins/builtinurl/
-
Plugin - GTPU
I: gtpu
M: Hongjun Ni <hongjun.ni@intel.com>
@@ -505,10 +500,10 @@ I: memif
M: Damjan Marion <damarion@cisco.com>
F: src/plugins/memif/
-Plugin - Marvell MUSDK device driver
-I: marvell
+Plugin - Marvell Armada device driver
+I: armada
M: Damjan Marion <damarion@cisco.com>
-F: src/plugins/marvell/
+F: src/plugins/dev_armada/
Plugin - performance counter
I: perfmon
diff --git a/Makefile b/Makefile
index ab4b3d8f991..98866e9be5f 100644
--- a/Makefile
+++ b/Makefile
@@ -90,16 +90,20 @@ DEB_DEPENDS += jq # for extracting test summary from .json report (hs-test)
LIBFFI=libffi6 # works on all but 20.04 and debian-testing
ifeq ($(OS_VERSION_ID),24.04)
- DEB_DEPENDS += libssl-dev
- DEB_DEPENDS += llvm clang clang-format-14
+ DEB_DEPENDS += libssl-dev
+ DEB_DEPENDS += llvm clang clang-format-15
# overwrite clang-format version to run `make checkstyle` successfully
- export CLANG_FORMAT_VER=14
- LIBFFI=libffi8
- DEB_DEPENDS += enchant-2 # for docs
+ # TODO: remove once ubuntu 20.04 is deprecated and extras/scripts/checkstyle.sh is upgraded to 15
+ export CLANG_FORMAT_VER=15
+ LIBFFI=libffi8
+ DEB_DEPENDS += enchant-2 # for docs
else ifeq ($(OS_VERSION_ID),22.04)
DEB_DEPENDS += python3-virtualenv
DEB_DEPENDS += libssl-dev
- DEB_DEPENDS += clang clang-format-11
+ DEB_DEPENDS += clang clang-format-15
+ # overwrite clang-format version to run `make checkstyle` successfully
+ # TODO: remove once ubuntu 20.04 is deprecated and extras/scripts/checkstyle.sh is upgraded to 15
+ export CLANG_FORMAT_VER=15
LIBFFI=libffi7
DEB_DEPENDS += enchant-2 # for docs
else ifeq ($(OS_VERSION_ID),20.04)
@@ -108,9 +112,6 @@ else ifeq ($(OS_VERSION_ID),20.04)
DEB_DEPENDS += clang clang-format-11
LIBFFI=libffi7
DEB_DEPENDS += enchant-2 # for docs
-else ifeq ($(OS_VERSION_ID),20.10)
- DEB_DEPENDS += clang clang-format-11
- LIBFFI=libffi8ubuntu1
else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-10)
DEB_DEPENDS += virtualenv
else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-11)
@@ -119,9 +120,10 @@ else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-11)
LIBFFI=libffi7
else ifeq ($(OS_ID)-$(OS_VERSION_ID),debian-12)
DEB_DEPENDS += virtualenv
- DEB_DEPENDS += clang-14 clang-format-14
+ DEB_DEPENDS += clang-14 clang-format-15
# for extras/scripts/checkstyle.sh
- export CLANG_FORMAT_VER=14
+ # TODO: remove once ubuntu 20.04 is deprecated and extras/scripts/checkstyle.sh is upgraded to -15
+ export CLANG_FORMAT_VER=15
LIBFFI=libffi8
else
DEB_DEPENDS += clang-11 clang-format-11
diff --git a/docs/configuration/reference.rst b/docs/configuration/reference.rst
index d288a6d7788..2a7726cccb4 100644
--- a/docs/configuration/reference.rst
+++ b/docs/configuration/reference.rst
@@ -552,7 +552,9 @@ 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**.
+If this is set to zero, no buffers are allocated for this domain.
+
+By default, the value configured in **buffers-per-numa** is used.
.. code-block:: console
diff --git a/docs/developer/plugins/dev_armada.rst b/docs/developer/plugins/dev_armada.rst
new file mode 120000
index 00000000000..a545313ec9c
--- /dev/null
+++ b/docs/developer/plugins/dev_armada.rst
@@ -0,0 +1 @@
+../../../src/plugins/dev_armada/README.rst \ No newline at end of file
diff --git a/docs/developer/plugins/index.rst b/docs/developer/plugins/index.rst
index c9081a8caaf..393eefec535 100644
--- a/docs/developer/plugins/index.rst
+++ b/docs/developer/plugins/index.rst
@@ -19,9 +19,9 @@ For more on plugins please refer to :ref:`add_plugin`.
quic
cnat
+ dev_armada
lcp
srv6/index
- marvell
lldp
nat64
nat44_ei_ha
diff --git a/docs/developer/plugins/marvell.rst b/docs/developer/plugins/marvell.rst
deleted file mode 120000
index 28f0cd0f664..00000000000
--- a/docs/developer/plugins/marvell.rst
+++ /dev/null
@@ -1 +0,0 @@
-../../../src/plugins/marvell/README.rst \ No newline at end of file
diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt
index f90ffa89216..8de7bf4ee24 100644
--- a/docs/spelling_wordlist.txt
+++ b/docs/spelling_wordlist.txt
@@ -805,6 +805,7 @@ operationalize
Optimisations
optimised
os
+osi
outacl
packagecloud
papi
@@ -1003,6 +1004,7 @@ screenshot
scrollbar
scrollbars
sctp
+sdl
sealert
seatbelt
seg
diff --git a/docs/usecases/webapp.rst b/docs/usecases/webapp.rst
index f76fd5b6353..43e600467c5 100644
--- a/docs/usecases/webapp.rst
+++ b/docs/usecases/webapp.rst
@@ -19,8 +19,7 @@ why returning data in .json format tends to work out pretty well.
::
static int
- handle_get_status (http_builtin_method_type_t reqtype,
- u8 * request, http_session_t * hs)
+ handle_get_status (hss_url_handler_args_t *args)
{
my_main_t *mm = &my_main;
u8 *s = 0;
@@ -34,11 +33,11 @@ why returning data in .json format tends to work out pretty well.
s = format (s, "}}");
/* And tell the static server plugin how to send the results */
- hs->data = s;
- hs->data_offset = 0;
- hs->cache_pool_index = ~0;
- hs->free_data = 1; /* free s when done with it, in the framework */
- return 0;
+ args->data = s;
+ args->data_len = vec_len (s);
+ args->ct = HTTP_CONTENT_APP_JSON;
+ args->free_vec_data = 1; /* free s when done with it, in the framework */
+ return HSS_URL_HANDLER_OK;
}
Words to the Wise: Chrome has a very nice set of debugging tools. Select
@@ -53,7 +52,7 @@ considerable amount of time debugging .json bugs.
Step 2: Register URL handlers with the server
---------------------------------------------
-Call http_static_server_register_builtin_handler() as shown. It’s likely
+Call ``hss_register_url_handler`` as shown. It’s likely
but not guaranteed that the static server plugin will be available.
::
@@ -65,7 +64,7 @@ but not guaranteed that the static server plugin will be available.
/* Look up the builtin URL registration handler */
fp = vlib_get_plugin_symbol ("http_static_plugin.so",
- "http_static_server_register_builtin_handler");
+ "hss_register_url_handler");
if (fp == 0)
{
@@ -259,7 +258,7 @@ above:
::
- http static server www-root /myhugosite/public uri tcp://0.0.0.0/2345 cache-size 5m fifo-size 8192
+ http static server url-handlers www-root /myhugosite/public uri tcp://0.0.0.0/2345 cache-size 5m fifo-size 8192
The www-root must be specified, and must correctly name the compiled
hugo site root. If your Hugo site is located at /myhugosite, specify
diff --git a/extras/configs/http/setup.http b/extras/configs/http/setup.http
index 78b7a2f19e8..c4d4d1e6b70 100644
--- a/extras/configs/http/setup.http
+++ b/extras/configs/http/setup.http
@@ -3,5 +3,4 @@ create tap host-if-name lstack host-ip4-addr 192.168.10.2/24
set int ip address tap0 192.168.10.1/24
set int state tap0 up
-http static server www-root <path> uri tcp://0.0.0.0/1234 cache-size 10m fifo-size 2048
-builtinurl enable
+http static server url-handlers www-root <path> uri tcp://0.0.0.0/1234 cache-size 10m fifo-size 2048
diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile
index 033d16bd48f..2a501580e53 100644
--- a/extras/hs-test/Makefile
+++ b/extras/hs-test/Makefile
@@ -62,6 +62,7 @@ help:
@echo "Make targets:"
@echo " test - run tests"
@echo " test-debug - run tests (vpp debug image)"
+ @echo " test-leak - run memory leak tests (vpp debug image)"
@echo " build - build test infra"
@echo " build-cov - coverage build of VPP and Docker images"
@echo " build-debug - build test infra (vpp debug image)"
@@ -118,30 +119,30 @@ build-vpp-gcov:
.PHONY: test
test: .deps.ok .build.ok
- @# '-' ignores the exit status, it is set in compress.sh
- @# necessary so gmake won't skip executing the bash script
- @-bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
+ @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
--unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \
- --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --cpu0=$(CPU0)
- @bash ./script/compress.sh
+ --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --cpu0=$(CPU0); \
+ ./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 ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
+ @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
--unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \
--vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --debug_build=true \
- --cpu0=$(CPU0)
- @bash ./script/compress.sh
+ --cpu0=$(CPU0); \
+ ./script/compress.sh $$?
.PHONY: test-cov
test-cov: .deps.ok .build.cov.ok
- @-bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
+ @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \
--unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST-HS) --cpus=$(CPUS) \
- --vppsrc=$(VPPSRC) --cpu0=$(CPU0)
- @$(MAKE) -C ../.. test-cov-post HS_TEST=1
- @bash ./script/compress.sh
+ --vppsrc=$(VPPSRC) --cpu0=$(CPU0); \
+ ./script/compress.sh $$?
+
+.PHONY: test-leak
+test-leak: .deps.ok .build_debug.ok
+ @bash ./hs_test.sh --test=$(TEST) --debug_build=true --leak_check=true --vppsrc=$(VPPSRC)
.PHONY: build-go
build-go:
diff --git a/extras/hs-test/README.rst b/extras/hs-test/README.rst
index 7841211e3ab..8a49ac6e7e2 100644
--- a/extras/hs-test/README.rst
+++ b/extras/hs-test/README.rst
@@ -307,8 +307,52 @@ It is possible to debug VPP by attaching ``gdb`` before test execution by adding
If a test consists of more VPP instances then this is done for each of them.
+**Memory leak testing**
-**Eternal dependencies**
+It is possible to use VPP memory traces to diagnose if and where memory leaks happen by comparing of two traces at different point in time.
+You can do it by test like following:
+
+::
+
+ func MemLeakTest(s *NoTopoSuite) {
+ s.SkipUnlessLeakCheck() // test is excluded from usual test run
+ vpp := s.GetContainerByName("vpp").VppInstance
+ /* do your configuration here */
+ vpp.Disconnect() // no goVPP less noise
+ vpp.EnableMemoryTrace() // enable memory traces
+ traces1, err := vpp.GetMemoryTrace() // get first sample
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.Vppctl("test mem-leak") // execute some action
+ traces2, err := vpp.GetMemoryTrace() // get second sample
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.MemLeakCheck(traces1, traces2) // compare samples and generate report
+ }
+
+To get your memory leak report run following command:
+
+::
+
+ $ make test-leak TEST=MemLeakTest
+ ...
+ NoTopoSuiteSolo mem_leak_test.go/MemLeakTest [SOLO]
+ /home/matus/vpp/extras/hs-test/infra/suite_no_topo.go:113
+
+ Report Entries >>
+
+ SUMMARY: 112 byte(s) leaked in 1 allocation(s)
+ - /home/matus/vpp/extras/hs-test/infra/vppinstance.go:624 @ 07/19/24 15:53:33.539
+
+ leak of 112 byte(s) in 1 allocation(s) from:
+ #0 clib_mem_heap_alloc_aligned + 0x31
+ #1 _vec_alloc_internal + 0x113
+ #2 _vec_validate + 0x81
+ #3 leak_memory_fn + 0x4f
+ #4 0x7fc167815ac3
+ #5 0x7fc1678a7850
+ << Report Entries
+ ------------------------------
+
+**External dependencies**
* Linux tools ``ip``, ``brctl``
* Standalone programs ``wget``, ``iperf3`` - since these are downloaded when Docker image is made,
diff --git a/extras/hs-test/docker/Dockerfile.build b/extras/hs-test/docker/Dockerfile.build
deleted file mode 100644
index 8b2652e93fc..00000000000
--- a/extras/hs-test/docker/Dockerfile.build
+++ /dev/null
@@ -1,8 +0,0 @@
-ARG UBUNTU_VERSION
-
-FROM ubuntu:${UBUNTU_VERSION}
-
-RUN apt-get update \
- && apt-get install -y gcc git make autoconf libtool pkg-config cmake ninja-build golang \
- && rm -rf /var/lib/apt/lists/*
-
diff --git a/extras/hs-test/docker/Dockerfile.curl b/extras/hs-test/docker/Dockerfile.curl
index 81d15e86c82..fe9b4d917c7 100644
--- a/extras/hs-test/docker/Dockerfile.curl
+++ b/extras/hs-test/docker/Dockerfile.curl
@@ -1,6 +1,13 @@
-FROM hs-test/build
+ARG UBUNTU_VERSION
+
+FROM ubuntu:${UBUNTU_VERSION}
+
+RUN apt-get update \
+ && apt-get install -y gcc git make autoconf libtool pkg-config cmake ninja-build golang \
+ && rm -rf /var/lib/apt/lists/*
COPY script/build_curl.sh /build_curl.sh
+RUN fallocate -l 10MB /tmp/testFile
RUN apt-get update && apt-get install wget
RUN /build_curl.sh
diff --git a/extras/hs-test/docker/Dockerfile.nginx-http3 b/extras/hs-test/docker/Dockerfile.nginx-http3
index 5d66a2528a6..8b2f8406d38 100644
--- a/extras/hs-test/docker/Dockerfile.nginx-http3
+++ b/extras/hs-test/docker/Dockerfile.nginx-http3
@@ -1,4 +1,10 @@
-FROM hs-test/build
+ARG UBUNTU_VERSION
+
+FROM ubuntu:${UBUNTU_VERSION}
+
+RUN apt-get update \
+ && apt-get install -y gcc git make autoconf libtool pkg-config cmake ninja-build golang \
+ && rm -rf /var/lib/apt/lists/*
COPY script/build_boringssl.sh /build_boringssl.sh
RUN git clone https://boringssl.googlesource.com/boringssl
diff --git a/extras/hs-test/docker/Dockerfile.nginx-server b/extras/hs-test/docker/Dockerfile.nginx-server
index 1971158131b..ecb8f590f89 100644
--- a/extras/hs-test/docker/Dockerfile.nginx-server
+++ b/extras/hs-test/docker/Dockerfile.nginx-server
@@ -7,6 +7,10 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
COPY resources/nginx/nginx_server_mirroring.conf /nginx.conf
+COPY script/nginx_server_entrypoint.sh /usr/bin/nginx_server_entrypoint.sh
+COPY resources/nginx/html/index.html /usr/share/nginx/index.html
+RUN fallocate -l 10MB /usr/share/nginx/httpTestFile
+RUN mkdir /usr/share/nginx/upload && chmod 777 /usr/share/nginx/upload
-ENTRYPOINT ["nginx", "-c", "/nginx.conf"]
+ENTRYPOINT ["nginx_server_entrypoint.sh"]
diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp
index f87ee30c332..82a1a1a73d3 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 libunwind-dev \
+ vim gdb libunwind-dev redis redis-tools iperf3 \
&& rm -rf /var/lib/apt/lists/*
ENV DIR=vpp-data/lib/vpp_plugins
diff --git a/extras/hs-test/go.mod b/extras/hs-test/go.mod
index f2659a7e2f3..01cb9000bdc 100644
--- a/extras/hs-test/go.mod
+++ b/extras/hs-test/go.mod
@@ -1,54 +1,67 @@
module fd.io/hs-test
-go 1.21
+go 1.22.5
require (
- github.com/docker/docker v27.0.3+incompatible
+ github.com/cilium/cilium v1.15.7
+ github.com/docker/docker v27.1.1+incompatible
github.com/docker/go-units v0.5.0
github.com/edwarnicke/exechelper v1.0.3
+ github.com/onsi/ginkgo/v2 v2.17.2
+ github.com/onsi/gomega v1.33.1
+ github.com/sirupsen/logrus v1.9.3
go.fd.io/govpp v0.10.0
gopkg.in/yaml.v3 v3.0.1
)
require (
- github.com/Microsoft/go-winio v0.4.14 // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
- github.com/docker/go-connections v0.5.0 // indirect
+ github.com/docker/go-connections v0.4.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
+ github.com/go-openapi/errors v0.22.0 // indirect
+ github.com/go-openapi/strfmt v0.23.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
+ github.com/go-openapi/validate v0.24.0 // indirect
+ github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
- github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
+ github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
+ github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
- github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
- github.com/opencontainers/image-spec v1.1.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
+ github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect
+ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/sasha-s/go-deadlock v0.3.1 // indirect
+ github.com/spf13/cobra v1.8.1 // indirect
+ github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect
+ github.com/spf13/viper v1.19.0 // indirect
+ github.com/vishvananda/netns v0.0.4 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect
+ golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.26.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+ golang.org/x/tools v0.22.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
- gotest.tools/v3 v3.5.1 // indirect
-)
-
-require (
- github.com/fsnotify/fsnotify v1.7.0 // indirect
- github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
- github.com/onsi/ginkgo/v2 v2.16.0
- github.com/onsi/gomega v1.32.0
- github.com/pkg/errors v0.9.1 // indirect
- github.com/sirupsen/logrus v1.9.3
- github.com/vishvananda/netns v0.0.4 // indirect
- golang.org/x/sys v0.21.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ gotest.tools/v3 v3.5.1 // indirect
+ k8s.io/apimachinery v0.30.2 // indirect
+ k8s.io/client-go v0.30.2 // indirect
+ k8s.io/klog/v2 v2.120.1 // indirect
+ k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
)
diff --git a/extras/hs-test/go.sum b/extras/hs-test/go.sum
index 6444f382883..fb555ad7abf 100644
--- a/extras/hs-test/go.sum
+++ b/extras/hs-test/go.sum
@@ -1,23 +1,30 @@
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/checkmate v1.0.3 h1:CQC5eOmlAZeEjPrVZY3ZwEBH64lHlx9mXYdUehEwI5w=
+github.com/cilium/checkmate v1.0.3/go.mod h1:KiBTasf39/F2hf2yAmHw21YFl3hcEyP4Yk6filxc12A=
+github.com/cilium/cilium v1.15.7 h1:7LwGfAW/fR/VFcm6zlESjE2Ut5vJWe+kdWq3RNJrNRc=
+github.com/cilium/cilium v1.15.7/go.mod h1:6Ml8eeyWjMJKDeadutWhn5NibMps0H+yLOgfKBoHTUs=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
-github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
-github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
+github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/edwarnicke/exechelper v1.0.3 h1:OY2ocGAITTqnEDvZk0dRQSeMIQvyH0SyL/4ncz+5GeQ=
@@ -31,71 +38,147 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
+github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
+github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
+github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
+github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
+github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
+github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
+github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
+github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
+github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
-github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
+github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
-github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
+github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
-github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
+github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
+github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe h1:ewr1srjRCmcQogPQ/NCx6XCk6LGVmsVCc9Y3vvPZj+Y=
+github.com/lunixbochs/struc v0.0.0-20200521075829-a4cb8d33dbbe/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM=
-github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
-github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
-github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
+github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
+github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
+github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
-github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
+github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ=
+github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
+github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
+github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
+github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
+github.com/shirou/gopsutil/v3 v3.23.2 h1:PAWSuiAszn7IhPMBtXsbSCafej7PqUOvY6YywlQUExU=
+github.com/shirou/gopsutil/v3 v3.23.2/go.mod h1:gv0aQw33GLo3pG8SiWKiQrbDzbRY1K80RyZJ7V4Th1M=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace h1:9PNP1jnUjRhfmGMlkXHjYPishpcw4jpSt/V/xYY3FMA=
+github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
+github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
+github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
+github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
+github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
+github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21 h1:tcHUxOT8j/R+0S+A1j8D2InqguXFNxAiij+8QFOlX7Y=
+github.com/vishvananda/netlink v1.2.1-beta.2.0.20240524165444-4d4ba1473f21/go.mod h1:whJevzBpTrid75eZy99s3DqCmy05NfibNaF2Ol5Ox5A=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
+github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.fd.io/govpp v0.10.0 h1:lL93SbqOILjON2pMvazrlHRekGYTRy0Qmj57RuAkxR0=
go.fd.io/govpp v0.10.0/go.mod h1:5m3bZM9ck+2EGC2O3ASmSSJAaoouyOlVWtiwj5BdCv0=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0=
+go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
+go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
@@ -110,9 +193,15 @@ go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
+go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
+golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -124,13 +213,12 @@ golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
@@ -144,12 +232,13 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
+golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
@@ -161,9 +250,19 @@ google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWn
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
+k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
+k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
+k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
+k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
+k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
diff --git a/extras/hs-test/hs_test.sh b/extras/hs-test/hs_test.sh
index 803b8f717da..85c0dd72705 100644
--- a/extras/hs-test/hs_test.sh
+++ b/extras/hs-test/hs_test.sh
@@ -7,8 +7,10 @@ single_test=0
persist_set=0
unconfigure_set=0
debug_set=0
+leak_check_set=0
debug_build=
ginkgo_args=
+tc_name=
for i in "$@"
do
@@ -74,6 +76,13 @@ case "${i}" in
args="$args -cpu0"
fi
;;
+ --leak_check=*)
+ leak_check="${i#*=}"
+ if [ "$leak_check" = "true" ]; then
+ args="$args -leak_check"
+ leak_check_set=1
+ fi
+ ;;
esac
done
@@ -97,9 +106,42 @@ if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then
exit 1
fi
+if [ $leak_check_set -eq 1 ]; then
+ if [ $single_test -eq 0 ]; then
+ echo "a single test has to be specified when leak_check is set"
+ exit 1
+ fi
+ ginkgo_args="--focus $tc_name"
+ sudo -E go run github.com/onsi/ginkgo/v2/ginkgo $ginkgo_args -- $args
+ exit 0
+fi
+
+if [ -n "${BUILD_NUMBER}" ]; then
+ ginkgo_args="$ginkgo_args --no-color"
+fi
+
mkdir -p summary
# shellcheck disable=SC2086
-sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --no-color --trace --json-report=summary/report.json $ginkgo_args -- $args
+sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --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.FailureNodeLocation.FileName)\nMessage:\n\(.Failure.Message)\n Full Stack Trace:\n\(.Failure.Location.FullStackTrace)\n"' summary/report.json > summary/failed-summary.log \
+if [ $? != 0 ]; then
+ jq -r '.[0] | .SpecReports[] | select((.State == "failed") or (.State == "timedout") or (.State == "panicked")) | select(.Failure != null) |
+"TestName:
+ \(.LeafNodeText)
+Suite:
+ \(.Failure.FailureNodeLocation.FileName)
+Message:\n"
++(if .ReportEntries? then .ReportEntries[] | select(.Name == "VPP Backtrace") |
+"\tVPP crashed
+Full Back Trace:
+\(.Value.Representation | ltrimstr("{{red}}") | rtrimstr("{{/}}"))" else
+ "\(.Failure.Message)"
+ + (if .Failure.Message == "A spec timeout occurred" then "\n" else
+"\nFull Stack Trace:
+\(.Failure.Location.FullStackTrace)\n" end) end)' summary/report.json > summary/failed-summary.log \
&& echo "Summary generated -> summary/failed-summary.log"
+else
+ if [ -e "summary/failed-summary.log" ]; then
+ rm summary/failed-summary.log
+ fi
+fi
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go
index a5694bfb54b..bfd2d34483c 100644
--- a/extras/hs-test/http_test.go
+++ b/extras/hs-test/http_test.go
@@ -3,9 +3,16 @@ package main
import (
"bytes"
"fmt"
+ "github.com/onsi/gomega/ghttp"
"github.com/onsi/gomega/gmeasure"
"io"
+ "math/rand"
+ "net"
"net/http"
+ "net/http/httptrace"
+ "os"
+ "strconv"
+ "sync"
"time"
. "fd.io/hs-test/infra"
@@ -14,15 +21,18 @@ import (
func init() {
RegisterVethTests(HttpCliTest, HttpCliConnectErrorTest)
- RegisterNoTopoTests(HeaderServerTest,
+ RegisterSoloVethTests(HttpClientGetMemLeakTest)
+ RegisterNoTopoTests(HeaderServerTest, HttpPersistentConnectionTest, HttpPipeliningTest,
HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest,
HttpCliBadRequestTest, HttpStaticBuildInUrlGetIfStatsTest, HttpStaticBuildInUrlPostIfStatsTest,
HttpInvalidRequestLineTest, HttpMethodNotImplementedTest, HttpInvalidHeadersTest,
HttpContentLengthTest, HttpStaticBuildInUrlGetIfListTest, HttpStaticBuildInUrlGetVersionTest,
HttpStaticMacTimeTest, HttpStaticBuildInUrlGetVersionVerboseTest, HttpVersionNotSupportedTest,
HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathTraversalTest, HttpUriDecodeTest,
- HttpHeadersTest)
- RegisterNoTopoSoloTests(HttpStaticPromTest, HttpTpsTest, HttpTpsInterruptModeTest)
+ HttpHeadersTest, HttpStaticFileHandlerTest, HttpStaticFileHandlerDefaultMaxAgeTest, HttpClientTest, HttpClientErrRespTest, HttpClientPostFormTest,
+ HttpClientPostFileTest, HttpClientPostFilePtrTest, AuthorityFormTargetTest, HttpRequestLineTest)
+ RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
+ PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest)
}
const wwwRootPath = "/tmp/www_root"
@@ -37,24 +47,159 @@ func httpDownloadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data in
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.AssertHttpStatus(resp, 200)
_, err = io.ReadAll(resp.Body)
+ s.AssertNil(err, fmt.Sprint(err))
duration := time.Since(t)
experiment.RecordValue("Download Speed", (float64(resp.ContentLength)/1024/1024)/duration.Seconds(), gmeasure.Units("MB/s"), gmeasure.Precision(2))
}
-func HttpTpsInterruptModeTest(s *NoTopoSuite) {
- HttpTpsTest(s)
+func HttpGetTpsInterruptModeTest(s *NoTopoSuite) {
+ HttpGetTpsTest(s)
}
-func HttpTpsTest(s *NoTopoSuite) {
+func HttpGetTpsTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
url := "http://" + serverAddress + ":8080/test_file_10M"
vpp.Vppctl("http tps uri tcp://0.0.0.0/8080")
- s.RunBenchmark("HTTP tps 10M", 10, 0, httpDownloadBenchmark, url)
+ s.RunBenchmark("HTTP tps download 10M", 10, 0, httpDownloadBenchmark, url)
+}
+
+func httpUploadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data interface{}) {
+ url, isValid := data.(string)
+ s.AssertEqual(true, isValid)
+ body := make([]byte, 10485760)
+ _, err := rand.Read(body)
+ client := NewHttpClient()
+ req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
+ s.AssertNil(err, fmt.Sprint(err))
+ t := time.Now()
+ resp, err := client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.AssertHttpStatus(resp, 200)
+ _, err = io.ReadAll(resp.Body)
+ s.AssertNil(err, fmt.Sprint(err))
+ duration := time.Since(t)
+ experiment.RecordValue("Upload Speed", (float64(req.ContentLength)/1024/1024)/duration.Seconds(), gmeasure.Units("MB/s"), gmeasure.Precision(2))
+}
+
+func HttpPostTpsInterruptModeTest(s *NoTopoSuite) {
+ HttpPostTpsTest(s)
+}
+
+func HttpPostTpsTest(s *NoTopoSuite) {
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ url := "http://" + serverAddress + ":8080/test_file_10M"
+
+ vpp.Vppctl("http tps uri tcp://0.0.0.0/8080")
+
+ s.RunBenchmark("HTTP tps upload 10M", 10, 0, httpUploadBenchmark, url)
+}
+
+func HttpPersistentConnectionTest(s *NoTopoSuite) {
+ // testing url handler app do not support multi-thread
+ s.SkipIfMultiWorker()
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
+ s.Log(vpp.Vppctl("test-url-handler enable"))
+
+ transport := http.DefaultTransport
+ transport.(*http.Transport).Proxy = nil
+ transport.(*http.Transport).DisableKeepAlives = false
+ client := &http.Client{
+ Transport: transport,
+ Timeout: time.Second * 30,
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ }}
+
+ body := []byte("{\"sandwich\": {\"spam\": 2, \"eggs\": 1}}")
+ req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test3", bytes.NewBuffer(body))
+ s.AssertNil(err, fmt.Sprint(err))
+ resp, err := client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertEqual(false, resp.Close)
+ s.AssertHttpContentLength(resp, int64(0))
+ o1 := vpp.Vppctl("show session verbose proto http state ready")
+ s.Log(o1)
+ s.AssertContains(o1, "ESTABLISHED")
+
+ req, err = http.NewRequest("GET", "http://"+serverAddress+":80/test1", nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ clientTrace := &httptrace.ClientTrace{
+ GotConn: func(info httptrace.GotConnInfo) {
+ s.AssertEqual(true, info.Reused, "connection not reused")
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), clientTrace))
+ resp, err = client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertEqual(false, resp.Close)
+ s.AssertHttpBody(resp, "hello")
+ o2 := vpp.Vppctl("show session verbose proto http state ready")
+ s.Log(o2)
+ s.AssertContains(o2, "ESTABLISHED")
+ s.AssertEqual(o1, o2)
+
+ req, err = http.NewRequest("GET", "http://"+serverAddress+":80/test2", nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), clientTrace))
+ resp, err = client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertEqual(false, resp.Close)
+ s.AssertHttpBody(resp, "some data")
+ o2 = vpp.Vppctl("show session verbose proto http state ready")
+ s.Log(o2)
+ s.AssertContains(o2, "ESTABLISHED")
+ s.AssertEqual(o1, o2)
+
+}
+
+func HttpPipeliningTest(s *NoTopoSuite) {
+ // testing url handler app do not support multi-thread
+ s.SkipIfMultiWorker()
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
+ s.Log(vpp.Vppctl("test-url-handler enable"))
+
+ req1 := "GET /test_delayed HTTP/1.1\r\nHost:" + serverAddress + ":80\r\nUser-Agent:test\r\n\r\n"
+ req2 := "GET /test1 HTTP/1.1\r\nHost:" + serverAddress + ":80\r\nUser-Agent:test\r\n\r\n"
+
+ conn, err := net.DialTimeout("tcp", serverAddress+":80", time.Second*30)
+ s.AssertNil(err, fmt.Sprint(err))
+ defer conn.Close()
+ err = conn.SetDeadline(time.Now().Add(time.Second * 15))
+ s.AssertNil(err, fmt.Sprint(err))
+ n, err := conn.Write([]byte(req1))
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertEqual(n, len([]rune(req1)))
+ // send second request a bit later so first is already in progress
+ time.Sleep(500 * time.Millisecond)
+ n, err = conn.Write([]byte(req2))
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertEqual(n, len([]rune(req2)))
+ reply := make([]byte, 1024)
+ n, err = conn.Read(reply)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(string(reply))
+ s.AssertContains(string(reply), "delayed data", "first request response not received")
+ s.AssertNotContains(string(reply), "hello", "second request response received")
+ // make sure response for second request is not received later
+ _, err = conn.Read(reply)
+ s.AssertMatchError(err, os.ErrDeadlineExceeded, "second request response received")
}
func HttpCliTest(s *VethsSuite) {
@@ -72,11 +217,11 @@ func HttpCliTest(s *VethsSuite) {
s.Log(o)
s.AssertContains(o, "<html>", "<html> not found in the result!")
+ 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"
@@ -88,28 +233,432 @@ func HttpCliConnectErrorTest(s *VethsSuite) {
s.AssertContains(o, "failed to connect")
}
+func HttpClientTest(s *NoTopoSuite) {
+ serverAddress := s.HostAddr()
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress+":80")
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ s.LogHttpReq(true),
+ ghttp.VerifyRequest("GET", "/test"),
+ ghttp.VerifyHeader(http.Header{"User-Agent": []string{"http_cli_client"}}),
+ ghttp.VerifyHeader(http.Header{"Accept": []string{"text/html"}}),
+ ghttp.RespondWith(http.StatusOK, "<html><body><p>Hello</p></body></html>"),
+ ))
+ server.Start()
+ defer server.Close()
+ uri := "http://" + serverAddress + "/80"
+ vpp := s.GetContainerByName("vpp").VppInstance
+ o := vpp.Vppctl("http cli client uri " + uri + " query /test")
+
+ s.Log(o)
+ s.AssertContains(o, "<html>", "<html> not found in the result!")
+ s.AssertContains(o, "</html>", "</html> not found in the result!")
+}
+
+func HttpClientErrRespTest(s *NoTopoSuite) {
+ serverAddress := s.HostAddr()
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress+":80")
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ s.LogHttpReq(true),
+ ghttp.VerifyRequest("GET", "/test"),
+ ghttp.RespondWith(http.StatusNotFound, "404: Not Found"),
+ ))
+ server.Start()
+ defer server.Close()
+ uri := "http://" + serverAddress + "/80"
+ vpp := s.GetContainerByName("vpp").VppInstance
+ o := vpp.Vppctl("http cli client uri " + uri + " query /test")
+
+ s.Log(o)
+ s.AssertContains(o, "404: Not Found", "error not found in the result!")
+}
+
+func HttpClientPostFormTest(s *NoTopoSuite) {
+ serverAddress := s.HostAddr()
+ body := "field1=value1&field2=value2"
+
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress+":80")
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ s.LogHttpReq(true),
+ ghttp.VerifyRequest("POST", "/test"),
+ ghttp.VerifyContentType("application/x-www-form-urlencoded"),
+ ghttp.VerifyBody([]byte(body)),
+ ghttp.RespondWith(http.StatusOK, nil),
+ ))
+ server.Start()
+ defer server.Close()
+
+ uri := "http://" + serverAddress + "/80"
+ vpp := s.GetContainerByName("vpp").VppInstance
+ o := vpp.Vppctl("http post uri " + uri + " target /test data " + body)
+
+ s.Log(o)
+ s.AssertNotContains(o, "error")
+}
+
+func httpClientPostFile(s *NoTopoSuite, usePtr bool, fileSize int) {
+ serverAddress := s.HostAddr()
+ vpp := s.GetContainerByName("vpp").VppInstance
+ fileName := "/tmp/test_file.txt"
+ s.Log(vpp.Container.Exec("fallocate -l " + strconv.Itoa(fileSize) + " " + fileName))
+ s.Log(vpp.Container.Exec("ls -la " + fileName))
+
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress+":80")
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ s.LogHttpReq(false),
+ ghttp.VerifyRequest("POST", "/test"),
+ ghttp.VerifyHeader(http.Header{"Content-Length": []string{strconv.Itoa(fileSize)}}),
+ ghttp.VerifyContentType("application/octet-stream"),
+ ghttp.RespondWith(http.StatusOK, nil),
+ ))
+ server.Start()
+ defer server.Close()
+
+ uri := "http://" + serverAddress + "/80"
+ cmd := "http post uri " + uri + " target /test file " + fileName
+ if usePtr {
+ cmd += " use-ptr"
+ }
+ o := vpp.Vppctl(cmd)
+
+ s.Log(o)
+ s.AssertNotContains(o, "error")
+}
+
+func HttpClientPostFileTest(s *NoTopoSuite) {
+ httpClientPostFile(s, false, 32768)
+}
+
+func HttpClientPostFilePtrTest(s *NoTopoSuite) {
+ httpClientPostFile(s, true, 131072)
+}
+
+func cliTestAuthority(s *NoTopoSuite, authority string) {
+ o := s.GetContainerByName("vpp").VppInstance.Vppctl("test http authority-form " + authority)
+ s.AssertNotContains(o, "error")
+ s.AssertContains(o, authority)
+}
+
+func cliTestAuthorityError(s *NoTopoSuite, authority string) {
+ o := s.GetContainerByName("vpp").VppInstance.Vppctl("test http authority-form " + authority)
+ s.AssertContains(o, "error")
+}
+
+func AuthorityFormTargetTest(s *NoTopoSuite) {
+ cliTestAuthority(s, "10.10.2.45:20")
+ cliTestAuthority(s, "[dead:beef::1234]:443")
+ cliTestAuthorityError(s, "example.com:80")
+ cliTestAuthorityError(s, "10.10.2.45")
+ cliTestAuthorityError(s, "1000.10.2.45:20")
+ cliTestAuthorityError(s, "[xyz0::1234]:443")
+}
+
func HttpStaticPromTest(s *NoTopoSuite) {
- finished := make(chan error, 1)
query := "stats.prom"
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
s.Log(vpp.Vppctl("prom enable"))
time.Sleep(time.Second * 5)
- go func() {
- defer GinkgoRecover()
- s.StartWget(finished, serverAddress, "80", query, "")
- }()
- err := <-finished
- s.AssertNil(err)
+ client := NewHttpClient()
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80/"+query, nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ resp, err := client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.Log(DumpHttpResp(resp, false))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/plain")
+ s.AssertGreaterThan(resp.ContentLength, 0)
+ _, err = io.ReadAll(resp.Body)
+ s.AssertNil(err, fmt.Sprint(err))
+}
+
+func promReq(s *NoTopoSuite, url string) {
+ client := NewHttpClient()
+ req, err := http.NewRequest("GET", url, nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ resp, err := client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ defer resp.Body.Close()
+ s.AssertHttpStatus(resp, 200)
+ _, err = io.ReadAll(resp.Body)
+ s.AssertNil(err, fmt.Sprint(err))
+}
+
+func promReqWg(s *NoTopoSuite, url string, wg *sync.WaitGroup) {
+ defer GinkgoRecover()
+ defer wg.Done()
+ promReq(s, url)
+}
+
+func PromConcurrentConnectionsTest(s *NoTopoSuite) {
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ url := "http://" + serverAddress + ":80/stats.prom"
+
+ s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
+ s.Log(vpp.Vppctl("prom enable"))
+ time.Sleep(time.Second * 5)
+
+ var wg sync.WaitGroup
+ for i := 0; i < 20; i++ {
+ wg.Add(1)
+ go promReqWg(s, url, &wg)
+ }
+ wg.Wait()
+ s.Log(vpp.Vppctl("show session verbose proto http"))
+}
+
+func PromMemLeakTest(s *NoTopoSuite) {
+ s.SkipUnlessLeakCheck()
+
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ url := "http://" + serverAddress + ":80/stats.prom"
+
+ /* no goVPP less noise */
+ vpp.Disconnect()
+
+ s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
+ s.Log(vpp.Vppctl("prom enable"))
+ time.Sleep(time.Second * 3)
+
+ /* warmup request (FIB) */
+ promReq(s, url)
+
+ vpp.EnableMemoryTrace()
+ traces1, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+
+ /* collect stats couple of times */
+ for i := 0; i < 5; i++ {
+ time.Sleep(time.Second * 1)
+ promReq(s, url)
+ }
+
+ /* let's give it some time to clean up sessions */
+ time.Sleep(time.Second * 5)
+
+ traces2, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.MemLeakCheck(traces1, traces2)
+}
+
+func HttpClientGetMemLeakTest(s *VethsSuite) {
+ s.SkipUnlessLeakCheck()
+
+ serverContainer := s.GetContainerByName("server-vpp").VppInstance
+ clientContainer := s.GetContainerByName("client-vpp").VppInstance
+ serverVeth := s.GetInterfaceByName(ServerInterfaceName)
+
+ /* no goVPP less noise */
+ clientContainer.Disconnect()
+
+ serverContainer.Vppctl("http cli server")
+
+ uri := "http://" + serverVeth.Ip4AddressString() + "/80"
+
+ /* warmup request (FIB) */
+ clientContainer.Vppctl("http cli client uri " + uri + " query /show/version")
+
+ /* let's give it some time to clean up sessions, so local port can be reused and we have less noise */
+ time.Sleep(time.Second * 12)
+
+ clientContainer.EnableMemoryTrace()
+ traces1, err := clientContainer.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+
+ clientContainer.Vppctl("http cli client uri " + uri + " query /show/vlib/graph")
+
+ /* let's give it some time to clean up sessions */
+ time.Sleep(time.Second * 12)
+
+ traces2, err := clientContainer.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ clientContainer.MemLeakCheck(traces1, traces2)
+}
+
+func HttpClientPostMemLeakTest(s *NoTopoSuite) {
+ s.SkipUnlessLeakCheck()
+
+ serverAddress := s.HostAddr()
+ body := "field1=value1&field2=value2"
+
+ uri := "http://" + serverAddress + "/80"
+ vpp := s.GetContainerByName("vpp").VppInstance
+
+ /* no goVPP less noise */
+ vpp.Disconnect()
+
+ server := ghttp.NewUnstartedServer()
+ l, err := net.Listen("tcp", serverAddress+":80")
+ s.AssertNil(err, fmt.Sprint(err))
+ server.HTTPTestServer.Listener = l
+ server.AppendHandlers(
+ ghttp.CombineHandlers(
+ ghttp.VerifyRequest("POST", "/test"),
+ ghttp.RespondWith(http.StatusOK, nil),
+ ),
+ ghttp.CombineHandlers(
+ ghttp.VerifyRequest("POST", "/test"),
+ ghttp.RespondWith(http.StatusOK, nil),
+ ),
+ )
+ server.Start()
+ defer server.Close()
+
+ /* warmup request (FIB) */
+ vpp.Vppctl("http post uri " + uri + " target /test data " + body)
+
+ /* let's give it some time to clean up sessions, so local port can be reused and we have less noise */
+ time.Sleep(time.Second * 12)
+
+ vpp.EnableMemoryTrace()
+ traces1, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+
+ vpp.Vppctl("http post uri " + uri + " target /test data " + body)
+
+ /* let's give it some time to clean up sessions */
+ time.Sleep(time.Second * 12)
+
+ traces2, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.MemLeakCheck(traces1, traces2)
+}
+
+func HttpInvalidClientRequestMemLeakTest(s *NoTopoSuite) {
+ s.SkipUnlessLeakCheck()
+
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+
+ /* no goVPP less noise */
+ vpp.Disconnect()
+
+ vpp.Vppctl("http cli server")
+
+ /* warmup request (FIB) */
+ _, err := TcpSendReceive(serverAddress+":80", "GET / HTTP/1.1\r\n")
+ s.AssertNil(err, fmt.Sprint(err))
+
+ /* let's give it some time to clean up sessions, so local port can be reused and we have less noise */
+ time.Sleep(time.Second * 12)
+
+ vpp.EnableMemoryTrace()
+ traces1, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+
+ _, err = TcpSendReceive(serverAddress+":80", "GET / HTTP/1.1\r\n")
+ s.AssertNil(err, fmt.Sprint(err))
+
+ /* let's give it some time to clean up sessions */
+ time.Sleep(time.Second * 12)
+
+ traces2, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.MemLeakCheck(traces1, traces2)
+
+}
+
+func HttpStaticFileHandlerDefaultMaxAgeTest(s *NoTopoSuite) {
+ HttpStaticFileHandlerTestFunction(s, "default")
+}
+
+func HttpStaticFileHandlerTest(s *NoTopoSuite) {
+ HttpStaticFileHandlerTestFunction(s, "123")
+}
+
+func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) {
+ var maxAgeFormatted string
+ if max_age == "default" {
+ maxAgeFormatted = ""
+ max_age = "600"
+ } else {
+ maxAgeFormatted = "max-age " + max_age
+ }
+
+ content := "<html><body><p>Hello</p></body></html>"
+ content2 := "<html><body><p>Page</p></body></html>"
+
+ vpp := s.GetContainerByName("vpp").VppInstance
+ vpp.Container.Exec("mkdir -p " + wwwRootPath)
+ err := vpp.Container.CreateFile(wwwRootPath+"/index.html", content)
+ s.AssertNil(err, fmt.Sprint(err))
+ err = vpp.Container.CreateFile(wwwRootPath+"/page.html", content2)
+ s.AssertNil(err, fmt.Sprint(err))
+ serverAddress := s.VppAddr()
+ s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug cache-size 2m " + maxAgeFormatted))
+
+ client := NewHttpClient()
+ req, err := http.NewRequest("GET", "http://"+serverAddress+":80/index.html", nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ resp, err := client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
+ s.AssertHttpHeaderWithValue(resp, "Cache-Control", "max-age="+max_age)
+ parsedTime, err := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified"))
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertTimeEqualWithinThreshold(parsedTime, time.Now(), time.Minute*5)
+ s.AssertEqual(len(resp.Header.Get("Last-Modified")), 29)
+ s.AssertHttpContentLength(resp, int64(len([]rune(content))))
+ s.AssertHttpBody(resp, content)
+ o := vpp.Vppctl("show http static server cache verbose")
+ s.Log(o)
+ s.AssertContains(o, "index.html")
+ s.AssertNotContains(o, "page.html")
+
+ resp, err = client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
+ s.AssertHttpHeaderWithValue(resp, "Cache-Control", "max-age="+max_age)
+ s.AssertHttpContentLength(resp, int64(len([]rune(content))))
+ s.AssertHttpBody(resp, content)
+
+ req, err = http.NewRequest("GET", "http://"+serverAddress+":80/page.html", nil)
+ s.AssertNil(err, fmt.Sprint(err))
+ resp, err = client.Do(req)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
+ s.AssertHttpHeaderWithValue(resp, "Cache-Control", "max-age="+max_age)
+ s.AssertHttpContentLength(resp, int64(len([]rune(content2))))
+ s.AssertHttpBody(resp, content2)
+ o = vpp.Vppctl("show http static server cache verbose")
+ s.Log(o)
+ s.AssertContains(o, "index.html")
+ s.AssertContains(o, "page.html")
}
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()
+ err := vpp.Container.CreateFile("/tmp/secret_folder/secret_file.txt", "secret")
+ s.AssertNil(err, fmt.Sprint(err))
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug"))
client := NewHttpClient()
@@ -118,14 +667,19 @@ func HttpStaticPathTraversalTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(404, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 404)
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpHeaderNotPresent(resp, "Cache-Control")
+ s.AssertHttpContentLength(resp, int64(0))
}
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()
+ err := vpp.Container.CreateFile(wwwRootPath+"/tmp.aaa/index.html", "<html><body><p>Hello</p></body></html>")
+ s.AssertNil(err, fmt.Sprint(err))
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug"))
client := NewHttpClient()
@@ -134,14 +688,18 @@ func HttpStaticMovedTest(s *NoTopoSuite) {
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"))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 301)
+ s.AssertHttpHeaderWithValue(resp, "Location", "http://"+serverAddress+"/tmp.aaa/index.html")
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpHeaderNotPresent(resp, "Cache-Control")
+ s.AssertHttpContentLength(resp, int64(0))
}
func HttpStaticNotFoundTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
vpp.Container.Exec("mkdir -p " + wwwRootPath)
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug"))
client := NewHttpClient()
@@ -150,12 +708,16 @@ func HttpStaticNotFoundTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(404, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 404)
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpHeaderNotPresent(resp, "Cache-Control")
+ s.AssertHttpContentLength(resp, int64(0))
}
func HttpCliMethodNotAllowedTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
client := NewHttpClient()
@@ -164,14 +726,16 @@ func HttpCliMethodNotAllowedTest(s *NoTopoSuite) {
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"))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 405)
+ s.AssertHttpHeaderWithValue(resp, "Allow", "GET", "server MUST generate an Allow header")
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpContentLength(resp, int64(0))
}
func HttpCliBadRequestTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
client := NewHttpClient()
@@ -180,12 +744,15 @@ func HttpCliBadRequestTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(400, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 400)
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpContentLength(resp, int64(0))
}
func HttpStaticBuildInUrlGetVersionTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
client := NewHttpClient()
@@ -194,7 +761,8 @@ func HttpStaticBuildInUrlGetVersionTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(string(data), "vpp_details")
@@ -203,11 +771,12 @@ func HttpStaticBuildInUrlGetVersionTest(s *NoTopoSuite) {
s.AssertNotContains(string(data), "build_by")
s.AssertNotContains(string(data), "build_host")
s.AssertNotContains(string(data), "build_dir")
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
}
func HttpStaticBuildInUrlGetVersionVerboseTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
client := NewHttpClient()
@@ -216,7 +785,8 @@ func HttpStaticBuildInUrlGetVersionVerboseTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(string(data), "vpp_details")
@@ -225,11 +795,12 @@ func HttpStaticBuildInUrlGetVersionVerboseTest(s *NoTopoSuite) {
s.AssertContains(string(data), "build_by")
s.AssertContains(string(data), "build_host")
s.AssertContains(string(data), "build_dir")
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
}
func HttpStaticBuildInUrlGetIfListTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
client := NewHttpClient()
@@ -238,16 +809,18 @@ func HttpStaticBuildInUrlGetIfListTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(string(data), "interface_list")
- s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).Peer.Name())
+ s.AssertContains(string(data), s.VppIfName())
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
}
func HttpStaticBuildInUrlGetIfStatsTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
client := NewHttpClient()
@@ -256,26 +829,28 @@ func HttpStaticBuildInUrlGetIfStatsTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(string(data), "interface_stats")
s.AssertContains(string(data), "local0")
- s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).Peer.Name())
+ s.AssertContains(string(data), s.VppIfName())
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
}
func validatePostInterfaceStats(s *NoTopoSuite, data string) {
s.AssertContains(data, "interface_stats")
- s.AssertContains(data, s.GetInterfaceByName(TapInterfaceName).Peer.Name())
+ s.AssertContains(data, s.VppIfName())
s.AssertNotContains(data, "error")
s.AssertNotContains(data, "local0")
}
func HttpStaticBuildInUrlPostIfStatsTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
- body := []byte(s.GetInterfaceByName(TapInterfaceName).Peer.Name())
+ body := []byte(s.VppIfName())
client := NewHttpClient()
req, err := http.NewRequest("POST",
@@ -284,17 +859,19 @@ func HttpStaticBuildInUrlPostIfStatsTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
validatePostInterfaceStats(s, string(data))
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
}
func HttpStaticMacTimeTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
- s.Log(vpp.Vppctl("mactime enable-disable " + s.GetInterfaceByName(TapInterfaceName).Peer.Name()))
+ s.Log(vpp.Vppctl("mactime enable-disable " + s.VppIfName()))
client := NewHttpClient()
req, err := http.NewRequest("GET", "http://"+serverAddress+":80/mactime.json", nil)
@@ -302,20 +879,38 @@ func HttpStaticMacTimeTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(string(data), "mactime")
- s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).Ip4AddressString())
+ s.AssertContains(string(data), s.HostAddr())
s.AssertContains(string(data), s.GetInterfaceByName(TapInterfaceName).HwAddress.String())
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "application/json")
+ parsedTime, err := time.Parse(time.RFC1123, resp.Header.Get("Date"))
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertTimeEqualWithinThreshold(parsedTime, time.Now(), time.Minute*5)
+ s.AssertEqual(len(resp.Header.Get("Date")), 29)
}
func HttpInvalidRequestLineTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
- resp, err := TcpSendReceive(serverAddress+":80", "GET / HTTP/1.1")
+ resp, err := TcpSendReceive(serverAddress+":80", " GET / HTTP/1.1")
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid request line start not allowed")
+
+ resp, err = TcpSendReceive(serverAddress+":80", "\rGET / HTTP/1.1")
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid request line start not allowed")
+
+ resp, err = TcpSendReceive(serverAddress+":80", "\nGET / HTTP/1.1")
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid request line start not allowed")
+
+ resp, err = TcpSendReceive(serverAddress+":80", "GET / HTTP/1.1")
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "invalid framing not allowed")
@@ -344,9 +939,20 @@ func HttpInvalidRequestLineTest(s *NoTopoSuite) {
s.AssertContains(resp, "HTTP/1.1 400 Bad Request", "'HTTP1.1' invalid http version not allowed")
}
+func HttpRequestLineTest(s *NoTopoSuite) {
+ vpp := s.GetContainerByName("vpp").VppInstance
+ serverAddress := s.VppAddr()
+ vpp.Vppctl("http cli server")
+
+ resp, err := TcpSendReceive(serverAddress+":80", "\r\nGET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser-Agent:test\r\n\r\n")
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertContains(resp, "HTTP/1.1 200 OK")
+ s.AssertContains(resp, "<html>", "html content not found")
+}
+
func HttpInvalidTargetSyntaxTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
resp, err := TcpSendReceive(serverAddress+":80", "GET /interface|stats.json HTTP/1.1\r\n\r\n")
@@ -394,7 +1000,7 @@ func HttpInvalidTargetSyntaxTest(s *NoTopoSuite) {
func HttpInvalidContentLengthTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
resp, err := TcpSendReceive(serverAddress+":80", "GET /show/version HTTP/1.1\r\nContent-Length:\r\n\r\n")
@@ -413,9 +1019,9 @@ func HttpInvalidContentLengthTest(s *NoTopoSuite) {
func HttpContentLengthTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug"))
- ifName := s.GetInterfaceByName(TapInterfaceName).Peer.Name()
+ ifName := s.VppIfName()
resp, err := TcpSendReceive(serverAddress+":80",
"POST /interface_stats.json HTTP/1.1\r\nContent-Length:4\r\n\r\n"+ifName)
@@ -435,7 +1041,7 @@ func HttpContentLengthTest(s *NoTopoSuite) {
func HttpMethodNotImplementedTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
client := NewHttpClient()
@@ -444,12 +1050,15 @@ func HttpMethodNotImplementedTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(501, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 501)
+ s.AssertHttpHeaderNotPresent(resp, "Content-Type")
+ s.AssertHttpContentLength(resp, int64(0))
}
func HttpVersionNotSupportedTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
resp, err := TcpSendReceive(serverAddress+":80", "GET / HTTP/2\r\n\r\n")
@@ -459,7 +1068,7 @@ func HttpVersionNotSupportedTest(s *NoTopoSuite) {
func HttpUriDecodeTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
client := NewHttpClient()
@@ -468,17 +1077,18 @@ func HttpUriDecodeTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual(200, resp.StatusCode)
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
data, err := io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
- s.Log(string(data))
s.AssertNotContains(string(data), "unknown input")
s.AssertContains(string(data), "Compiler")
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
}
func HttpHeadersTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
resp, err := TcpSendReceive(
@@ -486,13 +1096,13 @@ func HttpHeadersTest(s *NoTopoSuite) {
"GET /show/version HTTP/1.1\r\nHost:"+serverAddress+":80\r\nUser-Agent:test\r\nAccept:text/xml\r\nAccept:\ttext/plain\t \r\nAccept:text/html\r\n\r\n")
s.AssertNil(err, fmt.Sprint(err))
s.AssertContains(resp, "HTTP/1.1 200 OK")
- s.AssertContains(resp, "Content-Type: text / plain")
+ s.AssertContains(resp, "Content-Type: text/plain")
s.AssertNotContains(resp, "<html>", "html content received instead of plain text")
}
func HttpInvalidHeadersTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
resp, err := TcpSendReceive(serverAddress+":80", "GET /show/version HTTP/1.1\r\nUser-Agent: test\r\n")
@@ -530,7 +1140,7 @@ func HttpInvalidHeadersTest(s *NoTopoSuite) {
func HeaderServerTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp.Vppctl("http cli server")
client := NewHttpClient()
@@ -539,5 +1149,8 @@ func HeaderServerTest(s *NoTopoSuite) {
resp, err := client.Do(req)
s.AssertNil(err, fmt.Sprint(err))
defer resp.Body.Close()
- s.AssertEqual("http_cli_server", resp.Header.Get("Server"))
+ s.Log(DumpHttpResp(resp, true))
+ s.AssertHttpStatus(resp, 200)
+ s.AssertHttpHeaderWithValue(resp, "Server", "http_cli_server")
+ s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html")
}
diff --git a/extras/hs-test/infra/container.go b/extras/hs-test/infra/container.go
index d71761b2920..974d1547c03 100644
--- a/extras/hs-test/infra/container.go
+++ b/extras/hs-test/infra/container.go
@@ -4,18 +4,21 @@ import (
"bytes"
"context"
"fmt"
+ "github.com/docker/go-units"
"os"
"os/exec"
+ "regexp"
"slices"
"strconv"
"strings"
"text/template"
"time"
+ "github.com/cilium/cilium/pkg/sysctl"
containerTypes "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/pkg/stdcopy"
- "github.com/docker/go-units"
"github.com/edwarnicke/exechelper"
. "github.com/onsi/ginkgo/v2"
)
@@ -179,9 +182,10 @@ func (c *Container) Create() error {
resp, err := c.Suite.Docker.ContainerCreate(
c.ctx,
&containerTypes.Config{
- Image: c.Image,
- Env: c.getEnvVars(),
- Cmd: strings.Split(c.ExtraRunningArgs, " "),
+ Hostname: c.Name,
+ Image: c.Image,
+ Env: c.getEnvVars(),
+ Cmd: strings.Split(c.ExtraRunningArgs, " "),
},
&containerTypes.HostConfig{
Resources: containerTypes.Resources{
@@ -216,7 +220,9 @@ func (c *Container) allocateCpus() {
// Starts a container
func (c *Container) Start() error {
var err error
- for nTries := 0; nTries < 5; nTries++ {
+ var nTries int
+
+ for nTries = 0; nTries < 5; nTries++ {
err = c.Suite.Docker.ContainerStart(c.ctx, c.ID, containerTypes.StartOptions{})
if err == nil {
continue
@@ -224,6 +230,25 @@ func (c *Container) Start() error {
c.Suite.Log("Error while starting " + c.Name + ". Retrying...")
time.Sleep(1 * time.Second)
}
+ if nTries >= 5 {
+ return err
+ }
+
+ // wait for container to start
+ time.Sleep(1 * time.Second)
+
+ // check if container exited right after startup
+ containers, err := c.Suite.Docker.ContainerList(c.ctx, containerTypes.ListOptions{
+ All: true,
+ Filters: filters.NewArgs(filters.Arg("name", c.Name)),
+ })
+ if err != nil {
+ return err
+ }
+ if containers[0].State == "exited" {
+ c.Suite.Log("Container details: " + fmt.Sprint(containers[0]))
+ return fmt.Errorf("Container %s exited: '%s'", c.Name, containers[0].Status)
+ }
return err
}
@@ -288,7 +313,7 @@ func (c *Container) Run() {
func (c *Container) addVolume(hostDir string, containerDir string, isDefaultWorkDir bool) {
var volume Volume
- volume.HostDir = hostDir
+ volume.HostDir = strings.Replace(hostDir, "volumes", c.Suite.GetTestId()+"/"+"volumes", 1)
volume.ContainerDir = containerDir
volume.IsDefaultWorkDir = isDefaultWorkDir
c.Volumes[hostDir] = volume
@@ -301,12 +326,20 @@ func (c *Container) getVolumesAsSlice() []string {
volumeSlice = append(volumeSlice, fmt.Sprintf("%s:%s", *VppSourceFileDir, *VppSourceFileDir))
}
+ core_pattern, err := sysctl.Read("kernel.core_pattern")
+ if err == nil {
+ index := strings.LastIndex(core_pattern, "/")
+ core_pattern = core_pattern[:index]
+ volumeSlice = append(volumeSlice, c.Suite.getLogDirPath()+":"+core_pattern)
+ } else {
+ c.Suite.Log(err)
+ }
+
if len(c.Volumes) > 0 {
for _, volume := range c.Volumes {
volumeSlice = append(volumeSlice, fmt.Sprintf("%s:%s", volume.HostDir, volume.ContainerDir))
}
}
-
return volumeSlice
}
@@ -382,6 +415,11 @@ func (c *Container) CreateFile(destFileName string, content string) error {
return nil
}
+func (c *Container) GetFile(sourceFileName, targetFileName string) error {
+ cmd := exec.Command("docker", "cp", c.Name+":"+sourceFileName, targetFileName)
+ return cmd.Run()
+}
+
/*
* Executes in detached mode so that the started application can continue to run
* without blocking execution of test
@@ -406,21 +444,8 @@ func (c *Container) Exec(command string, arguments ...any) string {
return string(byteOutput)
}
-func (c *Container) getLogDirPath() string {
- testId := c.Suite.GetTestId()
- testName := c.Suite.GetCurrentTestName()
- logDirPath := logDir + testName + "/" + testId + "/"
-
- cmd := exec.Command("mkdir", "-p", logDirPath)
- if err := cmd.Run(); err != nil {
- Fail("mkdir error: " + fmt.Sprint(err))
- }
-
- return logDirPath
-}
-
func (c *Container) saveLogs() {
- testLogFilePath := c.getLogDirPath() + "container-" + c.Name + ".log"
+ testLogFilePath := c.Suite.getLogDirPath() + "container-" + c.Name + ".log"
logs, err := c.log(0)
if err != nil {
@@ -441,7 +466,7 @@ func (c *Container) saveLogs() {
func (c *Container) log(maxLines int) (string, error) {
var logOptions containerTypes.LogsOptions
if maxLines == 0 {
- logOptions = containerTypes.LogsOptions{ShowStdout: true, ShowStderr: true, Details: true}
+ logOptions = containerTypes.LogsOptions{ShowStdout: true, ShowStderr: true, Details: true, Timestamps: true}
} else {
logOptions = containerTypes.LogsOptions{ShowStdout: true, ShowStderr: true, Details: true, Tail: strconv.Itoa(maxLines)}
}
@@ -463,7 +488,13 @@ func (c *Container) log(maxLines int) (string, error) {
stdout := stdoutBuf.String()
stderr := stderrBuf.String()
- return stdout + " " + stderr, err
+ re := regexp.MustCompile("(?m)^.*==> /dev/null <==.*$[\r\n]+")
+ stdout = re.ReplaceAllString(stdout, "")
+
+ re = regexp.MustCompile("(?m)^.*tail: cannot open '' for reading: No such file or directory.*$[\r\n]+")
+ stderr = re.ReplaceAllString(stderr, "")
+
+ return stdout + stderr, err
}
func (c *Container) stop() error {
diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go
index 975e01d5b8e..ed8da3fe244 100644
--- a/extras/hs-test/infra/hst_suite.go
+++ b/extras/hs-test/infra/hst_suite.go
@@ -2,15 +2,18 @@ package hst
import (
"bufio"
- "errors"
"flag"
"fmt"
+ "github.com/edwarnicke/exechelper"
"io"
"log"
+ "net/http"
+ "net/http/httputil"
"os"
"os/exec"
"path/filepath"
"runtime"
+ "strconv"
"strings"
"time"
@@ -35,6 +38,8 @@ var NConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
var VppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory")
var IsDebugBuild = flag.Bool("debug_build", false, "some paths are different with debug build")
var UseCpu0 = flag.Bool("cpu0", false, "use cpu0")
+var IsLeakCheck = flag.Bool("leak_check", false, "run leak-check tests")
+var ParallelTotal = flag.Lookup("ginkgo.parallel.total")
var NumaAwareCpuAlloc bool
var SuiteTimeout time.Duration
@@ -56,11 +61,39 @@ type HstSuite struct {
Docker *client.Client
}
+// used for colorful ReportEntry
+type StringerStruct struct {
+ Label string
+}
+
+// ColorableString for ReportEntry to use
+func (s StringerStruct) ColorableString() string {
+ return fmt.Sprintf("{{red}}%s{{/}}", s.Label)
+}
+
+// non-colorable String() is used by go's string formatting support but ignored by ReportEntry
+func (s StringerStruct) String() string {
+ return s.Label
+}
+
func getTestFilename() string {
_, filename, _, _ := runtime.Caller(2)
return filepath.Base(filename)
}
+func (s *HstSuite) getLogDirPath() string {
+ testId := s.GetTestId()
+ testName := s.GetCurrentTestName()
+ logDirPath := logDir + testName + "/" + testId + "/"
+
+ cmd := exec.Command("mkdir", "-p", logDirPath)
+ if err := cmd.Run(); err != nil {
+ Fail("mkdir error: " + fmt.Sprint(err))
+ }
+
+ return logDirPath
+}
+
func (s *HstSuite) newDockerClient() {
var err error
s.Docker, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
@@ -114,6 +147,7 @@ func (s *HstSuite) TearDownTest() {
if *IsPersistent {
return
}
+ s.WaitForCoreDump()
s.ResetContainers()
if s.Ip4AddrAllocator != nil {
@@ -180,7 +214,7 @@ func (s *HstSuite) HstFail() {
out, err := container.log(20)
if err != nil {
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())
+ s.Log("The container might not be running - check logs in " + s.getLogDirPath())
continue
}
s.Log("\nvvvvvvvvvvvvvvv " +
@@ -192,35 +226,67 @@ func (s *HstSuite) HstFail() {
}
func (s *HstSuite) AssertNil(object interface{}, msgAndArgs ...interface{}) {
- Expect(object).To(BeNil(), msgAndArgs...)
+ ExpectWithOffset(2, object).To(BeNil(), msgAndArgs...)
}
func (s *HstSuite) AssertNotNil(object interface{}, msgAndArgs ...interface{}) {
- Expect(object).ToNot(BeNil(), msgAndArgs...)
+ ExpectWithOffset(2, object).ToNot(BeNil(), msgAndArgs...)
}
func (s *HstSuite) AssertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
- Expect(actual).To(Equal(expected), msgAndArgs...)
+ ExpectWithOffset(2, actual).To(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) AssertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
- Expect(actual).ToNot(Equal(expected), msgAndArgs...)
+ ExpectWithOffset(2, actual).ToNot(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) AssertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
- Expect(testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
+ ExpectWithOffset(2, testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) AssertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
- Expect(testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
+ ExpectWithOffset(2, testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) AssertEmpty(object interface{}, msgAndArgs ...interface{}) {
- Expect(object).To(BeEmpty(), msgAndArgs...)
+ ExpectWithOffset(2, object).To(BeEmpty(), msgAndArgs...)
}
func (s *HstSuite) AssertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
- Expect(object).ToNot(BeEmpty(), msgAndArgs...)
+ ExpectWithOffset(2, object).ToNot(BeEmpty(), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertMatchError(actual, expected error, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, actual).To(MatchError(expected), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertGreaterThan(actual, expected interface{}, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, actual).Should(BeNumerically(">=", expected), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertTimeEqualWithinThreshold(actual, expected time.Time, threshold time.Duration, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, actual).Should(BeTemporally("~", expected, threshold), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertHttpStatus(resp *http.Response, expectedStatus int, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, resp).To(HaveHTTPStatus(expectedStatus), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertHttpHeaderWithValue(resp *http.Response, key string, value interface{}, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue(key, value), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertHttpHeaderNotPresent(resp *http.Response, key string, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, resp.Header.Get(key)).To(BeEmpty(), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertHttpContentLength(resp *http.Response, expectedContentLen int64, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue("Content-Length", strconv.FormatInt(expectedContentLen, 10)), msgAndArgs...)
+}
+
+func (s *HstSuite) AssertHttpBody(resp *http.Response, expectedBody string, msgAndArgs ...interface{}) {
+ ExpectWithOffset(2, resp).To(HaveHTTPBody(expectedBody), msgAndArgs...)
}
func (s *HstSuite) CreateLogger() {
@@ -285,6 +351,74 @@ func (s *HstSuite) SkipUnlessExtendedTestsBuilt() {
}
}
+func (s *HstSuite) SkipUnlessLeakCheck() {
+ if !*IsLeakCheck {
+ s.Skip("leak-check tests excluded")
+ }
+}
+
+func (s *HstSuite) WaitForCoreDump() {
+ var filename string
+ dir, err := os.Open(s.getLogDirPath())
+ if err != nil {
+ s.Log(err)
+ return
+ }
+ defer dir.Close()
+
+ files, err := dir.Readdirnames(0)
+ if err != nil {
+ s.Log(err)
+ return
+ }
+ for _, file := range files {
+ if strings.Contains(file, "core") {
+ filename = file
+ }
+ }
+ timeout := 60
+ waitTime := 5
+
+ if filename != "" {
+ corePath := s.getLogDirPath() + filename
+ s.Log(fmt.Sprintf("WAITING FOR CORE DUMP (%s)", corePath))
+ for i := waitTime; i <= timeout; i += waitTime {
+ fileInfo, err := os.Stat(corePath)
+ if err != nil {
+ s.Log("Error while reading file info: " + fmt.Sprint(err))
+ return
+ }
+ currSize := fileInfo.Size()
+ s.Log(fmt.Sprintf("Waiting %ds/%ds...", i, timeout))
+ time.Sleep(time.Duration(waitTime) * time.Second)
+ fileInfo, _ = os.Stat(corePath)
+
+ if currSize == fileInfo.Size() {
+ debug := ""
+ if *IsDebugBuild {
+ debug = "_debug"
+ }
+ vppBinPath := fmt.Sprintf("../../build-root/build-vpp%s-native/vpp/bin/vpp", debug)
+ pluginsLibPath := fmt.Sprintf("build-root/build-vpp%s-native/vpp/lib/x86_64-linux-gnu/vpp_plugins", debug)
+ cmd := fmt.Sprintf("sudo gdb %s -c %s -ex 'set solib-search-path %s/%s' -ex 'bt full' -batch", vppBinPath, corePath, *VppSourceFileDir, pluginsLibPath)
+ s.Log(cmd)
+ output, _ := exechelper.Output(cmd)
+ AddReportEntry("VPP Backtrace", StringerStruct{Label: string(output)})
+ os.WriteFile(s.getLogDirPath()+"backtrace.log", output, os.FileMode(0644))
+ if s.CpuAllocator.runningInCi {
+ err = os.Remove(corePath)
+ if err == nil {
+ s.Log("removed " + corePath)
+ } else {
+ s.Log(err)
+ }
+ }
+ return
+ }
+ }
+ }
+}
+
func (s *HstSuite) ResetContainers() {
for _, container := range s.StartedContainers {
container.stop()
@@ -472,89 +606,12 @@ func (s *HstSuite) GetPortFromPpid() string {
return port[len(port)-3:] + s.ProcessIndex
}
-func (s *HstSuite) StartServerApp(running chan error, done chan struct{}, env []string) {
- cmd := exec.Command("iperf3", "-4", "-s", "-p", s.GetPortFromPpid())
- if env != nil {
- cmd.Env = env
- }
- s.Log(cmd)
- err := cmd.Start()
- if err != nil {
- msg := fmt.Errorf("failed to start iperf server: %v", err)
- running <- msg
- return
- }
- running <- nil
- <-done
- cmd.Process.Kill()
-}
-
-func (s *HstSuite) StartClientApp(ipAddress string, env []string, clnCh chan error, clnRes chan string) {
- defer func() {
- clnCh <- nil
- }()
-
- nTries := 0
-
- for {
- cmd := exec.Command("iperf3", "-c", ipAddress, "-u", "-l", "1460", "-b", "10g", "-p", s.GetPortFromPpid())
- if env != nil {
- cmd.Env = env
- }
- s.Log(cmd)
- o, err := cmd.CombinedOutput()
- if err != nil {
- if nTries > 5 {
- clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
- return
- }
- time.Sleep(1 * time.Second)
- nTries++
- continue
- } else {
- clnRes <- fmt.Sprintf("Client output: %s", o)
- }
- break
- }
-}
-
-func (s *HstSuite) StartHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
- cmd := newCommand([]string{"./http_server", addressPort, s.Ppid, s.ProcessIndex}, netNs)
- err := cmd.Start()
- s.Log(cmd)
- if err != nil {
- s.Log("Failed to start http server: " + fmt.Sprint(err))
- return
- }
- running <- struct{}{}
- <-done
- cmd.Process.Kill()
-}
-
-func (s *HstSuite) StartWget(finished chan error, server_ip, port, query, netNs string) {
- defer func() {
- finished <- errors.New("wget error")
- }()
-
- cmd := newCommand([]string{"wget", "--timeout=10", "--no-proxy", "--tries=5", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
- netNs)
- s.Log(cmd)
- o, err := cmd.CombinedOutput()
- if err != nil {
- finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
- return
- } else if !strings.Contains(string(o), "200 OK") {
- finished <- fmt.Errorf("wget error: response not 200 OK")
- return
- }
- finished <- nil
-}
-
/*
-runBenchmark creates Gomega's experiment with the passed-in name and samples the passed-in callback repeatedly (samplesNum times),
+RunBenchmark creates Gomega's experiment with the passed-in name and samples the passed-in callback repeatedly (samplesNum times),
passing in suite context, experiment and your data.
You can also instruct runBenchmark to run with multiple concurrent workers.
+Note that if running in parallel Gomega returns from Sample when spins up all samples and does not wait until all finished.
You can record multiple named measurements (float64 or duration) within passed-in callback.
runBenchmark then produces report to show statistical distribution of measurements.
*/
@@ -567,3 +624,19 @@ func (s *HstSuite) RunBenchmark(name string, samplesNum, parallelNum int, callba
}, gmeasure.SamplingConfig{N: samplesNum, NumParallel: parallelNum})
AddReportEntry(experiment.Name, experiment)
}
+
+/*
+LogHttpReq is Gomega's ghttp server handler which logs received HTTP request.
+
+You should put it at the first place, so request is logged always.
+*/
+func (s *HstSuite) LogHttpReq(body bool) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ dump, err := httputil.DumpRequest(req, body)
+ if err == nil {
+ s.Log("\n> Received request (" + req.RemoteAddr + "):\n" +
+ string(dump) +
+ "\n------------------------------\n")
+ }
+ }
+}
diff --git a/extras/hs-test/infra/suite_envoy_proxy.go b/extras/hs-test/infra/suite_envoy_proxy.go
new file mode 100644
index 00000000000..52f94bc76aa
--- /dev/null
+++ b/extras/hs-test/infra/suite_envoy_proxy.go
@@ -0,0 +1,201 @@
+// Suite for Envoy proxy testing
+//
+// The topology consists of 4 containers: curl (client), VPP (session layer), Envoy (proxy), nginx (target HTTP server).
+// VPP has 2 tap interfaces configured, one for client network and second for server/target network.
+
+package hst
+
+import (
+ "fmt"
+ . "github.com/onsi/ginkgo/v2"
+ "reflect"
+ "runtime"
+ "strings"
+)
+
+const (
+ VppContainerName = "vpp"
+ EnvoyProxyContainerName = "envoy-vcl"
+)
+
+type EnvoyProxySuite struct {
+ HstSuite
+ nginxPort uint16
+ proxyPort uint16
+}
+
+var envoyProxyTests = map[string][]func(s *EnvoyProxySuite){}
+var envoyProxySoloTests = map[string][]func(s *EnvoyProxySuite){}
+
+func RegisterEnvoyProxyTests(tests ...func(s *EnvoyProxySuite)) {
+ envoyProxyTests[getTestFilename()] = tests
+}
+
+func RegisterEnvoyProxySoloTests(tests ...func(s *EnvoyProxySuite)) {
+ envoyProxySoloTests[getTestFilename()] = tests
+}
+
+func (s *EnvoyProxySuite) SetupSuite() {
+ s.HstSuite.SetupSuite()
+ s.LoadNetworkTopology("2taps")
+ s.LoadContainerTopology("envoyProxy")
+}
+
+func (s *EnvoyProxySuite) SetupTest() {
+ s.HstSuite.SetupTest()
+
+ // VPP
+ var sessionConfig Stanza
+ sessionConfig.
+ NewStanza("session").
+ Append("enable").
+ Append("use-app-socket-api").
+ Append("evt_qs_memfd_seg").
+ Append("event-queue-length 100000")
+
+ vppContainer := s.GetContainerByName(VppContainerName)
+ vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus, sessionConfig)
+ s.AssertNotNil(vpp, fmt.Sprint(err))
+ s.AssertNil(vpp.Start())
+ clientInterface := s.GetInterfaceByName(ClientTapInterfaceName)
+ s.AssertNil(vpp.createTap(clientInterface, 1))
+ serverInterface := s.GetInterfaceByName(ServerTapInterfaceName)
+ s.AssertNil(vpp.createTap(serverInterface, 2))
+ vppContainer.Exec("chmod 777 -R %s", vppContainer.GetContainerWorkDir())
+
+ // nginx HTTP server
+ nginxContainer := s.GetTransientContainerByName(NginxServerContainerName)
+ s.AssertNil(nginxContainer.Create())
+ s.nginxPort = 80
+ nginxSettings := struct {
+ LogPrefix string
+ Address string
+ Port uint16
+ }{
+ LogPrefix: nginxContainer.Name,
+ Address: serverInterface.Ip4AddressString(),
+ Port: s.nginxPort,
+ }
+ nginxContainer.CreateConfig(
+ "/nginx.conf",
+ "./resources/nginx/nginx_server.conf",
+ nginxSettings,
+ )
+ s.AssertNil(nginxContainer.Start())
+
+ // Envoy
+ envoyContainer := s.GetContainerByName(EnvoyProxyContainerName)
+ s.AssertNil(envoyContainer.Create())
+ s.proxyPort = 8080
+ envoySettings := struct {
+ LogPrefix string
+ ServerAddress string
+ ServerPort uint16
+ ProxyPort uint16
+ }{
+ LogPrefix: envoyContainer.Name,
+ ServerAddress: serverInterface.Ip4AddressString(),
+ ServerPort: s.nginxPort,
+ ProxyPort: s.proxyPort,
+ }
+ envoyContainer.CreateConfig(
+ "/etc/envoy/envoy.yaml",
+ "resources/envoy/proxy.yaml",
+ envoySettings,
+ )
+ s.AssertNil(envoyContainer.Start())
+
+ // Add Ipv4 ARP entry for nginx HTTP server, otherwise first request fail (HTTP error 503)
+ arp := fmt.Sprintf("set ip neighbor %s %s %s",
+ serverInterface.Peer.Name(),
+ serverInterface.Ip4AddressString(),
+ serverInterface.HwAddress)
+ vppContainer.VppInstance.Vppctl(arp)
+}
+
+func (s *EnvoyProxySuite) TearDownTest() {
+ if CurrentSpecReport().Failed() {
+ s.CollectNginxLogs(NginxServerContainerName)
+ s.CollectEnvoyLogs(EnvoyProxyContainerName)
+ }
+ s.HstSuite.TearDownTest()
+}
+
+func (s *EnvoyProxySuite) ProxyPort() uint16 {
+ return s.proxyPort
+}
+
+func (s *EnvoyProxySuite) ProxyAddr() string {
+ return s.GetInterfaceByName(ClientTapInterfaceName).Peer.Ip4AddressString()
+}
+
+func (s *EnvoyProxySuite) CurlDownloadResource(uri string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' --remote-name --output-dir /tmp %s", uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertNotContains(log, "Recv failure")
+ s.AssertContains(log, "HTTP/1.1 200")
+}
+
+func (s *EnvoyProxySuite) CurlUploadResource(uri, file string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' -T %s %s", file, uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertContains(log, "HTTP/1.1 201")
+}
+
+var _ = Describe("EnvoyProxySuite", Ordered, ContinueOnFailure, func() {
+ var s EnvoyProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range envoyProxyTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
+
+var _ = Describe("EnvoyProxySuiteSolo", Ordered, ContinueOnFailure, func() {
+ var s EnvoyProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range envoyProxySoloTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
diff --git a/extras/hs-test/infra/suite_ldp.go b/extras/hs-test/infra/suite_ldp.go
new file mode 100644
index 00000000000..15b45f710ef
--- /dev/null
+++ b/extras/hs-test/infra/suite_ldp.go
@@ -0,0 +1,203 @@
+package hst
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
+// These correspond to names used in yaml config
+const (
+ ServerLdpInterfaceName = "srv"
+ ClientLdpInterfaceName = "cln"
+)
+
+var ldpTests = map[string][]func(s *LdpSuite){}
+var ldpSoloTests = map[string][]func(s *LdpSuite){}
+
+type LdpSuite struct {
+ HstSuite
+}
+
+func RegisterLdpTests(tests ...func(s *LdpSuite)) {
+ ldpTests[getTestFilename()] = tests
+}
+func RegisterSoloLdpTests(tests ...func(s *LdpSuite)) {
+ ldpSoloTests[getTestFilename()] = tests
+}
+
+func (s *LdpSuite) SetupSuite() {
+ time.Sleep(1 * time.Second)
+ s.HstSuite.SetupSuite()
+ s.ConfigureNetworkTopology("2peerVeth")
+ s.LoadContainerTopology("2peerVethLdp")
+}
+
+func (s *LdpSuite) SetupTest() {
+ s.HstSuite.SetupTest()
+
+ // Setup test conditions
+ var sessionConfig Stanza
+ sessionConfig.
+ NewStanza("session").
+ Append("enable").
+ Append("use-app-socket-api")
+
+ if strings.Contains(CurrentSpecReport().LeafNodeText, "InterruptMode") {
+ sessionConfig.Append("use-private-rx-mqs").Close()
+ s.Log("**********************INTERRUPT MODE**********************")
+ } else {
+ sessionConfig.Close()
+ }
+
+ // ... For server
+ serverContainer := s.GetContainerByName("server-vpp")
+
+ serverVpp, err := serverContainer.newVppInstance(serverContainer.AllocatedCpus, sessionConfig)
+ s.AssertNotNil(serverVpp, fmt.Sprint(err))
+
+ s.SetupServerVpp()
+
+ // ... For client
+ clientContainer := s.GetContainerByName("client-vpp")
+
+ clientVpp, err := clientContainer.newVppInstance(clientContainer.AllocatedCpus, sessionConfig)
+ s.AssertNotNil(clientVpp, fmt.Sprint(err))
+
+ s.setupClientVpp()
+
+ serverContainer.AddEnvVar("VCL_CONFIG", serverContainer.GetContainerWorkDir()+"/vcl_srv.conf")
+ clientContainer.AddEnvVar("VCL_CONFIG", clientContainer.GetContainerWorkDir()+"/vcl_cln.conf")
+
+ for _, container := range s.StartedContainers {
+ container.AddEnvVar("LD_PRELOAD", "/usr/lib/libvcl_ldpreload.so")
+ container.AddEnvVar("LDP_DEBUG", "0")
+ container.AddEnvVar("VCL_DEBUG", "0")
+ }
+}
+
+func (s *LdpSuite) TearDownTest() {
+ for _, container := range s.StartedContainers {
+ delete(container.EnvVars, "LD_PRELOAD")
+ delete(container.EnvVars, "VCL_CONFIG")
+ }
+ s.HstSuite.TearDownTest()
+
+}
+
+func (s *LdpSuite) SetupServerVpp() {
+ var srvVclConf Stanza
+ serverContainer := s.GetContainerByName("server-vpp")
+ serverVclFileName := serverContainer.GetHostWorkDir() + "/vcl_srv.conf"
+ serverVpp := serverContainer.VppInstance
+ s.AssertNil(serverVpp.Start())
+
+ serverVeth := s.GetInterfaceByName(ServerInterfaceName)
+ idx, err := serverVpp.createAfPacket(serverVeth)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertNotEqual(0, idx)
+
+ serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
+ serverContainer.GetContainerWorkDir())
+ err = srvVclConf.
+ NewStanza("vcl").
+ Append("rx-fifo-size 4000000").
+ Append("tx-fifo-size 4000000").
+ Append("app-scope-local").
+ Append("app-scope-global").
+ Append("use-mq-eventfd").
+ Append(serverAppSocketApi).Close().
+ SaveToFile(serverVclFileName)
+ s.AssertNil(err, fmt.Sprint(err))
+}
+
+func (s *LdpSuite) setupClientVpp() {
+ var clnVclConf Stanza
+ clientContainer := s.GetContainerByName("client-vpp")
+ clientVclFileName := clientContainer.GetHostWorkDir() + "/vcl_cln.conf"
+ clientVpp := clientContainer.VppInstance
+ s.AssertNil(clientVpp.Start())
+
+ clientVeth := s.GetInterfaceByName(ClientInterfaceName)
+ idx, err := clientVpp.createAfPacket(clientVeth)
+ s.AssertNil(err, fmt.Sprint(err))
+ s.AssertNotEqual(0, idx)
+
+ clientAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
+ clientContainer.GetContainerWorkDir())
+ err = clnVclConf.
+ NewStanza("vcl").
+ Append("rx-fifo-size 4000000").
+ Append("tx-fifo-size 4000000").
+ Append("app-scope-local").
+ Append("app-scope-global").
+ Append("use-mq-eventfd").
+ Append(clientAppSocketApi).Close().
+ SaveToFile(clientVclFileName)
+ s.AssertNil(err, fmt.Sprint(err))
+}
+
+var _ = Describe("LdpSuite", Ordered, ContinueOnFailure, func() {
+ var s LdpSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+ for filename, tests := range ldpTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
+
+var _ = Describe("LdpSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s LdpSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+ for filename, tests := range ldpSoloTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
diff --git a/extras/hs-test/infra/suite_nginx.go b/extras/hs-test/infra/suite_nginx.go
deleted file mode 100644
index 3a8b28e52eb..00000000000
--- a/extras/hs-test/infra/suite_nginx.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package hst
-
-import (
- "reflect"
- "runtime"
- "strings"
-
- . "github.com/onsi/ginkgo/v2"
-)
-
-// These correspond to names used in yaml config
-const (
- VppProxyContainerName = "vpp-proxy"
- NginxProxyContainerName = "nginx-proxy"
- NginxServerContainerName = "nginx-server"
- MirroringClientInterfaceName = "hstcln"
- MirroringServerInterfaceName = "hstsrv"
-)
-
-var nginxTests = map[string][]func(s *NginxSuite){}
-var nginxSoloTests = map[string][]func(s *NginxSuite){}
-
-type NginxSuite struct {
- HstSuite
-}
-
-func RegisterNginxTests(tests ...func(s *NginxSuite)) {
- nginxTests[getTestFilename()] = tests
-}
-func RegisterNginxSoloTests(tests ...func(s *NginxSuite)) {
- nginxSoloTests[getTestFilename()] = tests
-}
-
-func (s *NginxSuite) SetupSuite() {
- s.HstSuite.SetupSuite()
- s.LoadNetworkTopology("2taps")
- s.LoadContainerTopology("nginxProxyAndServer")
-}
-
-func (s *NginxSuite) SetupTest() {
- s.HstSuite.SetupTest()
-
- // Setup test conditions
- var sessionConfig Stanza
- sessionConfig.
- NewStanza("session").
- Append("enable").
- Append("use-app-socket-api")
-
- if strings.Contains(CurrentSpecReport().LeafNodeText, "InterruptMode") {
- sessionConfig.Append("use-private-rx-mqs").Close()
- s.Log("**********************INTERRUPT MODE**********************")
- } else {
- sessionConfig.Close()
- }
-
- // ... for proxy
- vppProxyContainer := s.GetContainerByName(VppProxyContainerName)
- proxyVpp, _ := vppProxyContainer.newVppInstance(vppProxyContainer.AllocatedCpus, sessionConfig)
- s.AssertNil(proxyVpp.Start())
-
- clientInterface := s.GetInterfaceByName(MirroringClientInterfaceName)
- s.AssertNil(proxyVpp.createTap(clientInterface, 1))
-
- serverInterface := s.GetInterfaceByName(MirroringServerInterfaceName)
- s.AssertNil(proxyVpp.createTap(serverInterface, 2))
-
- nginxContainer := s.GetTransientContainerByName(NginxProxyContainerName)
- s.AssertNil(nginxContainer.Create())
-
- values := struct {
- Proxy string
- Server string
- }{
- Proxy: clientInterface.Peer.Ip4AddressString(),
- Server: serverInterface.Ip4AddressString(),
- }
- nginxContainer.CreateConfig(
- "/nginx.conf",
- "./resources/nginx/nginx_proxy_mirroring.conf",
- values,
- )
- s.AssertNil(nginxContainer.Start())
-
- proxyVpp.WaitForApp("nginx-", 5)
-}
-
-var _ = Describe("NginxSuite", Ordered, ContinueOnFailure, func() {
- var s NginxSuite
- BeforeAll(func() {
- s.SetupSuite()
- })
- BeforeEach(func() {
- s.SetupTest()
- })
- AfterAll(func() {
- s.TearDownSuite()
- })
- AfterEach(func() {
- s.TearDownTest()
- })
-
- for filename, tests := range nginxTests {
- for _, test := range tests {
- test := test
- pc := reflect.ValueOf(test).Pointer()
- funcValue := runtime.FuncForPC(pc)
- testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
- It(testName, func(ctx SpecContext) {
- s.Log(testName + ": BEGIN")
- test(&s)
- }, SpecTimeout(SuiteTimeout))
- }
- }
-})
-
-var _ = Describe("NginxSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
- var s NginxSuite
- BeforeAll(func() {
- s.SetupSuite()
- })
- BeforeEach(func() {
- s.SetupTest()
- })
- AfterAll(func() {
- s.TearDownSuite()
- })
- AfterEach(func() {
- s.TearDownTest()
- })
-
- for filename, tests := range nginxSoloTests {
- for _, test := range tests {
- test := test
- pc := reflect.ValueOf(test).Pointer()
- funcValue := runtime.FuncForPC(pc)
- testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
- It(testName, Label("SOLO"), func(ctx SpecContext) {
- s.Log(testName + ": BEGIN")
- test(&s)
- }, SpecTimeout(SuiteTimeout))
- }
- }
-})
diff --git a/extras/hs-test/infra/suite_nginx_proxy.go b/extras/hs-test/infra/suite_nginx_proxy.go
new file mode 100644
index 00000000000..e43787df89c
--- /dev/null
+++ b/extras/hs-test/infra/suite_nginx_proxy.go
@@ -0,0 +1,181 @@
+package hst
+
+import (
+ "fmt"
+ "reflect"
+ "runtime"
+ "strings"
+
+ . "github.com/onsi/ginkgo/v2"
+)
+
+// These correspond to names used in yaml config
+const (
+ NginxProxyContainerName = "nginx-proxy"
+ NginxServerContainerName = "nginx-server"
+ MirroringClientInterfaceName = "hstcln"
+ MirroringServerInterfaceName = "hstsrv"
+)
+
+var nginxProxyTests = map[string][]func(s *NginxProxySuite){}
+var nginxProxySoloTests = map[string][]func(s *NginxProxySuite){}
+
+type NginxProxySuite struct {
+ HstSuite
+ proxyPort uint16
+}
+
+func RegisterNginxProxyTests(tests ...func(s *NginxProxySuite)) {
+ nginxProxyTests[getTestFilename()] = tests
+}
+func RegisterNginxProxySoloTests(tests ...func(s *NginxProxySuite)) {
+ nginxProxySoloTests[getTestFilename()] = tests
+}
+
+func (s *NginxProxySuite) SetupSuite() {
+ s.HstSuite.SetupSuite()
+ s.LoadNetworkTopology("2taps")
+ s.LoadContainerTopology("nginxProxy")
+}
+
+func (s *NginxProxySuite) SetupTest() {
+ s.HstSuite.SetupTest()
+
+ // VPP
+ var sessionConfig Stanza
+ sessionConfig.
+ NewStanza("session").
+ Append("enable").
+ Append("use-app-socket-api")
+
+ vppContainer := s.GetContainerByName(VppContainerName)
+ vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus, sessionConfig)
+ s.AssertNotNil(vpp, fmt.Sprint(err))
+ s.AssertNil(vpp.Start())
+ clientInterface := s.GetInterfaceByName(MirroringClientInterfaceName)
+ s.AssertNil(vpp.createTap(clientInterface, 1))
+ serverInterface := s.GetInterfaceByName(MirroringServerInterfaceName)
+ s.AssertNil(vpp.createTap(serverInterface, 2))
+
+ // nginx proxy
+ nginxProxyContainer := s.GetTransientContainerByName(NginxProxyContainerName)
+ s.AssertNil(nginxProxyContainer.Create())
+ s.proxyPort = 80
+ values := struct {
+ LogPrefix string
+ Proxy string
+ Server string
+ Port uint16
+ }{
+ LogPrefix: nginxProxyContainer.Name,
+ Proxy: clientInterface.Peer.Ip4AddressString(),
+ Server: serverInterface.Ip4AddressString(),
+ Port: s.proxyPort,
+ }
+ nginxProxyContainer.CreateConfig(
+ "/nginx.conf",
+ "./resources/nginx/nginx_proxy_mirroring.conf",
+ values,
+ )
+ s.AssertNil(nginxProxyContainer.Start())
+
+ // nginx HTTP server
+ nginxServerContainer := s.GetTransientContainerByName(NginxServerContainerName)
+ s.AssertNil(nginxServerContainer.Create())
+ nginxSettings := struct {
+ LogPrefix string
+ Address string
+ }{
+ LogPrefix: nginxServerContainer.Name,
+ Address: serverInterface.Ip4AddressString(),
+ }
+ nginxServerContainer.CreateConfig(
+ "/nginx.conf",
+ "./resources/nginx/nginx_server_mirroring.conf",
+ nginxSettings,
+ )
+ s.AssertNil(nginxServerContainer.Start())
+
+ vpp.WaitForApp("nginx-", 5)
+}
+
+func (s *NginxProxySuite) TearDownTest() {
+ if CurrentSpecReport().Failed() {
+ s.CollectNginxLogs(NginxServerContainerName)
+ s.CollectNginxLogs(NginxProxyContainerName)
+ }
+ s.HstSuite.TearDownTest()
+}
+
+func (s *NginxProxySuite) ProxyPort() uint16 {
+ return s.proxyPort
+}
+
+func (s *NginxProxySuite) ProxyAddr() string {
+ return s.GetInterfaceByName(MirroringClientInterfaceName).Peer.Ip4AddressString()
+}
+
+func (s *NginxProxySuite) CurlDownloadResource(uri string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' --remote-name --output-dir /tmp %s", uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertNotContains(log, "Recv failure")
+ s.AssertContains(log, "HTTP/1.1 200")
+}
+
+var _ = Describe("NginxProxySuite", Ordered, ContinueOnFailure, func() {
+ var s NginxProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range nginxProxyTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
+
+var _ = Describe("NginxProxySuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
+ var s NginxProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range nginxProxySoloTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
diff --git a/extras/hs-test/infra/suite_no_topo.go b/extras/hs-test/infra/suite_no_topo.go
index 5f53f55f1bb..9b4998a77a1 100644
--- a/extras/hs-test/infra/suite_no_topo.go
+++ b/extras/hs-test/infra/suite_no_topo.go
@@ -60,6 +60,18 @@ func (s *NoTopoSuite) SetupTest() {
s.AssertNil(vpp.createTap(tapInterface), "failed to create tap interface")
}
+func (s *NoTopoSuite) VppAddr() string {
+ return s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+}
+
+func (s *NoTopoSuite) VppIfName() string {
+ return s.GetInterfaceByName(TapInterfaceName).Peer.Name()
+}
+
+func (s *NoTopoSuite) HostAddr() string {
+ return s.GetInterfaceByName(TapInterfaceName).Ip4AddressString()
+}
+
var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() {
var s NoTopoSuite
BeforeAll(func() {
diff --git a/extras/hs-test/infra/suite_vpp_proxy.go b/extras/hs-test/infra/suite_vpp_proxy.go
new file mode 100644
index 00000000000..a13897eb8d0
--- /dev/null
+++ b/extras/hs-test/infra/suite_vpp_proxy.go
@@ -0,0 +1,198 @@
+// Suite for VPP proxy testing
+//
+// The topology consists of 3 containers: curl (client), VPP (proxy), nginx (target HTTP server).
+// VPP has 2 tap interfaces configured, one for client network and second for server/target network.
+
+package hst
+
+import (
+ "fmt"
+ . "github.com/onsi/ginkgo/v2"
+ "reflect"
+ "runtime"
+ "strings"
+)
+
+// These correspond to names used in yaml config
+const (
+ VppProxyContainerName = "vpp-proxy"
+ ClientTapInterfaceName = "hstcln"
+ ServerTapInterfaceName = "hstsrv"
+ CurlContainerTestFile = "/tmp/testFile"
+)
+
+type VppProxySuite struct {
+ HstSuite
+ nginxPort uint16
+}
+
+var vppProxyTests = map[string][]func(s *VppProxySuite){}
+var vppProxySoloTests = map[string][]func(s *VppProxySuite){}
+
+func RegisterVppProxyTests(tests ...func(s *VppProxySuite)) {
+ vppProxyTests[getTestFilename()] = tests
+}
+
+func RegisterVppProxySoloTests(tests ...func(s *VppProxySuite)) {
+ vppProxySoloTests[getTestFilename()] = tests
+}
+
+func (s *VppProxySuite) SetupSuite() {
+ s.HstSuite.SetupSuite()
+ s.LoadNetworkTopology("2taps")
+ s.LoadContainerTopology("vppProxy")
+}
+
+func (s *VppProxySuite) SetupTest() {
+ s.HstSuite.SetupTest()
+
+ // VPP HTTP connect-proxy
+ vppContainer := s.GetContainerByName(VppProxyContainerName)
+ vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus)
+ s.AssertNotNil(vpp, fmt.Sprint(err))
+ s.AssertNil(vpp.Start())
+ clientInterface := s.GetInterfaceByName(ClientTapInterfaceName)
+ s.AssertNil(vpp.createTap(clientInterface, 1))
+ serverInterface := s.GetInterfaceByName(ServerTapInterfaceName)
+ s.AssertNil(vpp.createTap(serverInterface, 2))
+
+ // nginx HTTP server
+ nginxContainer := s.GetTransientContainerByName(NginxServerContainerName)
+ s.AssertNil(nginxContainer.Create())
+ s.nginxPort = 80
+ nginxSettings := struct {
+ LogPrefix string
+ Address string
+ Port uint16
+ }{
+ LogPrefix: nginxContainer.Name,
+ Address: serverInterface.Ip4AddressString(),
+ Port: s.nginxPort,
+ }
+ nginxContainer.CreateConfig(
+ "/nginx.conf",
+ "./resources/nginx/nginx_server.conf",
+ nginxSettings,
+ )
+ s.AssertNil(nginxContainer.Start())
+}
+
+func (s *VppProxySuite) TearDownTest() {
+ if CurrentSpecReport().Failed() {
+ s.CollectNginxLogs(NginxServerContainerName)
+ }
+ s.HstSuite.TearDownTest()
+}
+
+func (s *VppProxySuite) NginxPort() uint16 {
+ return s.nginxPort
+}
+
+func (s *VppProxySuite) NginxAddr() string {
+ return s.GetInterfaceByName(ServerTapInterfaceName).Ip4AddressString()
+}
+
+func (s *VppProxySuite) VppProxyAddr() string {
+ return s.GetInterfaceByName(ClientTapInterfaceName).Peer.Ip4AddressString()
+}
+
+func (s *VppProxySuite) CurlRequest(targetUri string) (string, string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' %s", targetUri)
+ body, log := s.RunCurlContainer(args)
+ return body, log
+}
+
+func (s *VppProxySuite) CurlRequestViaTunnel(targetUri string, proxyUri string) (string, string) {
+ args := fmt.Sprintf("--max-time 60 --insecure -p -x %s %s", proxyUri, targetUri)
+ body, log := s.RunCurlContainer(args)
+ return body, log
+}
+
+func (s *VppProxySuite) CurlDownloadResource(uri string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' --remote-name --output-dir /tmp %s", uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertNotContains(log, "Recv failure")
+ s.AssertContains(log, "HTTP/1.1 200")
+}
+
+func (s *VppProxySuite) CurlUploadResource(uri, file string) {
+ args := fmt.Sprintf("--insecure --noproxy '*' -T %s %s", file, uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertContains(log, "HTTP/1.1 201")
+}
+
+func (s *VppProxySuite) CurlDownloadResourceViaTunnel(uri string, proxyUri string) {
+ args := fmt.Sprintf("--max-time 180 --insecure -p -x %s --remote-name --output-dir /tmp %s", proxyUri, uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertNotContains(log, "Recv failure")
+ s.AssertNotContains(log, "Operation timed out")
+ s.AssertContains(log, "CONNECT tunnel established")
+ s.AssertContains(log, "HTTP/1.1 200")
+ s.AssertNotContains(log, "bytes remaining to read")
+}
+
+func (s *VppProxySuite) CurlUploadResourceViaTunnel(uri, proxyUri, file string) {
+ args := fmt.Sprintf("--max-time 180 --insecure -p -x %s -T %s %s", proxyUri, file, uri)
+ _, log := s.RunCurlContainer(args)
+ s.AssertNotContains(log, "Operation timed out")
+ s.AssertContains(log, "CONNECT tunnel established")
+ s.AssertContains(log, "HTTP/1.1 201")
+}
+
+var _ = Describe("VppProxySuite", Ordered, ContinueOnFailure, func() {
+ var s VppProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range vppProxyTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
+
+var _ = Describe("VppProxySuiteSolo", Ordered, ContinueOnFailure, func() {
+ var s VppProxySuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SetupTest()
+ })
+ AfterAll(func() {
+ s.TearDownSuite()
+ })
+ AfterEach(func() {
+ s.TearDownTest()
+ })
+
+ for filename, tests := range vppProxySoloTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO"), func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(SuiteTimeout))
+ }
+ }
+})
diff --git a/extras/hs-test/infra/utils.go b/extras/hs-test/infra/utils.go
index 9619efbbf63..25d8519cb8a 100644
--- a/extras/hs-test/infra/utils.go
+++ b/extras/hs-test/infra/utils.go
@@ -1,11 +1,14 @@
package hst
import (
+ "errors"
"fmt"
"io"
"net"
"net/http"
+ "net/http/httputil"
"os"
+ "os/exec"
"strings"
"time"
)
@@ -96,6 +99,14 @@ func NewHttpClient() *http.Client {
return client
}
+func DumpHttpResp(resp *http.Response, body bool) string {
+ dump, err := httputil.DumpResponse(resp, body)
+ if err != nil {
+ return ""
+ }
+ return string(dump)
+}
+
func TcpSendReceive(address, data string) (string, error) {
conn, err := net.DialTimeout("tcp", address, time.Second*30)
if err != nil {
@@ -117,3 +128,189 @@ func TcpSendReceive(address, data string) (string, error) {
}
return string(reply), nil
}
+
+/*
+RunCurlContainer execute curl command with given args.
+Container with name "curl" must be available.
+Curl runs in verbose mode and progress meter switch off by default.
+*/
+func (s *HstSuite) RunCurlContainer(args string) (string, string) {
+ curlCont := s.GetContainerByName("curl")
+ cmd := fmt.Sprintf("curl -v -s %s", args)
+ s.Log(cmd)
+ curlCont.ExtraRunningArgs = cmd
+ curlCont.Run()
+ stdout, stderr := curlCont.GetOutput()
+ s.Log(stderr)
+ s.Log(stdout)
+ return stdout, stderr
+}
+
+/*
+CollectNginxLogs save access and error logs to the test execution directory.
+Nginx logging need to be set following way:
+
+ - error_log <default-work-dir>/{{.LogPrefix}}-error.log;
+ - access_log <default-work-dir>/{{.LogPrefix}}-access.log;
+
+where LogPrefix is set to nginxContainer.Name
+*/
+func (s *HstSuite) CollectNginxLogs(containerName string) {
+ nginxContainer := s.GetContainerByName(containerName)
+ targetDir := nginxContainer.Suite.getLogDirPath()
+ source := nginxContainer.GetHostWorkDir() + "/" + nginxContainer.Name + "-"
+ cmd := exec.Command("cp", "-t", targetDir, source+"error.log", source+"access.log")
+ s.Log(cmd.String())
+ err := cmd.Run()
+ if err != nil {
+ s.Log(fmt.Sprint(err))
+ }
+}
+
+/*
+CollectEnvoyLogs save access logs to the test execution directory.
+Envoy access log path need to be set following way:
+<default-work-dir>/{{.LogPrefix}}-access.log
+where LogPrefix is set to envoyContainer.Name
+*/
+func (s *HstSuite) CollectEnvoyLogs(containerName string) {
+ envoyContainer := s.GetContainerByName(containerName)
+ targetDir := envoyContainer.Suite.getLogDirPath()
+ source := envoyContainer.GetHostWorkDir() + "/" + envoyContainer.Name + "-"
+ cmd := exec.Command("cp", "-t", targetDir, source+"access.log")
+ s.Log(cmd.String())
+ err := cmd.Run()
+ if err != nil {
+ s.Log(fmt.Sprint(err))
+ }
+}
+
+func (s *HstSuite) StartIperfServerApp(running chan error, done chan struct{}, env []string) {
+ cmd := exec.Command("iperf3", "-4", "-s", "-p", s.GetPortFromPpid())
+ if env != nil {
+ cmd.Env = env
+ }
+ s.Log(cmd)
+ err := cmd.Start()
+ if err != nil {
+ msg := fmt.Errorf("failed to start iperf server: %v", err)
+ running <- msg
+ return
+ }
+ running <- nil
+ <-done
+ cmd.Process.Kill()
+}
+
+func (s *HstSuite) StartIperfClientApp(ipAddress string, env []string, clnCh chan error, clnRes chan string) {
+ defer func() {
+ clnCh <- nil
+ }()
+
+ nTries := 0
+
+ for {
+ cmd := exec.Command("iperf3", "-c", ipAddress, "-u", "-l", "1460", "-b", "10g", "-p", s.GetPortFromPpid())
+ if env != nil {
+ cmd.Env = env
+ }
+ s.Log(cmd)
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ if nTries > 5 {
+ clnRes <- ""
+ clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
+ return
+ }
+ time.Sleep(1 * time.Second)
+ nTries++
+ continue
+ } else {
+ clnRes <- fmt.Sprintf("Client output: %s", o)
+ }
+ break
+ }
+}
+
+func (s *HstSuite) StartHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
+ cmd := newCommand([]string{"./http_server", addressPort, s.Ppid, s.ProcessIndex}, netNs)
+ err := cmd.Start()
+ s.Log(cmd)
+ if err != nil {
+ s.Log("Failed to start http server: " + fmt.Sprint(err))
+ return
+ }
+ running <- struct{}{}
+ <-done
+ cmd.Process.Kill()
+}
+
+func (s *HstSuite) StartWget(finished chan error, server_ip, port, query, netNs string) {
+ defer func() {
+ finished <- errors.New("wget error")
+ }()
+
+ cmd := newCommand([]string{"wget", "--timeout=10", "--no-proxy", "--tries=5", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
+ netNs)
+ s.Log(cmd)
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
+ return
+ } else if !strings.Contains(string(o), "200 OK") {
+ finished <- fmt.Errorf("wget error: response not 200 OK")
+ return
+ }
+ finished <- nil
+}
+
+// Start a server app. 'processName' is used to check whether the app started correctly.
+func (s *HstSuite) StartServerApp(c *Container, processName string, cmd string,
+ running chan error, done chan struct{}) {
+
+ s.Log("starting server")
+ c.ExecServer(cmd)
+ cmd2 := exec.Command("docker", "exec", c.Name, "pidof", processName)
+ err := cmd2.Run()
+ if err != nil {
+ msg := fmt.Errorf("failed to start server app: %v", err)
+ running <- msg
+ <-done
+ return
+ }
+ running <- nil
+ <-done
+}
+
+func (s *HstSuite) StartClientApp(c *Container, cmd string,
+ clnCh chan error, clnRes chan string) {
+ defer func() {
+ close(clnCh)
+ close(clnRes)
+ }()
+
+ s.Log("starting client app, please wait")
+
+ nTries := 0
+ for {
+ // exec.Cmd can only be used once, which is why it's in the loop
+ cmd2 := exec.Command("/bin/sh", "-c", "docker exec "+c.getEnvVarsAsCliOption()+" "+
+ c.Name+" "+cmd)
+ s.Log(cmd2)
+ o, err := cmd2.CombinedOutput()
+ if err != nil {
+ s.Log(err)
+ if nTries > 5 {
+ clnRes <- ""
+ clnCh <- fmt.Errorf("failed to start client app '%s'", err)
+ s.AssertNil(err, fmt.Sprint(err))
+ break
+ }
+ time.Sleep(1 * time.Second)
+ nTries++
+ } else {
+ clnRes <- fmt.Sprintf("Client output: %s", o)
+ break
+ }
+ }
+}
diff --git a/extras/hs-test/infra/vppinstance.go b/extras/hs-test/infra/vppinstance.go
index d4f570046c7..a93921ed5be 100644
--- a/extras/hs-test/infra/vppinstance.go
+++ b/extras/hs-test/infra/vppinstance.go
@@ -2,6 +2,7 @@ package hst
import (
"context"
+ "encoding/json"
"fmt"
"go.fd.io/govpp/binapi/ethernet_types"
"io"
@@ -32,19 +33,15 @@ const vppConfigTemplate = `unix {
nodaemon
log %[1]s%[4]s
full-coredump
+ coredump-size unlimited
cli-listen %[1]s%[2]s
runtime-dir %[1]s/var/run
- gid vpp
}
api-trace {
on
}
-api-segment {
- gid vpp
-}
-
socksvr {
socket-name %[1]s%[3]s
}
@@ -97,6 +94,13 @@ type VppCpuConfig struct {
SkipCores int
}
+type VppMemTrace struct {
+ Count int `json:"count"`
+ Size int `json:"bytes"`
+ Sample string `json:"sample"`
+ Traceback []string `json:"traceback"`
+}
+
func (vpp *VppInstance) getSuite() *HstSuite {
return vpp.Container.Suite
}
@@ -471,7 +475,7 @@ func (vpp *VppInstance) createTap(
}
func (vpp *VppInstance) saveLogs() {
- logTarget := vpp.Container.getLogDirPath() + "vppinstance-" + vpp.Container.Name + ".log"
+ logTarget := vpp.getSuite().getLogDirPath() + "vppinstance-" + vpp.Container.Name + ".log"
logSource := vpp.Container.GetHostWorkDir() + defaultLogFilePath
cmd := exec.Command("cp", logSource, logTarget)
vpp.getSuite().Log(cmd.String())
@@ -535,3 +539,83 @@ func (vpp *VppInstance) generateVPPCpuConfig() string {
return c.Close().ToString()
}
+
+// EnableMemoryTrace enables memory traces of VPP main-heap
+func (vpp *VppInstance) EnableMemoryTrace() {
+ vpp.getSuite().Log(vpp.Vppctl("memory-trace on main-heap"))
+}
+
+// GetMemoryTrace dumps memory traces for analysis
+func (vpp *VppInstance) GetMemoryTrace() ([]VppMemTrace, error) {
+ var trace []VppMemTrace
+ vpp.getSuite().Log(vpp.Vppctl("save memory-trace trace.json"))
+ err := vpp.Container.GetFile("/tmp/trace.json", "/tmp/trace.json")
+ if err != nil {
+ return nil, err
+ }
+ fileBytes, err := os.ReadFile("/tmp/trace.json")
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(fileBytes, &trace)
+ if err != nil {
+ return nil, err
+ }
+ return trace, nil
+}
+
+// memTracesSuppressCli filter out CLI related samples
+func memTracesSuppressCli(traces []VppMemTrace) []VppMemTrace {
+ var filtered []VppMemTrace
+ for i := 0; i < len(traces); i++ {
+ isCli := false
+ for j := 0; j < len(traces[i].Traceback); j++ {
+ if strings.Contains(traces[i].Traceback[j], "unix_cli") {
+ isCli = true
+ break
+ }
+ }
+ if !isCli {
+ filtered = append(filtered, traces[i])
+ }
+ }
+ return filtered
+}
+
+// MemLeakCheck compares memory traces at different point in time, analyzes if memory leaks happen and produces report
+func (vpp *VppInstance) MemLeakCheck(first, second []VppMemTrace) {
+ totalBytes := 0
+ totalCounts := 0
+ trace1 := memTracesSuppressCli(first)
+ trace2 := memTracesSuppressCli(second)
+ report := ""
+ for i := 0; i < len(trace2); i++ {
+ match := false
+ for j := 0; j < len(trace1); j++ {
+ if trace1[j].Sample == trace2[i].Sample {
+ if trace2[i].Size > trace1[j].Size {
+ deltaBytes := trace2[i].Size - trace1[j].Size
+ deltaCounts := trace2[i].Count - trace1[j].Count
+ report += fmt.Sprintf("grow %d byte(s) in %d allocation(s) from:\n", deltaBytes, deltaCounts)
+ for j := 0; j < len(trace2[i].Traceback); j++ {
+ report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
+ }
+ totalBytes += deltaBytes
+ totalCounts += deltaCounts
+ }
+ match = true
+ break
+ }
+ }
+ if !match {
+ report += fmt.Sprintf("\nleak of %d byte(s) in %d allocation(s) from:\n", trace2[i].Size, trace2[i].Count)
+ for j := 0; j < len(trace2[i].Traceback); j++ {
+ report += fmt.Sprintf("\t#%d %s\n", j, trace2[i].Traceback[j])
+ }
+ totalBytes += trace2[i].Size
+ totalCounts += trace2[i].Count
+ }
+ }
+ summary := fmt.Sprintf("\nSUMMARY: %d byte(s) leaked in %d allocation(s)\n", totalBytes, totalCounts)
+ AddReportEntry(summary, report)
+}
diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go
index e9e8bba9274..03636b11191 100644
--- a/extras/hs-test/ldp_test.go
+++ b/extras/hs-test/ldp_test.go
@@ -2,86 +2,42 @@ package main
import (
"fmt"
- "os"
. "fd.io/hs-test/infra"
. "github.com/onsi/ginkgo/v2"
)
func init() {
- RegisterVethTests(LDPreloadIperfVppTest, LDPreloadIperfVppInterruptModeTest)
+ RegisterLdpTests(LDPreloadIperfVppTest, LDPreloadIperfVppInterruptModeTest, RedisBenchmarkTest)
}
-func LDPreloadIperfVppInterruptModeTest(s *VethsSuite) {
+func LDPreloadIperfVppInterruptModeTest(s *LdpSuite) {
LDPreloadIperfVppTest(s)
}
-func LDPreloadIperfVppTest(s *VethsSuite) {
- var clnVclConf, srvVclConf Stanza
- var ldpreload string
-
- serverContainer := s.GetContainerByName("server-vpp")
- serverVclFileName := serverContainer.GetHostWorkDir() + "/vcl_srv.conf"
-
+func LDPreloadIperfVppTest(s *LdpSuite) {
clientContainer := s.GetContainerByName("client-vpp")
- clientVclFileName := clientContainer.GetHostWorkDir() + "/vcl_cln.conf"
-
- if *IsDebugBuild {
- ldpreload = "LD_PRELOAD=../../build-root/build-vpp_debug-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so"
- } else {
- ldpreload = "LD_PRELOAD=../../build-root/build-vpp-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so"
- }
+ serverContainer := s.GetContainerByName("server-vpp")
stopServerCh := make(chan struct{}, 1)
srvCh := make(chan error, 1)
clnCh := make(chan error)
+ clnRes := make(chan string, 1)
- s.Log("starting VPPs")
-
- clientAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
- clientContainer.GetHostWorkDir())
- err := clnVclConf.
- NewStanza("vcl").
- Append("rx-fifo-size 4000000").
- Append("tx-fifo-size 4000000").
- Append("app-scope-local").
- Append("app-scope-global").
- Append("use-mq-eventfd").
- Append(clientAppSocketApi).Close().
- SaveToFile(clientVclFileName)
- s.AssertNil(err, fmt.Sprint(err))
-
- serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
- serverContainer.GetHostWorkDir())
- err = srvVclConf.
- NewStanza("vcl").
- Append("rx-fifo-size 4000000").
- Append("tx-fifo-size 4000000").
- Append("app-scope-local").
- Append("app-scope-global").
- Append("use-mq-eventfd").
- Append(serverAppSocketApi).Close().
- SaveToFile(serverVclFileName)
- s.AssertNil(err, fmt.Sprint(err))
-
- s.Log("attaching server to vpp")
-
- srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+serverVclFileName)
go func() {
defer GinkgoRecover()
- s.StartServerApp(srvCh, stopServerCh, srvEnv)
+ cmd := "iperf3 -4 -s -p " + s.GetPortFromPpid()
+ s.StartServerApp(serverContainer, "iperf3", cmd, srvCh, stopServerCh)
}()
- err = <-srvCh
+ err := <-srvCh
s.AssertNil(err, fmt.Sprint(err))
- s.Log("attaching client to vpp")
- var clnRes = make(chan string, 1)
- clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName)
serverVethAddress := s.GetInterfaceByName(ServerInterfaceName).Ip4AddressString()
go func() {
defer GinkgoRecover()
- s.StartClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
+ cmd := "iperf3 -c " + serverVethAddress + " -u -l 1460 -b 10g -p " + s.GetPortFromPpid()
+ s.StartClientApp(clientContainer, cmd, clnCh, clnRes)
}()
s.Log(<-clnRes)
@@ -92,3 +48,43 @@ func LDPreloadIperfVppTest(s *VethsSuite) {
// stop server
stopServerCh <- struct{}{}
}
+
+func RedisBenchmarkTest(s *LdpSuite) {
+ s.SkipIfMultiWorker()
+
+ serverContainer := s.GetContainerByName("server-vpp")
+ clientContainer := s.GetContainerByName("client-vpp")
+
+ serverVethAddress := s.GetInterfaceByName(ServerInterfaceName).Ip4AddressString()
+ runningSrv := make(chan error)
+ doneSrv := make(chan struct{})
+ clnCh := make(chan error)
+ clnRes := make(chan string, 1)
+
+ go func() {
+ defer GinkgoRecover()
+ cmd := "redis-server --daemonize yes --protected-mode no --bind " + serverVethAddress
+ s.StartServerApp(serverContainer, "redis-server", cmd, runningSrv, doneSrv)
+ }()
+
+ err := <-runningSrv
+ s.AssertNil(err)
+
+ go func() {
+ defer GinkgoRecover()
+ var cmd string
+ if *NConfiguredCpus == 1 {
+ cmd = "redis-benchmark --threads 1 -h " + serverVethAddress
+ } else {
+ cmd = "redis-benchmark --threads " + fmt.Sprint(*NConfiguredCpus) + "-h " + serverVethAddress
+ }
+ s.StartClientApp(clientContainer, cmd, clnCh, clnRes)
+ }()
+
+ s.Log(<-clnRes)
+ // wait for client's result
+ err = <-clnCh
+ s.AssertNil(err, fmt.Sprint(err))
+ // stop server
+ doneSrv <- struct{}{}
+}
diff --git a/extras/hs-test/linux_iperf_test.go b/extras/hs-test/linux_iperf_test.go
index f49d9bcf227..9342e862f04 100644
--- a/extras/hs-test/linux_iperf_test.go
+++ b/extras/hs-test/linux_iperf_test.go
@@ -21,7 +21,7 @@ func LinuxIperfTest(s *TapSuite) {
go func() {
defer GinkgoRecover()
- s.StartServerApp(srvCh, stopServerCh, nil)
+ s.StartIperfServerApp(srvCh, stopServerCh, nil)
}()
err := <-srvCh
s.AssertNil(err, fmt.Sprint(err))
@@ -30,7 +30,7 @@ func LinuxIperfTest(s *TapSuite) {
ipAddress := s.GetInterfaceByName(TapInterfaceName).Ip4AddressString()
go func() {
defer GinkgoRecover()
- s.StartClientApp(ipAddress, nil, clnCh, clnRes)
+ s.StartIperfClientApp(ipAddress, nil, clnCh, clnRes)
}()
s.Log("client running")
s.Log(<-clnRes)
diff --git a/extras/hs-test/mem_leak_test.go b/extras/hs-test/mem_leak_test.go
new file mode 100644
index 00000000000..76966ae968a
--- /dev/null
+++ b/extras/hs-test/mem_leak_test.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ . "fd.io/hs-test/infra"
+ "fmt"
+)
+
+func init() {
+ RegisterNoTopoSoloTests(MemLeakTest)
+}
+
+func MemLeakTest(s *NoTopoSuite) {
+ s.SkipUnlessLeakCheck()
+ vpp := s.GetContainerByName("vpp").VppInstance
+ /* no goVPP less noise */
+ vpp.Disconnect()
+ vpp.EnableMemoryTrace()
+ traces1, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.Vppctl("test mem-leak")
+ traces2, err := vpp.GetMemoryTrace()
+ s.AssertNil(err, fmt.Sprint(err))
+ vpp.MemLeakCheck(traces1, traces2)
+}
diff --git a/extras/hs-test/nginx_test.go b/extras/hs-test/nginx_test.go
index 45358435546..fa6afda58fc 100644
--- a/extras/hs-test/nginx_test.go
+++ b/extras/hs-test/nginx_test.go
@@ -3,35 +3,16 @@ package main
import (
. "fd.io/hs-test/infra"
"fmt"
- "github.com/edwarnicke/exechelper"
. "github.com/onsi/ginkgo/v2"
"os"
"strings"
)
func init() {
- RegisterNginxTests(MirroringTest)
RegisterNoTopoTests(NginxHttp3Test, NginxAsServerTest, NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest,
NginxPerfCpsInterruptModeTest, NginxPerfRpsInterruptModeTest, NginxPerfWrkInterruptModeTest)
}
-// broken when CPUS > 1
-func MirroringTest(s *NginxSuite) {
- s.SkipIfMultiWorker()
- proxyAddress := s.GetInterfaceByName(MirroringClientInterfaceName).Peer.Ip4AddressString()
-
- path := "/64B.json"
-
- testCommand := "wrk -c 20 -t 10 -d 10 http://" + proxyAddress + ":80" + path
- s.Log(testCommand)
- o, _ := exechelper.Output(testCommand)
- s.Log(string(o))
- s.AssertNotEmpty(o)
-
- vppProxyContainer := s.GetContainerByName(VppProxyContainerName)
- s.AssertEqual(0, vppProxyContainer.VppInstance.GetSessionStat("no lcl port"))
-}
-
func NginxHttp3Test(s *NoTopoSuite) {
s.SkipUnlessExtendedTestsBuilt()
@@ -41,7 +22,7 @@ func NginxHttp3Test(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
vpp.WaitForApp("nginx-", 5)
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
defer func() { os.Remove(query) }()
curlCont := s.GetContainerByName("curl")
@@ -63,7 +44,7 @@ func NginxAsServerTest(s *NoTopoSuite) {
vpp := s.GetContainerByName("vpp").VppInstance
vpp.WaitForApp("nginx-", 5)
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
defer func() { os.Remove(query) }()
go func() {
@@ -87,7 +68,7 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
nRequests := 1000000
nClients := 1000
- serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString()
+ serverAddress := s.VppAddr()
vpp := s.GetContainerByName("vpp").VppInstance
diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go
index e646a969214..7ec97c76c02 100644
--- a/extras/hs-test/proxy_test.go
+++ b/extras/hs-test/proxy_test.go
@@ -3,112 +3,68 @@ package main
import (
. "fd.io/hs-test/infra"
"fmt"
- "github.com/edwarnicke/exechelper"
- . "github.com/onsi/ginkgo/v2"
- "os"
)
func init() {
- RegisterNsTests(VppProxyHttpTcpTest, VppProxyHttpTlsTest, EnvoyProxyHttpTcpTest)
+ RegisterVppProxyTests(VppProxyHttpGetTcpTest, VppProxyHttpGetTlsTest, VppProxyHttpPutTcpTest, VppProxyHttpPutTlsTest)
+ RegisterEnvoyProxyTests(EnvoyProxyHttpGetTcpTest, EnvoyProxyHttpPutTcpTest)
+ RegisterNginxProxyTests(NginxMirroringTest)
}
-func testProxyHttpTcp(s *NsSuite, proto string) error {
- var outputFile string = s.ProcessIndex + "test" + s.Ppid + ".data"
- var srcFilePpid string = s.ProcessIndex + "httpTestFile" + s.Ppid
- const srcFileNoPpid = "httpTestFile"
- const fileSize string = "10M"
- stopServer := make(chan struct{}, 1)
- serverRunning := make(chan struct{}, 1)
- serverNetns := s.GetNetNamespaceByName("srv")
- clientNetns := s.GetNetNamespaceByName("cln")
-
- // create test file
- err := exechelper.Run(fmt.Sprintf("ip netns exec %s truncate -s %s %s", serverNetns, fileSize, srcFilePpid))
- s.AssertNil(err, "failed to run truncate command: "+fmt.Sprint(err))
- defer func() { os.Remove(srcFilePpid) }()
-
- s.Log("test file created...")
-
- go func() {
- defer GinkgoRecover()
- s.StartHttpServer(serverRunning, stopServer, ":666", serverNetns)
- }()
- // TODO better error handling and recovery
- <-serverRunning
-
- defer func(chan struct{}) {
- stopServer <- struct{}{}
- }(stopServer)
-
- s.Log("http server started...")
-
- clientVeth := s.GetInterfaceByName(ClientInterface)
- c := fmt.Sprintf("ip netns exec %s wget --no-proxy --retry-connrefused"+
- " --retry-on-http-error=503 --tries=10 -O %s ", clientNetns, outputFile)
- if proto == "tls" {
- c += " --secure-protocol=TLSv1_3 --no-check-certificate https://"
- }
- c += fmt.Sprintf("%s:555/%s", clientVeth.Ip4AddressString(), srcFileNoPpid)
- s.Log(c)
- _, err = exechelper.CombinedOutput(c)
-
- defer func() { os.Remove(outputFile) }()
-
- s.AssertNil(err, "failed to run wget: '%s', cmd: %s", err, c)
- stopServer <- struct{}{}
-
- s.AssertNil(AssertFileSize(outputFile, srcFilePpid))
- return nil
-}
-
-func configureVppProxy(s *NsSuite, proto string) {
- serverVeth := s.GetInterfaceByName(ServerInterface)
- clientVeth := s.GetInterfaceByName(ClientInterface)
-
- testVppProxy := s.GetContainerByName("vpp").VppInstance
- output := testVppProxy.Vppctl(
- "test proxy server server-uri %s://%s/555 client-uri tcp://%s/666",
+func configureVppProxy(s *VppProxySuite, proto string, proxyPort uint16) {
+ vppProxy := s.GetContainerByName(VppProxyContainerName).VppInstance
+ output := vppProxy.Vppctl(
+ "test proxy server server-uri %s://%s/%d client-uri tcp://%s/%d",
proto,
- clientVeth.Ip4AddressString(),
- serverVeth.Peer.Ip4AddressString(),
+ s.VppProxyAddr(),
+ proxyPort,
+ s.NginxAddr(),
+ s.NginxPort(),
)
s.Log("proxy configured: " + output)
}
-func VppProxyHttpTcpTest(s *NsSuite) {
- proto := "tcp"
- configureVppProxy(s, proto)
- err := testProxyHttpTcp(s, proto)
- s.AssertNil(err, fmt.Sprint(err))
+func VppProxyHttpGetTcpTest(s *VppProxySuite) {
+ var proxyPort uint16 = 8080
+ configureVppProxy(s, "tcp", proxyPort)
+ uri := fmt.Sprintf("http://%s:%d/httpTestFile", s.VppProxyAddr(), proxyPort)
+ s.CurlDownloadResource(uri)
}
-func VppProxyHttpTlsTest(s *NsSuite) {
- proto := "tls"
- configureVppProxy(s, proto)
- err := testProxyHttpTcp(s, proto)
- s.AssertNil(err, fmt.Sprint(err))
+func VppProxyHttpGetTlsTest(s *VppProxySuite) {
+ var proxyPort uint16 = 8080
+ configureVppProxy(s, "tls", proxyPort)
+ uri := fmt.Sprintf("https://%s:%d/httpTestFile", s.VppProxyAddr(), proxyPort)
+ s.CurlDownloadResource(uri)
}
-func configureEnvoyProxy(s *NsSuite) {
- envoyContainer := s.GetContainerByName("envoy")
- s.AssertNil(envoyContainer.Create())
+func VppProxyHttpPutTcpTest(s *VppProxySuite) {
+ var proxyPort uint16 = 8080
+ configureVppProxy(s, "tcp", proxyPort)
+ uri := fmt.Sprintf("http://%s:%d/upload/testFile", s.VppProxyAddr(), proxyPort)
+ s.CurlUploadResource(uri, CurlContainerTestFile)
+}
- serverVeth := s.GetInterfaceByName(ServerInterface)
- address := struct {
- Server string
- }{
- Server: serverVeth.Peer.Ip4AddressString(),
- }
- envoyContainer.CreateConfig(
- "/etc/envoy/envoy.yaml",
- "resources/envoy/proxy.yaml",
- address,
- )
- s.AssertNil(envoyContainer.Start())
+func VppProxyHttpPutTlsTest(s *VppProxySuite) {
+ var proxyPort uint16 = 8080
+ configureVppProxy(s, "tls", proxyPort)
+ uri := fmt.Sprintf("https://%s:%d/upload/testFile", s.VppProxyAddr(), proxyPort)
+ s.CurlUploadResource(uri, CurlContainerTestFile)
+}
+
+func EnvoyProxyHttpGetTcpTest(s *EnvoyProxySuite) {
+ uri := fmt.Sprintf("http://%s:%d/httpTestFile", s.ProxyAddr(), s.ProxyPort())
+ s.CurlDownloadResource(uri)
+}
+
+func EnvoyProxyHttpPutTcpTest(s *EnvoyProxySuite) {
+ uri := fmt.Sprintf("http://%s:%d/upload/testFile", s.ProxyAddr(), s.ProxyPort())
+ s.CurlUploadResource(uri, CurlContainerTestFile)
}
-func EnvoyProxyHttpTcpTest(s *NsSuite) {
- configureEnvoyProxy(s)
- err := testProxyHttpTcp(s, "tcp")
- s.AssertNil(err, fmt.Sprint(err))
+// broken when CPUS > 1
+func NginxMirroringTest(s *NginxProxySuite) {
+ s.SkipIfMultiWorker()
+ uri := fmt.Sprintf("http://%s:%d/httpTestFile", s.ProxyAddr(), s.ProxyPort())
+ s.CurlDownloadResource(uri)
}
diff --git a/extras/hs-test/resources/envoy/proxy.yaml b/extras/hs-test/resources/envoy/proxy.yaml
index 77da80d934d..67eb6909ed2 100644
--- a/extras/hs-test/resources/envoy/proxy.yaml
+++ b/extras/hs-test/resources/envoy/proxy.yaml
@@ -1,17 +1,15 @@
admin:
- access_log_path: /tmp/envoy.log
address:
socket_address:
address: 0.0.0.0
port_value: 8081
static_resources:
listeners:
- # define a reverse proxy on :10001 that always uses :80 as an origin.
- address:
socket_address:
protocol: TCP
address: 0.0.0.0
- port_value: 555
+ port_value: {{.ProxyPort}}
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
@@ -30,6 +28,13 @@ static_resources:
cluster: proxy_service
http_filters:
- name: envoy.filters.http.router
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+ access_log:
+ - name: envoy.access_loggers.file
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
+ path: /tmp/vpp-envoy/{{.LogPrefix}}-access.log
clusters:
- name: proxy_service
connect_timeout: 0.25s
@@ -43,9 +48,8 @@ static_resources:
- endpoint:
address:
socket_address:
- # following address will be generated by Addresser during test run
- address: {{.Server}}
- port_value: 666
+ address: {{.ServerAddress}}
+ port_value: {{.ServerPort}}
bootstrap_extensions:
- name: envoy.extensions.vcl.vcl_socket_interface
typed_config:
diff --git a/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf b/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf
index 56debf5c290..7f6b09c6050 100644
--- a/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf
+++ b/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf
@@ -3,7 +3,7 @@ worker_processes 4;
worker_rlimit_nofile 102400;
daemon off;
-error_log /tmp/nginx/error.log;
+error_log /tmp/nginx/{{.LogPrefix}}-error.log info;
events {
use epoll;
@@ -44,7 +44,8 @@ http {
}
server {
- listen 80;
+ access_log /tmp/nginx/{{.LogPrefix}}-access.log;
+ listen {{.Port}};
server_name {{.Proxy}};
server_tokens off;
diff --git a/extras/hs-test/resources/nginx/nginx_server.conf b/extras/hs-test/resources/nginx/nginx_server.conf
new file mode 100644
index 00000000000..62d27cbbc65
--- /dev/null
+++ b/extras/hs-test/resources/nginx/nginx_server.conf
@@ -0,0 +1,40 @@
+master_process on;
+worker_rlimit_nofile 10240;
+worker_processes 2;
+daemon off;
+
+error_log /tmp/nginx/{{.LogPrefix}}-error.log info;
+
+events {
+ use epoll;
+ worker_connections 10240;
+ accept_mutex off;
+ multi_accept off;
+}
+
+http {
+ keepalive_timeout 300s;
+ keepalive_requests 1000000;
+ sendfile on;
+ server {
+ access_log /tmp/nginx/{{.LogPrefix}}-access.log;
+ listen {{.Port}};
+ server_name {{.Address}};
+ root /usr/share/nginx;
+ index index.html index.htm;
+ location ~ "/upload/([0-9a-zA-Z-.]*)$" {
+ alias /usr/share/nginx/upload/$1;
+ client_body_temp_path /tmp;
+ client_max_body_size 200M;
+ dav_methods PUT;
+ create_full_put_path off;
+ dav_access all:rw;
+ }
+ location /64B {
+ return 200 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
+ }
+ location / {
+ sendfile on;
+ }
+ }
+}
diff --git a/extras/hs-test/resources/nginx/nginx_server_mirroring.conf b/extras/hs-test/resources/nginx/nginx_server_mirroring.conf
index 4056801ea13..921eb2eefd5 100644
--- a/extras/hs-test/resources/nginx/nginx_server_mirroring.conf
+++ b/extras/hs-test/resources/nginx/nginx_server_mirroring.conf
@@ -3,6 +3,8 @@ worker_rlimit_nofile 10240;
worker_processes 2;
daemon off;
+error_log /tmp/nginx/{{.LogPrefix}}-error.log info;
+
events {
use epoll;
worker_connections 10240;
@@ -15,18 +17,17 @@ http {
keepalive_requests 1000000;
sendfile on;
server {
+ access_log /tmp/nginx/{{.LogPrefix}}-access.log;
listen 8091;
listen 8092;
listen 8093;
root /usr/share/nginx;
index index.html index.htm;
- location /return_ok
- {
- return 200 '';
- }
- location /64B.json
- {
+ location /64B {
return 200 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
}
+ location / {
+ sendfile on;
+ }
}
}
diff --git a/extras/hs-test/script/build_hst.sh b/extras/hs-test/script/build_hst.sh
index e7e8a0fb2fa..9b11f5f0272 100755
--- a/extras/hs-test/script/build_hst.sh
+++ b/extras/hs-test/script/build_hst.sh
@@ -84,10 +84,9 @@ docker_build () {
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
index c6b23cf9bdd..09db9b6720d 100755
--- a/extras/hs-test/script/compress.sh
+++ b/extras/hs-test/script/compress.sh
@@ -6,12 +6,12 @@ then
if [ -n "${WORKSPACE}" ]
then
echo -n "Copying docker logs..."
- dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText' ${HS_ROOT}/summary/report.json)
+ dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText | split("/")[1]' ${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/
+ rsync -a --exclude 'volumes' $logDir ${WORKSPACE}/archives/summary/
fi
done
echo "Done."
@@ -32,4 +32,6 @@ then
echo "*************************** SUMMARY ***************************"
cat "${HS_ROOT}/summary/failed-summary.log"
exit 1
+else
+ exit $1
fi
diff --git a/extras/hs-test/script/nginx_server_entrypoint.sh b/extras/hs-test/script/nginx_server_entrypoint.sh
new file mode 100755
index 00000000000..6581c8b74d3
--- /dev/null
+++ b/extras/hs-test/script/nginx_server_entrypoint.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+nginx -c /nginx.conf
diff --git a/extras/hs-test/topo-containers/2peerVethLdp.yaml b/extras/hs-test/topo-containers/2peerVethLdp.yaml
new file mode 100644
index 00000000000..bd6e63a945d
--- /dev/null
+++ b/extras/hs-test/topo-containers/2peerVethLdp.yaml
@@ -0,0 +1,18 @@
+---
+volumes:
+ - volume: &server-vol
+ host-dir: "$HST_VOLUME_DIR/server-share"
+ container-dir: "/tmp/server-share"
+ is-default-work-dir: true
+ - volume: &client-vol
+ host-dir: "$HST_VOLUME_DIR/client-share"
+ container-dir: "/tmp/client-share"
+ is-default-work-dir: true
+
+containers:
+ - name: "server-vpp"
+ volumes:
+ - <<: *server-vol
+ - name: "client-vpp"
+ volumes:
+ - <<: *client-vol
diff --git a/extras/hs-test/topo-containers/envoyProxy.yaml b/extras/hs-test/topo-containers/envoyProxy.yaml
new file mode 100644
index 00000000000..92dd9b93c47
--- /dev/null
+++ b/extras/hs-test/topo-containers/envoyProxy.yaml
@@ -0,0 +1,40 @@
+---
+volumes:
+ - volume: &shared-vol
+ host-dir: "$HST_VOLUME_DIR/shared-vol"
+
+containers:
+ - name: "vpp"
+ volumes:
+ - <<: *shared-vol
+ container-dir: "/tmp/vpp"
+ is-default-work-dir: true
+ - name: "envoy-vcl"
+ volumes:
+ - <<: *shared-vol
+ container-dir: "/tmp/vpp-envoy"
+ is-default-work-dir: true
+ - host-dir: "$HST_DIR/resources/envoy"
+ container-dir: "/tmp"
+ vars:
+ - name: "ENVOY_UID"
+ value: "0"
+ - name: "VCL_CONFIG"
+ value: "/tmp/vcl.conf"
+ image: "envoyproxy/envoy-contrib:v1.30-latest"
+ extra-args: "--log-format [%t][%l][%g:%#]%_ --concurrency 2 -c /etc/envoy/envoy.yaml"
+ is-optional: true
+ - name: "nginx-server"
+ volumes:
+ - <<: *shared-vol
+ container-dir: "/tmp/nginx"
+ is-default-work-dir: true
+ image: "hs-test/nginx-server"
+ is-optional: true
+ - name: "curl"
+ vars:
+ - name: LD_LIBRARY_PATH
+ value: "/usr/local/lib"
+ image: "hs-test/curl"
+ is-optional: true
+ run-detached: false
diff --git a/extras/hs-test/topo-containers/nginxProxy.yaml b/extras/hs-test/topo-containers/nginxProxy.yaml
new file mode 100644
index 00000000000..d9ddc14590f
--- /dev/null
+++ b/extras/hs-test/topo-containers/nginxProxy.yaml
@@ -0,0 +1,32 @@
+---
+volumes:
+ - volume: &shared-vol-nginx-proxy
+ host-dir: "$HST_VOLUME_DIR/shared-vol-nginx-proxy"
+
+containers:
+ - name: "vpp"
+ volumes:
+ - <<: *shared-vol-nginx-proxy
+ container-dir: "/tmp/vpp"
+ is-default-work-dir: true
+ - name: "nginx-proxy"
+ volumes:
+ - <<: *shared-vol-nginx-proxy
+ container-dir: "/tmp/nginx"
+ is-default-work-dir: true
+ image: "hs-test/nginx-ldp"
+ is-optional: true
+ - name: "nginx-server"
+ volumes:
+ - <<: *shared-vol-nginx-proxy
+ container-dir: "/tmp/nginx"
+ is-default-work-dir: true
+ image: "hs-test/nginx-server"
+ is-optional: true
+ - name: "curl"
+ vars:
+ - name: LD_LIBRARY_PATH
+ value: "/usr/local/lib"
+ image: "hs-test/curl"
+ is-optional: true
+ run-detached: false
diff --git a/extras/hs-test/topo-containers/ns.yaml b/extras/hs-test/topo-containers/ns.yaml
index 2298ad232c2..3de5af59569 100644
--- a/extras/hs-test/topo-containers/ns.yaml
+++ b/extras/hs-test/topo-containers/ns.yaml
@@ -22,6 +22,6 @@ containers:
value: "0"
- name: "VCL_CONFIG"
value: "/tmp/vcl.conf"
- image: "envoyproxy/envoy-contrib:v1.21-latest"
+ image: "envoyproxy/envoy-contrib:v1.30-latest"
extra-args: "--concurrency 2 -c /etc/envoy/envoy.yaml"
is-optional: true
diff --git a/extras/hs-test/topo-containers/nginxProxyAndServer.yaml b/extras/hs-test/topo-containers/vppProxy.yaml
index cc6b780bafc..a1f24bbc187 100644
--- a/extras/hs-test/topo-containers/nginxProxyAndServer.yaml
+++ b/extras/hs-test/topo-containers/vppProxy.yaml
@@ -1,20 +1,25 @@
---
volumes:
- - volume: &shared-vol-proxy
- host-dir: "$HST_VOLUME_DIR/shared-vol-proxy"
+ - volume: &shared-vol
+ host-dir: "$HST_VOLUME_DIR/shared-vol"
containers:
- name: "vpp-proxy"
volumes:
- - <<: *shared-vol-proxy
+ - <<: *shared-vol
container-dir: "/tmp/vpp"
is-default-work-dir: true
- - name: "nginx-proxy"
+ - name: "nginx-server"
volumes:
- - <<: *shared-vol-proxy
+ - <<: *shared-vol
container-dir: "/tmp/nginx"
is-default-work-dir: true
- image: "hs-test/nginx-ldp"
- is-optional: true
- - name: "nginx-server"
image: "hs-test/nginx-server"
+ is-optional: true
+ - name: "curl"
+ vars:
+ - name: LD_LIBRARY_PATH
+ value: "/usr/local/lib"
+ image: "hs-test/curl"
+ is-optional: true
+ run-detached: false
diff --git a/extras/scripts/checkstyle.sh b/extras/scripts/checkstyle.sh
index 2b884f5f08b..304beff51d0 100755
--- a/extras/scripts/checkstyle.sh
+++ b/extras/scripts/checkstyle.sh
@@ -19,7 +19,7 @@ CLANG_FORMAT_VER_REGEX='([0-9]+)\.[0-9]+\.[0-9]+'
CLANG_FORMAT_DIFF="/usr/share/clang/clang-format-diff.py"
# TODO: Remove clang-format-${CLANG_FORMAT_VER} from 'make install-deps' when
-# CLANG_FORMAT_VER default value is upgraded
+# CLANG_FORMAT_VER default value is upgraded to 15 after Ubuntu-20.04 is deprecated
CLANG_FORMAT_VER=${CLANG_FORMAT_VER:-11}
GIT_DIFF_ARGS="-U0 --no-color --relative HEAD~1"
GIT_DIFF_EXCLUDE_LIST=(
@@ -30,16 +30,20 @@ CLANG_FORMAT_DIFF_ARGS="-style file -p1"
SUFFIX="-${CLANG_FORMAT_VER}"
# Attempt to find clang-format to confirm Clang version.
-if command -v clang-format${SUFFIX} &> /dev/null;
+if command -v "clang-format${SUFFIX}" &> /dev/null;
then
- CLANG_FORMAT=clang-format${SUFFIX}
-elif command -v clang-format &> /dev/null;
-then
- CLANG_FORMAT=clang-format
+ CLANG_FORMAT="clang-format${SUFFIX}"
+else
+ echo "*******************************************************************"
+ echo "* CHECKSTYLE FAILED"
+ echo "* Could not locate the clang-format${SUFFIX} script"
+ echo "* Run 'make install-deps' to install it"
+ echo "*******************************************************************"
+ exit 1
fi
CLANG_FORMAT_VERSION=$(${CLANG_FORMAT} --version)
-echo $CLANG_FORMAT_VERSION
+echo "$CLANG_FORMAT_VERSION"
# Confirm that Clang is the expected version.
if [[ ! $CLANG_FORMAT_VERSION =~ $CLANG_FORMAT_VER_REGEX ]];
@@ -75,6 +79,7 @@ then
echo "*******************************************************************"
echo "* CHECKSTYLE FAILED"
echo "* Could not locate the clang-format-diff script"
+ echo "* Run 'make install-deps' to install it"
echo "*******************************************************************"
exit 1
fi
diff --git a/src/cmake/platform/cn913x.cmake b/src/cmake/platform/cn913x.cmake
new file mode 100644
index 00000000000..8c5cb739f9b
--- /dev/null
+++ b/src/cmake/platform/cn913x.cmake
@@ -0,0 +1,3 @@
+
+set(VPP_PLATFORM_CACHE_LINE_SIZE 64)
+set(VPP_PLATFORM_MARCH_FLAGS -march=armv8-a+crc+crypto)
diff --git a/src/plugins/avf/avf.h b/src/plugins/avf/avf.h
index f6f79cf0e09..774aac0151b 100644
--- a/src/plugins/avf/avf.h
+++ b/src/plugins/avf/avf.h
@@ -180,6 +180,7 @@ typedef struct
u8 int_mode;
u8 buffer_pool_index;
u32 queue_index;
+ u64 total_packets;
} avf_rxq_t;
typedef struct
@@ -198,6 +199,8 @@ typedef struct
avf_tx_desc_t *tmp_descs;
u32 *tmp_bufs;
u32 queue_index;
+ u64 total_packets;
+ u64 no_free_tx_count;
} avf_txq_t;
typedef struct
diff --git a/src/plugins/avf/device.c b/src/plugins/avf/device.c
index 1618800c432..98169f0bcfe 100644
--- a/src/plugins/avf/device.c
+++ b/src/plugins/avf/device.c
@@ -288,6 +288,7 @@ avf_rxq_init (vlib_main_t * vm, avf_device_t * ad, u16 qid, u16 rxq_size)
d->qword[0] = vlib_buffer_get_pa (vm, b);
d++;
}
+ rxq->total_packets = 0;
return 0;
}
@@ -337,6 +338,9 @@ avf_txq_init (vlib_main_t * vm, avf_device_t * ad, u16 qid, u16 txq_size)
vec_validate_aligned (txq->tmp_descs, txq->size, CLIB_CACHE_LINE_BYTES);
vec_validate_aligned (txq->tmp_bufs, txq->size, CLIB_CACHE_LINE_BYTES);
+ txq->total_packets = 0;
+ txq->no_free_tx_count = 0;
+
return 0;
}
diff --git a/src/plugins/avf/format.c b/src/plugins/avf/format.c
index 0a153a093d9..436f5b9fbf2 100644
--- a/src/plugins/avf/format.c
+++ b/src/plugins/avf/format.c
@@ -104,6 +104,7 @@ format_avf_device (u8 * s, va_list * args)
u8 *a = 0;
avf_rxq_t *rxq = vec_elt_at_index (ad->rxqs, 0);
avf_txq_t *txq = vec_elt_at_index (ad->txqs, 0);
+ u32 idx = 0;
s = format (s, "rx: queues %u, desc %u (min %u max %u)", ad->n_rx_queues,
rxq->size, AVF_QUEUE_SZ_MIN, AVF_QUEUE_SZ_MAX);
@@ -114,6 +115,22 @@ format_avf_device (u8 * s, va_list * args)
format_avf_device_flags, ad);
s = format (s, "\n%Ucapability flags: %U", format_white_space, indent,
format_avf_vf_cap_flags, ad->cap_flags);
+ s =
+ format (s, "\n%U Rx Queue: Total Packets", format_white_space, indent + 4);
+ for (idx = 0; idx < ad->n_rx_queues; idx++)
+ {
+ rxq = vec_elt_at_index (ad->rxqs, idx);
+ s = format (s, "\n%U %8u : %llu", format_white_space, indent + 4, idx,
+ rxq->total_packets);
+ }
+ s = format (s, "\n%U Tx Queue: Total Packets\t Total Drops",
+ format_white_space, indent + 4);
+ for (idx = 0; idx < ad->n_tx_queues; idx++)
+ {
+ txq = vec_elt_at_index (ad->txqs, idx);
+ s = format (s, "\n%U %8u : %llu\t %llu", format_white_space, indent + 4,
+ idx, txq->total_packets, txq->no_free_tx_count);
+ }
s = format (s, "\n%Unum-queue-pairs %d max-vectors %u max-mtu %u "
"rss-key-size %u rss-lut-size %u", format_white_space, indent,
diff --git a/src/plugins/avf/input.c b/src/plugins/avf/input.c
index 06007db540d..890259c88ab 100644
--- a/src/plugins/avf/input.c
+++ b/src/plugins/avf/input.c
@@ -539,6 +539,8 @@ done:
else
avf_rxq_refill (vm, node, rxq, 0 /* use_va_dma */ );
+ rxq->total_packets += n_rx_packets;
+
return n_rx_packets;
}
diff --git a/src/plugins/avf/output.c b/src/plugins/avf/output.c
index daa86ae86b2..0952886aaee 100644
--- a/src/plugins/avf/output.c
+++ b/src/plugins/avf/output.c
@@ -510,6 +510,7 @@ retry:
avf_tail_write (txq->qtx_tail, txq->next);
txq->n_enqueued += n_desc;
n_left -= n_enq;
+ txq->total_packets += n_enq;
}
if (n_left)
@@ -522,6 +523,7 @@ retry:
vlib_buffer_free (vm, buffers, n_left);
vlib_error_count (vm, node->node_index,
AVF_TX_ERROR_NO_FREE_SLOTS, n_left);
+ txq->no_free_tx_count += n_left;
}
if (tf->shared_queue)
diff --git a/src/plugins/builtinurl/FEATURE.yaml b/src/plugins/builtinurl/FEATURE.yaml
deleted file mode 100644
index ba8e3c7ea7b..00000000000
--- a/src/plugins/builtinurl/FEATURE.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
----
-name: Builtin URL support for the static http or https server
-maintainer: Dave Barach <dave@barachs.net>
-features:
- - Builtin URLs for the static http/https server
-description: "The (builtinurl) plugin adds a set of URLs to the static http/https server.
- Current URLs, all of which return data in .json fmt:
- <root-url>/version.json - vpp version info
- <root-url>/interface_list.json - list of interfaces
- <root-url>/interface_stats - single interface via HTTP POST
- <root-url>/interface_stats - all intfcs via HTTP GET."
-state: development
-properties: [API, CLI, MULTITHREAD]
diff --git a/src/plugins/builtinurl/builtins.c b/src/plugins/builtinurl/builtins.c
deleted file mode 100644
index 6a0975503a7..00000000000
--- a/src/plugins/builtinurl/builtins.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vnet/vnet.h>
-#include <builtinurl/builtinurl.h>
-#include <http_static/http_static.h>
-#include <vpp/app/version.h>
-
-hss_url_handler_rc_t
-handle_get_version (hss_url_handler_args_t *args)
-{
- u8 *s = 0;
-
- /* Build some json bullshit */
- s = format (s, "{\"vpp_details\": {");
- s = format (s, " \"version\": \"%s\",", VPP_BUILD_VER);
- s = format (s, " \"build_date\": \"%s\"}}\r\n", VPP_BUILD_DATE);
-
- args->data = s;
- args->data_len = vec_len (s);
- args->free_vec_data = 1;
- return HSS_URL_HANDLER_OK;
-}
-
-void
-trim_path_from_request (u8 * s, char *path)
-{
- u8 *cp;
- int trim_length = strlen (path) + 1 /* remove '?' */ ;
-
- /* Get rid of the path and question-mark */
- vec_delete (s, trim_length, 0);
-
- /* Tail trim irrelevant browser info */
- cp = s;
- while ((cp - s) < vec_len (s))
- {
- if (*cp == ' ')
- {
- /*
- * Makes request a vector which happens to look
- * like a c-string.
- */
- *cp = 0;
- vec_set_len (s, cp - s);
- break;
- }
- cp++;
- }
-}
-
-hss_url_handler_rc_t
-handle_get_interface_stats (hss_url_handler_args_t *args)
-{
- u8 *s = 0, *stats = 0;
- uword *p;
- u32 *sw_if_indices = 0;
- vnet_hw_interface_t *hi;
- vnet_sw_interface_t *si;
- char *q = "\"";
- int i;
- int need_comma = 0;
- u8 *format_vnet_sw_interface_cntrs (u8 * s, vnet_interface_main_t * im,
- vnet_sw_interface_t * si, int json);
- vnet_main_t *vnm = vnet_get_main ();
- vnet_interface_main_t *im = &vnm->interface_main;
-
- /* Get stats for a single interface via http POST */
- if (args->req_type == HTTP_REQ_POST)
- {
- /* Find the sw_if_index */
- p = hash_get (im->hw_interface_by_name, args->req_data);
- if (!p)
- {
- s = format (s, "{\"interface_stats\": {[\n");
- s = format (s, " \"name\": \"%s\",", args->req_data);
- s = format (s, " \"error\": \"%s\"", "UnknownInterface");
- s = format (s, "]}\n");
- goto out;
- }
-
- vec_add1 (sw_if_indices, p[0]);
- }
- else /* default, HTTP_BUILTIN_METHOD_GET */
- {
- pool_foreach (hi, im->hw_interfaces)
- {
- vec_add1 (sw_if_indices, hi->sw_if_index);
- }
- }
-
- s = format (s, "{%sinterface_stats%s: [\n", q, q);
-
- for (i = 0; i < vec_len (sw_if_indices); i++)
- {
- si = vnet_get_sw_interface (vnm, sw_if_indices[i]);
- if (need_comma)
- s = format (s, ",\n");
-
- need_comma = 1;
-
- s = format (s, "{%sname%s: %s%U%s, ", q, q, q,
- format_vnet_sw_if_index_name, vnm, sw_if_indices[i], q);
-
- stats = format_vnet_sw_interface_cntrs (stats, &vnm->interface_main, si,
- 1 /* want json */ );
- if (vec_len (stats))
- s = format (s, "%v}", stats);
- else
- s = format (s, "%snone%s: %strue%s}", q, q, q, q);
- vec_reset_length (stats);
- }
-
- s = format (s, "]}\n");
-
-out:
- args->data = s;
- args->data_len = vec_len (s);
- args->free_vec_data = 1;
- vec_free (sw_if_indices);
- vec_free (stats);
- return HSS_URL_HANDLER_OK;
-}
-
-hss_url_handler_rc_t
-handle_get_interface_list (hss_url_handler_args_t *args)
-{
- u8 *s = 0;
- int i;
- vnet_main_t *vnm = vnet_get_main ();
- vnet_interface_main_t *im = &vnm->interface_main;
- vnet_hw_interface_t *hi;
- u32 *hw_if_indices = 0;
- int need_comma = 0;
-
- /* Construct vector of active hw_if_indexes ... */
- pool_foreach (hi, im->hw_interfaces)
- {
- /* No point in mentioning "local0"... */
- if (hi - im->hw_interfaces)
- vec_add1 (hw_if_indices, hi - im->hw_interfaces);
- }
-
- /* Build answer */
- s = format (s, "{\"interface_list\": [\n");
- for (i = 0; i < vec_len (hw_if_indices); i++)
- {
- if (need_comma)
- s = format (s, ",\n");
- hi = pool_elt_at_index (im->hw_interfaces, hw_if_indices[i]);
- s = format (s, "\"%v\"", hi->name);
- need_comma = 1;
- }
- s = format (s, "]}\n");
- vec_free (hw_if_indices);
-
- args->data = s;
- args->data_len = vec_len (s);
- args->free_vec_data = 1;
- return HSS_URL_HANDLER_OK;
-}
-
-void
-builtinurl_handler_init (builtinurl_main_t * bm)
-{
-
- bm->register_handler (handle_get_version, "version.json", HTTP_REQ_GET);
- bm->register_handler (handle_get_interface_list, "interface_list.json",
- HTTP_REQ_GET);
- bm->register_handler (handle_get_interface_stats, "interface_stats.json",
- HTTP_REQ_GET);
- bm->register_handler (handle_get_interface_stats, "interface_stats.json",
- HTTP_REQ_POST);
-}
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/builtinurl/builtinurl.api b/src/plugins/builtinurl/builtinurl.api
deleted file mode 100644
index 80efa73c725..00000000000
--- a/src/plugins/builtinurl/builtinurl.api
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * builtinurl.api - binary API skeleton
- *
- * Copyright (c) <current-year> <your-organization>
- * 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.
- */
-
-/**
- * @file builtinurl.api
- * @brief VPP control-plane API messages.
- *
- * This file defines VPP control-plane binary API messages which are generally
- * called through a shared memory interface.
- */
-
-/* Version and type recitations */
-
-option version = "1.0.0";
-
-/** @brief API to enable / disable builtinurl on an interface
- @param client_index - opaque cookie to identify the sender
- @param context - sender context, to match reply w/ request
- @param enable_disable - 1 to enable, 0 to disable the feature
- @param sw_if_index - interface handle
-*/
-
-autoreply define builtinurl_enable {
- option deprecated="incorporated in http_static plugin";
- /* Client identifier, set from api_main.my_client_index */
- u32 client_index;
-
- /* Arbitrary context, so client can match reply to request */
- u32 context;
-};
diff --git a/src/plugins/builtinurl/builtinurl.c b/src/plugins/builtinurl/builtinurl.c
deleted file mode 100644
index 749a2c93b8a..00000000000
--- a/src/plugins/builtinurl/builtinurl.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * builtinurl.c - skeleton vpp engine plug-in
- *
- * Copyright (c) 2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vnet/vnet.h>
-#include <vnet/plugin/plugin.h>
-#include <builtinurl/builtinurl.h>
-
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <vpp/app/version.h>
-#include <stdbool.h>
-
-/* define message IDs */
-#include <builtinurl/builtinurl.api_enum.h>
-#include <builtinurl/builtinurl.api_types.h>
-
-#define REPLY_MSG_ID_BASE bmp->msg_id_base
-#include <vlibapi/api_helper_macros.h>
-
-builtinurl_main_t builtinurl_main;
-
-/* Action function shared between message handler and debug CLI */
-
-int
-builtinurl_enable (builtinurl_main_t * bmp)
-{
- void (*fp) (void *, char *, int);
-
- if (bmp->initialized)
- return 0;
-
- /* Look up the builtin URL registration handler */
- fp = vlib_get_plugin_symbol
- ("http_static_plugin.so", "http_static_server_register_builtin_handler");
-
- /* Most likely, the http_static plugin isn't loaded. Done. */
- if (fp == 0)
- return VNET_API_ERROR_NO_SUCH_TABLE;
-
- bmp->register_handler = fp;
- builtinurl_handler_init (bmp);
- bmp->initialized = 1;
-
- return 0;
-}
-
-static clib_error_t *
-builtinurl_enable_command_fn (vlib_main_t * vm,
- unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- builtinurl_main_t *bmp = &builtinurl_main;
-
- int rv;
-
- rv = builtinurl_enable (bmp);
-
- switch (rv)
- {
- case 0:
- break;
-
- case VNET_API_ERROR_NO_SUCH_TABLE:
- return clib_error_return
- (0, "http_static_server_register_builtin_handler undefined");
- break;
-
- default:
- return clib_error_return (0, "builtinurl_enable returned %d", rv);
- }
- return 0;
-}
-
-VLIB_CLI_COMMAND (builtinurl_enable_command, static) =
-{
- .path = "builtinurl enable",
- .short_help = "Turn on builtin http/https GET and POST urls",
- .function = builtinurl_enable_command_fn,
-};
-
-/* API message handler */
-static void vl_api_builtinurl_enable_t_handler
- (vl_api_builtinurl_enable_t * mp)
-{
- vl_api_builtinurl_enable_reply_t *rmp;
- builtinurl_main_t *bmp = &builtinurl_main;
- int rv;
-
- rv = builtinurl_enable (bmp);
-
- REPLY_MACRO (VL_API_BUILTINURL_ENABLE_REPLY);
-}
-
-#include <builtinurl/builtinurl.api.c>
-static clib_error_t *
-builtinurl_init (vlib_main_t * vm)
-{
- builtinurl_main_t *bmp = &builtinurl_main;
-
- bmp->vlib_main = vm;
- bmp->vnet_main = vnet_get_main ();
-
- /* Ask for a correctly-sized block of API message decode slots */
- bmp->msg_id_base = setup_message_id_table ();
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (builtinurl_init);
-
-VLIB_PLUGIN_REGISTER () =
-{
- .version = VPP_BUILD_VER,
- .description = "vpp built-in URL support",
-};
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/builtinurl/builtinurl.h b/src/plugins/builtinurl/builtinurl.h
deleted file mode 100644
index 91302c1eee5..00000000000
--- a/src/plugins/builtinurl/builtinurl.h
+++ /dev/null
@@ -1,57 +0,0 @@
-
-/*
- * builtinurl.h - built-in URLs for the http static server
- *
- * Copyright (c) 2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef __included_builtinurl_h__
-#define __included_builtinurl_h__
-
-#include <vnet/vnet.h>
-#include <vnet/ip/ip.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <vppinfra/hash.h>
-#include <vppinfra/error.h>
-
-typedef struct
-{
- /* API message ID base */
- u16 msg_id_base;
-
- /* GET / POST handler registration function */
- void (*register_handler) (void *, char *, int);
-
- /* Been there, done that */
- int initialized;
-
- /* convenience */
- vlib_main_t *vlib_main;
- vnet_main_t *vnet_main;
- ethernet_main_t *ethernet_main;
-} builtinurl_main_t;
-
-extern builtinurl_main_t builtinurl_main;
-
-void builtinurl_handler_init (builtinurl_main_t * bm);
-
-#endif /* __included_builtinurl_h__ */
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/builtinurl/builtinurl_test.c b/src/plugins/builtinurl/builtinurl_test.c
deleted file mode 100644
index 9edfb81c525..00000000000
--- a/src/plugins/builtinurl/builtinurl_test.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * builtinurl.c - skeleton vpp-api-test plug-in
- *
- * Copyright (c) 2019 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <vat/vat.h>
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-#include <vppinfra/error.h>
-#include <stdbool.h>
-
-uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
-
-/* Declare message IDs */
-#include <builtinurl/builtinurl.api_enum.h>
-#include <builtinurl/builtinurl.api_types.h>
-
-typedef struct
-{
- /* API message ID base */
- u16 msg_id_base;
- vat_main_t *vat_main;
-} builtinurl_test_main_t;
-
-builtinurl_test_main_t builtinurl_test_main;
-
-#define __plugin_msg_base builtinurl_test_main.msg_id_base
-#include <vlibapi/vat_helper_macros.h>
-
-static int
-api_builtinurl_enable (vat_main_t * vam)
-{
- vl_api_builtinurl_enable_t *mp;
- int ret;
-
- /* Construct the API message */
- M (BUILTINURL_ENABLE, mp);
-
- /* send it... */
- S (mp);
-
- /* Wait for a reply... */
- W (ret);
- return ret;
-}
-
-#include <builtinurl/builtinurl.api_test.c>
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/crypto_native/aes_cbc.c b/src/plugins/crypto_native/aes_cbc.c
index dd7ca3f1cf1..c981897783f 100644
--- a/src/plugins/crypto_native/aes_cbc.c
+++ b/src/plugins/crypto_native/aes_cbc.c
@@ -25,191 +25,40 @@
#pragma GCC optimize ("O3")
#endif
-#if defined(__VAES__) && defined(__AVX512F__)
-#define u8xN u8x64
-#define u32xN u32x16
-#define u32xN_min_scalar u32x16_min_scalar
-#define u32xN_is_all_zero u32x16_is_all_zero
-#define u32xN_splat u32x16_splat
-#elif defined(__VAES__)
-#define u8xN u8x32
-#define u32xN u32x8
-#define u32xN_min_scalar u32x8_min_scalar
-#define u32xN_is_all_zero u32x8_is_all_zero
-#define u32xN_splat u32x8_splat
-#else
-#define u8xN u8x16
-#define u32xN u32x4
-#define u32xN_min_scalar u32x4_min_scalar
-#define u32xN_is_all_zero u32x4_is_all_zero
-#define u32xN_splat u32x4_splat
-#endif
+#define CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE 256
static_always_inline u32
aes_ops_enc_aes_cbc (vlib_main_t * vm, vnet_crypto_op_t * ops[],
u32 n_ops, aes_key_size_t ks)
{
crypto_native_main_t *cm = &crypto_native_main;
- int rounds = AES_KEY_ROUNDS (ks);
- u8 placeholder[8192];
- u32 i, j, count, n_left = n_ops;
- u32xN placeholder_mask = { };
- u32xN len = { };
- vnet_crypto_key_index_t key_index[4 * N_AES_LANES];
- u8 *src[4 * N_AES_LANES] = {};
- u8 *dst[4 * N_AES_LANES] = {};
- u8xN r[4] = {};
- u8xN k[15][4] = {};
-
- for (i = 0; i < 4 * N_AES_LANES; i++)
- key_index[i] = ~0;
-
-more:
- for (i = 0; i < 4 * N_AES_LANES; i++)
- if (len[i] == 0)
- {
- if (n_left == 0)
- {
- /* no more work to enqueue, so we are enqueueing placeholder buffer */
- src[i] = dst[i] = placeholder;
- len[i] = sizeof (placeholder);
- placeholder_mask[i] = 0;
- }
- else
- {
- u8x16 t = aes_block_load (ops[0]->iv);
- ((u8x16 *) r)[i] = t;
-
- src[i] = ops[0]->src;
- dst[i] = ops[0]->dst;
- len[i] = ops[0]->len;
- placeholder_mask[i] = ~0;
- if (key_index[i] != ops[0]->key_index)
- {
- aes_cbc_key_data_t *kd;
- key_index[i] = ops[0]->key_index;
- kd = (aes_cbc_key_data_t *) cm->key_data[key_index[i]];
- for (j = 0; j < rounds + 1; j++)
- ((u8x16 *) k[j])[i] = kd->encrypt_key[j];
- }
- ops[0]->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
- n_left--;
- ops++;
- }
- }
-
- count = u32xN_min_scalar (len);
-
- ASSERT (count % 16 == 0);
-
- for (i = 0; i < count; i += 16)
+ u32 i, n_left = n_ops;
+ uword key_indices[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {};
+ u8 *plaintext[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {};
+ uword oplen[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {};
+ u8 *iv[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {};
+ u8 *ciphertext[CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE] = {};
+
+ while (n_left)
{
-#if defined(__VAES__) && defined(__AVX512F__)
- r[0] = u8x64_xor3 (r[0], aes_block_load_x4 (src, i), k[0][0]);
- r[1] = u8x64_xor3 (r[1], aes_block_load_x4 (src + 4, i), k[0][1]);
- r[2] = u8x64_xor3 (r[2], aes_block_load_x4 (src + 8, i), k[0][2]);
- r[3] = u8x64_xor3 (r[3], aes_block_load_x4 (src + 12, i), k[0][3]);
-
- for (j = 1; j < rounds; j++)
+ i = 0;
+ while (n_left && i < CRYPTO_NATIVE_AES_CBC_ENC_VEC_SIZE)
{
- r[0] = aes_enc_round_x4 (r[0], k[j][0]);
- r[1] = aes_enc_round_x4 (r[1], k[j][1]);
- r[2] = aes_enc_round_x4 (r[2], k[j][2]);
- r[3] = aes_enc_round_x4 (r[3], k[j][3]);
+ key_indices[i] = ops[0]->key_index;
+ plaintext[i] = ops[0]->src;
+ ciphertext[i] = ops[0]->dst;
+ oplen[i] = ops[0]->len;
+ iv[i] = ops[0]->iv;
+ ops[0]->status = VNET_CRYPTO_OP_STATUS_COMPLETED;
+
+ ops++;
+ n_left--;
+ i++;
}
- r[0] = aes_enc_last_round_x4 (r[0], k[j][0]);
- r[1] = aes_enc_last_round_x4 (r[1], k[j][1]);
- r[2] = aes_enc_last_round_x4 (r[2], k[j][2]);
- r[3] = aes_enc_last_round_x4 (r[3], k[j][3]);
-
- aes_block_store_x4 (dst, i, r[0]);
- aes_block_store_x4 (dst + 4, i, r[1]);
- aes_block_store_x4 (dst + 8, i, r[2]);
- aes_block_store_x4 (dst + 12, i, r[3]);
-#elif defined(__VAES__)
- r[0] = u8x32_xor3 (r[0], aes_block_load_x2 (src, i), k[0][0]);
- r[1] = u8x32_xor3 (r[1], aes_block_load_x2 (src + 2, i), k[0][1]);
- r[2] = u8x32_xor3 (r[2], aes_block_load_x2 (src + 4, i), k[0][2]);
- r[3] = u8x32_xor3 (r[3], aes_block_load_x2 (src + 6, i), k[0][3]);
-
- for (j = 1; j < rounds; j++)
- {
- r[0] = aes_enc_round_x2 (r[0], k[j][0]);
- r[1] = aes_enc_round_x2 (r[1], k[j][1]);
- r[2] = aes_enc_round_x2 (r[2], k[j][2]);
- r[3] = aes_enc_round_x2 (r[3], k[j][3]);
- }
- r[0] = aes_enc_last_round_x2 (r[0], k[j][0]);
- r[1] = aes_enc_last_round_x2 (r[1], k[j][1]);
- r[2] = aes_enc_last_round_x2 (r[2], k[j][2]);
- r[3] = aes_enc_last_round_x2 (r[3], k[j][3]);
-
- aes_block_store_x2 (dst, i, r[0]);
- aes_block_store_x2 (dst + 2, i, r[1]);
- aes_block_store_x2 (dst + 4, i, r[2]);
- aes_block_store_x2 (dst + 6, i, r[3]);
-#else
-#if __x86_64__
- r[0] = u8x16_xor3 (r[0], aes_block_load (src[0] + i), k[0][0]);
- r[1] = u8x16_xor3 (r[1], aes_block_load (src[1] + i), k[0][1]);
- r[2] = u8x16_xor3 (r[2], aes_block_load (src[2] + i), k[0][2]);
- r[3] = u8x16_xor3 (r[3], aes_block_load (src[3] + i), k[0][3]);
-
- for (j = 1; j < rounds; j++)
- {
- r[0] = aes_enc_round_x1 (r[0], k[j][0]);
- r[1] = aes_enc_round_x1 (r[1], k[j][1]);
- r[2] = aes_enc_round_x1 (r[2], k[j][2]);
- r[3] = aes_enc_round_x1 (r[3], k[j][3]);
- }
-
- r[0] = aes_enc_last_round_x1 (r[0], k[j][0]);
- r[1] = aes_enc_last_round_x1 (r[1], k[j][1]);
- r[2] = aes_enc_last_round_x1 (r[2], k[j][2]);
- r[3] = aes_enc_last_round_x1 (r[3], k[j][3]);
-
- aes_block_store (dst[0] + i, r[0]);
- aes_block_store (dst[1] + i, r[1]);
- aes_block_store (dst[2] + i, r[2]);
- aes_block_store (dst[3] + i, r[3]);
-#else
- r[0] ^= aes_block_load (src[0] + i);
- r[1] ^= aes_block_load (src[1] + i);
- r[2] ^= aes_block_load (src[2] + i);
- r[3] ^= aes_block_load (src[3] + i);
- for (j = 0; j < rounds - 1; j++)
- {
- r[0] = vaesmcq_u8 (vaeseq_u8 (r[0], k[j][0]));
- r[1] = vaesmcq_u8 (vaeseq_u8 (r[1], k[j][1]));
- r[2] = vaesmcq_u8 (vaeseq_u8 (r[2], k[j][2]));
- r[3] = vaesmcq_u8 (vaeseq_u8 (r[3], k[j][3]));
- }
- r[0] = vaeseq_u8 (r[0], k[j][0]) ^ k[rounds][0];
- r[1] = vaeseq_u8 (r[1], k[j][1]) ^ k[rounds][1];
- r[2] = vaeseq_u8 (r[2], k[j][2]) ^ k[rounds][2];
- r[3] = vaeseq_u8 (r[3], k[j][3]) ^ k[rounds][3];
- aes_block_store (dst[0] + i, r[0]);
- aes_block_store (dst[1] + i, r[1]);
- aes_block_store (dst[2] + i, r[2]);
- aes_block_store (dst[3] + i, r[3]);
-#endif
-#endif
+ clib_aes_cbc_encrypt_multi ((aes_cbc_key_data_t **) cm->key_data,
+ key_indices, plaintext, oplen, iv, ks,
+ ciphertext, i);
}
-
- len -= u32xN_splat (count);
-
- for (i = 0; i < 4 * N_AES_LANES; i++)
- {
- src[i] += count;
- dst[i] += count;
- }
-
- if (n_left > 0)
- goto more;
-
- if (!u32xN_is_all_zero (len & placeholder_mask))
- goto more;
-
return n_ops;
}
diff --git a/src/plugins/dev_armada/CMakeLists.txt b/src/plugins/dev_armada/CMakeLists.txt
new file mode 100644
index 00000000000..f955a9baa91
--- /dev/null
+++ b/src/plugins/dev_armada/CMakeLists.txt
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright(c) 2022 Cisco Systems, Inc.
+
+
+find_path(MUSDK_INCLUDE_DIR NAMES mv_std.h)
+find_library(MUSDK_LIB NAMES libmusdk.a)
+
+if(NOT MUSDK_INCLUDE_DIR OR NOT MUSDK_LIB)
+ message(WARNING "Marvell MUSDK not found - dev_armada plugin disabled")
+ return()
+endif()
+
+get_filename_component(MUSDK_LIB_DIR ${MUSDK_LIB} DIRECTORY)
+set(MUSDK_LINK_FLAGS "-Wl,--whole-archive,${MUSDK_LIB_DIR}/libmusdk.a,--no-whole-archive")
+
+add_vpp_plugin(dev_armada
+ SOURCES
+ plugin.c
+ pp2/init.c
+ pp2/format.c
+ pp2/port.c
+ pp2/queue.c
+ pp2/rx.c
+ pp2/tx.c
+
+ LINK_FLAGS
+ ${MUSDK_LINK_FLAGS}
+)
+include_directories(${MUSDK_INCLUDE_DIR})
+
diff --git a/src/plugins/dev_armada/README.rst b/src/plugins/dev_armada/README.rst
new file mode 100644
index 00000000000..2c757d04a06
--- /dev/null
+++ b/src/plugins/dev_armada/README.rst
@@ -0,0 +1,61 @@
+Armada device plugin
+=====================
+
+Overview
+--------
+
+This plugins provides native device support for Marvell PP2 network
+device, found in Marvel Armada family of SOCs.
+It uses Marvell Usermode SDK
+(`MUSDK <https://github.com/MarvellEmbeddedProcessors/musdk-marvell>`__).
+
+Prerequisites
+-------------
+
+Plugins depends on installed MUSDK and Marvell provided linux in Marvell SDK.
+Following kernel modules from MUSDK must be loaded for plugin to work:
+``musdk_cma.ko``
+``mv_pp_uio.ko``
+
+Musdk 18.09.3 compilation steps
+-------------------------------
+
+::
+
+ ./bootstrap
+ ./configure --prefix=/opt/vpp/external/aarch64/ CFLAGS="-Wno-error=unused-result -g -fPIC" --enable-shared=no
+ sed -i -e 's/marvell,mv-pp-uio/generic-uio/' modules/pp2/mv_pp_uio.c
+ sed -i -e 's/O_CREAT/O_CREAT, S_IRUSR | S_IWUSR/' src/lib/file_utils.c
+ make
+ sudo make install
+
+Usage
+-----
+
+Interface Creation and Deletion
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Interfaces are using new vnet dev APIs, CLIs or startup.conf to create and
+delete interfaces.
+
+Sample startup.conf:
+
+::
+
+ devices {
+ dev platform/f2000000.ethernet {
+ port 1 { name ppio1 }
+ }
+
+Device identifier in this example is 'platform/f2000000.ethernet' where
+'platform' is bus name and 'f2000000.ethernet' is linux platform bus
+identifier for specific PP2.
+
+Platform identifier can be found in sysfs:
+
+::
+
+ $ ls /sys/bus/platform/devices | grep ethernet
+ f2000000.ethernet
+
+
diff --git a/src/plugins/dev_armada/musdk.h b/src/plugins/dev_armada/musdk.h
new file mode 100644
index 00000000000..aad2f4a1cef
--- /dev/null
+++ b/src/plugins/dev_armada/musdk.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#ifndef _MUSDK_H_
+#define _MUSDK_H_
+
+#define MVCONF_DBG_LEVEL 0
+#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
+#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
+#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
+#define MVCONF_SYS_DMA_UIO
+#define MVCONF_TYPES_PUBLIC
+#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
+
+#include <mv_std.h>
+#include <env/mv_sys_dma.h>
+#include <drivers/mv_pp2.h>
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_ppio.h>
+
+#endif /* _MUSDK_H_ */
diff --git a/src/plugins/dev_armada/plugin.c b/src/plugins/dev_armada/plugin.c
new file mode 100644
index 00000000000..1dc465c9a25
--- /dev/null
+++ b/src/plugins/dev_armada/plugin.c
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+VLIB_PLUGIN_REGISTER () = {
+ .version = VPP_BUILD_VER,
+ .description = "Marvell Armada Drivers",
+};
diff --git a/src/plugins/dev_armada/pp2/format.c b/src/plugins/dev_armada/pp2/format.c
new file mode 100644
index 00000000000..37d482b5ce8
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/format.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/counters.h>
+#include <vnet/dev/bus/platform.h>
+#include <dev_armada/musdk.h>
+#include <dev_armada/pp2/pp2.h>
+
+static inline u32
+mrvl_get_u32_bits (void *start, int offset, int first, int last)
+{
+ u32 value = *(u32 *) (((u8 *) start) + offset);
+ if ((last == 0) && (first == 31))
+ return value;
+ value >>= last;
+ value &= (1 << (first - last + 1)) - 1;
+ return value;
+}
+
+u8 *
+format_pp2_ppio_link_info (u8 *s, va_list *args)
+{
+ struct pp2_ppio_link_info *li = va_arg (*args, struct pp2_ppio_link_info *);
+
+ char *port_duplex[] = {
+ [MV_NET_LINK_DUPLEX_HALF] = "half",
+ [MV_NET_LINK_DUPLEX_FULL] = "full",
+ };
+
+ u32 port_speeds[] = {
+ [MV_NET_LINK_SPEED_10] = 10, [MV_NET_LINK_SPEED_100] = 100,
+ [MV_NET_LINK_SPEED_1000] = 1000, [MV_NET_LINK_SPEED_2500] = 2500,
+ [MV_NET_LINK_SPEED_10000] = 10000,
+ };
+
+ char *port_phy_modes[] = {
+ [MV_NET_PHY_MODE_NONE] = "NONE",
+ [MV_NET_PHY_MODE_MII] = "MII",
+ [MV_NET_PHY_MODE_GMII] = "GMII",
+ [MV_NET_PHY_MODE_SGMII] = "SGMII",
+ [MV_NET_PHY_MODE_TBI] = "TBI",
+ [MV_NET_PHY_MODE_REVMII] = "REVMII",
+ [MV_NET_PHY_MODE_RMII] = "RMII",
+ [MV_NET_PHY_MODE_RGMII] = "RGMII",
+ [MV_NET_PHY_MODE_RGMII_ID] = "RGMII_ID",
+ [MV_NET_PHY_MODE_RGMII_RXID] = "RGMII_RXID",
+ [MV_NET_PHY_MODE_RGMII_TXID] = "RGMII_TXID",
+ [MV_NET_PHY_MODE_RTBI] = "RTBI",
+ [MV_NET_PHY_MODE_SMII] = "SMII",
+ [MV_NET_PHY_MODE_XGMII] = "XGMII",
+ [MV_NET_PHY_MODE_MOCA] = "MOCA",
+ [MV_NET_PHY_MODE_QSGMII] = "QSGMII",
+ [MV_NET_PHY_MODE_XAUI] = "XAUI",
+ [MV_NET_PHY_MODE_RXAUI] = "RXAUI",
+ [MV_NET_PHY_MODE_KR] = "KR",
+ };
+
+ s =
+ format (s, "duplex %s speed %d up %d phy_mode %s", port_duplex[li->duplex],
+ port_speeds[li->speed], li->up, port_phy_modes[li->phy_mode]);
+
+ return s;
+}
+
+u8 *
+format_mvpp2_port_status (u8 *s, va_list *args)
+{
+ vnet_dev_format_args_t __clib_unused *a =
+ va_arg (*args, vnet_dev_format_args_t *);
+ vnet_dev_port_t *port = va_arg (*args, vnet_dev_port_t *);
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ struct pp2_ppio_link_info li = {};
+
+ if (mp->ppio == 0 || pp2_ppio_get_link_info (mp->ppio, &li))
+ return format (s, "link info not available");
+
+ return format (s, "%U", format_pp2_ppio_link_info, &li);
+}
+
+u8 *
+format_mvpp2_dev_info (u8 *s, va_list *args)
+{
+ vnet_dev_format_args_t __clib_unused *a =
+ va_arg (*args, vnet_dev_format_args_t *);
+ vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+
+ format (s, "pp_id is %u", md->pp_id);
+ return s;
+}
+
+#define foreach_pp2_rx_desc_field \
+ _ (0x00, 6, 0, l3_offset) \
+ _ (0x00, 12, 8, ip_hdlen) \
+ _ (0x00, 14, 13, ec) \
+ _ (0x00, 15, 15, es) \
+ _ (0x00, 19, 16, pool_id) \
+ _ (0x00, 21, 21, hwf_sync) \
+ _ (0x00, 22, 22, l4_chk_ok) \
+ _ (0x00, 23, 23, ip_frg) \
+ _ (0x00, 24, 24, ipv4_hdr_err) \
+ _ (0x00, 27, 25, l4_info) \
+ _ (0x00, 30, 28, l3_info) \
+ _ (0x00, 31, 31, buf_header) \
+ _ (0x04, 5, 0, lookup_id) \
+ _ (0x04, 8, 6, cpu_code) \
+ _ (0x04, 9, 9, pppoe) \
+ _ (0x04, 11, 10, l3_cast_info) \
+ _ (0x04, 13, 12, l2_cast_info) \
+ _ (0x04, 15, 14, vlan_info) \
+ _ (0x04, 31, 16, byte_count) \
+ _ (0x08, 11, 0, gem_port_id) \
+ _ (0x08, 13, 12, color) \
+ _ (0x08, 14, 14, gop_sop_u) \
+ _ (0x08, 15, 15, key_hash_enable) \
+ _ (0x08, 31, 16, l4chk) \
+ _ (0x0c, 31, 0, timestamp) \
+ _ (0x10, 31, 0, buf_phys_ptr_lo) \
+ _ (0x14, 7, 0, buf_phys_ptr_hi) \
+ _ (0x14, 31, 8, key_hash) \
+ _ (0x18, 31, 0, buf_virt_ptr_lo) \
+ _ (0x1c, 7, 0, buf_virt_ptr_hi) \
+ _ (0x1c, 14, 8, buf_qset_no) \
+ _ (0x1c, 15, 15, buf_type) \
+ _ (0x1c, 21, 16, mod_dscp) \
+ _ (0x1c, 24, 22, mod_pri) \
+ _ (0x1c, 25, 25, mdscp) \
+ _ (0x1c, 26, 26, mpri) \
+ _ (0x1c, 27, 27, mgpid) \
+ _ (0x1c, 31, 29, port_num)
+
+u8 *
+format_mvpp2_rx_desc (u8 *s, va_list *args)
+
+{
+ struct pp2_ppio_desc *d = va_arg (*args, struct pp2_ppio_desc *);
+ u32 indent = format_get_indent (s);
+ u32 r32;
+
+#define _(a, b, c, n) \
+ r32 = mrvl_get_u32_bits (d, a, b, c); \
+ if (r32 > 9) \
+ s = format (s, "%s %u (0x%x)", #n, r32, r32); \
+ else \
+ s = format (s, "%s %u", #n, r32); \
+ if (format_get_indent (s) > 72) \
+ s = format (s, "\n%U", format_white_space, indent + 2); \
+ else \
+ s = format (s, " ");
+
+ foreach_pp2_rx_desc_field;
+ return s;
+}
+
+u8 *
+format_mvpp2_rx_trace (u8 *s, va_list *args)
+{
+ vlib_main_t *vm = va_arg (*args, vlib_main_t *);
+ vlib_node_t *node = va_arg (*args, vlib_node_t *);
+ mvpp2_rx_trace_t *t = va_arg (*args, mvpp2_rx_trace_t *);
+ vnet_main_t *vnm = vnet_get_main ();
+ u32 hw_if_index = t->rxq->port->intf.hw_if_index;
+ vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+ u32 indent = format_get_indent (s);
+ struct pp2_ppio_desc *d = &t->desc;
+
+ s = format (s, "pp2: %v (%d) next-node %U", hi->name, hw_if_index,
+ format_vlib_next_node_name, vm, node->index, t->rxq->next_index);
+ s = format (s, "\n%U%U", format_white_space, indent + 2,
+ format_mvpp2_rx_desc, d);
+
+ return s;
+}
diff --git a/src/plugins/dev_armada/pp2/init.c b/src/plugins/dev_armada/pp2/init.c
new file mode 100644
index 00000000000..38ff32d8f53
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/init.c
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/counters.h>
+#include <vnet/dev/bus/platform.h>
+#include <vppinfra/ring.h>
+#include <dev_armada/musdk.h>
+#include <dev_armada/pp2/pp2.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/plugin/plugin.h>
+#include <vpp/app/version.h>
+
+#include <linux/if.h>
+#include <sys/ioctl.h>
+
+#define MV_SYS_DMA_MEM_SZ (2 << 20)
+
+VLIB_REGISTER_LOG_CLASS (mvpp2_log, static) = {
+ .class_name = "armada",
+ .subclass_name = "init",
+};
+
+static int num_pp2_in_use = 0;
+static int dma_mem_initialized = 0;
+static int global_pp2_initialized = 0;
+
+#define _(f, n, s, d) \
+ { .name = #n, .desc = d, .severity = VL_COUNTER_SEVERITY_##s },
+
+vlib_error_desc_t mvpp2_rx_node_counters[] = { foreach_mvpp2_rx_node_counter };
+vlib_error_desc_t mvpp2_tx_node_counters[] = { foreach_mvpp2_tx_node_counter };
+#undef _
+
+vnet_dev_node_t mvpp2_rx_node = {
+ .error_counters = mvpp2_rx_node_counters,
+ .n_error_counters = ARRAY_LEN (mvpp2_rx_node_counters),
+ .format_trace = format_mvpp2_rx_trace,
+};
+
+vnet_dev_node_t mvpp2_tx_node = {
+ .error_counters = mvpp2_tx_node_counters,
+ .n_error_counters = ARRAY_LEN (mvpp2_tx_node_counters),
+};
+
+static u8 *
+mvpp2_probe (vlib_main_t *vm, vnet_dev_bus_index_t bus_index, void *dev_info)
+{
+ vnet_dev_bus_platform_device_info_t *di = dev_info;
+
+ if (clib_dt_node_is_compatible (di->node, "marvell,armada-7k-pp22"))
+ return format (0, "Marvell Armada Packet Processor v2.2");
+ return 0;
+}
+static void
+mvpp2_global_deinit (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ log_debug (dev, "");
+ if (--num_pp2_in_use == 0)
+ {
+ if (global_pp2_initialized)
+ {
+ for (u32 i = 0; i < ARRAY_LEN (md->thread); i++)
+ if (md->thread[i].bpool)
+ {
+ pp2_bpool_deinit (md->thread[i].bpool);
+ md->thread[i].bpool = 0;
+ }
+ for (u32 i = 0; i < ARRAY_LEN (md->hif); i++)
+ if (md->hif[i])
+ {
+ pp2_hif_deinit (md->hif[i]);
+ md->hif[i] = 0;
+ }
+
+ pp2_deinit ();
+ global_pp2_initialized = 0;
+ }
+ if (dma_mem_initialized)
+ {
+ mv_sys_dma_mem_destroy ();
+ log_debug (0, "mv_sys_dma_mem_destroy()");
+ dma_mem_initialized = 0;
+ }
+ }
+}
+
+static void
+mvpp2_deinit (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ log_debug (dev, "");
+ mvpp2_global_deinit (vm, dev);
+}
+
+static vnet_dev_rv_t
+mvpp2_global_init (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ int mrv;
+ u16 free_hifs, free_bpools;
+ u16 n_threads = vlib_get_n_threads ();
+
+ struct pp2_init_params init_params = {
+ .hif_reserved_map = 0xf,
+ .bm_pool_reserved_map = 0x7,
+ };
+
+ if (num_pp2_in_use++)
+ return rv;
+
+ mrv = mv_sys_dma_mem_init (MV_SYS_DMA_MEM_SZ);
+ if (mrv < 0)
+ {
+ log_err (0, "mv_sys_dma_mem_init failed, err %d", mrv);
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ goto done;
+ }
+
+ dma_mem_initialized = 1;
+ log_debug (0, "mv_sys_dma_mem_init(%u) ok", MV_SYS_DMA_MEM_SZ);
+
+ if ((mrv = pp2_init (&init_params)))
+ {
+ log_err (dev, "pp2_init failed, err %d", mrv);
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ goto done;
+ }
+
+ log_debug (dev, "pp2_init() ok");
+
+ free_hifs = pow2_mask (MVPP2_NUM_HIFS) ^ init_params.hif_reserved_map;
+ free_bpools =
+ pow2_mask (MVPP2_NUM_BPOOLS) ^ init_params.bm_pool_reserved_map;
+
+ if (n_threads > count_set_bits (free_hifs))
+ {
+ log_err (dev, "no enough HIFs (needed %u available %u)", n_threads,
+ count_set_bits (free_hifs));
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ goto done;
+ }
+
+ for (u32 i = 0; i < n_threads; i++)
+ {
+ char match[16];
+ u8 index;
+ struct pp2_hif_params hif_params = {
+ .match = match,
+ .out_size = 2048,
+ };
+ struct pp2_bpool_params bpool_params = {
+ .match = match,
+ .buff_len = vlib_buffer_get_default_data_size (vm),
+ };
+
+ index = get_lowest_set_bit_index (free_hifs);
+ free_hifs ^= 1 << index;
+ snprintf (match, sizeof (match), "hif-%u", index);
+
+ mrv = pp2_hif_init (&hif_params, md->hif + i);
+ if (mrv < 0)
+ {
+ log_err (dev, "pp2_hif_init failed for hif %u thread %u, err %d",
+ index, i, mrv);
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ goto done;
+ }
+ log_debug (dev, "pp2_hif_init(hif %u, thread %u) ok", index, i);
+
+ index = get_lowest_set_bit_index (free_bpools);
+ free_bpools ^= 1 << index;
+ snprintf (match, sizeof (match), "pool-%u:%u", md->pp_id, index);
+
+ mrv = pp2_bpool_init (&bpool_params, &md->thread[i].bpool);
+ if (mrv < 0)
+ {
+ log_err (dev, "pp2_bpool_init failed for bpool %u thread %u, err %d",
+ index, i, mrv);
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ goto done;
+ }
+ log_debug (dev, "pp2_bpool_init(bpool %u, thread %u) pool-%u:%u ok",
+ index, i, md->thread[i].bpool->pp2_id,
+ md->thread[i].bpool->id);
+ for (u32 j = 0; j < ARRAY_LEN (md->thread[0].bre); j++)
+ md->thread[i].bre[j].bpool = md->thread[i].bpool;
+ }
+
+done:
+ return rv;
+}
+
+static vnet_dev_rv_t
+mvpp2_init (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ vnet_dev_bus_platform_device_data_t *dd = vnet_dev_get_bus_data (dev);
+ clib_dt_node_t *sc;
+ int pp_id = -1;
+
+ if (!clib_dt_node_is_compatible (dd->node, "marvell,armada-7k-pp22"))
+ return VNET_DEV_ERR_NOT_SUPPORTED;
+
+ sc = clib_dt_dereference_node (dd->node, "marvell,system-controller");
+
+ if (sc && vec_len (sc->path) > strlen ("/cpX/"))
+ {
+ if (strncmp ((char *) sc->path, "/cp0/", 4) == 0)
+ pp_id = 0;
+ else if (strncmp ((char *) sc->path, "/cp1/", 4) == 0)
+ pp_id = 1;
+ }
+
+ if (pp_id < 0)
+ return VNET_DEV_ERR_UNKNOWN_DEVICE;
+
+ if ((mvpp2_global_init (vm, dev)) != VNET_DEV_OK)
+ return rv;
+
+ md->pp_id = pp_id;
+
+ vec_foreach_pointer (cn, dd->node->child_nodes)
+ {
+ clib_dt_property_t *p;
+ char netdev_name[IFNAMSIZ];
+ struct ifreq s = {};
+ u8 ppio_id;
+ int fd, srv;
+
+ p = clib_dt_get_node_property_by_name (cn, "port-id");
+
+ if (!clib_dt_proprerty_is_u32 (p))
+ continue;
+
+ ppio_id = clib_dt_proprerty_get_u32 (p);
+ log_debug (dev, "found port with ppio id %u", ppio_id);
+
+ if (pp2_ppio_available (md->pp_id, ppio_id) == 0)
+ continue;
+
+ if (pp2_netdev_get_ifname (md->pp_id, ppio_id, netdev_name) < 0)
+ {
+ log_warn (dev, "failed to get ifname, skipping port %u ", ppio_id);
+ continue;
+ }
+
+ srv = -1;
+ if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_IP)) >= 0)
+ {
+ strcpy (s.ifr_name, netdev_name);
+ srv = ioctl (fd, SIOCGIFHWADDR, &s);
+ close (fd);
+ }
+
+ if (srv < 0)
+ {
+ log_warn (dev, "unable to get hw address, skipping port %u",
+ ppio_id);
+ continue;
+ }
+
+ log_debug (dev, "adding ppio %u (netdev name %s, hwaddr %U)", ppio_id,
+ netdev_name, format_ethernet_address, s.ifr_addr.sa_data);
+
+ mvpp2_port_t mvpp2_port = {
+ .ppio_id = ppio_id,
+ };
+
+ vnet_dev_port_add_args_t port_add_args = {
+ .port = {
+ .attr = {
+ .type = VNET_DEV_PORT_TYPE_ETHERNET,
+ .max_rx_queues = PP2_PPIO_MAX_NUM_INQS,
+ .max_tx_queues = PP2_PPIO_MAX_NUM_OUTQS,
+ .max_supported_rx_frame_size = 9216,
+ },
+ .ops = {
+ .init = mvpp2_port_init,
+ .deinit = mvpp2_port_deinit,
+ .start = mvpp2_port_start,
+ .stop = mvpp2_port_stop,
+ .config_change = mvpp2_port_cfg_change,
+ .config_change_validate = mvpp2_port_cfg_change_validate,
+ .format_status = format_mvpp2_port_status,
+ },
+ .data_size = sizeof (mvpp2_port_t),
+ .initial_data = &mvpp2_port,
+ },
+ .rx_node = &mvpp2_rx_node,
+ .tx_node = &mvpp2_tx_node,
+ .rx_queue = {
+ .config = {
+ .data_size = sizeof (mvpp2_rxq_t),
+ .default_size = 512,
+ .multiplier = 32,
+ .min_size = 32,
+ .max_size = 4096,
+ .size_is_power_of_two = 1,
+ },
+ },
+ .tx_queue = {
+ .config = {
+ .data_size = sizeof (mvpp2_txq_t),
+ .default_size = 512,
+ .multiplier = 32,
+ .min_size = 32,
+ .max_size = 4096,
+ .size_is_power_of_two = 1,
+ },
+ .ops = {
+ .alloc = mvpp2_txq_alloc,
+ .free = mvpp2_txq_free,
+ },
+ },
+ };
+
+ vnet_dev_set_hw_addr_eth_mac (&port_add_args.port.attr.hw_addr,
+ (u8 *) s.ifr_addr.sa_data);
+
+ vnet_dev_port_add (vm, dev, ppio_id, &port_add_args);
+ }
+
+ if (rv != VNET_DEV_OK)
+ mvpp2_deinit (vm, dev);
+ return rv;
+}
+
+VNET_DEV_REGISTER_DRIVER (pp2) = {
+ .name = "mvpp2",
+ .bus = PLATFORM_BUS_NAME,
+ .device_data_sz = sizeof (mvpp2_device_t),
+ .ops = {
+ .init = mvpp2_init,
+ .deinit = mvpp2_deinit,
+ .probe = mvpp2_probe,
+ .format_info = format_mvpp2_dev_info,
+ },
+};
diff --git a/src/plugins/dev_armada/pp2/port.c b/src/plugins/dev_armada/pp2/port.c
new file mode 100644
index 00000000000..8e785e5e0e4
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/port.c
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/counters.h>
+#include <vnet/dev/bus/platform.h>
+#include <vppinfra/ring.h>
+#include <dev_armada/musdk.h>
+#include <dev_armada/pp2/pp2.h>
+
+VLIB_REGISTER_LOG_CLASS (mvpp2_log, static) = {
+ .class_name = "armada",
+ .subclass_name = "pp2-port",
+};
+
+vnet_dev_rv_t
+mvpp2_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ vnet_dev_t *dev = port->dev;
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ struct pp2_ppio_link_info li;
+ char match[16];
+ int mrv;
+
+ log_debug (port->dev, "");
+
+ snprintf (match, sizeof (match), "ppio-%d:%d", md->pp_id, port->port_id);
+
+ struct pp2_ppio_params ppio_params = {
+ .match = match,
+ .type = PP2_PPIO_T_NIC,
+ .eth_start_hdr = mp->is_dsa ? PP2_PPIO_HDR_ETH_DSA : PP2_PPIO_HDR_ETH,
+ .inqs_params = {
+ .num_tcs = 1,
+ .tcs_params[0] = {
+ .pkt_offset = 0,
+ .num_in_qs = 1,
+ .inqs_params = &(struct pp2_ppio_inq_params) { .size = 512 },
+ .pools[0][0] = md->thread[0].bpool,
+ },
+ },
+ };
+
+ foreach_vnet_dev_port_rx_queue (q, port)
+ {
+ struct pp2_ppio_outqs_params *oqs = &ppio_params.outqs_params;
+ oqs->outqs_params[0].weight = 1;
+ oqs->outqs_params[0].size = q->size;
+ oqs->num_outqs++;
+ }
+
+ mrv = pp2_ppio_init (&ppio_params, &mp->ppio);
+ if (mrv)
+ {
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ log_err (dev, "port %u ppio '%s' init failed, rv %d", port->port_id,
+ match, mrv);
+ goto done;
+ }
+ log_debug (dev, "port %u ppio '%s' init ok", port->port_id, match);
+
+ mrv = pp2_ppio_get_link_info (mp->ppio, &li);
+ if (mrv)
+ {
+ rv = VNET_DEV_ERR_INIT_FAILED;
+ log_err (dev, "failed to get link info for port %u, rv %d",
+ port->port_id, mrv);
+ goto done;
+ }
+
+ log_debug (dev, "port %u %U", port->port_id, format_pp2_ppio_link_info, &li);
+
+done:
+ if (rv != VNET_DEV_OK)
+ mvpp2_port_stop (vm, port);
+ return rv;
+}
+
+void
+mvpp2_port_deinit (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+
+ log_debug (port->dev, "");
+
+ if (mp->ppio)
+ {
+ pp2_ppio_deinit (mp->ppio);
+ mp->ppio = 0;
+ }
+}
+
+void
+mvpp2_port_poll (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_t *dev = port->dev;
+ vnet_dev_port_state_changes_t changes = {};
+ struct pp2_ppio_link_info li;
+ int mrv;
+
+ mrv = pp2_ppio_get_link_info (mp->ppio, &li);
+
+ if (mrv)
+ {
+ log_debug (dev, "pp2_ppio_get_link_info: failed, rv %d", mrv);
+ return;
+ }
+
+ if (mp->last_link_info.up != li.up)
+ {
+ changes.change.link_state = 1;
+ changes.link_state = li.up != 0;
+ log_debug (dev, "link state changed to %u", changes.link_state);
+ }
+
+ if (mp->last_link_info.duplex != li.duplex)
+ {
+ changes.change.link_duplex = 1;
+ changes.full_duplex = li.duplex != 0;
+ log_debug (dev, "link full duplex changed to %u", changes.full_duplex);
+ }
+
+ if (mp->last_link_info.speed != li.speed)
+ {
+ u32 speeds[] = {
+ [MV_NET_LINK_SPEED_AN] = 0,
+ [MV_NET_LINK_SPEED_10] = 10000,
+ [MV_NET_LINK_SPEED_100] = 100000,
+ [MV_NET_LINK_SPEED_1000] = 1000000,
+ [MV_NET_LINK_SPEED_2500] = 2500000,
+ [MV_NET_LINK_SPEED_10000] = 10000000,
+ };
+
+ if (li.speed < ARRAY_LEN (speeds))
+ {
+ changes.change.link_speed = 1;
+ changes.link_speed = speeds[li.speed];
+ log_debug (dev, "link speed changed to %u", changes.link_speed);
+ }
+ }
+
+ if (changes.change.any == 0)
+ return;
+
+ mp->last_link_info = li;
+
+ vnet_dev_port_state_change (vm, port, changes);
+}
+
+vnet_dev_rv_t
+mvpp2_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ int mrv;
+
+ log_debug (port->dev, "");
+
+ mrv = pp2_ppio_enable (mp->ppio);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_enable() failed, rv %d", mrv);
+ return VNET_DEV_ERR_NOT_READY;
+ }
+
+ mp->is_enabled = 1;
+
+ vnet_dev_poll_port_add (vm, port, 0.5, mvpp2_port_poll);
+
+ return VNET_DEV_OK;
+}
+
+void
+mvpp2_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
+{
+ int rv;
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+
+ log_debug (port->dev, "");
+
+ if (mp->is_enabled)
+ {
+ vnet_dev_poll_port_remove (vm, port, mvpp2_port_poll);
+
+ rv = pp2_ppio_disable (mp->ppio);
+ if (rv)
+ log_err (port->dev, "pp2_ppio_disable() failed, rv %d", rv);
+
+ vnet_dev_port_state_change (vm, port,
+ (vnet_dev_port_state_changes_t){
+ .change.link_state = 1,
+ .change.link_speed = 1,
+ .link_speed = 0,
+ .link_state = 0,
+ });
+ mp->is_enabled = 0;
+ }
+}
+
+vnet_dev_rv_t
+mvpp2_port_cfg_change_validate (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_port_cfg_change_req_t *req)
+{
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+
+ switch (req->type)
+ {
+ case VNET_DEV_PORT_CFG_PROMISC_MODE:
+ case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
+ case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
+ break;
+
+ default:
+ rv = VNET_DEV_ERR_NOT_SUPPORTED;
+ };
+
+ return rv;
+}
+
+vnet_dev_rv_t
+mvpp2_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
+ vnet_dev_port_cfg_change_req_t *req)
+{
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ eth_addr_t addr;
+ int mrv;
+
+ switch (req->type)
+ {
+
+ case VNET_DEV_PORT_CFG_PROMISC_MODE:
+ mrv = pp2_ppio_set_promisc (mp->ppio, req->promisc);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_set_promisc: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_set_promisc: promisc %u",
+ req->promisc);
+ break;
+
+ case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
+ clib_memcpy (&addr, req->addr.eth_mac, sizeof (addr));
+ mrv = pp2_ppio_add_mac_addr (mp->ppio, addr);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_add_mac_addr: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_add_mac_addr: %U added",
+ format_ethernet_address, &addr);
+ break;
+
+ case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
+ clib_memcpy (&addr, req->addr.eth_mac, sizeof (addr));
+ mrv = pp2_ppio_remove_mac_addr (mp->ppio, addr);
+ if (mrv)
+ {
+ log_err (port->dev, "pp2_ppio_remove_mac_addr: failed, rv %d", mrv);
+ rv = VNET_DEV_ERR_INTERNAL;
+ }
+ else
+ log_debug (port->dev, "pp2_ppio_remove_mac_addr: %U added",
+ format_ethernet_address, &addr);
+ break;
+
+ default:
+ return VNET_DEV_ERR_NOT_SUPPORTED;
+ };
+
+ return rv;
+}
diff --git a/src/plugins/dev_armada/pp2/pp2.h b/src/plugins/dev_armada/pp2/pp2.h
new file mode 100644
index 00000000000..6b12dc737a7
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/pp2.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#ifndef _PP2_H_
+#define _PP2_H_
+
+#include <vppinfra/clib.h>
+#include <vppinfra/error_bootstrap.h>
+#include <vppinfra/format.h>
+#include <vnet/vnet.h>
+#include <vnet/dev/dev.h>
+
+#define MVCONF_DBG_LEVEL 0
+#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
+#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
+#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
+#define MVCONF_SYS_DMA_UIO
+#define MVCONF_TYPES_PUBLIC
+#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
+
+#include "mv_std.h"
+#include "env/mv_sys_dma.h"
+#include "drivers/mv_pp2.h"
+#include <drivers/mv_pp2_bpool.h>
+#include <drivers/mv_pp2_ppio.h>
+
+#define MVPP2_NUM_HIFS 9
+#define MVPP2_NUM_BPOOLS 16
+#define MVPP2_MAX_THREADS 4
+#define MRVL_PP2_BUFF_BATCH_SZ 32
+
+typedef struct
+{
+ u8 pp_id;
+ struct pp2_hif *hif[MVPP2_NUM_HIFS];
+ struct
+ {
+ struct pp2_bpool *bpool;
+ struct buff_release_entry bre[MRVL_PP2_BUFF_BATCH_SZ];
+ } thread[MVPP2_NUM_BPOOLS];
+
+} mvpp2_device_t;
+
+typedef struct
+{
+ u8 is_enabled : 1;
+ u8 is_dsa : 1;
+ struct pp2_ppio *ppio;
+ u8 ppio_id;
+ struct pp2_ppio_link_info last_link_info;
+} mvpp2_port_t;
+
+typedef struct
+{
+ u16 next;
+ u16 n_enq;
+ u32 *buffers;
+} mvpp2_txq_t;
+
+typedef struct
+{
+} mvpp2_rxq_t;
+
+typedef struct
+{
+ struct pp2_ppio_desc desc;
+ vnet_dev_rx_queue_t *rxq;
+} mvpp2_rx_trace_t;
+
+/* format.c */
+format_function_t format_pp2_ppio_link_info;
+format_function_t format_mvpp2_port_status;
+format_function_t format_mvpp2_dev_info;
+format_function_t format_mvpp2_rx_trace;
+format_function_t format_mvpp2_rx_desc;
+
+/* port.c */
+vnet_dev_port_op_t mvpp2_port_init;
+vnet_dev_port_op_no_rv_t mvpp2_port_deinit;
+vnet_dev_port_op_t mvpp2_port_start;
+vnet_dev_port_op_no_rv_t mvpp2_port_stop;
+vnet_dev_rv_t mvpp2_port_cfg_change (vlib_main_t *, vnet_dev_port_t *,
+ vnet_dev_port_cfg_change_req_t *);
+vnet_dev_rv_t
+mvpp2_port_cfg_change_validate (vlib_main_t *, vnet_dev_port_t *,
+ vnet_dev_port_cfg_change_req_t *);
+
+/* queue.c */
+vnet_dev_tx_queue_op_t mvpp2_txq_alloc;
+vnet_dev_tx_queue_op_no_rv_t mvpp2_txq_free;
+
+/* inline funcs */
+
+#define log_debug(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_DEBUG, mvpp2_log.class, "%U" f, \
+ format_vnet_dev_log, (dev), \
+ clib_string_skip_prefix (__func__, "mvpp2_"), ##__VA_ARGS__)
+#define log_info(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_INFO, mvpp2_log.class, "%U" f, \
+ format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
+#define log_notice(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_NOTICE, mvpp2_log.class, "%U" f, \
+ format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
+#define log_warn(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_WARNING, mvpp2_log.class, "%U" f, \
+ format_vnet_dev_log, (dev), 0, ##__VA_ARGS__)
+#define log_err(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_ERR, mvpp2_log.class, "%U" f, format_vnet_dev_log, \
+ (dev), 0, ##__VA_ARGS__)
+
+#define foreach_mvpp2_tx_node_counter \
+ _ (NO_FREE_SLOTS, no_free_slots, ERROR, "no free tx slots") \
+ _ (PPIO_SEND, ppio_semd, ERROR, "pp2_ppio_send errors") \
+ _ (PPIO_GET_NUM_OUTQ_DONE, ppio_get_num_outq_done, ERROR, \
+ "pp2_ppio_get_num_outq_done errors")
+
+typedef enum
+{
+#define _(f, n, s, d) MVPP2_TX_NODE_CTR_##f,
+ foreach_mvpp2_tx_node_counter
+#undef _
+} mvpp2_tx_node_counter_t;
+
+#define foreach_mvpp2_rx_node_counter \
+ _ (PPIO_RECV, ppio_recv, ERROR, "pp2_ppio_recv error") \
+ _ (BPOOL_GET_NUM_BUFFS, bpool_get_num_bufs, ERROR, \
+ "pp2_bpool_get_num_buffs error") \
+ _ (BPOOL_PUT_BUFFS, bpool_put_buffs, ERROR, "pp2_bpool_put_buffs error") \
+ _ (BUFFER_ALLOC, buffer_alloc, ERROR, "buffer alloc error") \
+ _ (MAC_CE, mac_ce, ERROR, "MAC error (CRC error)") \
+ _ (MAC_OR, mac_or, ERROR, "overrun error") \
+ _ (MAC_RSVD, mac_rsvd, ERROR, "unknown MAC error") \
+ _ (MAC_RE, mac_re, ERROR, "resource error") \
+ _ (IP_HDR, ip_hdr, ERROR, "ip4 header error")
+
+typedef enum
+{
+#define _(f, n, s, d) MVPP2_RX_NODE_CTR_##f,
+ foreach_mvpp2_rx_node_counter
+#undef _
+} mvpp2_rx_node_counter_t;
+
+#endif /* _PP2_H_ */
diff --git a/src/plugins/dev_armada/pp2/queue.c b/src/plugins/dev_armada/pp2/queue.c
new file mode 100644
index 00000000000..05015414816
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/queue.c
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/ethernet/ethernet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/counters.h>
+#include <vnet/dev/bus/platform.h>
+#include <vppinfra/ring.h>
+#include <dev_armada/musdk.h>
+#include <dev_armada/pp2/pp2.h>
+
+VLIB_REGISTER_LOG_CLASS (mvpp2_log, static) = {
+ .class_name = "armada",
+ .subclass_name = "pp2-queue",
+};
+
+vnet_dev_rv_t
+mvpp2_txq_alloc (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
+{
+ vnet_dev_rv_t rv = VNET_DEV_OK;
+ mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
+ log_debug (txq->port->dev, "");
+
+ ASSERT (mtq->buffers == 0);
+ if (mtq->buffers == 0)
+ {
+ u32 sz = sizeof (u32) * txq->size;
+ mtq->buffers = clib_mem_alloc_aligned (sz, CLIB_CACHE_LINE_BYTES);
+ clib_memset (mtq->buffers, 0, sz);
+ }
+
+ return rv;
+}
+
+void
+mvpp2_txq_free (vlib_main_t *vm, vnet_dev_tx_queue_t *txq)
+{
+ mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
+
+ log_debug (txq->port->dev, "");
+ if (mtq->buffers)
+ {
+ clib_mem_free (mtq->buffers);
+ mtq->buffers = 0;
+ }
+}
diff --git a/src/plugins/dev_armada/pp2/rx.c b/src/plugins/dev_armada/pp2/rx.c
new file mode 100644
index 00000000000..81101ef9313
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/rx.c
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/dev/dev.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <dev_armada/pp2/pp2.h>
+
+static_always_inline void
+mvpp2_rx_trace (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vnet_dev_rx_queue_t *rxq, vlib_buffer_t *b0, uword *n_trace,
+ struct pp2_ppio_desc *d)
+{
+ if (PREDICT_TRUE (vlib_trace_buffer (vm, node, rxq->next_index, b0,
+ /* follow_chain */ 0)))
+ {
+ mvpp2_rx_trace_t *tr;
+ vlib_set_trace_count (vm, node, --(*n_trace));
+ tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
+ tr->desc = *d;
+ tr->rxq = rxq;
+ }
+}
+
+static_always_inline uword
+mrvl_pp2_rx_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, vnet_dev_rx_queue_t *rxq)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ vnet_dev_port_t *port = rxq->port;
+ vnet_dev_t *dev = port->dev;
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ vlib_buffer_template_t bt = rxq->buffer_template;
+ u32 thread_index = vm->thread_index;
+ uword n_trace = vlib_get_trace_count (vm, node);
+ u32 next_index = rxq->next_index;
+ u32 n_rx_packets = 0, n_rx_bytes = 0;
+ struct pp2_hif *hif = md->hif[thread_index];
+ struct pp2_ppio_desc descs[VLIB_FRAME_SIZE], *d;
+ struct pp2_bpool *bpool = md->thread[thread_index].bpool;
+ struct buff_release_entry *bre = md->thread[thread_index].bre;
+ u16 n_desc = VLIB_FRAME_SIZE;
+ u32 buffers[VLIB_FRAME_SIZE];
+ u32 n_bufs, *bi, i;
+ vlib_buffer_t *b0, *b1;
+
+ if (PREDICT_FALSE (
+ pp2_ppio_recv (mp->ppio, 0, rxq->queue_id, descs, &n_desc)))
+ {
+ vlib_error_count (vm, node->node_index, MVPP2_RX_NODE_CTR_PPIO_RECV, 1);
+ n_desc = 0;
+ }
+
+ n_rx_packets = n_desc;
+
+ for (i = 0; i < n_desc; i++)
+ buffers[i] = pp2_ppio_inq_desc_get_cookie (descs + i);
+
+ bt.current_data = 2;
+
+ for (d = descs, bi = buffers; n_desc >= 4; d += 2, bi += 2, n_desc -= 2)
+ {
+ /* prefetch */
+ b0 = vlib_get_buffer (vm, bi[0]);
+ b1 = vlib_get_buffer (vm, bi[1]);
+ b0->template = bt;
+ b1->template = bt;
+
+ n_rx_bytes += b0->current_length = pp2_ppio_inq_desc_get_pkt_len (d);
+ n_rx_bytes += b1->current_length = pp2_ppio_inq_desc_get_pkt_len (d + 1);
+
+ if (PREDICT_FALSE (n_trace > 0))
+ {
+ mvpp2_rx_trace (vm, node, rxq, b0, &n_trace, d);
+ if (n_trace > 0)
+ mvpp2_rx_trace (vm, node, rxq, b1, &n_trace, d + 1);
+ }
+ }
+
+ for (; n_desc; d++, bi++, n_desc--)
+ {
+ b0 = vlib_get_buffer (vm, bi[0]);
+ b0->template = bt;
+
+ n_rx_bytes += b0->current_length = pp2_ppio_inq_desc_get_pkt_len (d);
+
+ if (PREDICT_FALSE (n_trace > 0))
+ mvpp2_rx_trace (vm, node, rxq, b0, &n_trace, d);
+ }
+
+ vlib_buffer_enqueue_to_single_next (vm, node, buffers, next_index,
+ n_rx_packets);
+
+ vlib_increment_combined_counter (
+ vnm->interface_main.combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX,
+ thread_index, port->intf.sw_if_index, n_rx_packets, n_rx_bytes);
+
+ if (PREDICT_FALSE (pp2_bpool_get_num_buffs (bpool, &n_bufs)))
+ {
+ vlib_error_count (vm, node->node_index,
+ MVPP2_RX_NODE_CTR_BPOOL_GET_NUM_BUFFS, 1);
+ goto done;
+ }
+
+ n_bufs = rxq->size - n_bufs;
+ while (n_bufs >= MRVL_PP2_BUFF_BATCH_SZ)
+ {
+ u16 n_alloc, i;
+ struct buff_release_entry *e = bre;
+
+ n_alloc = vlib_buffer_alloc (vm, buffers, MRVL_PP2_BUFF_BATCH_SZ);
+ i = n_alloc;
+
+ if (PREDICT_FALSE (n_alloc == 0))
+ {
+ vlib_error_count (vm, node->node_index,
+ MVPP2_RX_NODE_CTR_BUFFER_ALLOC, 1);
+ goto done;
+ }
+
+ for (bi = buffers; i--; e++, bi++)
+ {
+
+ vlib_buffer_t *b = vlib_get_buffer (vm, bi[0]);
+ e->buff.addr = vlib_buffer_get_pa (vm, b) - 64;
+ e->buff.cookie = bi[0];
+ }
+
+ i = n_alloc;
+ if (PREDICT_FALSE (pp2_bpool_put_buffs (hif, bre, &i)))
+ {
+ vlib_error_count (vm, node->node_index,
+ MVPP2_RX_NODE_CTR_BPOOL_PUT_BUFFS, 1);
+ vlib_buffer_free (vm, buffers, n_alloc);
+ goto done;
+ }
+
+ if (PREDICT_FALSE (i != n_alloc))
+ vlib_buffer_free (vm, buffers + i, n_alloc - i);
+
+ n_bufs -= i;
+ }
+
+done:
+ return n_rx_packets;
+}
+
+VNET_DEV_NODE_FN (mvpp2_rx_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ u32 n_rx = 0;
+ foreach_vnet_dev_rx_queue_runtime (rxq, node)
+ n_rx += mrvl_pp2_rx_inline (vm, node, frame, rxq);
+ return n_rx;
+}
diff --git a/src/plugins/dev_armada/pp2/tx.c b/src/plugins/dev_armada/pp2/tx.c
new file mode 100644
index 00000000000..1e6675c9746
--- /dev/null
+++ b/src/plugins/dev_armada/pp2/tx.c
@@ -0,0 +1,83 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/dev/dev.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <dev_armada/pp2/pp2.h>
+
+VNET_DEV_NODE_FN (mvpp2_tx_node)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
+{
+ vnet_dev_tx_node_runtime_t *rt = vnet_dev_get_tx_node_runtime (node);
+ vnet_dev_tx_queue_t *txq = rt->tx_queue;
+ vnet_dev_port_t *port = txq->port;
+ vnet_dev_t *dev = port->dev;
+ mvpp2_txq_t *mtq = vnet_dev_get_tx_queue_data (txq);
+ mvpp2_port_t *mp = vnet_dev_get_port_data (port);
+ mvpp2_device_t *md = vnet_dev_get_data (dev);
+ u8 qid = txq->queue_id;
+ u32 *buffers = vlib_frame_vector_args (frame);
+ u32 n_vectors = frame->n_vectors, n_left;
+ u16 n_sent;
+ struct pp2_ppio *ppio = mp->ppio;
+ struct pp2_hif *hif = md->hif[vm->thread_index];
+ struct pp2_ppio_desc descs[VLIB_FRAME_SIZE], *d = descs;
+ u16 sz = txq->size;
+ u16 mask = sz - 1;
+
+ if (mtq->n_enq)
+ {
+ u16 n_done = 0;
+ if (PREDICT_FALSE (pp2_ppio_get_num_outq_done (ppio, hif, qid, &n_done)))
+ vlib_error_count (vm, node->node_index,
+ MVPP2_TX_NODE_CTR_PPIO_GET_NUM_OUTQ_DONE, 1);
+
+ if (n_done)
+ {
+ vlib_buffer_free_from_ring (
+ vm, mtq->buffers, (mtq->next - mtq->n_enq) & mask, sz, n_done);
+ mtq->n_enq -= n_done;
+ }
+ }
+
+ n_sent = clib_min (n_vectors, sz - mtq->n_enq);
+
+ for (d = descs, n_left = n_sent; n_left; d++, buffers++, n_left--)
+ {
+ vlib_buffer_t *b0 = vlib_get_buffer (vm, buffers[0]);
+ u64 paddr = vlib_buffer_get_pa (vm, b0);
+
+ pp2_ppio_outq_desc_reset (d);
+ pp2_ppio_outq_desc_set_phys_addr (d, paddr + b0->current_data);
+ pp2_ppio_outq_desc_set_pkt_offset (d, 0);
+ pp2_ppio_outq_desc_set_pkt_len (d, b0->current_length);
+ }
+
+ buffers = vlib_frame_vector_args (frame);
+
+ if (pp2_ppio_send (ppio, hif, qid, descs, &n_sent))
+ {
+ n_sent = 0;
+ vlib_error_count (vm, node->node_index, MVPP2_TX_NODE_CTR_PPIO_SEND, 1);
+ }
+ else if (n_sent)
+ {
+ vlib_buffer_copy_indices_to_ring (mtq->buffers, buffers,
+ mtq->next & mask, sz, n_sent);
+ mtq->next += n_sent;
+ mtq->n_enq += n_sent;
+ }
+
+ /* free unsent buffers */
+ if (PREDICT_FALSE (n_sent != n_vectors))
+ {
+ vlib_buffer_free (vm, buffers + n_sent, n_vectors - n_sent);
+ vlib_error_count (vm, node->node_index, MVPP2_TX_NODE_CTR_NO_FREE_SLOTS,
+ n_vectors - n_sent);
+ }
+
+ return n_sent;
+}
diff --git a/src/plugins/dev_iavf/port.c b/src/plugins/dev_iavf/port.c
index 7e4200ab37c..f1578fccb59 100644
--- a/src/plugins/dev_iavf/port.c
+++ b/src/plugins/dev_iavf/port.c
@@ -91,7 +91,7 @@ iavf_port_init_rss (vlib_main_t *vm, vnet_dev_port_t *port)
.key_len = keylen,
};
- clib_memcpy (key->key, default_rss_key, sizeof (default_rss_key));
+ clib_memcpy (key->key, default_rss_key, keylen);
return iavf_vc_op_config_rss_key (vm, dev, key);
}
@@ -425,17 +425,20 @@ iavf_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port,
int is_primary)
{
iavf_port_t *ap = vnet_dev_get_port_data (port);
- virtchnl_ether_addr_list_t al = {
+ u8 buffer[VIRTCHNL_MSG_SZ (virtchnl_ether_addr_list_t, list, 1)];
+ virtchnl_ether_addr_list_t *al = (virtchnl_ether_addr_list_t *) buffer;
+
+ *al = (virtchnl_ether_addr_list_t){
.vsi_id = ap->vsi_id,
.num_elements = 1,
.list[0].primary = is_primary ? 1 : 0,
.list[0].extra = is_primary ? 0 : 1,
};
- clib_memcpy (al.list[0].addr, addr, sizeof (al.list[0].addr));
+ clib_memcpy (al->list[0].addr, addr, sizeof (al->list[0].addr));
- return is_add ? iavf_vc_op_add_eth_addr (vm, port->dev, &al) :
- iavf_vc_op_del_eth_addr (vm, port->dev, &al);
+ return is_add ? iavf_vc_op_add_eth_addr (vm, port->dev, al) :
+ iavf_vc_op_del_eth_addr (vm, port->dev, al);
}
static vnet_dev_rv_t
diff --git a/src/plugins/dev_iavf/virtchnl_funcs.h b/src/plugins/dev_iavf/virtchnl_funcs.h
index e7f3901e0ee..0d4ab2835f4 100644
--- a/src/plugins/dev_iavf/virtchnl_funcs.h
+++ b/src/plugins/dev_iavf/virtchnl_funcs.h
@@ -9,6 +9,10 @@
#include <vnet/dev/dev.h>
#include <dev_iavf/iavf.h>
+/* The "+ 1" fakes a trailing element, but the driver requires that.
+ * Using this "wrong" macro is the easiest solution, as long as
+ * port.c uses buffer sized by the same macro as the functions here.
+ */
#define VIRTCHNL_MSG_SZ(s, e, n) STRUCT_OFFSET_OF (s, e[(n) + 1])
typedef struct
diff --git a/src/plugins/dev_octeon/flow.c b/src/plugins/dev_octeon/flow.c
index 35aabde76a7..5bef25f5369 100644
--- a/src/plugins/dev_octeon/flow.c
+++ b/src/plugins/dev_octeon/flow.c
@@ -189,6 +189,14 @@ oct_flow_rule_create (vnet_dev_port_t *port, struct roc_npc_action *actions,
npc = &oct_port->npc;
+ for (int i = 0; item_info[i].type != ROC_NPC_ITEM_TYPE_END; i++)
+ {
+ log_debug (port->dev, "Flow[%d] Item[%d] type %d spec 0x%U mask 0x%U",
+ flow->index, i, item_info[i].type, format_hex_bytes,
+ item_info[i].spec, item_info[i].size, format_hex_bytes,
+ item_info[i].mask, item_info[i].size);
+ }
+
npc_flow =
roc_npc_flow_create (npc, &attr, item_info, actions, npc->pf_func, &rv);
if (rv)
@@ -530,6 +538,14 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
struct roc_npc_item_info item_info[ROC_NPC_ITEM_TYPE_END] = {};
struct roc_npc_action actions[ROC_NPC_ITEM_TYPE_END] = {};
oct_port_t *oct_port = vnet_dev_get_port_data (port);
+ ethernet_header_t eth_spec = {}, eth_mask = {};
+ sctp_header_t sctp_spec = {}, sctp_mask = {};
+ gtpu_header_t gtpu_spec = {}, gtpu_mask = {};
+ ip4_header_t ip4_spec = {}, ip4_mask = {};
+ ip6_header_t ip6_spec = {}, ip6_mask = {};
+ udp_header_t udp_spec = {}, udp_mask = {};
+ tcp_header_t tcp_spec = {}, tcp_mask = {};
+ esp_header_t esp_spec = {}, esp_mask = {};
u16 l4_src_port = 0, l4_dst_port = 0;
u16 l4_src_mask = 0, l4_dst_mask = 0;
struct roc_npc_action_rss rss_conf = {};
@@ -537,6 +553,7 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
struct roc_npc_action_mark mark = {};
struct roc_npc *npc = &oct_port->npc;
u8 *flow_spec = 0, *flow_mask = 0;
+ u8 *drv_spec = 0, *drv_mask = 0;
vnet_dev_rv_t rv = VNET_DEV_OK;
int layer = 0, index = 0;
u16 *queues = NULL;
@@ -546,7 +563,6 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
if (FLOW_IS_GENERIC_TYPE (flow))
{
- u8 drv_item_spec[1024] = { 0 }, drv_item_mask[1024] = { 0 };
unformat_input_t input;
int rc;
@@ -562,11 +578,13 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
unformat_user (&input, unformat_hex_string, &flow_mask);
unformat_free (&input);
+ vec_validate (drv_spec, 1024);
+ vec_validate (drv_mask, 1024);
oct_flow_parse_state pst = {
.nxt_proto = 0,
.port = port,
.items = item_info,
- .oct_drv = { .spec = drv_item_spec, .mask = drv_item_mask },
+ .oct_drv = { .spec = drv_spec, .mask = drv_mask },
.generic = { .spec = flow_spec,
.mask = flow_mask,
.len = vec_len (flow_spec) },
@@ -577,6 +595,8 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
{
vec_free (flow_spec);
vec_free (flow_mask);
+ vec_free (drv_spec);
+ vec_free (drv_mask);
return VNET_DEV_ERR_NOT_SUPPORTED;
}
@@ -585,9 +605,8 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
if (FLOW_IS_ETHERNET_CLASS (flow))
{
- ethernet_header_t eth_spec = { .type = clib_host_to_net_u16 (
- flow->ethernet.eth_hdr.type) },
- eth_mask = { .type = 0xFFFF };
+ eth_spec.type = clib_host_to_net_u16 (flow->ethernet.eth_hdr.type);
+ eth_mask.type = 0xFFFF;
item_info[layer].spec = (void *) &eth_spec;
item_info[layer].mask = (void *) &eth_mask;
@@ -600,10 +619,11 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
{
vnet_flow_ip4_t *ip4_hdr = &flow->ip4;
proto = ip4_hdr->protocol.prot;
- ip4_header_t ip4_spec = { .src_address = ip4_hdr->src_addr.addr,
- .dst_address = ip4_hdr->dst_addr.addr },
- ip4_mask = { .src_address = ip4_hdr->src_addr.mask,
- .dst_address = ip4_hdr->dst_addr.mask };
+
+ ip4_spec.src_address = ip4_hdr->src_addr.addr;
+ ip4_spec.dst_address = ip4_hdr->dst_addr.addr;
+ ip4_mask.src_address = ip4_hdr->src_addr.mask;
+ ip4_mask.dst_address = ip4_hdr->dst_addr.mask;
item_info[layer].spec = (void *) &ip4_spec;
item_info[layer].mask = (void *) &ip4_mask;
@@ -625,10 +645,11 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
{
vnet_flow_ip6_t *ip6_hdr = &flow->ip6;
proto = ip6_hdr->protocol.prot;
- ip6_header_t ip6_spec = { .src_address = ip6_hdr->src_addr.addr,
- .dst_address = ip6_hdr->dst_addr.addr },
- ip6_mask = { .src_address = ip6_hdr->src_addr.mask,
- .dst_address = ip6_hdr->dst_addr.mask };
+
+ ip6_spec.src_address = ip6_hdr->src_addr.addr;
+ ip6_spec.dst_address = ip6_hdr->dst_addr.addr;
+ ip6_mask.src_address = ip6_hdr->src_addr.mask;
+ ip6_mask.dst_address = ip6_hdr->dst_addr.mask;
item_info[layer].spec = (void *) &ip6_spec;
item_info[layer].mask = (void *) &ip6_mask;
@@ -653,16 +674,15 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
switch (proto)
{
case IP_PROTOCOL_UDP:
- item_info[layer].type = ROC_NPC_ITEM_TYPE_UDP;
-
- udp_header_t udp_spec = { .src_port = l4_src_port,
- .dst_port = l4_dst_port },
- udp_mask = { .src_port = l4_src_mask,
- .dst_port = l4_dst_mask };
+ udp_spec.src_port = l4_src_port;
+ udp_spec.dst_port = l4_dst_port;
+ udp_mask.src_port = l4_src_mask;
+ udp_mask.dst_port = l4_dst_mask;
item_info[layer].spec = (void *) &udp_spec;
item_info[layer].mask = (void *) &udp_mask;
item_info[layer].size = sizeof (udp_header_t);
+ item_info[layer].type = ROC_NPC_ITEM_TYPE_UDP;
layer++;
if (FLOW_IS_L4_TUNNEL_TYPE (flow))
@@ -670,14 +690,13 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
switch (flow->type)
{
case VNET_FLOW_TYPE_IP4_GTPU:
- item_info[layer].type = ROC_NPC_ITEM_TYPE_GTPU;
- gtpu_header_t gtpu_spec = { .teid = clib_host_to_net_u32 (
- flow->ip4_gtpu.teid) },
- gtpu_mask = { .teid = 0XFFFFFFFF };
+ gtpu_spec.teid = clib_host_to_net_u32 (flow->ip4_gtpu.teid);
+ gtpu_mask.teid = 0XFFFFFFFF;
item_info[layer].spec = (void *) &gtpu_spec;
item_info[layer].mask = (void *) &gtpu_mask;
item_info[layer].size = sizeof (gtpu_header_t);
+ item_info[layer].type = ROC_NPC_ITEM_TYPE_GTPU;
layer++;
break;
@@ -689,42 +708,39 @@ oct_flow_add (vlib_main_t *vm, vnet_dev_port_t *port, vnet_flow_t *flow,
break;
case IP_PROTOCOL_TCP:
- item_info[layer].type = ROC_NPC_ITEM_TYPE_TCP;
-
- tcp_header_t tcp_spec = { .src_port = l4_src_port,
- .dst_port = l4_dst_port },
- tcp_mask = { .src_port = l4_src_mask,
- .dst_port = l4_dst_mask };
+ tcp_spec.src_port = l4_src_port;
+ tcp_spec.dst_port = l4_dst_port;
+ tcp_mask.src_port = l4_src_mask;
+ tcp_mask.dst_port = l4_dst_mask;
item_info[layer].spec = (void *) &tcp_spec;
item_info[layer].mask = (void *) &tcp_mask;
item_info[layer].size = sizeof (tcp_header_t);
+ item_info[layer].type = ROC_NPC_ITEM_TYPE_TCP;
layer++;
break;
case IP_PROTOCOL_SCTP:
- item_info[layer].type = ROC_NPC_ITEM_TYPE_SCTP;
-
- sctp_header_t sctp_spec = { .src_port = l4_src_port,
- .dst_port = l4_dst_port },
- sctp_mask = { .src_port = l4_src_mask,
- .dst_port = l4_dst_mask };
+ sctp_spec.src_port = l4_src_port;
+ sctp_spec.dst_port = l4_dst_port;
+ sctp_mask.src_port = l4_src_mask;
+ sctp_mask.dst_port = l4_dst_mask;
item_info[layer].spec = (void *) &sctp_spec;
item_info[layer].mask = (void *) &sctp_mask;
item_info[layer].size = sizeof (sctp_header_t);
+ item_info[layer].type = ROC_NPC_ITEM_TYPE_SCTP;
layer++;
break;
case IP_PROTOCOL_IPSEC_ESP:
- item_info[layer].type = ROC_NPC_ITEM_TYPE_ESP;
- esp_header_t esp_spec = { .spi = clib_host_to_net_u32 (
- flow->ip4_ipsec_esp.spi) },
- esp_mask = { .spi = 0xFFFFFFFF };
+ esp_spec.spi = clib_host_to_net_u32 (flow->ip4_ipsec_esp.spi);
+ esp_mask.spi = 0xFFFFFFFF;
item_info[layer].spec = (void *) &esp_spec;
item_info[layer].mask = (void *) &esp_mask;
item_info[layer].size = sizeof (u32);
+ item_info[layer].type = ROC_NPC_ITEM_TYPE_ESP;
layer++;
break;
@@ -803,10 +819,10 @@ parse_flow_actions:
if (queues)
clib_mem_free (queues);
- if (flow_spec)
- vec_free (flow_spec);
- if (flow_mask)
- vec_free (flow_mask);
+ vec_free (flow_spec);
+ vec_free (flow_mask);
+ vec_free (drv_spec);
+ vec_free (drv_mask);
return rv;
}
diff --git a/src/plugins/dev_octeon/init.c b/src/plugins/dev_octeon/init.c
index fd65ce6d9e2..29d1c16ad96 100644
--- a/src/plugins/dev_octeon/init.c
+++ b/src/plugins/dev_octeon/init.c
@@ -131,6 +131,9 @@ oct_init_nix (vlib_main_t *vm, vnet_dev_t *dev)
.rx_offloads = {
.ip4_cksum = 1,
},
+ .tx_offloads = {
+ .ip4_cksum = 1,
+ },
},
.ops = {
.init = oct_port_init,
diff --git a/src/plugins/dev_octeon/port.c b/src/plugins/dev_octeon/port.c
index e2402fb9399..8290880be31 100644
--- a/src/plugins/dev_octeon/port.c
+++ b/src/plugins/dev_octeon/port.c
@@ -58,6 +58,7 @@ oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
vnet_dev_t *dev = port->dev;
oct_device_t *cd = vnet_dev_get_data (dev);
oct_port_t *cp = vnet_dev_get_port_data (port);
+ u8 mac_addr[PLT_ETHER_ADDR_LEN];
struct roc_nix *nix = cd->nix;
vnet_dev_rv_t rv;
int rrv;
@@ -75,6 +76,22 @@ oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
}
cp->lf_allocated = 1;
+ if (!roc_nix_is_vf_or_sdp (nix))
+ {
+ if ((rrv = roc_nix_npc_mac_addr_get (nix, mac_addr)))
+ {
+ oct_port_deinit (vm, port);
+ return oct_roc_err (dev, rrv, "roc_nix_npc_mac_addr_get failed");
+ }
+
+ /* Sync MAC address to CGX/RPM table */
+ if ((rrv = roc_nix_mac_addr_set (nix, mac_addr)))
+ {
+ oct_port_deinit (vm, port);
+ return oct_roc_err (dev, rrv, "roc_nix_mac_addr_set failed");
+ }
+ }
+
if ((rrv = roc_nix_tm_init (nix)))
{
oct_port_deinit (vm, port);
@@ -125,6 +142,12 @@ oct_port_init (vlib_main_t *vm, vnet_dev_port_t *port)
oct_port_add_counters (vm, port);
+ if ((rrv = roc_nix_mac_mtu_set (nix, port->max_rx_frame_size)))
+ {
+ rv = oct_roc_err (dev, rrv, "roc_nix_mac_mtu_set() failed");
+ return rv;
+ }
+
return VNET_DEV_OK;
}
@@ -344,12 +367,6 @@ oct_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
ctq->n_enq = 0;
}
- if ((rrv = roc_nix_mac_mtu_set (nix, 9200)))
- {
- rv = oct_roc_err (dev, rrv, "roc_nix_mac_mtu_set() failed");
- goto done;
- }
-
if ((rrv = roc_nix_npc_rx_ena_dis (nix, true)))
{
rv = oct_roc_err (dev, rrv, "roc_nix_npc_rx_ena_dis() failed");
@@ -457,7 +474,6 @@ oct_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port,
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)
@@ -483,6 +499,24 @@ oct_port_add_del_eth_addr (vlib_main_t *vm, vnet_dev_port_t *port,
}
}
}
+
+ return rv;
+}
+
+vnet_dev_rv_t
+oct_op_config_max_rx_len (vlib_main_t *vm, vnet_dev_port_t *port,
+ u32 rx_frame_size)
+{
+ 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;
+
+ rrv = roc_nix_mac_max_rx_len_set (nix, rx_frame_size);
+ if (rrv)
+ rv = oct_roc_err (dev, rrv, "roc_nix_mac_max_rx_len_set() failed");
+
return rv;
}
@@ -547,6 +581,7 @@ oct_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
break;
case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
+ rv = oct_op_config_max_rx_len (vm, port, req->max_rx_frame_size);
break;
case VNET_DEV_PORT_CFG_ADD_RX_FLOW:
diff --git a/src/plugins/dev_octeon/tx_node.c b/src/plugins/dev_octeon/tx_node.c
index 0907493814d..6d239836a20 100644
--- a/src/plugins/dev_octeon/tx_node.c
+++ b/src/plugins/dev_octeon/tx_node.c
@@ -255,19 +255,18 @@ oct_tx_enq1 (vlib_main_t *vm, oct_tx_ctx_t *ctx, vlib_buffer_t *b,
if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
{
d.hdr_w1.ol3type = NIX_SENDL3TYPE_IP4_CKSUM;
- d.hdr_w1.ol3ptr = vnet_buffer (b)->l3_hdr_offset;
- d.hdr_w1.ol4ptr =
- vnet_buffer (b)->l3_hdr_offset + sizeof (ip4_header_t);
+ d.hdr_w1.ol3ptr = vnet_buffer (b)->l3_hdr_offset - b->current_data;
+ d.hdr_w1.ol4ptr = d.hdr_w1.ol3ptr + sizeof (ip4_header_t);
}
if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
{
d.hdr_w1.ol4type = NIX_SENDL4TYPE_UDP_CKSUM;
- d.hdr_w1.ol4ptr = vnet_buffer (b)->l4_hdr_offset;
+ d.hdr_w1.ol4ptr = vnet_buffer (b)->l4_hdr_offset - b->current_data;
}
else if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
{
d.hdr_w1.ol4type = NIX_SENDL4TYPE_TCP_CKSUM;
- d.hdr_w1.ol4ptr = vnet_buffer (b)->l4_hdr_offset;
+ d.hdr_w1.ol4ptr = vnet_buffer (b)->l4_hdr_offset - b->current_data;
}
}
diff --git a/src/plugins/dpdk/device/dpdk.h b/src/plugins/dpdk/device/dpdk.h
index 692bbbc09d9..a069fbe3818 100644
--- a/src/plugins/dpdk/device/dpdk.h
+++ b/src/plugins/dpdk/device/dpdk.h
@@ -241,6 +241,7 @@ typedef struct
_ (num_rx_desc) \
_ (num_tx_desc) \
_ (max_lro_pkt_size) \
+ _ (disable_rxq_int) \
_ (rss_fn)
typedef enum
diff --git a/src/plugins/dpdk/device/init.c b/src/plugins/dpdk/device/init.c
index 453d9cff7ef..827f8801ca6 100644
--- a/src/plugins/dpdk/device/init.c
+++ b/src/plugins/dpdk/device/init.c
@@ -588,6 +588,9 @@ dpdk_lib_init (dpdk_main_t * dm)
if (devconf->max_lro_pkt_size)
xd->conf.max_lro_pkt_size = devconf->max_lro_pkt_size;
+ if (devconf->disable_rxq_int)
+ xd->conf.enable_rxq_int = 0;
+
dpdk_device_setup (xd);
/* rss queues should be configured after dpdk_device_setup() */
@@ -1006,6 +1009,10 @@ dpdk_device_config (dpdk_config_main_t *conf, void *addr,
if (error)
break;
}
+ else if (unformat (input, "no-rx-interrupts"))
+ {
+ devconf->disable_rxq_int = 1;
+ }
else if (unformat (input, "tso on"))
{
devconf->tso = DPDK_DEVICE_TSO_ON;
@@ -1122,6 +1129,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
#ifdef __linux
vlib_thread_main_t *tm = vlib_get_thread_main ();
uword default_hugepage_sz, x;
+ u8 file_prefix = 0;
#endif /* __linux__ */
u8 *s, *tmp = 0;
int ret, i;
@@ -1129,7 +1137,6 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
int eal_no_hugetlb = 0;
u8 no_pci = 0;
u8 no_vmbus = 0;
- u8 file_prefix = 0;
u8 *socket_mem = 0;
u32 vendor, device, domain, bus, func;
void *fmt_func;
@@ -1289,6 +1296,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
}
foreach_eal_double_hyphen_predicate_arg
#undef _
+#ifdef __linux__
#define _(a) \
else if (unformat(input, #a " %s", &s)) \
{ \
@@ -1304,6 +1312,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
}
foreach_eal_double_hyphen_arg
#undef _
+#endif /* __linux__ */
#define _(a,b) \
else if (unformat(input, #a " %s", &s)) \
{ \
diff --git a/src/plugins/flowprobe/flowprobe.c b/src/plugins/flowprobe/flowprobe.c
index 58a7cfe22f1..ee0a8eb8a31 100644
--- a/src/plugins/flowprobe/flowprobe.c
+++ b/src/plugins/flowprobe/flowprobe.c
@@ -48,7 +48,7 @@ uword flowprobe_walker_process (vlib_main_t * vm, vlib_node_runtime_t * rt,
VNET_FEATURE_INIT (flowprobe_input_ip4_unicast, static) = {
.arc_name = "ip4-unicast",
.node_name = "flowprobe-input-ip4",
- .runs_before = VNET_FEATURES ("ip4-lookup"),
+ .runs_before = VNET_FEATURES ("ip4-lookup", "ip4-inacl"),
};
VNET_FEATURE_INIT (flowprobe_input_ip4_multicast, static) = {
.arc_name = "ip4-multicast",
@@ -58,7 +58,7 @@ VNET_FEATURE_INIT (flowprobe_input_ip4_multicast, static) = {
VNET_FEATURE_INIT (flowprobe_input_ip6_unicast, static) = {
.arc_name = "ip6-unicast",
.node_name = "flowprobe-input-ip6",
- .runs_before = VNET_FEATURES ("ip6-lookup"),
+ .runs_before = VNET_FEATURES ("ip6-lookup", "ip6-inacl"),
};
VNET_FEATURE_INIT (flowprobe_input_ip6_multicast, static) = {
.arc_name = "ip6-multicast",
diff --git a/src/plugins/hs_apps/CMakeLists.txt b/src/plugins/hs_apps/CMakeLists.txt
index 179c9c7a4c4..ba03e393f44 100644
--- a/src/plugins/hs_apps/CMakeLists.txt
+++ b/src/plugins/hs_apps/CMakeLists.txt
@@ -21,8 +21,10 @@ add_vpp_plugin(hs_apps
hs_apps.c
http_cli.c
http_client_cli.c
+ http_simple_post.c
http_tps.c
proxy.c
+ test_builtins.c
)
##############################################################################
diff --git a/src/plugins/hs_apps/echo_client.c b/src/plugins/hs_apps/echo_client.c
index d1443e75e80..8dec5d86824 100644
--- a/src/plugins/hs_apps/echo_client.c
+++ b/src/plugins/hs_apps/echo_client.c
@@ -429,8 +429,11 @@ ec_init (vlib_main_t *vm)
ecm->app_is_init = 1;
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
vlib_worker_thread_barrier_sync (vm);
- vnet_session_enable_disable (vm, 1 /* turn on session and transports */);
+ vnet_session_enable_disable (vm, &args);
/* Turn on the builtin client input nodes */
foreach_vlib_main ()
diff --git a/src/plugins/hs_apps/echo_server.c b/src/plugins/hs_apps/echo_server.c
index 0243252434a..756a1cc3451 100644
--- a/src/plugins/hs_apps/echo_server.c
+++ b/src/plugins/hs_apps/echo_server.c
@@ -736,7 +736,10 @@ echo_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
goto cleanup;
}
- vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
if (!server_uri_set)
{
diff --git a/src/plugins/hs_apps/http_cli.c b/src/plugins/hs_apps/http_cli.c
index 4970da72012..e0bb9afba4a 100644
--- a/src/plugins/hs_apps/http_cli.c
+++ b/src/plugins/hs_apps/http_cli.c
@@ -17,6 +17,8 @@
#include <vnet/session/application_interface.h>
#include <vnet/session/session.h>
#include <http/http.h>
+#include <http/http_header_names.h>
+#include <http/http_content_types.h>
#define HCS_DEBUG 0
@@ -43,6 +45,7 @@ typedef struct
u8 *tx_buf;
u32 tx_offset;
u32 vpp_session_index;
+ http_header_t *resp_headers;
} hcs_session_t;
typedef struct
@@ -148,31 +151,52 @@ hcs_cli_output (uword arg, u8 *buffer, uword buffer_bytes)
}
static void
-start_send_data (hcs_session_t *hs, http_status_code_t status,
- http_content_type_t type)
+start_send_data (hcs_session_t *hs, http_status_code_t status)
{
http_msg_t msg;
session_t *ts;
+ u8 *headers_buf = 0;
int rv;
+ if (vec_len (hs->resp_headers))
+ {
+ headers_buf = http_serialize_headers (hs->resp_headers);
+ vec_free (hs->resp_headers);
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = vec_len (headers_buf);
+ }
+ else
+ {
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = 0;
+ }
+
msg.type = HTTP_MSG_REPLY;
msg.code = status;
- msg.content_type = type;
msg.data.type = HTTP_MSG_DATA_INLINE;
- msg.data.len = vec_len (hs->tx_buf);
+ msg.data.body_len = vec_len (hs->tx_buf);
+ msg.data.body_offset = msg.data.headers_len;
+ msg.data.len = msg.data.body_len + msg.data.headers_len;
ts = session_get (hs->vpp_session_index, hs->thread_index);
rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
ASSERT (rv == sizeof (msg));
- if (!msg.data.len)
+ if (msg.data.headers_len)
+ {
+ rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+ ASSERT (rv == msg.data.headers_len);
+ vec_free (headers_buf);
+ }
+
+ if (!msg.data.body_len)
goto done;
rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (hs->tx_buf), hs->tx_buf);
if (rv != vec_len (hs->tx_buf))
{
- hs->tx_offset = rv;
+ hs->tx_offset = (rv > 0) ? rv : 0;
svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
}
else
@@ -183,7 +207,7 @@ start_send_data (hcs_session_t *hs, http_status_code_t status,
done:
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
}
static void
@@ -203,7 +227,12 @@ send_data_to_http (void *rpc_args)
hs->tx_buf = args->buf;
if (args->plain_text)
type = HTTP_CONTENT_TEXT_PLAIN;
- start_send_data (hs, HTTP_STATUS_OK, type);
+
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (type));
+
+ start_send_data (hs, HTTP_STATUS_OK);
cleanup:
@@ -325,6 +354,7 @@ hcs_ts_rx_callback (session_t *ts)
hs = hcs_session_get (ts->thread_index, ts->opaque);
hs->tx_buf = 0;
+ hs->resp_headers = 0;
/* Read the http message header */
rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
@@ -332,16 +362,17 @@ hcs_ts_rx_callback (session_t *ts)
if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET)
{
- start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED,
- HTTP_CONTENT_TEXT_HTML);
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_ALLOW),
+ http_token_lit ("GET"));
+ start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
goto done;
}
if (msg.data.target_path_len == 0 ||
msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
{
- hs->tx_buf = 0;
- start_send_data (hs, HTTP_STATUS_BAD_REQUEST, HTTP_CONTENT_TEXT_HTML);
+ start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
goto done;
}
@@ -353,7 +384,7 @@ hcs_ts_rx_callback (session_t *ts)
HCS_DBG ("%v", args.buf);
if (http_validate_abs_path_syntax (args.buf, &is_encoded))
{
- start_send_data (hs, HTTP_STATUS_BAD_REQUEST, HTTP_CONTENT_TEXT_HTML);
+ start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
vec_free (args.buf);
goto done;
}
@@ -374,13 +405,13 @@ hcs_ts_rx_callback (session_t *ts)
ASSERT (rv == msg.data.headers_len);
if (http_parse_headers (headers, &ht))
{
- start_send_data (hs, HTTP_STATUS_BAD_REQUEST,
- HTTP_CONTENT_TEXT_HTML);
+ start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
vec_free (args.buf);
vec_free (headers);
goto done;
}
- const char *accept_value = http_get_header (ht, HTTP_HEADER_ACCEPT);
+ const char *accept_value =
+ http_get_header (ht, http_header_name_str (HTTP_HEADER_ACCEPT));
if (accept_value)
{
HCS_DBG ("client accept: %s", accept_value);
@@ -438,7 +469,7 @@ hcs_ts_tx_callback (session_t *ts)
}
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
return 0;
}
@@ -700,7 +731,10 @@ start_server:
if (hcm->app_index != (u32) ~0)
return clib_error_return (0, "test http server is already running");
- vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
rv = hcs_create (vm);
switch (rv)
diff --git a/src/plugins/hs_apps/http_client_cli.c b/src/plugins/hs_apps/http_client_cli.c
index a99169bafea..4b8ef173bd9 100644
--- a/src/plugins/hs_apps/http_client_cli.c
+++ b/src/plugins/hs_apps/http_client_cli.c
@@ -16,6 +16,9 @@
#include <vnet/session/application_interface.h>
#include <vnet/session/session.h>
#include <http/http.h>
+#include <http/http_header_names.h>
+#include <http/http_content_types.h>
+#include <http/http_status_codes.h>
#define HCC_DEBUG 0
@@ -32,14 +35,14 @@ typedef struct
u32 thread_index;
u32 rx_offset;
u32 vpp_session_index;
- u32 to_recv;
+ u64 to_recv;
u8 is_closed;
+ http_header_t *req_headers;
} hcc_session_t;
typedef struct
{
hcc_session_t *sessions;
- u8 *rx_buf;
u32 thread_index;
} hcc_worker_t;
@@ -95,13 +98,6 @@ hcc_session_get (u32 hs_index, u32 thread_index)
return pool_elt_at_index (wrk->sessions, hs_index);
}
-static void
-hcc_session_free (u32 thread_index, hcc_session_t *hs)
-{
- hcc_worker_t *wrk = hcc_worker_get (thread_index);
- pool_put (wrk->sessions, hs);
-}
-
static int
hcc_ts_accept_callback (session_t *ts)
{
@@ -128,6 +124,7 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
hcc_session_t *hs, *new_hs;
hcc_worker_t *wrk;
http_msg_t msg;
+ u8 *headers_buf;
int rv;
HCC_DBG ("hc_index: %d", hc_index);
@@ -149,24 +146,42 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
hs->vpp_session_index = as->session_index;
+ http_add_header (&hs->req_headers,
+ http_header_name_token (HTTP_HEADER_ACCEPT),
+ http_content_type_token (HTTP_CONTENT_TEXT_HTML));
+ headers_buf = http_serialize_headers (hs->req_headers);
+ vec_free (hs->req_headers);
+
msg.type = HTTP_MSG_REQUEST;
msg.method_type = HTTP_REQ_GET;
- msg.content_type = HTTP_CONTENT_TEXT_HTML;
+ /* request target */
+ msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
+ msg.data.target_path_offset = 0;
+ msg.data.target_path_len = vec_len (hcm->http_query);
+ /* custom headers */
+ msg.data.headers_offset = msg.data.target_path_len;
+ msg.data.headers_len = vec_len (headers_buf);
+ /* request body */
+ msg.data.body_len = 0;
+ /* data type and total length */
msg.data.type = HTTP_MSG_DATA_INLINE;
- msg.data.len = vec_len (hcm->http_query);
+ msg.data.len =
+ msg.data.target_path_len + msg.data.headers_len + msg.data.body_len;
- svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
- { hcm->http_query, vec_len (hcm->http_query) } };
+ svm_fifo_seg_t segs[3] = { { (u8 *) &msg, sizeof (msg) },
+ { hcm->http_query, vec_len (hcm->http_query) },
+ { headers_buf, vec_len (headers_buf) } };
- rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 2, 0 /* allow partial */);
- if (rv < 0 || rv != sizeof (msg) + vec_len (hcm->http_query))
+ rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 3, 0 /* allow partial */);
+ vec_free (headers_buf);
+ if (rv < 0 || rv != sizeof (msg) + msg.data.len)
{
clib_warning ("failed app enqueue");
return -1;
}
if (svm_fifo_set_event (as->tx_fifo))
- session_send_io_evt_to_thread (as->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (as->handle, SESSION_IO_EVT_TX);
return 0;
}
@@ -221,23 +236,32 @@ hcc_ts_rx_callback (session_t *ts)
if (hs->to_recv == 0)
{
+ /* read the http message header */
rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
ASSERT (rv == sizeof (msg));
- if (msg.type != HTTP_MSG_REPLY || msg.code != HTTP_STATUS_OK)
+ if (msg.type != HTTP_MSG_REPLY)
{
clib_warning ("unexpected msg type %d", msg.type);
return 0;
}
- vec_validate (hcm->http_response, msg.data.len - 1);
+ /* drop everything up to body */
+ svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset);
+ hs->to_recv = msg.data.body_len;
+ if (msg.code != HTTP_STATUS_OK && hs->to_recv == 0)
+ {
+ hcm->http_response = format (0, "request failed, response code: %U",
+ format_http_status_code, msg.code);
+ goto done;
+ }
+ vec_validate (hcm->http_response, msg.data.body_len - 1);
vec_reset_length (hcm->http_response);
- hs->to_recv = msg.data.len;
}
u32 max_deq = svm_fifo_max_dequeue (ts->rx_fifo);
u32 n_deq = clib_min (hs->to_recv, max_deq);
- u32 curr = vec_len (hcm->http_response);
+ u64 curr = vec_len (hcm->http_response);
rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, hcm->http_response + curr);
if (rv < 0)
{
@@ -251,10 +275,12 @@ hcc_ts_rx_callback (session_t *ts)
vec_set_len (hcm->http_response, curr + n_deq);
ASSERT (hs->to_recv >= rv);
hs->to_recv -= rv;
- HCC_DBG ("app rcvd %d, remains %d", rv, hs->to_recv);
+ HCC_DBG ("app rcvd %d, remains %llu", rv, hs->to_recv);
+done:
if (hs->to_recv == 0)
{
+ HCC_DBG ("all data received, going to disconnect");
hcc_session_disconnect (ts);
vlib_process_signal_event_mt (hcm->vlib_main, hcm->cli_node_index,
HCC_REPLY_RECEIVED, 0);
@@ -264,18 +290,6 @@ hcc_ts_rx_callback (session_t *ts)
}
static void
-hcc_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf)
-{
- hcc_session_t *hs;
-
- hs = hcc_session_get (s->thread_index, s->opaque);
- if (!hs)
- return;
-
- hcc_session_free (s->thread_index, hs);
-}
-
-static void
hcc_ts_transport_closed (session_t *s)
{
hcc_main_t *hcm = &hcc_main;
@@ -293,7 +307,6 @@ static session_cb_vft_t hcc_session_cb_vft = {
.builtin_app_rx_callback = hcc_ts_rx_callback,
.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,
};
@@ -423,7 +436,6 @@ hcc_run (vlib_main_t *vm, int print_output)
case HCC_REPLY_RECEIVED:
if (print_output)
vlib_cli_output (vm, "%v", hcm->http_response);
- vec_free (hcm->http_response);
break;
case HCC_TRANSPORT_CLOSED:
err = clib_error_return (0, "error, transport closed");
@@ -460,6 +472,28 @@ hcc_detach ()
return rv;
}
+static void
+hcc_worker_cleanup (hcc_worker_t *wrk)
+{
+ pool_free (wrk->sessions);
+}
+
+static void
+hcc_cleanup ()
+{
+ hcc_main_t *hcm = &hcc_main;
+ hcc_worker_t *wrk;
+
+ vec_foreach (wrk, hcm->wrk)
+ hcc_worker_cleanup (wrk);
+
+ vec_free (hcm->uri);
+ vec_free (hcm->http_query);
+ vec_free (hcm->http_response);
+ vec_free (hcm->appns_id);
+ vec_free (hcm->wrk);
+}
+
static clib_error_t *
hcc_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
@@ -509,7 +543,6 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
}
- vec_free (hcm->appns_id);
hcm->appns_id = appns_id;
hcm->cli_node_index = vlib_get_current_process (vm)->node_runtime.node_index;
@@ -525,8 +558,11 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input,
goto done;
}
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
vlib_worker_thread_barrier_sync (vm);
- vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */);
+ vnet_session_enable_disable (vm, &args);
vlib_worker_thread_barrier_release (vm);
err = hcc_run (vm, print_output);
@@ -540,8 +576,7 @@ hcc_command_fn (vlib_main_t *vm, unformat_input_t *input,
}
done:
- vec_free (hcm->uri);
- vec_free (hcm->http_query);
+ hcc_cleanup ();
unformat_free (line_input);
return err;
}
diff --git a/src/plugins/hs_apps/http_simple_post.c b/src/plugins/hs_apps/http_simple_post.c
new file mode 100644
index 00000000000..6212eac1c97
--- /dev/null
+++ b/src/plugins/hs_apps/http_simple_post.c
@@ -0,0 +1,581 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vnet/session/application.h>
+#include <vnet/session/application_interface.h>
+#include <vnet/session/session.h>
+#include <http/http.h>
+#include <http/http_header_names.h>
+#include <http/http_content_types.h>
+#include <vppinfra/unix.h>
+
+typedef struct
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ u32 session_index;
+ u32 thread_index;
+ u32 vpp_session_index;
+ u8 is_closed;
+} hsp_session_t;
+
+typedef struct
+{
+ hsp_session_t *sessions;
+ u32 thread_index;
+} hsp_worker_t;
+
+typedef struct
+{
+ u32 app_index;
+ vlib_main_t *vlib_main;
+ u32 cli_node_index;
+ u8 attached;
+ u8 *uri;
+ session_endpoint_cfg_t connect_sep;
+ u8 *target;
+ u8 *headers_buf;
+ u8 *data;
+ u64 data_offset;
+ hsp_worker_t *wrk;
+ u8 *http_response;
+ u8 is_file;
+ u8 use_ptr;
+} hsp_main_t;
+
+typedef enum
+{
+ HSP_CONNECT_FAILED = 1,
+ HSP_TRANSPORT_CLOSED,
+ HSP_REPLY_RECEIVED,
+} hsp_cli_signal_t;
+
+static hsp_main_t hsp_main;
+
+static inline hsp_worker_t *
+hsp_worker_get (u32 thread_index)
+{
+ return &hsp_main.wrk[thread_index];
+}
+
+static inline hsp_session_t *
+hsp_session_get (u32 session_index, u32 thread_index)
+{
+ hsp_worker_t *wrk = hsp_worker_get (thread_index);
+ return pool_elt_at_index (wrk->sessions, session_index);
+}
+
+static hsp_session_t *
+hsp_session_alloc (hsp_worker_t *wrk)
+{
+ hsp_session_t *s;
+
+ pool_get_zero (wrk->sessions, s);
+ s->session_index = s - wrk->sessions;
+ s->thread_index = wrk->thread_index;
+
+ return s;
+}
+
+static int
+hsp_session_connected_callback (u32 app_index, u32 hsp_session_index,
+ session_t *s, session_error_t err)
+{
+ hsp_main_t *hspm = &hsp_main;
+ hsp_session_t *hsp_session, *new_hsp_session;
+ hsp_worker_t *wrk;
+ http_header_t *headers = 0;
+ http_msg_t msg;
+ u64 to_send;
+ u32 n_enq;
+ int rv;
+
+ if (err)
+ {
+ clib_warning ("hsp_session_index[%d] connected error: %U",
+ hsp_session_index, format_session_error, err);
+ vlib_process_signal_event_mt (hspm->vlib_main, hspm->cli_node_index,
+ HSP_CONNECT_FAILED, 0);
+ return -1;
+ }
+
+ hsp_session = hsp_session_get (hsp_session_index, 0);
+ wrk = hsp_worker_get (s->thread_index);
+ new_hsp_session = hsp_session_alloc (wrk);
+ clib_memcpy_fast (new_hsp_session, hsp_session, sizeof (*hsp_session));
+ hsp_session->vpp_session_index = s->session_index;
+
+ if (hspm->is_file)
+ {
+ http_add_header (
+ &headers, http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (HTTP_CONTENT_APP_OCTET_STREAM));
+ }
+ else
+ {
+ http_add_header (
+ &headers, http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (HTTP_CONTENT_APP_X_WWW_FORM_URLENCODED));
+ }
+ hspm->headers_buf = http_serialize_headers (headers);
+ vec_free (headers);
+
+ msg.type = HTTP_MSG_REQUEST;
+ msg.method_type = HTTP_REQ_POST;
+ /* request target */
+ msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
+ msg.data.target_path_len = vec_len (hspm->target);
+ /* custom headers */
+ msg.data.headers_len = vec_len (hspm->headers_buf);
+ /* request body */
+ msg.data.body_len = vec_len (hspm->data);
+ /* total length */
+ msg.data.len =
+ msg.data.target_path_len + msg.data.headers_len + msg.data.body_len;
+
+ if (hspm->use_ptr)
+ {
+ uword target = pointer_to_uword (hspm->target);
+ uword headers = pointer_to_uword (hspm->headers_buf);
+ uword body = pointer_to_uword (hspm->data);
+ msg.data.type = HTTP_MSG_DATA_PTR;
+ svm_fifo_seg_t segs[4] = {
+ { (u8 *) &msg, sizeof (msg) },
+ { (u8 *) &target, sizeof (target) },
+ { (u8 *) &headers, sizeof (headers) },
+ { (u8 *) &body, sizeof (body) },
+ };
+
+ rv =
+ svm_fifo_enqueue_segments (s->tx_fifo, segs, 4, 0 /* allow partial */);
+ ASSERT (rv == (sizeof (msg) + sizeof (target) + sizeof (headers) +
+ sizeof (body)));
+ goto done;
+ }
+
+ msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.target_path_offset = 0;
+ msg.data.headers_offset = msg.data.target_path_len;
+ msg.data.body_offset = msg.data.headers_offset + msg.data.headers_len;
+
+ rv = svm_fifo_enqueue (s->tx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
+
+ rv = svm_fifo_enqueue (s->tx_fifo, vec_len (hspm->target), hspm->target);
+ ASSERT (rv == vec_len (hspm->target));
+
+ rv = svm_fifo_enqueue (s->tx_fifo, vec_len (hspm->headers_buf),
+ hspm->headers_buf);
+ ASSERT (rv == msg.data.headers_len);
+
+ to_send = vec_len (hspm->data);
+ n_enq = clib_min (svm_fifo_size (s->tx_fifo), to_send);
+
+ rv = svm_fifo_enqueue (s->tx_fifo, n_enq, hspm->data);
+
+ if (rv < to_send)
+ {
+ hspm->data_offset = (rv > 0) ? rv : 0;
+ svm_fifo_add_want_deq_ntf (s->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ }
+
+done:
+ if (svm_fifo_set_event (s->tx_fifo))
+ session_program_tx_io_evt (s->handle, SESSION_IO_EVT_TX);
+
+ return 0;
+}
+
+static void
+hsp_session_disconnect_callback (session_t *s)
+{
+ hsp_main_t *hspm = &hsp_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+ int rv;
+
+ a->handle = session_handle (s);
+ a->app_index = hspm->app_index;
+ if ((rv = vnet_disconnect_session (a)))
+ clib_warning ("warning: disconnect returned: %U", format_session_error,
+ rv);
+}
+
+static void
+hsp_session_transport_closed_callback (session_t *s)
+{
+ hsp_main_t *hspm = &hsp_main;
+
+ vlib_process_signal_event_mt (hspm->vlib_main, hspm->cli_node_index,
+ HSP_TRANSPORT_CLOSED, 0);
+}
+
+static void
+hsp_session_reset_callback (session_t *s)
+{
+ hsp_main_t *hspm = &hsp_main;
+ hsp_session_t *hsp_session;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+ int rv;
+
+ hsp_session = hsp_session_get (s->opaque, s->thread_index);
+ hsp_session->is_closed = 1;
+
+ a->handle = session_handle (s);
+ a->app_index = hspm->app_index;
+ if ((rv = vnet_disconnect_session (a)))
+ clib_warning ("warning: disconnect returned: %U", format_session_error,
+ rv);
+}
+
+static int
+hsp_rx_callback (session_t *s)
+{
+ hsp_main_t *hspm = &hsp_main;
+ hsp_session_t *hsp_session;
+ http_msg_t msg;
+ int rv;
+
+ hsp_session = hsp_session_get (s->opaque, s->thread_index);
+
+ if (hsp_session->is_closed)
+ {
+ clib_warning ("hsp_session_index[%d] is closed", s->opaque);
+ return -1;
+ }
+
+ rv = svm_fifo_dequeue (s->rx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
+
+ if (msg.type != HTTP_MSG_REPLY)
+ {
+ clib_warning ("unexpected msg type %d", msg.type);
+ return -1;
+ }
+
+ svm_fifo_dequeue_drop_all (s->rx_fifo);
+
+ if (msg.code == HTTP_STATUS_OK)
+ hspm->http_response = format (0, "request success");
+ else
+ hspm->http_response = format (0, "request failed");
+
+ hsp_session_disconnect_callback (s);
+ vlib_process_signal_event_mt (hspm->vlib_main, hspm->cli_node_index,
+ HSP_REPLY_RECEIVED, 0);
+ return 0;
+}
+
+static int
+hsp_tx_callback (session_t *s)
+{
+ hsp_main_t *hspm = &hsp_main;
+ u64 to_send;
+ u32 n_enq;
+ int rv;
+
+ to_send = vec_len (hspm->data) - hspm->data_offset;
+ n_enq = clib_min (svm_fifo_size (s->tx_fifo), to_send);
+
+ rv = svm_fifo_enqueue (s->tx_fifo, n_enq, hspm->data + hspm->data_offset);
+
+ if (rv <= 0)
+ {
+ svm_fifo_add_want_deq_ntf (s->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ return 0;
+ }
+
+ if (rv < to_send)
+ {
+ hspm->data_offset += rv;
+ svm_fifo_add_want_deq_ntf (s->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ }
+
+ if (svm_fifo_set_event (s->tx_fifo))
+ session_program_tx_io_evt (s->handle, SESSION_IO_EVT_TX);
+
+ return 0;
+}
+
+static session_cb_vft_t hsp_session_cb_vft = {
+ .session_connected_callback = hsp_session_connected_callback,
+ .session_disconnect_callback = hsp_session_disconnect_callback,
+ .session_transport_closed_callback = hsp_session_transport_closed_callback,
+ .session_reset_callback = hsp_session_reset_callback,
+ .builtin_app_rx_callback = hsp_rx_callback,
+ .builtin_app_tx_callback = hsp_tx_callback,
+};
+
+static clib_error_t *
+hsp_attach ()
+{
+ hsp_main_t *hspm = &hsp_main;
+ vnet_app_attach_args_t _a, *a = &_a;
+ u64 options[18];
+ int rv;
+
+ clib_memset (a, 0, sizeof (*a));
+ clib_memset (options, 0, sizeof (options));
+
+ a->api_client_index = APP_INVALID_INDEX;
+ a->name = format (0, "http_simple_post");
+ a->session_cb_vft = &hsp_session_cb_vft;
+ a->options = options;
+ a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+
+ if ((rv = vnet_application_attach (a)))
+ return clib_error_return (0, "attach returned: %U", format_session_error,
+ rv);
+
+ hspm->app_index = a->app_index;
+ vec_free (a->name);
+ hspm->attached = 1;
+
+ return 0;
+}
+
+static int
+hsp_connect_rpc (void *rpc_args)
+{
+ vnet_connect_args_t *a = rpc_args;
+ int rv;
+
+ rv = vnet_connect (a);
+ if (rv)
+ clib_warning (0, "connect returned: %U", format_session_error, rv);
+
+ vec_free (a);
+ return rv;
+}
+
+static void
+hsp_connect ()
+{
+ hsp_main_t *hspm = &hsp_main;
+ vnet_connect_args_t *a = 0;
+ hsp_worker_t *wrk;
+ hsp_session_t *hsp_session;
+
+ vec_validate (a, 0);
+ clib_memset (a, 0, sizeof (a[0]));
+
+ clib_memcpy (&a->sep_ext, &hspm->connect_sep, sizeof (hspm->connect_sep));
+ a->app_index = hspm->app_index;
+
+ /* allocate http session on main thread */
+ wrk = hsp_worker_get (0);
+ hsp_session = hsp_session_alloc (wrk);
+ a->api_context = hsp_session->session_index;
+
+ session_send_rpc_evt_to_thread_force (transport_cl_thread (),
+ hsp_connect_rpc, a);
+}
+
+static clib_error_t *
+hsp_run (vlib_main_t *vm)
+{
+ hsp_main_t *hspm = &hsp_main;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ u32 num_threads;
+ hsp_worker_t *wrk;
+ uword event_type, *event_data = 0;
+ clib_error_t *err;
+
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+ vec_validate (hspm->wrk, num_threads);
+ vec_foreach (wrk, hspm->wrk)
+ wrk->thread_index = wrk - hspm->wrk;
+
+ if ((err = hsp_attach ()))
+ return clib_error_return (0, "http simple post attach: %U",
+ format_clib_error, err);
+
+ hsp_connect ();
+
+ vlib_process_wait_for_event_or_clock (vm, 10);
+ event_type = vlib_process_get_events (vm, &event_data);
+ switch (event_type)
+ {
+ case ~0:
+ err = clib_error_return (0, "error: timeout");
+ break;
+ case HSP_CONNECT_FAILED:
+ err = clib_error_return (0, "error: failed to connect");
+ break;
+ case HSP_TRANSPORT_CLOSED:
+ err = clib_error_return (0, "error: transport closed");
+ break;
+ case HSP_REPLY_RECEIVED:
+ vlib_cli_output (vm, "%v", hspm->http_response);
+ break;
+ default:
+ err = clib_error_return (0, "error: unexpected event %d", event_type);
+ break;
+ }
+
+ vec_free (event_data);
+ return err;
+}
+
+static int
+hsp_detach ()
+{
+ hsp_main_t *hspm = &hsp_main;
+ vnet_app_detach_args_t _da, *da = &_da;
+ int rv;
+
+ if (!hspm->attached)
+ return 0;
+
+ da->app_index = hspm->app_index;
+ da->api_client_index = APP_INVALID_INDEX;
+ rv = vnet_application_detach (da);
+ hspm->attached = 0;
+ hspm->app_index = APP_INVALID_INDEX;
+
+ return rv;
+}
+
+static void
+hcc_worker_cleanup (hsp_worker_t *wrk)
+{
+ pool_free (wrk->sessions);
+}
+
+static void
+hsp_cleanup ()
+{
+ hsp_main_t *hspm = &hsp_main;
+ hsp_worker_t *wrk;
+
+ vec_foreach (wrk, hspm->wrk)
+ hcc_worker_cleanup (wrk);
+
+ vec_free (hspm->uri);
+ vec_free (hspm->target);
+ vec_free (hspm->headers_buf);
+ vec_free (hspm->data);
+ vec_free (hspm->http_response);
+ vec_free (hspm->wrk);
+}
+
+static clib_error_t *
+hsp_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ hsp_main_t *hspm = &hsp_main;
+ clib_error_t *err = 0;
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u8 *path = 0;
+ u8 *file_data;
+ int rv;
+
+ if (hspm->attached)
+ return clib_error_return (0, "failed: already running!");
+
+ hspm->use_ptr = 0;
+
+ /* Get a line of input. */
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "expected required arguments");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "uri %s", &hspm->uri))
+ ;
+ else if (unformat (line_input, "data %v", &hspm->data))
+ hspm->is_file = 0;
+ else if (unformat (line_input, "target %s", &hspm->target))
+ ;
+ else if (unformat (line_input, "file %s", &path))
+ hspm->is_file = 1;
+ else if (unformat (line_input, "use-ptr"))
+ hspm->use_ptr = 1;
+ else
+ {
+ err = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (!hspm->uri)
+ {
+ err = clib_error_return (0, "URI not defined");
+ goto done;
+ }
+ if (!hspm->target)
+ {
+ err = clib_error_return (0, "target not defined");
+ goto done;
+ }
+ if (!hspm->data)
+ {
+ if (path)
+ {
+ err = clib_file_contents ((char *) path, &file_data);
+ if (err)
+ goto done;
+ hspm->data = file_data;
+ }
+ else
+ {
+ err = clib_error_return (0, "data not defined");
+ goto done;
+ }
+ }
+
+ if ((rv = parse_uri ((char *) hspm->uri, &hspm->connect_sep)))
+ {
+ err =
+ clib_error_return (0, "URI parse error: %U", format_session_error, rv);
+ goto done;
+ }
+
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vlib_worker_thread_barrier_sync (vm);
+ vnet_session_enable_disable (vm, &args);
+ vlib_worker_thread_barrier_release (vm);
+
+ hspm->cli_node_index =
+ vlib_get_current_process (vm)->node_runtime.node_index;
+
+ err = hsp_run (vm);
+
+ if ((rv = hsp_detach ()))
+ {
+ /* don't override last error */
+ if (!err)
+ err = clib_error_return (0, "detach returned: %U",
+ format_session_error, rv);
+ else
+ clib_warning ("warning: detach returned: %U", format_session_error,
+ rv);
+ }
+
+done:
+ hsp_cleanup ();
+ unformat_free (line_input);
+ return err;
+}
+
+VLIB_CLI_COMMAND (hsp_command, static) = {
+ .path = "http post",
+ .short_help = "uri http://<ip-addr> target <origin-form> "
+ "[data <form-urlencoded> | file <file-path>] [use-ptr]",
+ .function = hsp_command_fn,
+ .is_mp_safe = 1,
+};
+
+static clib_error_t *
+hsp_main_init (vlib_main_t *vm)
+{
+ hsp_main_t *hspm = &hsp_main;
+
+ hspm->app_index = APP_INVALID_INDEX;
+ hspm->vlib_main = vm;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (hsp_main_init);
diff --git a/src/plugins/hs_apps/http_tps.c b/src/plugins/hs_apps/http_tps.c
index 3a086501f86..cdeafa5d54a 100644
--- a/src/plugins/hs_apps/http_tps.c
+++ b/src/plugins/hs_apps/http_tps.c
@@ -17,6 +17,10 @@
#include <vnet/session/application_interface.h>
#include <vnet/session/session.h>
#include <http/http.h>
+#include <http/http_header_names.h>
+#include <http/http_content_types.h>
+
+#define HTS_RX_BUF_SIZE (64 << 10)
typedef struct
{
@@ -26,6 +30,8 @@ typedef struct
u64 data_len;
u64 data_offset;
u32 vpp_session_index;
+ u64 left_recv;
+ u64 total_recv;
union
{
/** threshold after which connection is closed */
@@ -34,6 +40,8 @@ typedef struct
u32 close_rate;
};
u8 *uri;
+ u8 *rx_buf;
+ http_header_t *resp_headers;
} hts_session_t;
typedef struct hts_listen_cfg_
@@ -102,6 +110,8 @@ hts_session_free (hts_session_t *hs)
if (htm->debug_level > 0)
clib_warning ("Freeing session %u", hs->session_index);
+ vec_free (hs->rx_buf);
+
if (CLIB_DEBUG)
clib_memset (hs, 0xfa, sizeof (*hs));
@@ -151,7 +161,7 @@ hts_session_tx_zc (hts_session_t *hs, session_t *ts)
svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
}
static void
@@ -198,7 +208,7 @@ hts_session_tx_no_zc (hts_session_t *hs, session_t *ts)
svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
}
static inline void
@@ -223,22 +233,46 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status)
{
http_msg_t msg;
session_t *ts;
+ u8 *headers_buf = 0;
+ u32 n_segs = 1;
+ svm_fifo_seg_t seg[2];
int rv;
+ if (vec_len (hs->resp_headers))
+ {
+ headers_buf = http_serialize_headers (hs->resp_headers);
+ vec_free (hs->resp_headers);
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = vec_len (headers_buf);
+ seg[1].data = headers_buf;
+ seg[1].len = msg.data.headers_len;
+ n_segs = 2;
+ }
+ else
+ {
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = 0;
+ }
+
msg.type = HTTP_MSG_REPLY;
msg.code = status;
- msg.content_type = HTTP_CONTENT_APP_OCTET_STREAM;
msg.data.type = HTTP_MSG_DATA_INLINE;
- msg.data.len = hs->data_len;
+ msg.data.body_len = hs->data_len;
+ msg.data.body_offset = msg.data.headers_len;
+ msg.data.len = msg.data.body_len + msg.data.headers_len;
+ seg[0].data = (u8 *) &msg;
+ seg[0].len = sizeof (msg);
ts = session_get (hs->vpp_session_index, hs->thread_index);
- rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
- ASSERT (rv == sizeof (msg));
+ rv = svm_fifo_enqueue_segments (ts->tx_fifo, seg, n_segs,
+ 0 /* allow partial */);
+ vec_free (headers_buf);
+ ASSERT (rv == (sizeof (msg) + msg.data.headers_len));
- if (!msg.data.len)
+ if (!msg.data.body_len)
{
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
return;
}
@@ -286,6 +320,10 @@ try_test_file (hts_session_t *hs, u8 *target)
}
}
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (HTTP_CONTENT_APP_OCTET_STREAM));
+
hts_start_send_data (hs, HTTP_STATUS_OK);
done:
@@ -294,6 +332,40 @@ done:
return rc;
}
+static inline void
+hts_session_rx_body (hts_session_t *hs, session_t *ts)
+{
+ hts_main_t *htm = &hts_main;
+ u32 n_deq;
+ int rv;
+
+ n_deq = svm_fifo_max_dequeue (ts->rx_fifo);
+ if (!htm->no_zc)
+ {
+ svm_fifo_dequeue_drop_all (ts->rx_fifo);
+ }
+ else
+ {
+ n_deq = clib_min (n_deq, HTS_RX_BUF_SIZE);
+ rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, hs->rx_buf);
+ ASSERT (rv == n_deq);
+ }
+ hs->left_recv -= n_deq;
+
+ if (hs->close_threshold > 0)
+ {
+ if ((f64) (hs->total_recv - hs->left_recv) / hs->total_recv >
+ hs->close_threshold)
+ hts_disconnect_transport (hs);
+ }
+
+ if (hs->left_recv == 0)
+ {
+ hts_start_send_data (hs, HTTP_STATUS_OK);
+ vec_free (hs->rx_buf);
+ }
+}
+
static int
hts_ts_rx_callback (session_t *ts)
{
@@ -305,38 +377,77 @@ hts_ts_rx_callback (session_t *ts)
hs = hts_session_get (ts->thread_index, ts->opaque);
- /* Read the http message header */
- rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
- ASSERT (rv == sizeof (msg));
-
- if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET)
+ if (hs->left_recv == 0)
{
- hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
- goto done;
- }
+ hs->data_len = 0;
+ hs->resp_headers = 0;
+ hs->rx_buf = 0;
- if (msg.data.target_path_len == 0 ||
- msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
- {
- hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
- goto done;
- }
+ /* Read the http message header */
+ rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
- vec_validate (target, msg.data.target_path_len - 1);
- rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset,
- msg.data.target_path_len, target);
- ASSERT (rv == msg.data.target_path_len);
+ if (msg.type != HTTP_MSG_REQUEST)
+ {
+ hts_start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR);
+ goto done;
+ }
+ if (msg.method_type != HTTP_REQ_GET && msg.method_type != HTTP_REQ_POST)
+ {
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_ALLOW),
+ http_token_lit ("GET, POST"));
+ hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
+ goto done;
+ }
- if (htm->debug_level)
- clib_warning ("Request target: %v", target);
+ if (msg.data.target_path_len == 0 ||
+ msg.data.target_form != HTTP_TARGET_ORIGIN_FORM)
+ {
+ hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
+ goto done;
+ }
- if (try_test_file (hs, target))
- hts_start_send_data (hs, HTTP_STATUS_NOT_FOUND);
+ vec_validate (target, msg.data.target_path_len - 1);
+ rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset,
+ msg.data.target_path_len, target);
+ ASSERT (rv == msg.data.target_path_len);
- vec_free (target);
+ if (htm->debug_level)
+ clib_warning ("%s request target: %v",
+ msg.method_type == HTTP_REQ_GET ? "GET" : "POST",
+ target);
+
+ if (msg.method_type == HTTP_REQ_GET)
+ {
+ if (try_test_file (hs, target))
+ hts_start_send_data (hs, HTTP_STATUS_NOT_FOUND);
+ vec_free (target);
+ }
+ else
+ {
+ vec_free (target);
+ if (!msg.data.body_len)
+ {
+ hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST);
+ goto done;
+ }
+ /* drop everything up to body */
+ svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset);
+ hs->left_recv = msg.data.body_len;
+ hs->total_recv = msg.data.body_len;
+ if (htm->no_zc)
+ vec_validate (hs->rx_buf, HTS_RX_BUF_SIZE - 1);
+ hts_session_rx_body (hs, ts);
+ return 0;
+ }
+
+ done:
+ svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len);
+ }
+ else
+ hts_session_rx_body (hs, ts);
-done:
- svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len);
return 0;
}
@@ -363,6 +474,7 @@ hts_ts_accept_callback (session_t *ts)
hs = hts_session_alloc (ts->thread_index);
hs->vpp_session_index = ts->session_index;
+ hs->left_recv = 0;
ts->opaque = hs->session_index;
ts->session_state = SESSION_STATE_READY;
@@ -726,7 +838,10 @@ start_server:
if (htm->app_index == (u32) ~0)
{
- vnet_session_enable_disable (vm, 1 /* is_enable */);
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
if (hts_create (vm))
{
diff --git a/src/plugins/hs_apps/proxy.c b/src/plugins/hs_apps/proxy.c
index e8fedf921a5..c7e7b2a653c 100644
--- a/src/plugins/hs_apps/proxy.c
+++ b/src/plugins/hs_apps/proxy.c
@@ -368,6 +368,13 @@ proxy_rx_callback (session_t * s)
u32 max_dequeue, ps_index;
int actual_transfer __attribute__ ((unused));
+ /* maybe we were already here */
+ if (ps->active_open_establishing)
+ {
+ clib_spinlock_unlock_if_init (&pm->sessions_lock);
+ return 0;
+ }
+
rx_fifo = s->rx_fifo;
tx_fifo = s->tx_fifo;
@@ -418,12 +425,12 @@ static void
proxy_force_ack (void *handlep)
{
transport_connection_t *tc;
- session_t *ao_s;
+ session_t *s;
- ao_s = session_get_from_handle (pointer_to_uword (handlep));
- if (session_get_transport_proto (ao_s) != TRANSPORT_PROTO_TCP)
+ s = session_get_from_handle (pointer_to_uword (handlep));
+ if (session_get_transport_proto (s) != TRANSPORT_PROTO_TCP)
return;
- tc = session_get_transport (ao_s);
+ tc = session_get_transport (s);
tcp_send_ack ((tcp_connection_t *) tc);
}
@@ -619,9 +626,7 @@ static int
active_open_tx_callback (session_t * ao_s)
{
proxy_main_t *pm = &proxy_main;
- transport_connection_t *tc;
proxy_session_t *ps;
- session_t *proxy_s;
u32 min_free;
min_free = clib_min (svm_fifo_size (ao_s->tx_fifo) >> 3, 128 << 10);
@@ -637,14 +642,13 @@ active_open_tx_callback (session_t * ao_s)
if (!ps)
goto unlock;
- if (ps->vpp_server_handle == ~0)
+ if (ps->vpp_server_handle == SESSION_INVALID_HANDLE)
goto unlock;
- proxy_s = session_get_from_handle (ps->vpp_server_handle);
-
/* Force ack on proxy side to update rcv wnd */
- tc = session_get_transport (proxy_s);
- tcp_send_ack ((tcp_connection_t *) tc);
+ void *arg = uword_to_pointer (ps->vpp_server_handle, void *);
+ session_send_rpc_evt_to_thread (
+ session_thread_from_handle (ps->vpp_server_handle), proxy_force_ack, arg);
unlock:
clib_spinlock_unlock_if_init (&pm->sessions_lock);
@@ -915,7 +919,10 @@ proxy_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
goto done;
}
- vnet_session_enable_disable (vm, 1 /* turn on session and transport */ );
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
rv = proxy_server_create (vm);
switch (rv)
diff --git a/src/plugins/hs_apps/test_builtins.c b/src/plugins/hs_apps/test_builtins.c
new file mode 100644
index 00000000000..631c1f1a8a2
--- /dev/null
+++ b/src/plugins/hs_apps/test_builtins.c
@@ -0,0 +1,179 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#include <http_static/http_static.h>
+#include <vppinfra/tw_timer_2t_1w_2048sl.h>
+
+typedef struct
+{
+ u32 stop_timer_handle;
+ hss_session_handle_t sh;
+} tw_timer_elt_t;
+
+typedef struct tb_main_
+{
+ tw_timer_elt_t *delayed_resps;
+ tw_timer_wheel_2t_1w_2048sl_t tw;
+ hss_session_send_fn send_data;
+} tb_main_t;
+
+static tb_main_t tb_main;
+
+static uword
+test_builtins_timer_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
+ vlib_frame_t *f)
+{
+ tb_main_t *tbm = &tb_main;
+ f64 now, timeout = 1.0;
+ uword *event_data = 0;
+ uword __clib_unused event_type;
+
+ while (1)
+ {
+ vlib_process_wait_for_event_or_clock (vm, timeout);
+ now = vlib_time_now (vm);
+ event_type = vlib_process_get_events (vm, (uword **) &event_data);
+
+ /* expire timers */
+ tw_timer_expire_timers_2t_1w_2048sl (&tbm->tw, now);
+
+ vec_reset_length (event_data);
+ }
+ return 0;
+}
+
+VLIB_REGISTER_NODE (test_builtins_timer_process_node) = {
+ .function = test_builtins_timer_process,
+ .type = VLIB_NODE_TYPE_PROCESS,
+ .name = "test-builtins-timer-process",
+ .state = VLIB_NODE_STATE_DISABLED,
+};
+
+static void
+send_data_to_hss (hss_session_handle_t sh, u8 *data)
+{
+ tb_main_t *tbm = &tb_main;
+ hss_url_handler_args_t args = {};
+
+ args.sh = sh;
+ args.data = data;
+ args.data_len = vec_len (data);
+ args.ct = HTTP_CONTENT_TEXT_PLAIN;
+ args.sc = HTTP_STATUS_OK;
+ args.free_vec_data = 1;
+
+ tbm->send_data (&args);
+}
+
+static hss_url_handler_rc_t
+handle_get_test1 (hss_url_handler_args_t *args)
+{
+ u8 *data;
+
+ clib_warning ("get request on test1");
+ data = format (0, "hello");
+ send_data_to_hss (args->sh, data);
+
+ return HSS_URL_HANDLER_ASYNC;
+}
+
+static hss_url_handler_rc_t
+handle_get_test2 (hss_url_handler_args_t *args)
+{
+ u8 *data;
+
+ clib_warning ("get request on test2");
+ data = format (0, "some data");
+ send_data_to_hss (args->sh, data);
+
+ return HSS_URL_HANDLER_ASYNC;
+}
+
+static void
+delayed_resp_cb (u32 *expired_timers)
+{
+ tb_main_t *tbm = &tb_main;
+ int i;
+ u32 pool_index;
+ tw_timer_elt_t *e;
+ u8 *data;
+
+ for (i = 0; i < vec_len (expired_timers); i++)
+ {
+ pool_index = expired_timers[i] & 0x7FFFFFFF;
+ e = pool_elt_at_index (tbm->delayed_resps, pool_index);
+ clib_warning ("sending delayed data");
+ data = format (0, "delayed data");
+ send_data_to_hss (e->sh, data);
+ pool_put (tbm->delayed_resps, e);
+ }
+}
+
+static hss_url_handler_rc_t
+handle_get_test_delayed (hss_url_handler_args_t *args)
+{
+ tb_main_t *tbm = &tb_main;
+ tw_timer_elt_t *e;
+
+ clib_warning ("get request on test_delayed");
+ pool_get (tbm->delayed_resps, e);
+ e->sh = args->sh;
+ e->stop_timer_handle =
+ tw_timer_start_2t_1w_2048sl (&tbm->tw, e - tbm->delayed_resps, 0, 5);
+
+ return HSS_URL_HANDLER_ASYNC;
+}
+
+static hss_url_handler_rc_t
+handle_post_test3 (hss_url_handler_args_t *args)
+{
+ send_data_to_hss (args->sh, 0);
+ return HSS_URL_HANDLER_ASYNC;
+}
+
+static void
+test_builtins_init (vlib_main_t *vm)
+{
+ tb_main_t *tbm = &tb_main;
+ hss_register_url_fn fp;
+ vlib_node_t *n;
+
+ fp = vlib_get_plugin_symbol ("http_static_plugin.so",
+ "hss_register_url_handler");
+
+ if (fp == 0)
+ {
+ clib_warning ("http_static_plugin.so not loaded...");
+ return;
+ }
+
+ (*fp) (handle_get_test1, "test1", HTTP_REQ_GET);
+ (*fp) (handle_get_test2, "test2", HTTP_REQ_GET);
+ (*fp) (handle_get_test_delayed, "test_delayed", HTTP_REQ_GET);
+ (*fp) (handle_post_test3, "test3", HTTP_REQ_POST);
+
+ tbm->send_data =
+ vlib_get_plugin_symbol ("http_static_plugin.so", "hss_session_send_data");
+
+ tw_timer_wheel_init_2t_1w_2048sl (&tbm->tw, delayed_resp_cb, 1.0, ~0);
+
+ vlib_node_set_state (vm, test_builtins_timer_process_node.index,
+ VLIB_NODE_STATE_POLLING);
+ n = vlib_get_node (vm, test_builtins_timer_process_node.index);
+ vlib_start_process (vm, n->runtime_index);
+}
+
+static clib_error_t *
+test_builtins_enable_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ test_builtins_init (vm);
+ return 0;
+}
+
+VLIB_CLI_COMMAND (test_builtins_enable_command, static) = {
+ .path = "test-url-handler enable",
+ .short_help = "test-url-handler enable",
+ .function = test_builtins_enable_command_fn,
+};
diff --git a/src/plugins/hs_apps/vcl/vcl_test.h b/src/plugins/hs_apps/vcl/vcl_test.h
index 0ce27ef84e2..2b45339099e 100644
--- a/src/plugins/hs_apps/vcl/vcl_test.h
+++ b/src/plugins/hs_apps/vcl/vcl_test.h
@@ -420,6 +420,39 @@ vcl_test_write (vcl_test_session_t *ts, void *buf, uint32_t nbytes)
return (tx_bytes);
}
+static inline int
+vcl_test_write_ds (vcl_test_session_t *ts)
+{
+ vcl_test_stats_t *stats = &ts->stats;
+ int tx_bytes;
+
+ do
+ {
+ stats->tx_xacts++;
+ if (ts->ds[1].len)
+ tx_bytes = vppcom_session_write_segments (ts->fd, ts->ds, 2);
+ else
+ tx_bytes = vppcom_session_write_segments (ts->fd, ts->ds, 1);
+
+ if (tx_bytes < 0)
+ errno = -tx_bytes;
+ if ((tx_bytes == 0) ||
+ ((tx_bytes < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))))
+ stats->rx_eagain++;
+ }
+ while ((tx_bytes == 0) ||
+ ((tx_bytes < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))));
+
+ if (tx_bytes < 0)
+ {
+ vterr ("vppcom_session_write_segments()", -errno);
+ }
+ else
+ stats->tx_bytes += tx_bytes;
+
+ return (tx_bytes);
+}
+
static inline void
dump_help (void)
{
diff --git a/src/plugins/hs_apps/vcl/vcl_test_server.c b/src/plugins/hs_apps/vcl/vcl_test_server.c
index d17a2089ba7..5de53173784 100644
--- a/src/plugins/hs_apps/vcl/vcl_test_server.c
+++ b/src/plugins/hs_apps/vcl/vcl_test_server.c
@@ -282,11 +282,7 @@ vts_server_process_rx (vcl_test_session_t *conn, int rx_bytes)
if (conn->cfg.test == HS_TEST_TYPE_BI)
{
if (vsm->use_ds)
- {
- (void) vcl_test_write (conn, conn->ds[0].data, conn->ds[0].len);
- if (conn->ds[1].len)
- (void) vcl_test_write (conn, conn->ds[1].data, conn->ds[1].len);
- }
+ (void) vcl_test_write_ds (conn);
else
(void) vcl_test_write (conn, conn->rxbuf, rx_bytes);
}
diff --git a/src/plugins/http/CMakeLists.txt b/src/plugins/http/CMakeLists.txt
index d9cd84a3955..c51a7dce36d 100644
--- a/src/plugins/http/CMakeLists.txt
+++ b/src/plugins/http/CMakeLists.txt
@@ -16,4 +16,5 @@ add_vpp_plugin(http
http.c
http_buffer.c
http_timer.c
+ http_test.c
)
diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c
index c5e2cc1df7d..4f741c2e6b4 100644
--- a/src/plugins/http/http.c
+++ b/src/plugins/http/http.c
@@ -16,11 +16,11 @@
#include <http/http.h>
#include <vnet/session/session.h>
#include <http/http_timer.h>
+#include <http/http_status_codes.h>
static http_main_t http_main;
#define HTTP_FIFO_THRESH (16 << 10)
-#define CONTENT_LEN_STR "Content-Length: "
/* HTTP state machine result */
typedef enum http_sm_result_t_
@@ -30,24 +30,12 @@ typedef enum http_sm_result_t_
HTTP_SM_ERROR = -1,
} http_sm_result_t;
-const char *http_status_code_str[] = {
-#define _(c, s, str) str,
- foreach_http_status_code
-#undef _
-};
-
-const char *http_content_type_str[] = {
-#define _(s, ext, str) str,
- foreach_http_content_type
-#undef _
-};
-
const http_buffer_type_t msg_to_buf_type[] = {
[HTTP_MSG_DATA_INLINE] = HTTP_BUFFER_FIFO,
[HTTP_MSG_DATA_PTR] = HTTP_BUFFER_PTR,
};
-u8 *
+static u8 *
format_http_state (u8 *s, va_list *va)
{
http_state_t state = va_arg (*va, http_state_t);
@@ -88,11 +76,19 @@ http_state_is_tx_valid (http_conn_t *hc)
{
http_state_t state = hc->http_state;
return (state == HTTP_STATE_APP_IO_MORE_DATA ||
- state == HTTP_STATE_CLIENT_IO_MORE_DATA ||
state == HTTP_STATE_WAIT_APP_REPLY ||
state == HTTP_STATE_WAIT_APP_METHOD);
}
+static inline int
+http_state_is_rx_valid (http_conn_t *hc)
+{
+ http_state_t state = hc->http_state;
+ return (state == HTTP_STATE_WAIT_SERVER_REPLY ||
+ state == HTTP_STATE_CLIENT_IO_MORE_DATA ||
+ state == HTTP_STATE_WAIT_CLIENT_METHOD);
+}
+
static inline http_worker_t *
http_worker_get (u32 thread_index)
{
@@ -374,47 +370,54 @@ http_ts_reset_callback (session_t *ts)
*/
static const char *http_error_template = "HTTP/1.1 %s\r\n"
"Date: %U GMT\r\n"
- "Content-Type: text/html\r\n"
"Connection: close\r\n"
- "Pragma: no-cache\r\n"
"Content-Length: 0\r\n\r\n";
-static const char *http_redirect_template = "HTTP/1.1 %s\r\n";
-
/**
* http response boilerplate
*/
static const char *http_response_template = "HTTP/1.1 %s\r\n"
"Date: %U GMT\r\n"
- "Expires: %U GMT\r\n"
"Server: %v\r\n"
- "Content-Type: %s\r\n"
- "Content-Length: %lu\r\n\r\n";
+ "Content-Length: %llu\r\n"
+ "%s";
+
+/**
+ * http request boilerplate
+ */
+static const char *http_get_request_template = "GET %s HTTP/1.1\r\n"
+ "Host: %v\r\n"
+ "User-Agent: %v\r\n"
+ "%s";
-static const char *http_request_template = "GET %s HTTP/1.1\r\n"
- "User-Agent: %v\r\n"
- "Accept: */*\r\n\r\n";
+static const char *http_post_request_template = "POST %s HTTP/1.1\r\n"
+ "Host: %v\r\n"
+ "User-Agent: %v\r\n"
+ "Content-Length: %llu\r\n"
+ "%s";
static u32
-http_send_data (http_conn_t *hc, u8 *data, u32 length, u32 offset)
+http_send_data (http_conn_t *hc, u8 *data, u32 length)
{
const u32 max_burst = 64 << 10;
session_t *ts;
u32 to_send;
- int sent;
+ int rv;
ts = session_get_from_handle (hc->h_tc_session_handle);
- to_send = clib_min (length - offset, max_burst);
- sent = svm_fifo_enqueue (ts->tx_fifo, to_send, data + offset);
-
- if (sent <= 0)
- return offset;
+ to_send = clib_min (length, max_burst);
+ rv = svm_fifo_enqueue (ts->tx_fifo, to_send, data);
+ if (rv <= 0)
+ {
+ clib_warning ("svm_fifo_enqueue failed, rv %d", rv);
+ return 0;
+ }
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
- return (offset + sent);
+ return rv;
}
static void
@@ -430,33 +433,56 @@ http_send_error (http_conn_t *hc, http_status_code_t ec)
now = clib_timebase_now (&hm->timebase);
data = format (0, http_error_template, http_status_code_str[ec],
format_clib_timebase_time, now);
- http_send_data (hc, data, vec_len (data), 0);
+ HTTP_DBG (1, "%v", data);
+ http_send_data (hc, data, vec_len (data));
vec_free (data);
}
static int
http_read_message (http_conn_t *hc)
{
- u32 max_deq, cursize;
+ u32 max_deq;
session_t *ts;
int n_read;
ts = session_get_from_handle (hc->h_tc_session_handle);
- cursize = vec_len (hc->rx_buf);
max_deq = svm_fifo_max_dequeue (ts->rx_fifo);
if (PREDICT_FALSE (max_deq == 0))
return -1;
- vec_validate (hc->rx_buf, cursize + max_deq - 1);
- n_read = svm_fifo_dequeue (ts->rx_fifo, max_deq, hc->rx_buf + cursize);
+ vec_validate (hc->rx_buf, max_deq - 1);
+ n_read = svm_fifo_peek (ts->rx_fifo, 0, max_deq, hc->rx_buf);
ASSERT (n_read == max_deq);
+ HTTP_DBG (1, "read %u bytes from rx_fifo", n_read);
+
+ return 0;
+}
+
+static void
+http_read_message_drop (http_conn_t *hc, u32 len)
+{
+ session_t *ts;
+
+ ts = session_get_from_handle (hc->h_tc_session_handle);
+ svm_fifo_dequeue_drop (ts->rx_fifo, len);
+ vec_reset_length (hc->rx_buf);
if (svm_fifo_is_empty (ts->rx_fifo))
svm_fifo_unset_event (ts->rx_fifo);
+}
- vec_set_len (hc->rx_buf, cursize + n_read);
- return 0;
+static void
+http_read_message_drop_all (http_conn_t *hc)
+{
+ session_t *ts;
+
+ ts = session_get_from_handle (hc->h_tc_session_handle);
+ svm_fifo_dequeue_drop_all (ts->rx_fifo);
+ vec_reset_length (hc->rx_buf);
+
+ if (svm_fifo_is_empty (ts->rx_fifo))
+ svm_fifo_unset_event (ts->rx_fifo);
}
/**
@@ -501,13 +527,18 @@ v_find_index (u8 *vec, u32 offset, u32 num, char *str)
static void
http_identify_optional_query (http_conn_t *hc)
{
- u32 pos = vec_search (hc->rx_buf, '?');
- if (~0 != pos)
+ int i;
+ for (i = hc->target_path_offset;
+ i < (hc->target_path_offset + hc->target_path_len); i++)
{
- hc->target_query_offset = pos + 1;
- hc->target_query_len =
- hc->target_path_offset + hc->target_path_len - hc->target_query_offset;
- hc->target_path_len = hc->target_path_len - hc->target_query_len - 1;
+ if (hc->rx_buf[i] == '?')
+ {
+ hc->target_query_offset = i + 1;
+ hc->target_query_len = hc->target_path_offset + hc->target_path_len -
+ hc->target_query_offset;
+ hc->target_path_len = hc->target_path_len - hc->target_query_len - 1;
+ break;
+ }
}
}
@@ -563,10 +594,10 @@ static int
http_parse_request_line (http_conn_t *hc, http_status_code_t *ec)
{
int i, target_len;
- u32 next_line_offset;
+ u32 next_line_offset, method_offset;
/* request-line = method SP request-target SP HTTP-version CRLF */
- i = v_find_index (hc->rx_buf, 0, 0, "\r\n");
+ i = v_find_index (hc->rx_buf, 8, 0, "\r\n");
if (i < 0)
{
clib_warning ("request line incomplete");
@@ -574,7 +605,8 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec)
return -1;
}
HTTP_DBG (0, "request line length: %d", i);
- next_line_offset = i + 2;
+ hc->control_data_len = i + 2;
+ next_line_offset = hc->control_data_len;
/* there should be at least one more CRLF */
if (vec_len (hc->rx_buf) < (next_line_offset + 2))
@@ -584,24 +616,40 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec)
return -1;
}
+ /*
+ * RFC9112 2.2:
+ * In the interest of robustness, a server that is expecting to receive and
+ * parse a request-line SHOULD ignore at least one empty line (CRLF)
+ * received prior to the request-line.
+ */
+ method_offset = hc->rx_buf[0] == '\r' && hc->rx_buf[1] == '\n' ? 2 : 0;
/* parse method */
- if ((i = v_find_index (hc->rx_buf, 0, next_line_offset, "GET ")) >= 0)
+ if (!memcmp (hc->rx_buf + method_offset, "GET ", 4))
{
HTTP_DBG (0, "GET method");
hc->method = HTTP_REQ_GET;
- hc->target_path_offset = i + 4;
+ hc->target_path_offset = method_offset + 4;
}
- else if ((i = v_find_index (hc->rx_buf, 0, next_line_offset, "POST ")) >= 0)
+ else if (!memcmp (hc->rx_buf + method_offset, "POST ", 5))
{
HTTP_DBG (0, "POST method");
hc->method = HTTP_REQ_POST;
- hc->target_path_offset = i + 5;
+ hc->target_path_offset = method_offset + 5;
}
else
{
- clib_warning ("method not implemented: %8v", hc->rx_buf);
- *ec = HTTP_STATUS_NOT_IMPLEMENTED;
- return -1;
+ if (hc->rx_buf[method_offset] - 'A' <= 'Z' - hc->rx_buf[method_offset])
+ {
+ clib_warning ("not method name: %8v", hc->rx_buf);
+ *ec = HTTP_STATUS_BAD_REQUEST;
+ return -1;
+ }
+ else
+ {
+ clib_warning ("method not implemented: %8v", hc->rx_buf);
+ *ec = HTTP_STATUS_NOT_IMPLEMENTED;
+ return -1;
+ }
}
/* find version */
@@ -631,7 +679,9 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec)
}
/* parse request-target */
+ HTTP_DBG (0, "http at %d", i);
target_len = i - hc->target_path_offset;
+ HTTP_DBG (0, "target_len %d", target_len);
if (target_len < 1)
{
clib_warning ("request-target not present");
@@ -658,6 +708,112 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec)
return 0;
}
+#define expect_char(c) \
+ if (*p++ != c) \
+ { \
+ clib_warning ("unexpected character"); \
+ return -1; \
+ }
+
+#define parse_int(val, mul) \
+ do \
+ { \
+ if (!isdigit (*p)) \
+ { \
+ clib_warning ("expected digit"); \
+ return -1; \
+ } \
+ val += mul * (*p++ - '0'); \
+ } \
+ while (0)
+
+static int
+http_parse_status_line (http_conn_t *hc)
+{
+ int i;
+ u32 next_line_offset;
+ u8 *p, *end;
+ u16 status_code = 0;
+
+ i = v_find_index (hc->rx_buf, 0, 0, "\r\n");
+ /* status-line = HTTP-version SP status-code SP [ reason-phrase ] CRLF */
+ if (i < 0)
+ {
+ clib_warning ("status line incomplete");
+ return -1;
+ }
+ HTTP_DBG (0, "status line length: %d", i);
+ if (i < 12)
+ {
+ clib_warning ("status line too short (%d)", i);
+ return -1;
+ }
+ hc->control_data_len = i + 2;
+ next_line_offset = hc->control_data_len;
+ p = hc->rx_buf;
+ end = hc->rx_buf + i;
+
+ /* there should be at least one more CRLF */
+ if (vec_len (hc->rx_buf) < (next_line_offset + 2))
+ {
+ clib_warning ("malformed message, too short");
+ return -1;
+ }
+
+ /* parse version */
+ expect_char ('H');
+ expect_char ('T');
+ expect_char ('T');
+ expect_char ('P');
+ expect_char ('/');
+ expect_char ('1');
+ expect_char ('.');
+ if (!isdigit (*p++))
+ {
+ clib_warning ("invalid HTTP minor version");
+ return -1;
+ }
+
+ /* skip space(s) */
+ if (*p != ' ')
+ {
+ clib_warning ("no space after HTTP version");
+ return -1;
+ }
+ do
+ {
+ p++;
+ if (p == end)
+ {
+ clib_warning ("no status code");
+ return -1;
+ }
+ }
+ while (*p == ' ');
+
+ /* parse status code */
+ if ((end - p) < 3)
+ {
+ clib_warning ("not enough characters for status code");
+ return -1;
+ }
+ parse_int (status_code, 100);
+ parse_int (status_code, 10);
+ parse_int (status_code, 1);
+ if (status_code < 100 || status_code > 599)
+ {
+ clib_warning ("invalid status code %d", status_code);
+ return -1;
+ }
+ hc->status_code = status_code;
+ HTTP_DBG (0, "status code: %d", hc->status_code);
+
+ /* set buffer offset to nex line start */
+ hc->rx_buf_offset = next_line_offset;
+
+ return 0;
+}
+
static int
http_identify_headers (http_conn_t *hc, http_status_code_t *ec)
{
@@ -670,6 +826,7 @@ http_identify_headers (http_conn_t *hc, http_status_code_t *ec)
/* just another CRLF -> no headers */
HTTP_DBG (0, "no headers");
hc->headers_len = 0;
+ hc->control_data_len += 2;
return 0;
}
@@ -683,6 +840,7 @@ http_identify_headers (http_conn_t *hc, http_status_code_t *ec)
}
hc->headers_offset = hc->rx_buf_offset;
hc->headers_len = i - hc->rx_buf_offset + 2;
+ hc->control_data_len += (hc->headers_len + 2);
HTTP_DBG (0, "headers length: %u", hc->headers_len);
HTTP_DBG (0, "headers offset: %u", hc->headers_offset);
@@ -695,6 +853,7 @@ http_identify_message_body (http_conn_t *hc, http_status_code_t *ec)
unformat_input_t input;
int i, len;
u8 *line;
+ u64 body_len;
hc->body_len = 0;
@@ -736,76 +895,32 @@ http_identify_message_body (http_conn_t *hc, http_status_code_t *ec)
HTTP_DBG (0, "%v", line);
unformat_init_vector (&input, line);
- if (!unformat (&input, "%lu", &hc->body_len))
+ if (!unformat (&input, "%llu", &body_len))
{
clib_warning ("failed to unformat content length value");
*ec = HTTP_STATUS_BAD_REQUEST;
return -1;
}
unformat_free (&input);
+ hc->body_len = body_len;
hc->body_offset = hc->headers_offset + hc->headers_len + 2;
- HTTP_DBG (0, "body length: %u", hc->body_len);
+ HTTP_DBG (0, "body length: %llu", hc->body_len);
HTTP_DBG (0, "body offset: %u", hc->body_offset);
return 0;
}
-static int
-http_parse_header (http_conn_t *hc, int *content_length)
-{
- unformat_input_t input;
- int i, len;
- u8 *line;
-
- i = v_find_index (hc->rx_buf, hc->rx_buf_offset, 0, CONTENT_LEN_STR);
- if (i < 0)
- {
- clib_warning ("cannot find '%s' in the header!", CONTENT_LEN_STR);
- return -1;
- }
-
- hc->rx_buf_offset = i;
-
- i = v_find_index (hc->rx_buf, hc->rx_buf_offset, 0, "\n");
- if (i < 0)
- {
- clib_warning ("end of line missing; incomplete data");
- return -1;
- }
-
- len = i - hc->rx_buf_offset;
- line = vec_new (u8, len);
- clib_memcpy (line, hc->rx_buf + hc->rx_buf_offset, len);
-
- unformat_init_vector (&input, line);
- if (!unformat (&input, CONTENT_LEN_STR "%d", content_length))
- {
- clib_warning ("failed to unformat content length!");
- return -1;
- }
- unformat_free (&input);
-
- /* skip rest of the header */
- hc->rx_buf_offset += len;
- i = v_find_index (hc->rx_buf, hc->rx_buf_offset, 0, "<html>");
- if (i < 0)
- {
- clib_warning ("<html> tag not found");
- return -1;
- }
- hc->rx_buf_offset = i;
-
- return 0;
-}
-
static http_sm_result_t
http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp)
{
- int i, rv, content_length;
+ int rv;
http_msg_t msg = {};
app_worker_t *app_wrk;
session_t *as;
+ u32 len, max_enq, body_sent;
+ http_status_code_t ec;
+ http_main_t *hm = &http_main;
rv = http_read_message (hc);
@@ -816,72 +931,74 @@ http_state_wait_server_reply (http_conn_t *hc, transport_send_params_t *sp)
return HTTP_SM_STOP;
}
+ HTTP_DBG (0, "%v", hc->rx_buf);
+
if (vec_len (hc->rx_buf) < 8)
{
clib_warning ("response buffer too short");
goto error;
}
- if ((i = v_find_index (hc->rx_buf, 0, 0, "200 OK")) >= 0)
+ rv = http_parse_status_line (hc);
+ if (rv)
+ goto error;
+
+ rv = http_identify_headers (hc, &ec);
+ if (rv)
+ goto error;
+
+ rv = http_identify_message_body (hc, &ec);
+ if (rv)
+ goto error;
+
+ /* send at least "control data" which is necessary minimum,
+ * if there is some space send also portion of body */
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ max_enq = svm_fifo_max_enqueue (as->rx_fifo);
+ if (max_enq < hc->control_data_len)
{
- msg.type = HTTP_MSG_REPLY;
- msg.content_type = HTTP_CONTENT_TEXT_HTML;
- msg.code = HTTP_STATUS_OK;
- msg.data.type = HTTP_MSG_DATA_INLINE;
- msg.data.len = 0;
+ clib_warning ("not enough room for control data in app's rx fifo");
+ goto error;
+ }
+ len = clib_min (max_enq, vec_len (hc->rx_buf));
- rv = http_parse_header (hc, &content_length);
- if (rv)
- {
- clib_warning ("failed to parse http reply");
- goto error;
- }
- msg.data.len = content_length;
- u32 dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset;
- as = session_get_from_handle (hc->h_pa_session_handle);
- svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
- { &hc->rx_buf[hc->rx_buf_offset], dlen } };
-
- rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2,
- 0 /* allow partial */);
- if (rv < 0)
- {
- clib_warning ("error enqueue");
- return HTTP_SM_ERROR;
- }
+ msg.type = HTTP_MSG_REPLY;
+ msg.code = hm->sc_by_u16[hc->status_code];
+ msg.data.headers_offset = hc->headers_offset;
+ msg.data.headers_len = hc->headers_len;
+ msg.data.body_offset = hc->body_offset;
+ msg.data.body_len = hc->body_len;
+ msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.len = len;
- hc->rx_buf_offset += dlen;
- hc->to_recv = content_length - dlen;
+ svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
+ { hc->rx_buf, len } };
- if (hc->rx_buf_offset == vec_len (hc->rx_buf))
- {
- vec_reset_length (hc->rx_buf);
- hc->rx_buf_offset = 0;
- }
+ rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0 /* allow partial */);
+ ASSERT (rv == (sizeof (msg) + len));
- 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);
- }
- else
- {
- http_state_change (hc, HTTP_STATE_CLIENT_IO_MORE_DATA);
- }
+ http_read_message_drop (hc, len);
- app_wrk = app_worker_get_if_valid (as->app_wrk_index);
- if (app_wrk)
- app_worker_rx_notify (app_wrk, as);
- return HTTP_SM_STOP;
+ body_sent = len - hc->control_data_len;
+ hc->to_recv = hc->body_len - body_sent;
+ if (hc->to_recv == 0)
+ {
+ /* all sent, we are done */
+ http_state_change (hc, HTTP_STATE_WAIT_APP_METHOD);
}
else
{
- clib_warning ("Unknown http method %v", hc->rx_buf);
- goto error;
+ /* stream rest of the response body */
+ http_state_change (hc, HTTP_STATE_CLIENT_IO_MORE_DATA);
}
+ app_wrk = app_worker_get_if_valid (as->app_wrk_index);
+ if (app_wrk)
+ app_worker_rx_notify (app_wrk, as);
+ return HTTP_SM_STOP;
+
error:
+ http_read_message_drop_all (hc);
session_transport_closing_notify (&hc->connection);
session_transport_closed_notify (&hc->connection);
http_disconnect_transport (hc);
@@ -896,7 +1013,8 @@ http_state_wait_client_method (http_conn_t *hc, transport_send_params_t *sp)
http_msg_t msg;
session_t *as;
int rv;
- u32 len;
+ u32 len, max_enq, body_sent;
+ u64 max_deq;
rv = http_read_message (hc);
@@ -924,11 +1042,23 @@ http_state_wait_client_method (http_conn_t *hc, transport_send_params_t *sp)
if (rv)
goto error;
- len = vec_len (hc->rx_buf);
+ /* send at least "control data" which is necessary minimum,
+ * if there is some space send also portion of body */
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ max_enq = svm_fifo_max_enqueue (as->rx_fifo);
+ if (max_enq < hc->control_data_len)
+ {
+ clib_warning ("not enough room for control data in app's rx fifo");
+ ec = HTTP_STATUS_INTERNAL_ERROR;
+ goto error;
+ }
+ /* do not dequeue more than one HTTP request, we do not support pipelining */
+ max_deq =
+ clib_min (hc->control_data_len + hc->body_len, vec_len (hc->rx_buf));
+ len = clib_min (max_enq, max_deq);
msg.type = HTTP_MSG_REQUEST;
msg.method_type = hc->method;
- msg.content_type = HTTP_CONTENT_TEXT_HTML;
msg.data.type = HTTP_MSG_DATA_INLINE;
msg.data.len = len;
msg.data.target_form = hc->target_form;
@@ -944,19 +1074,24 @@ http_state_wait_client_method (http_conn_t *hc, transport_send_params_t *sp)
svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
{ hc->rx_buf, len } };
- as = session_get_from_handle (hc->h_pa_session_handle);
rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0 /* allow partial */);
- if (rv < 0 || rv != sizeof (msg) + len)
+ ASSERT (rv == (sizeof (msg) + len));
+
+ body_sent = len - hc->control_data_len;
+ hc->to_recv = hc->body_len - body_sent;
+ if (hc->to_recv == 0)
{
- clib_warning ("failed app enqueue");
- /* This should not happen as we only handle 1 request per session,
- * and fifo is allocated, but going forward we should consider
- * rescheduling */
- return HTTP_SM_ERROR;
+ /* drop everything, we do not support pipelining */
+ http_read_message_drop_all (hc);
+ /* all sent, we are done */
+ http_state_change (hc, HTTP_STATE_WAIT_APP_REPLY);
+ }
+ else
+ {
+ http_read_message_drop (hc, len);
+ /* stream rest of the response body */
+ http_state_change (hc, HTTP_STATE_CLIENT_IO_MORE_DATA);
}
-
- vec_free (hc->rx_buf);
- http_state_change (hc, HTTP_STATE_WAIT_APP_REPLY);
app_wrk = app_worker_get_if_valid (as->app_wrk_index);
if (app_wrk)
@@ -965,7 +1100,7 @@ http_state_wait_client_method (http_conn_t *hc, transport_send_params_t *sp)
return HTTP_SM_STOP;
error:
-
+ http_read_message_drop_all (hc);
http_send_error (hc, ec);
session_transport_closing_notify (&hc->connection);
http_disconnect_transport (hc);
@@ -977,13 +1112,14 @@ static http_sm_result_t
http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
{
http_main_t *hm = &http_main;
- u8 *header;
- u32 offset;
+ u8 *response;
+ u32 sent;
f64 now;
session_t *as;
http_status_code_t sc;
http_msg_t msg;
int rv;
+ http_sm_result_t sm_result = HTTP_SM_ERROR;
as = session_get_from_handle (hc->h_pa_session_handle);
@@ -1004,69 +1140,82 @@ http_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
goto error;
}
- http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type], as->tx_fifo,
- msg.data.len);
+ if (msg.code >= HTTP_N_STATUS)
+ {
+ clib_warning ("unsupported status code: %d", msg.code);
+ return HTTP_SM_ERROR;
+ }
/*
- * Add headers. For now:
+ * Add "protocol layer" headers:
* - current time
- * - expiration time
* - server name
- * - content type
* - data length
*/
now = clib_timebase_now (&hm->timebase);
-
- 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_FORBIDDEN:
- case HTTP_STATUS_OK:
- header =
- format (0, http_response_template, http_status_code_str[msg.code],
- /* Date */
- format_clib_timebase_time, now,
- /* Expires */
- format_clib_timebase_time, now + 600.0,
- /* Server */
- hc->app_name,
- /* Content type */
- http_content_type_str[msg.content_type],
- /* Length */
- msg.data.len);
- break;
- case HTTP_STATUS_MOVED:
- header =
- format (0, http_redirect_template, http_status_code_str[msg.code]);
- /* Location: http(s)://new-place already queued up as data */
- break;
- default:
- clib_warning ("unsupported status code: %d", msg.code);
- return HTTP_SM_ERROR;
+ response = format (0, http_response_template, http_status_code_str[msg.code],
+ /* Date */
+ format_clib_timebase_time, now,
+ /* Server */
+ hc->app_name,
+ /* Length */
+ msg.data.body_len,
+ /* Any headers from app? */
+ msg.data.headers_len ? "" : "\r\n");
+
+ /* Add headers from app (if any) */
+ if (msg.data.headers_len)
+ {
+ HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
+ if (msg.data.type == HTTP_MSG_DATA_PTR)
+ {
+ uword app_headers_ptr;
+ rv = svm_fifo_dequeue (as->tx_fifo, sizeof (app_headers_ptr),
+ (u8 *) &app_headers_ptr);
+ ASSERT (rv == sizeof (app_headers_ptr));
+ vec_append (response, uword_to_pointer (app_headers_ptr, u8 *));
+ }
+ else
+ {
+ u32 orig_len = vec_len (response);
+ vec_resize (response, msg.data.headers_len);
+ u8 *p = response + orig_len;
+ rv = svm_fifo_dequeue (as->tx_fifo, msg.data.headers_len, p);
+ ASSERT (rv == msg.data.headers_len);
+ }
}
+ HTTP_DBG (0, "%v", response);
- offset = http_send_data (hc, header, vec_len (header), 0);
- if (offset != vec_len (header))
+ sent = http_send_data (hc, response, vec_len (response));
+ if (sent != vec_len (response))
{
- clib_warning ("couldn't send response header!");
+ clib_warning ("sending status-line and headers failed!");
sc = HTTP_STATUS_INTERNAL_ERROR;
- vec_free (header);
+ vec_free (response);
goto error;
}
- vec_free (header);
+ vec_free (response);
- /* Start sending the actual data */
- http_state_change (hc, HTTP_STATE_APP_IO_MORE_DATA);
+ if (msg.data.body_len)
+ {
+ /* Start sending the actual data */
+ http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type],
+ as->tx_fifo, msg.data.body_len);
+ http_state_change (hc, HTTP_STATE_APP_IO_MORE_DATA);
+ sm_result = HTTP_SM_CONTINUE;
+ }
+ else
+ {
+ /* No response body, we are done */
+ http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD);
+ sm_result = HTTP_SM_STOP;
+ }
- ASSERT (sp->max_burst_size >= offset);
- sp->max_burst_size -= offset;
- return HTTP_SM_CONTINUE;
+ ASSERT (sp->max_burst_size >= sent);
+ sp->max_burst_size -= sent;
+ return sm_result;
error:
- clib_warning ("unexpected msg type from app %u", msg.type);
http_send_error (hc, sc);
http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD);
session_transport_closing_notify (&hc->connection);
@@ -1079,9 +1228,11 @@ http_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
{
http_msg_t msg;
session_t *as;
- u8 *buf = 0, *request;
- u32 offset;
+ u8 *target_buff = 0, *request = 0, *target;
+ u32 sent;
int rv;
+ http_sm_result_t sm_result = HTTP_SM_ERROR;
+ http_state_t next_state;
as = session_get_from_handle (hc->h_pa_session_handle);
@@ -1100,38 +1251,131 @@ 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)
+ /* read request target */
+ if (msg.data.type == HTTP_MSG_DATA_PTR)
+ {
+ uword target_ptr;
+ rv = svm_fifo_dequeue (as->tx_fifo, sizeof (target_ptr),
+ (u8 *) &target_ptr);
+ ASSERT (rv == sizeof (target_ptr));
+ target = uword_to_pointer (target_ptr, u8 *);
+ }
+ else
+ {
+ vec_validate (target_buff, msg.data.target_path_len - 1);
+ rv =
+ svm_fifo_dequeue (as->tx_fifo, msg.data.target_path_len, target_buff);
+ ASSERT (rv == msg.data.target_path_len);
+ target = target_buff;
+ }
+
+ /* currently we support only GET and POST method */
+ if (msg.method_type == HTTP_REQ_GET)
+ {
+ if (msg.data.body_len)
+ {
+ clib_warning ("GET request shouldn't include data");
+ goto error;
+ }
+ /*
+ * Add "protocol layer" headers:
+ * - host
+ * - user agent
+ */
+ request = format (0, http_get_request_template,
+ /* target */
+ target,
+ /* Host */
+ hc->host,
+ /* User-Agent */
+ hc->app_name,
+ /* Any headers from app? */
+ msg.data.headers_len ? "" : "\r\n");
+
+ next_state = HTTP_STATE_WAIT_SERVER_REPLY;
+ sm_result = HTTP_SM_STOP;
+ }
+ else if (msg.method_type == HTTP_REQ_POST)
+ {
+ if (!msg.data.body_len)
+ {
+ clib_warning ("POST request should include data");
+ goto error;
+ }
+ /*
+ * Add "protocol layer" headers:
+ * - host
+ * - user agent
+ * - content length
+ */
+ request = format (0, http_post_request_template,
+ /* target */
+ target,
+ /* Host */
+ hc->host,
+ /* User-Agent */
+ hc->app_name,
+ /* Content-Length */
+ msg.data.body_len,
+ /* Any headers from app? */
+ msg.data.headers_len ? "" : "\r\n");
+
+ http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type],
+ as->tx_fifo, msg.data.body_len);
+
+ next_state = HTTP_STATE_APP_IO_MORE_DATA;
+ sm_result = HTTP_SM_CONTINUE;
+ }
+ else
{
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);
+ /* Add headers from app (if any) */
+ if (msg.data.headers_len)
+ {
+ HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
+ if (msg.data.type == HTTP_MSG_DATA_PTR)
+ {
+ uword app_headers_ptr;
+ rv = svm_fifo_dequeue (as->tx_fifo, sizeof (app_headers_ptr),
+ (u8 *) &app_headers_ptr);
+ ASSERT (rv == sizeof (app_headers_ptr));
+ vec_append (request, uword_to_pointer (app_headers_ptr, u8 *));
+ }
+ else
+ {
+ u32 orig_len = vec_len (request);
+ vec_resize (request, msg.data.headers_len);
+ u8 *p = request + orig_len;
+ rv = svm_fifo_dequeue (as->tx_fifo, msg.data.headers_len, p);
+ ASSERT (rv == msg.data.headers_len);
+ }
+ }
+ HTTP_DBG (0, "%v", request);
- 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))
+ sent = http_send_data (hc, request, vec_len (request));
+ if (sent != vec_len (request))
{
- clib_warning ("sending request failed!");
+ clib_warning ("sending request-line and headers failed!");
+ sm_result = HTTP_SM_ERROR;
goto error;
}
- http_state_change (hc, HTTP_STATE_WAIT_SERVER_REPLY);
-
- vec_free (buf);
- vec_free (request);
-
- return HTTP_SM_STOP;
+ http_state_change (hc, next_state);
+ goto done;
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;
+
+done:
+ vec_free (target_buff);
+ vec_free (request);
+ return sm_result;
}
static http_sm_result_t
@@ -1186,14 +1430,14 @@ http_state_client_io_more_data (http_conn_t *hc, transport_send_params_t *sp)
return HTTP_SM_ERROR;
}
hc->to_recv -= rv;
- HTTP_DBG (1, "drained %d from ts; remains %d", rv, hc->to_recv);
+ HTTP_DBG (1, "drained %d from ts; remains %lu", rv, hc->to_recv);
+ /* Finished transaction:
+ * server back to HTTP_STATE_WAIT_APP_REPLY
+ * client to HTTP_STATE_WAIT_APP_METHOD */
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);
- }
+ http_state_change (hc, hc->is_server ? HTTP_STATE_WAIT_APP_REPLY :
+ HTTP_STATE_WAIT_APP_METHOD);
app_wrk = app_worker_get_if_valid (as->app_wrk_index);
if (app_wrk)
@@ -1231,7 +1475,7 @@ http_state_app_io_more_data (http_conn_t *hc, transport_send_params_t *sp)
if (!http_buffer_is_drained (hb))
{
if (sent && svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
if (svm_fifo_max_enqueue (ts->tx_fifo) < HTTP_FIFO_THRESH)
{
@@ -1245,10 +1489,13 @@ http_state_app_io_more_data (http_conn_t *hc, transport_send_params_t *sp)
else
{
if (sent && svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX_FLUSH);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX_FLUSH);
- /* Finished transaction, back to HTTP_STATE_WAIT_METHOD */
- http_state_change (hc, HTTP_STATE_WAIT_CLIENT_METHOD);
+ /* Finished transaction:
+ * server back to HTTP_STATE_WAIT_METHOD
+ * client to HTTP_STATE_WAIT_SERVER_REPLY */
+ http_state_change (hc, hc->is_server ? HTTP_STATE_WAIT_CLIENT_METHOD :
+ HTTP_STATE_WAIT_SERVER_REPLY);
http_buffer_free (&hc->tx_buf);
}
@@ -1300,12 +1547,16 @@ http_ts_rx_callback (session_t *ts)
return -1;
}
- if (hc->state == HTTP_CONN_STATE_CLOSED)
+ if (!http_state_is_rx_valid (hc))
{
+ if (hc->state != HTTP_CONN_STATE_CLOSED)
+ clib_warning ("app data req state '%U' session state %u",
+ format_http_state, hc->http_state, hc->state);
svm_fifo_dequeue_drop_all (ts->tx_fifo);
return 0;
}
+ HTTP_DBG (1, "run state machine");
http_req_run_state_machine (hc, 0);
if (hc->state == HTTP_CONN_STATE_TRANSPORT_CLOSED)
@@ -1341,6 +1592,7 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf)
clib_warning ("no http connection for %u", ts->session_index);
return;
}
+ HTTP_DBG (1, "going to free session %x", ts->opaque);
vec_free (hc->rx_buf);
@@ -1348,6 +1600,12 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf)
http_conn_timer_stop (hc);
session_transport_delete_notify (&hc->connection);
+
+ if (!hc->is_server)
+ {
+ vec_free (hc->app_name);
+ vec_free (hc->host);
+ }
http_conn_free (hc);
}
@@ -1453,11 +1711,20 @@ http_transport_connect (transport_endpoint_cfg_t *tep)
hc->state = HTTP_CONN_STATE_CONNECTING;
cargs->api_context = hc_index;
+ hc->is_server = 0;
+
if (vec_len (app->name))
hc->app_name = vec_dup (app->name);
else
hc->app_name = format (0, "VPP HTTP client");
+ if (sep->is_ip4)
+ hc->host = format (0, "%U:%d", format_ip4_address, &sep->ip.ip4,
+ clib_net_to_host_u16 (sep->port));
+ else
+ hc->host = format (0, "%U:%d", format_ip6_address, &sep->ip.ip6,
+ clib_net_to_host_u16 (sep->port));
+
HTTP_DBG (1, "hc ho_index %x", hc_index);
if ((error = vnet_connect (cargs)))
@@ -1510,6 +1777,8 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep)
lhc->c_s_index = app_listener_index;
lhc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
+ lhc->is_server = 1;
+
if (vec_len (app->name))
lhc->app_name = vec_dup (app->name);
else
@@ -1611,6 +1880,7 @@ http_app_tx_callback (void *session, transport_send_params_t *sp)
max_burst_sz = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS;
sp->max_burst_size = max_burst_sz;
+ HTTP_DBG (1, "run state machine");
http_req_run_state_machine (hc, sp);
if (hc->state == HTTP_CONN_STATE_APP_CLOSED)
@@ -1756,6 +2026,7 @@ static clib_error_t *
http_transport_init (vlib_main_t *vm)
{
http_main_t *hm = &http_main;
+ int i;
transport_register_protocol (TRANSPORT_PROTO_HTTP, &http_proto,
FIB_PROTOCOL_IP4, ~0);
@@ -1767,7 +2038,26 @@ http_transport_init (vlib_main_t *vm)
hm->first_seg_size = 32 << 20;
hm->fifo_size = 512 << 10;
- return 0;
+ /* Setup u16 to http_status_code_t map */
+ /* Unrecognized status code is equivalent to the x00 status */
+ vec_validate (hm->sc_by_u16, 599);
+ for (i = 100; i < 200; i++)
+ hm->sc_by_u16[i] = HTTP_STATUS_CONTINUE;
+ for (i = 200; i < 300; i++)
+ hm->sc_by_u16[i] = HTTP_STATUS_OK;
+ for (i = 300; i < 400; i++)
+ hm->sc_by_u16[i] = HTTP_STATUS_MULTIPLE_CHOICES;
+ for (i = 400; i < 500; i++)
+ hm->sc_by_u16[i] = HTTP_STATUS_BAD_REQUEST;
+ for (i = 500; i < 600; i++)
+ hm->sc_by_u16[i] = HTTP_STATUS_INTERNAL_ERROR;
+
+ /* Registered status codes */
+#define _(c, s, str) hm->sc_by_u16[c] = HTTP_STATUS_##s;
+ foreach_http_status_code
+#undef _
+
+ return 0;
}
VLIB_INIT_FUNCTION (http_transport_init);
diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h
index debdebcf050..5f74edb5e47 100644
--- a/src/plugins/http/http.h
+++ b/src/plugins/http/http.h
@@ -51,6 +51,14 @@ typedef struct http_conn_id_
STATIC_ASSERT (sizeof (http_conn_id_t) <= TRANSPORT_CONN_ID_LEN,
"ctx id must be less than TRANSPORT_CONN_ID_LEN");
+typedef struct
+{
+ char *base;
+ uword len;
+} http_token_t;
+
+#define http_token_lit(s) (s), sizeof (s) - 1
+
typedef enum http_conn_state_
{
HTTP_CONN_STATE_LISTEN,
@@ -94,85 +102,87 @@ typedef enum http_target_form_
} http_target_form_t;
#define foreach_http_content_type \
- _ (APP_7Z, ".7z", "application / x - 7z - compressed") \
- _ (APP_DOC, ".doc", "application / msword") \
+ _ (APP_7Z, ".7z", "application/x-7z-compressed") \
+ _ (APP_DOC, ".doc", "application/msword") \
_ (APP_DOCX, ".docx", \
- "application / vnd.openxmlformats - " \
+ "application/vnd.openxmlformats-" \
"officedocument.wordprocessingml.document") \
- _ (APP_EPUB, ".epub", "application / epub + zip") \
- _ (APP_FONT, ".eot", "application / vnd.ms - fontobject") \
- _ (APP_JAR, ".jar", "application / java - archive") \
- _ (APP_JSON, ".json", "application / json") \
- _ (APP_JSON_LD, ".jsonld", "application / ld + json") \
- _ (APP_MPKG, ".mpkg", "application / vnd.apple.installer + xml") \
- _ (APP_ODP, ".odp", "application / vnd.oasis.opendocument.presentation") \
- _ (APP_ODS, ".ods", "application / vnd.oasis.opendocument.spreadsheet") \
- _ (APP_ODT, ".odt", "application / vnd.oasis.opendocument.text") \
- _ (APP_OGX, ".ogx", "application / ogg") \
- _ (APP_PDF, ".pdf", "application / pdf") \
- _ (APP_PHP, ".php", "application / x - httpd - php") \
- _ (APP_PPT, ".ppt", "application / vnd.ms - powerpoint") \
- _ (APP_PPTX, ".pptx", "application / vnd.ms - powerpoint") \
- _ (APP_RAR, ".rar", "application / vnd.rar") \
- _ (APP_RTF, ".rtf", "application / rtf") \
- _ (APP_SH, ".sh", "application / x - sh") \
- _ (APP_TAR, ".tar", "application / x - tar") \
- _ (APP_VSD, ".vsd", "application / vnd.visio") \
- _ (APP_XHTML, ".xhtml", "application / xhtml + xml") \
- _ (APP_XLS, ".xls", "application / vnd.ms - excel") \
- _ (APP_XML, ".xml", "application / xml") \
+ _ (APP_EPUB, ".epub", "application/epub+zip") \
+ _ (APP_FONT, ".eot", "application/vnd.ms-fontobject") \
+ _ (APP_JAR, ".jar", "application/java-archive") \
+ _ (APP_JSON, ".json", "application/json") \
+ _ (APP_JSON_LD, ".jsonld", "application/ld+json") \
+ _ (APP_MPKG, ".mpkg", "application/vnd.apple.installer+xml") \
+ _ (APP_ODP, ".odp", "application/vnd.oasis.opendocument.presentation") \
+ _ (APP_ODS, ".ods", "application/vnd.oasis.opendocument.spreadsheet") \
+ _ (APP_ODT, ".odt", "application/vnd.oasis.opendocument.text") \
+ _ (APP_OGX, ".ogx", "application/ogg") \
+ _ (APP_PDF, ".pdf", "application/pdf") \
+ _ (APP_PHP, ".php", "application/x-httpd-php") \
+ _ (APP_PPT, ".ppt", "application/vnd.ms-powerpoint") \
+ _ (APP_PPTX, ".pptx", "application/vnd.ms-powerpoint") \
+ _ (APP_RAR, ".rar", "application/vnd.rar") \
+ _ (APP_RTF, ".rtf", "application/rtf") \
+ _ (APP_SH, ".sh", "application/x-sh") \
+ _ (APP_TAR, ".tar", "application/x-tar") \
+ _ (APP_VSD, ".vsd", "application/vnd.visio") \
+ _ (APP_XHTML, ".xhtml", "application/xhtml+xml") \
+ _ (APP_XLS, ".xls", "application/vnd.ms-excel") \
+ _ (APP_XML, ".xml", "application/xml") \
_ (APP_XSLX, ".xlsx", \
- "application / vnd.openxmlformats - officedocument.spreadsheetml.sheet") \
- _ (APP_XUL, ".xul", "application / vnd.mozilla.xul + xml") \
- _ (APP_ZIP, ".zip", "application / zip") \
- _ (AUDIO_AAC, ".aac", "audio / aac") \
- _ (AUDIO_CD, ".cda", "application / x - cdf") \
- _ (AUDIO_WAV, ".wav", "audio / wav") \
- _ (AUDIO_WEBA, ".weba", "audio / webm") \
- _ (AUDO_MIDI, ".midi", "audio / midi") \
- _ (AUDO_MID, ".mid", "audo / midi") \
- _ (AUDO_MP3, ".mp3", "audio / mpeg") \
- _ (AUDO_OGA, ".oga", "audio / ogg") \
- _ (AUDO_OPUS, ".opus", "audio / opus") \
- _ (APP_OCTET_STREAM, ".bin", "application / octet - stream") \
- _ (BZIP2, ".bz2", "application / x - bzip2") \
- _ (BZIP, ".bz", "application / x - bzip") \
- _ (FONT_OTF, ".otf", "font / otf") \
- _ (FONT_TTF, ".ttf", "font / ttf") \
- _ (FONT_WOFF2, ".woff2", "font / woff2") \
- _ (FONT_WOFF, ".woff", "font / woff") \
- _ (GZIP, ".gz", "application / gzip") \
- _ (IMAGE_AVIF, ".avif", "image / avif") \
- _ (IMAGE_BMP, ".bmp", "image / bmp") \
- _ (IMAGE_GIF, ".gif", "image / gif") \
- _ (IMAGE_ICON, ".ico", "image / vnd.microsoft.icon") \
- _ (IMAGE_JPEG, ".jpeg", "image / jpeg") \
- _ (IMAGE_JPG, ".jpg", "image / jpeg") \
- _ (IMAGE_PNG, ".png", "image / png") \
- _ (IMAGE_SVG, ".svg", "image / svg + xml") \
- _ (IMAGE_TIFF, ".tiff", "image / tiff") \
- _ (IMAGE_TIF, ".tif", "image / tiff") \
- _ (IMAGE_WEBP, ".webp", "image / webp") \
- _ (SCRIPT_CSH, ".csh", "application / x - csh") \
- _ (TEXT_ABIWORD, ".abw", "application / x - abiword") \
- _ (TEXT_ARCHIVE, ".arc", "application / x - freearc") \
- _ (TEXT_AZW, ".azw", "application / vnd.amazon.ebook") \
- _ (TEXT_CALENDAR, ".ics", "text / calendar") \
- _ (TEXT_CSS, ".css", "text / css") \
- _ (TEXT_CSV, ".csv", "text / csv") \
- _ (TEXT_HTM, ".htm", "text / html") \
- _ (TEXT_HTML, ".html", "text / html") \
- _ (TEXT_JS, ".js", "text / javascript") \
- _ (TEXT_MJS, ".mjs", "text / javascript") \
- _ (TEXT_PLAIN, ".txt", "text / plain") \
- _ (VIDEO_3GP2, ".3g2", "video / 3gpp2") \
- _ (VIDEO_3GP, ".3gp", "video / 3gpp") \
- _ (VIDEO_AVI, ".avi", "video / x - msvideo") \
- _ (VIDEO_MP4, ".mp4", "video / mp4") \
- _ (VIDEO_MPEG, ".mpeg", "video / mpeg") \
- _ (VIDEO_OGG, ".ogv", "video / ogg") \
- _ (VIDEO_TS, ".ts", "video / mp2t") \
- _ (VIDEO_WEBM, ".webm", "video / webm")
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") \
+ _ (APP_XUL, ".xul", "application/vnd.mozilla.xul+xml") \
+ _ (APP_X_WWW_FORM_URLENCODED, ".invalid", \
+ "application/x-www-form-urlencoded") \
+ _ (APP_ZIP, ".zip", "application/zip") \
+ _ (AUDIO_AAC, ".aac", "audio/aac") \
+ _ (AUDIO_CD, ".cda", "application/x-cdf") \
+ _ (AUDIO_WAV, ".wav", "audio/wav") \
+ _ (AUDIO_WEBA, ".weba", "audio/webm") \
+ _ (AUDO_MIDI, ".midi", "audio/midi") \
+ _ (AUDO_MID, ".mid", "audo/midi") \
+ _ (AUDO_MP3, ".mp3", "audio/mpeg") \
+ _ (AUDO_OGA, ".oga", "audio/ogg") \
+ _ (AUDO_OPUS, ".opus", "audio/opus") \
+ _ (APP_OCTET_STREAM, ".bin", "application/octet-stream") \
+ _ (BZIP2, ".bz2", "application/x-bzip2") \
+ _ (BZIP, ".bz", "application/x-bzip") \
+ _ (FONT_OTF, ".otf", "font/otf") \
+ _ (FONT_TTF, ".ttf", "font/ttf") \
+ _ (FONT_WOFF2, ".woff2", "font/woff2") \
+ _ (FONT_WOFF, ".woff", "font/woff") \
+ _ (GZIP, ".gz", "application/gzip") \
+ _ (IMAGE_AVIF, ".avif", "image/avif") \
+ _ (IMAGE_BMP, ".bmp", "image/bmp") \
+ _ (IMAGE_GIF, ".gif", "image/gif") \
+ _ (IMAGE_ICON, ".ico", "image/vnd.microsoft.icon") \
+ _ (IMAGE_JPEG, ".jpeg", "image/jpeg") \
+ _ (IMAGE_JPG, ".jpg", "image/jpeg") \
+ _ (IMAGE_PNG, ".png", "image/png") \
+ _ (IMAGE_SVG, ".svg", "image/svg+xml") \
+ _ (IMAGE_TIFF, ".tiff", "image/tiff") \
+ _ (IMAGE_TIF, ".tif", "image/tiff") \
+ _ (IMAGE_WEBP, ".webp", "image/webp") \
+ _ (SCRIPT_CSH, ".csh", "application/x-csh") \
+ _ (TEXT_ABIWORD, ".abw", "application/x-abiword") \
+ _ (TEXT_ARCHIVE, ".arc", "application/x-freearc") \
+ _ (TEXT_AZW, ".azw", "application/vnd.amazon.ebook") \
+ _ (TEXT_CALENDAR, ".ics", "text/calendar") \
+ _ (TEXT_CSS, ".css", "text/css") \
+ _ (TEXT_CSV, ".csv", "text/csv") \
+ _ (TEXT_HTM, ".htm", "text/html") \
+ _ (TEXT_HTML, ".html", "text/html") \
+ _ (TEXT_JS, ".js", "text/javascript") \
+ _ (TEXT_MJS, ".mjs", "text/javascript") \
+ _ (TEXT_PLAIN, ".txt", "text/plain") \
+ _ (VIDEO_3GP2, ".3g2", "video/3gpp2") \
+ _ (VIDEO_3GP, ".3gp", "video/3gpp") \
+ _ (VIDEO_AVI, ".avi", "video/x-msvideo") \
+ _ (VIDEO_MP4, ".mp4", "video/mp4") \
+ _ (VIDEO_MPEG, ".mpeg", "video/mpeg") \
+ _ (VIDEO_OGG, ".ogv", "video/ogg") \
+ _ (VIDEO_TS, ".ts", "video/mp2t") \
+ _ (VIDEO_WEBM, ".webm", "video/webm")
typedef enum http_content_type_
{
@@ -235,50 +245,100 @@ typedef enum http_status_code_
HTTP_N_STATUS
} http_status_code_t;
-#define HTTP_HEADER_ACCEPT "Accept"
-#define HTTP_HEADER_ACCEPT_CHARSET "Accept-Charset"
-#define HTTP_HEADER_ACCEPT_ENCODING "Accept-Encoding"
-#define HTTP_HEADER_ACCEPT_LANGUAGE "Accept-Language"
-#define HTTP_HEADER_ACCEPT_RANGES "Accept-Ranges"
-#define HTTP_HEADER_ALLOW "Allow"
-#define HTTP_HEADER_AUTHENTICATION_INFO "Authentication-Info"
-#define HTTP_HEADER_AUTHORIZATION "Authorization"
-#define HTTP_HEADER_CLOSE "Close"
-#define HTTP_HEADER_CONNECTION "Connection"
-#define HTTP_HEADER_CONTENT_ENCODING "Content-Encoding"
-#define HTTP_HEADER_CONTENT_LANGUAGE "Content-Language"
-#define HTTP_HEADER_CONTENT_LENGTH "Content-Length"
-#define HTTP_HEADER_CONTENT_LOCATION "Content-Location"
-#define HTTP_HEADER_CONTENT_RANGE "Content-Range"
-#define HTTP_HEADER_CONTENT_TYPE "Content-Type"
-#define HTTP_HEADER_DATE "Date"
-#define HTTP_HEADER_ETAG "ETag"
-#define HTTP_HEADER_EXPECT "Expect"
-#define HTTP_HEADER_FROM "From"
-#define HTTP_HEADER_HOST "Host"
-#define HTTP_HEADER_IF_MATCH "If-Match"
-#define HTTP_HEADER_IF_MODIFIED_SINCE "If-Modified-Since"
-#define HTTP_HEADER_IF_NONE_MATCH "If-None-Match"
-#define HTTP_HEADER_IF_RANGE "If-Range"
-#define HTTP_HEADER_IF_UNMODIFIED_SINCE "If-Unmodified-Since"
-#define HTTP_HEADER_LAST_MODIFIED "Last-Modified"
-#define HTTP_HEADER_LOCATION "Location"
-#define HTTP_HEADER_MAX_FORWARDS "Max-Forwards"
-#define HTTP_HEADER_PROXY_AUTHENTICATE "Proxy-Authenticate"
-#define HTTP_HEADER_PROXY_AUTHENTICATION_INFO "Proxy-Authentication-Info"
-#define HTTP_HEADER_PROXY_AUTHORIZATION "Proxy-Authorization"
-#define HTTP_HEADER_RANGE "Range"
-#define HTTP_HEADER_REFERER "Referer"
-#define HTTP_HEADER_RETRY_AFTER "Retry-After"
-#define HTTP_HEADER_SERVER "Server"
-#define HTTP_HEADER_TE "TE"
-#define HTTP_HEADER_TRAILER "Trailer"
-#define HTTP_HEADER_TRANSFER_ENCODING "Transfer-Encoding"
-#define HTTP_HEADER_UPGRADE "Upgrade"
-#define HTTP_HEADER_USER_AGENT "User-Agent"
-#define HTTP_HEADER_VARY "Vary"
-#define HTTP_HEADER_VIA "Via"
-#define HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate"
+#define foreach_http_header_name \
+ _ (ACCEPT, "Accept") \
+ _ (ACCEPT_CHARSET, "Accept-Charset") \
+ _ (ACCEPT_ENCODING, "Accept-Encoding") \
+ _ (ACCEPT_LANGUAGE, "Accept-Language") \
+ _ (ACCEPT_RANGES, "Accept-Ranges") \
+ _ (ACCESS_CONTROL_ALLOW_CREDENTIALS, "Access-Control-Allow-Credentials") \
+ _ (ACCESS_CONTROL_ALLOW_HEADERS, "Access-Control-Allow-Headers") \
+ _ (ACCESS_CONTROL_ALLOW_METHODS, "Access-Control-Allow-Methods") \
+ _ (ACCESS_CONTROL_ALLOW_ORIGIN, "Access-Control-Allow-Origin") \
+ _ (ACCESS_CONTROL_EXPOSE_HEADERS, "Access-Control-Expose-Headers") \
+ _ (ACCESS_CONTROL_MAX_AGE, "Access-Control-Max-Age") \
+ _ (ACCESS_CONTROL_REQUEST_HEADERS, "Access-Control-Request-Headers") \
+ _ (ACCESS_CONTROL_REQUEST_METHOD, "Access-Control-Request-Method") \
+ _ (AGE, "Age") \
+ _ (ALLOW, "Allow") \
+ _ (ALPN, "ALPN") \
+ _ (ALT_SVC, "Alt-Svc") \
+ _ (ALT_USED, "Alt-Used") \
+ _ (ALTERNATES, "Alternates") \
+ _ (AUTHENTICATION_CONTROL, "Authentication-Control") \
+ _ (AUTHENTICATION_INFO, "Authentication-Info") \
+ _ (AUTHORIZATION, "Authorization") \
+ _ (CACHE_CONTROL, "Cache-Control") \
+ _ (CACHE_STATUS, "Cache-Status") \
+ _ (CAPSULE_PROTOCOL, "Capsule-Protocol") \
+ _ (CDN_CACHE_CONTROL, "CDN-Cache-Control") \
+ _ (CDN_LOOP, "CDN-Loop") \
+ _ (CLIENT_CERT, "Client-Cert") \
+ _ (CLIENT_CERT_CHAIN, "Client-Cert-Chain") \
+ _ (CLOSE, "Close") \
+ _ (CONNECTION, "Connection") \
+ _ (CONTENT_DIGEST, "Content-Digest") \
+ _ (CONTENT_DISPOSITION, "Content-Disposition") \
+ _ (CONTENT_ENCODING, "Content-Encoding") \
+ _ (CONTENT_LANGUAGE, "Content-Language") \
+ _ (CONTENT_LENGTH, "Content-Length") \
+ _ (CONTENT_LOCATION, "Content-Location") \
+ _ (CONTENT_RANGE, "Content-Range") \
+ _ (CONTENT_TYPE, "Content-Type") \
+ _ (COOKIE, "Cookie") \
+ _ (DATE, "Date") \
+ _ (DIGEST, "Digest") \
+ _ (DPOP, "DPoP") \
+ _ (DPOP_NONCE, "DPoP-Nonce") \
+ _ (EARLY_DATA, "Early-Data") \
+ _ (ETAG, "ETag") \
+ _ (EXPECT, "Expect") \
+ _ (EXPIRES, "Expires") \
+ _ (FORWARDED, "Forwarded") \
+ _ (FROM, "From") \
+ _ (HOST, "Host") \
+ _ (IF_MATCH, "If-Match") \
+ _ (IF_MODIFIED_SINCE, "If-Modified-Since") \
+ _ (IF_NONE_MATCH, "If-None-Match") \
+ _ (IF_RANGE, "If-Range") \
+ _ (IF_UNMODIFIED_SINCE, "If-Unmodified-Since") \
+ _ (KEEP_ALIVE, "Keep-Alive") \
+ _ (LAST_MODIFIED, "Last-Modified") \
+ _ (LINK, "Link") \
+ _ (LOCATION, "Location") \
+ _ (MAX_FORWARDS, "Max-Forwards") \
+ _ (ORIGIN, "Origin") \
+ _ (PRIORITY, "Priority") \
+ _ (PROXY_AUTHENTICATE, "Proxy-Authenticate") \
+ _ (PROXY_AUTHENTICATION_INFO, "Proxy-Authentication-Info") \
+ _ (PROXY_AUTHORIZATION, "Proxy-Authorization") \
+ _ (PROXY_STATUS, "Proxy-Status") \
+ _ (RANGE, "Range") \
+ _ (REFERER, "Referer") \
+ _ (REPR_DIGEST, "Repr-Digest") \
+ _ (SET_COOKIE, "Set-Cookie") \
+ _ (SIGNATURE, "Signature") \
+ _ (SIGNATURE_INPUT, "Signature-Input") \
+ _ (STRICT_TRANSPORT_SECURITY, "Strict-Transport-Security") \
+ _ (RETRY_AFTER, "Retry-After") \
+ _ (SERVER, "Server") \
+ _ (TE, "TE") \
+ _ (TRAILER, "Trailer") \
+ _ (TRANSFER_ENCODING, "Transfer-Encoding") \
+ _ (UPGRADE, "Upgrade") \
+ _ (USER_AGENT, "User-Agent") \
+ _ (VARY, "Vary") \
+ _ (VIA, "Via") \
+ _ (WANT_CONTENT_DIGEST, "Want-Content-Digest") \
+ _ (WANT_REPR_DIGEST, "Want-Repr-Digest") \
+ _ (WWW_AUTHENTICATE, "WWW-Authenticate")
+
+typedef enum http_header_name_
+{
+#define _(sym, str) HTTP_HEADER_##sym,
+ foreach_http_header_name
+#undef _
+} http_header_name_t;
typedef enum http_msg_data_type_
{
@@ -298,7 +358,7 @@ typedef struct http_msg_data_
u32 headers_offset;
u32 headers_len;
u32 body_offset;
- u32 body_len;
+ u64 body_len;
u8 data[0];
} http_msg_data_t;
@@ -310,7 +370,6 @@ typedef struct http_msg_
http_req_method_t method_type;
http_status_code_t code;
};
- http_content_type_t content_type;
http_msg_data_t data;
} http_msg_t;
@@ -330,6 +389,8 @@ typedef struct http_tc_
http_conn_state_t state;
u32 timer_handle;
u8 *app_name;
+ u8 *host;
+ u8 is_server;
/*
* Current request
@@ -339,8 +400,9 @@ typedef struct http_tc_
u8 *rx_buf;
u32 rx_buf_offset;
http_buffer_t tx_buf;
- u32 to_recv;
+ u64 to_recv;
u32 bytes_dequeued;
+ u32 control_data_len; /* start line + headers + empty line */
http_target_form_t target_form;
u32 target_path_offset;
u32 target_path_len;
@@ -349,7 +411,8 @@ typedef struct http_tc_
u32 headers_offset;
u32 headers_len;
u32 body_offset;
- u32 body_len;
+ u64 body_len;
+ u16 status_code;
} http_conn_t;
typedef struct http_worker_
@@ -365,6 +428,7 @@ typedef struct http_main_
clib_timebase_t timebase;
+ u16 *sc_by_u16;
/*
* Runtime config
*/
@@ -669,11 +733,17 @@ typedef struct
{
u8 *name;
u8 *value;
+} http_header_ht_t;
+
+typedef struct
+{
+ http_token_t name;
+ http_token_t value;
} http_header_t;
typedef struct
{
- http_header_t *headers;
+ http_header_ht_t *headers;
uword *value_by_name;
} http_header_table_t;
@@ -685,7 +755,7 @@ typedef struct
always_inline void
http_free_header_table (http_header_table_t *ht)
{
- http_header_t *header;
+ http_header_ht_t *header;
vec_foreach (header, ht->headers)
{
vec_free (header->name);
@@ -713,7 +783,7 @@ http_parse_headers (u8 *headers, http_header_table_t **header_table)
u8 *pos, *end, *name_start, *value_start, *name;
u32 name_len, value_len;
int rv;
- http_header_t *header;
+ http_header_ht_t *header;
http_header_table_t *ht;
uword *p;
@@ -779,7 +849,7 @@ always_inline const char *
http_get_header (http_header_table_t *header_table, const char *name)
{
uword *p;
- http_header_t *header;
+ http_header_ht_t *header;
p = hash_get_mem (header_table->value_by_name, name);
if (p)
@@ -791,6 +861,119 @@ http_get_header (http_header_table_t *header_table, const char *name)
return 0;
}
+/**
+ * Add header to the list.
+ *
+ * @param headers Header list.
+ * @param name Pointer to header's name buffer.
+ * @param name_len Length of the name.
+ * @param value Pointer to header's value buffer.
+ * @param value_len Length of the value.
+ *
+ * @note Headers added at protocol layer: Date, Server, Content-Length
+ */
+always_inline void
+http_add_header (http_header_t **headers, const char *name, uword name_len,
+ const char *value, uword value_len)
+{
+ http_header_t *header;
+ vec_add2 (*headers, header, 1);
+ header->name.base = (char *) name;
+ header->name.len = name_len;
+ header->value.base = (char *) value;
+ header->value.len = value_len;
+}
+
+/**
+ * Serialize the header list.
+ *
+ * @param headers Header list to serialize.
+ *
+ * @return New vector with serialized headers.
+ *
+ * The caller is always responsible to free the returned vector.
+ */
+always_inline u8 *
+http_serialize_headers (http_header_t *headers)
+{
+ u8 *headers_buf = 0, *dst;
+ u32 headers_buf_len = 2;
+ http_header_t *header;
+
+ vec_foreach (header, headers)
+ headers_buf_len += header->name.len + header->value.len + 4;
+
+ vec_validate (headers_buf, headers_buf_len - 1);
+ dst = headers_buf;
+
+ vec_foreach (header, headers)
+ {
+ clib_memcpy (dst, header->name.base, header->name.len);
+ dst += header->name.len;
+ *dst++ = ':';
+ *dst++ = ' ';
+ clib_memcpy (dst, header->value.base, header->value.len);
+ dst += header->value.len;
+ *dst++ = '\r';
+ *dst++ = '\n';
+ }
+ *dst++ = '\r';
+ *dst = '\n';
+ return headers_buf;
+}
+
+typedef struct
+{
+ ip46_address_t ip;
+ u16 port;
+ u8 is_ip4;
+} http_uri_t;
+
+always_inline int
+http_parse_authority_form_target (u8 *target, http_uri_t *authority)
+{
+ unformat_input_t input;
+ u32 port;
+ int rv = 0;
+
+ unformat_init_vector (&input, vec_dup (target));
+ if (unformat (&input, "[%U]:%d", unformat_ip6_address, &authority->ip.ip6,
+ &port))
+ {
+ authority->port = clib_host_to_net_u16 (port);
+ authority->is_ip4 = 0;
+ }
+ else if (unformat (&input, "%U:%d", unformat_ip4_address, &authority->ip.ip4,
+ &port))
+ {
+ authority->port = clib_host_to_net_u16 (port);
+ authority->is_ip4 = 1;
+ }
+ /* TODO reg-name resolution */
+ else
+ {
+ clib_warning ("unsupported format '%v'", target);
+ rv = -1;
+ }
+ unformat_free (&input);
+ return rv;
+}
+
+always_inline u8 *
+http_serialize_authority_form_target (http_uri_t *authority)
+{
+ u8 *s;
+
+ if (authority->is_ip4)
+ s = format (0, "%U:%d", format_ip4_address, &authority->ip.ip4,
+ clib_net_to_host_u16 (authority->port));
+ else
+ s = format (0, "[%U]:%d", format_ip6_address, &authority->ip.ip6,
+ clib_net_to_host_u16 (authority->port));
+
+ return s;
+}
+
#endif /* SRC_PLUGINS_HTTP_HTTP_H_ */
/*
diff --git a/src/plugins/http/http_buffer.c b/src/plugins/http/http_buffer.c
index f3dc308dbf8..bc1b8c08630 100644
--- a/src/plugins/http/http_buffer.c
+++ b/src/plugins/http/http_buffer.c
@@ -173,7 +173,7 @@ buf_ptr_drain (http_buffer_t *hb, u32 len)
bf->segs[1].data += len;
bf->segs[0].len -= len;
- HTTP_DBG (1, "drained %u left %u", len, bf->segs[1].len);
+ HTTP_DBG (1, "drained %u left %u", len, bf->segs[0].len);
if (!bf->segs[0].len)
{
diff --git a/src/plugins/http/http_content_types.h b/src/plugins/http/http_content_types.h
new file mode 100644
index 00000000000..ddc02566db7
--- /dev/null
+++ b/src/plugins/http/http_content_types.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#ifndef SRC_PLUGINS_HTTP_HTTP_CONTENT_TYPES_H_
+#define SRC_PLUGINS_HTTP_HTTP_CONTENT_TYPES_H_
+
+#include <http/http.h>
+
+static http_token_t http_content_types[] = {
+#define _(s, ext, str) { http_token_lit (str) },
+ foreach_http_content_type
+#undef _
+};
+
+#define http_content_type_token(e) \
+ http_content_types[e].base, http_content_types[e].len
+
+#endif /* SRC_PLUGINS_HTTP_HTTP_CONTENT_TYPES_H_ */
diff --git a/src/plugins/http/http_header_names.h b/src/plugins/http/http_header_names.h
new file mode 100644
index 00000000000..99acac786db
--- /dev/null
+++ b/src/plugins/http/http_header_names.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#ifndef SRC_PLUGINS_HTTP_HTTP_HEADER_NAMES_H_
+#define SRC_PLUGINS_HTTP_HTTP_HEADER_NAMES_H_
+
+#include <http/http.h>
+
+static http_token_t http_header_names[] = {
+#define _(sym, str) { http_token_lit (str) },
+ foreach_http_header_name
+#undef _
+};
+
+#define http_header_name_token(e) \
+ http_header_names[e].base, http_header_names[e].len
+
+#define http_header_name_str(e) http_header_names[e].base
+
+#endif /* SRC_PLUGINS_HTTP_HTTP_HEADER_NAMES_H_ */
diff --git a/src/plugins/http/http_plugin.rst b/src/plugins/http/http_plugin.rst
index c4c4d2c8234..56da3a810b9 100644
--- a/src/plugins/http/http_plugin.rst
+++ b/src/plugins/http/http_plugin.rst
@@ -9,14 +9,14 @@ Overview
--------
This plugin adds the HTTP protocol to VPP's Host Stack.
-As a result parsing of HTTP/1 request or response is available for internal VPP applications.
+As a result parsing and serializing of HTTP/1 requests or responses are available for internal VPP applications.
Usage
-----
The plugin exposes following inline functions: ``http_validate_abs_path_syntax``, ``http_validate_query_syntax``,
``http_percent_decode``, ``http_path_remove_dot_segments``, ``http_parse_headers``, ``http_get_header``,
-``http_free_header_table``.
+``http_free_header_table``, ``http_add_header``, ``http_serialize_headers``.
It relies on the hoststack constructs and uses ``http_msg_data_t`` data structure for passing metadata to/from applications.
@@ -121,6 +121,7 @@ Following example shows how to parse headers:
.. code-block:: C
+ #include <http/http_header_names.h>
if (msg.data.headers_len)
{
u8 *headers = 0;
@@ -134,7 +135,7 @@ Following example shows how to parse headers:
/* your error handling */
}
/* get Accept header */
- const char *accept_value = http_get_header (ht, HTTP_HEADER_ACCEPT);
+ const char *accept_value = http_get_header (ht, http_header_name_str (HTTP_HEADER_ACCEPT));
if (accept_value)
{
/* do something interesting */
@@ -143,14 +144,364 @@ Following example shows how to parse headers:
vec_free (headers);
}
-Finally application reads body:
+Finally application reads body (if any), which might be received in multiple pieces (depends on size), so we might need some state machine in ``builtin_app_rx_callback``.
+We will add following members to our session context structure:
.. code-block:: C
- u8 *body = 0;
- if (msg.data.body_len)
+ typedef struct
+ {
+ /* ... */
+ u64 to_recv;
+ u8 *resp_body;
+ } session_ctx_t;
+
+First we prepare vector for response body, do it only once when you are reading metadata:
+
+.. code-block:: C
+
+ /* drop everything up to body */
+ svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset);
+ ctx->to_recv = msg.data.body_len;
+ /* prepare vector for response body */
+ vec_validate (ctx->resp_body, msg.data.body_len - 1);
+ vec_reset_length (ctx->resp_body);
+
+Now we can start reading body content, following block of code could be executed multiple times:
+
+.. code-block:: C
+
+ /* dequeue */
+ u32 n_deq = svm_fifo_max_dequeue (ts->rx_fifo);
+ /* current offset */
+ u64 curr = vec_len (ctx->resp_body);
+ rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, ctx->resp_body + curr);
+ ASSERT (rv == n_deq);
+ /* update length of the vector */
+ vec_set_len (ctx->resp_body, curr + n_deq);
+ /* update number of remaining bytes to receive */
+ ctx->to_recv -= rv;
+ /* check if all data received */
+ if (ctx->to_recv == 0)
+ {
+ /* we are done */
+ /* send 200 OK response */
+ }
+
+Sending data
+""""""""""""""
+
+When server application sends response back to HTTP layer it starts with message metadata, followed by optional serialized headers and finally body (if any).
+
+Application should set following items:
+
+* Status code
+* target form
+* header section offset and length
+* body offset and length
+
+Application could pass headers back to HTTP layer. Header list is created dynamically as vector of ``http_header_t``,
+where we store only pointers to buffers (zero copy).
+Well known header names are predefined.
+The list is serialized just before you send buffer to HTTP layer.
+
+.. note::
+ Following headers are added at protocol layer and **MUST NOT** be set by application: Date, Server, Content-Length
+
+Following example shows how to create headers section:
+
+.. code-block:: C
+
+ #include <http/http.h>
+ #include <http/http_header_names.h>
+ #include <http/http_content_types.h>
+ http_header_t *resp_headers = 0;
+ u8 *headers_buf = 0;
+ http_add_header (resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (HTTP_CONTENT_TEXT_HTML));
+ http_add_header (resp_headers,
+ http_header_name_token (HTTP_HEADER_CACHE_CONTROL),
+ http_token_lit ("max-age=600"));
+ http_add_header (resp_headers,
+ http_header_name_token (HTTP_HEADER_LOCATION),
+ (const char *) redirect, vec_len (redirect));
+ headers_buf = http_serialize_headers (resp_headers);
+
+The example below show how to create and send response HTTP message metadata:
+
+.. code-block:: C
+
+ http_msg_t msg;
+ msg.type = HTTP_MSG_REPLY;
+ msg.code = HTTP_STATUS_MOVED
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = vec_len (headers_buf);
+ msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.body_len = vec_len (tx_buf);
+ msg.data.body_offset = msg.data.headers_len;
+ msg.data.len = msg.data.body_len + msg.data.headers_len;
+ ts = session_get (hs->vpp_session_index, hs->thread_index);
+ rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
+
+Next you will send your serialized headers:
+
+.. code-block:: C
+
+ rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+ ASSERT (rv == msg.data.headers_len);
+ vec_free (headers_buf);
+
+Finally application sends response body:
+
+.. code-block:: C
+
+ rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (tx_buf), tx_buf);
+ if (rv != vec_len (hs->tx_buf))
+ {
+ hs->tx_offset = rv;
+ svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ }
+ else
+ {
+ vec_free (tx_buf);
+ }
+ if (svm_fifo_set_event (ts->tx_fifo))
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
+
+Examples above shows how to send body and headers by copy, alternatively you could pass them as pointer:
+
+.. code-block:: C
+
+ msg.data.type = HTTP_MSG_DATA_PTR;
+ /* code omitted for brevity */
+ if (msg.data.headers_len)
+ {
+ uword headers = pointer_to_uword (headers_buf);
+ rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (headers), (u8 *) &headers);
+ ASSERT (rv == sizeof (headers));
+ }
+ uword data = pointer_to_uword (tx_buf);
+ rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (data), (u8 *) &data);
+ ASSERT (rv == sizeof (data));
+
+In this case you need to free data when you receive next request or when session is closed.
+
+
+Client application
+^^^^^^^^^^^^^^^^^^
+
+Client application opens connection with vnet URI where transport protocol is set to ``http``.
+
+Sending data
+""""""""""""""
+
+HTTP request is sent when connection is successfully established in ``session_connected_callback``.
+
+When client application sends message to HTTP layer it starts with message metadata, followed by request target, optional headers and body (if any) buffers.
+
+Application should set following items:
+
+* HTTP method
+* target form, offset and length
+* header section offset and length
+* body offset and length
+
+Application could pass headers to HTTP layer. Header list is created dynamically as vector of ``http_header_t``,
+where we store only pointers to buffers (zero copy).
+Well known header names are predefined.
+The list is serialized just before you send buffer to HTTP layer.
+
+.. note::
+ Following headers are added at protocol layer and **MUST NOT** be set by application: Host, User-Agent
+
+
+The example below shows how to create headers section:
+
+.. code-block:: C
+
+ #include <http/http.h>
+ #include <http/http_header_names.h>
+ #include <http/http_content_types.h>
+ http_header_t *req_headers = 0;
+ u8 *headers_buf = 0;
+ http_add_header (req_headers,
+ http_header_name_token (HTTP_HEADER_ACCEPT),
+ http_content_type_token (HTTP_CONTENT_TEXT_HTML));
+ headers_buf = http_serialize_headers (req_headers);
+ vec_free (hs->req_headers);
+
+Following example shows how to set message metadata:
+
+.. code-block:: C
+
+ http_msg_t msg;
+ msg.type = HTTP_MSG_REQUEST;
+ msg.method_type = HTTP_REQ_GET;
+ msg.data.headers_offset = 0;
+ /* request target */
+ msg.data.target_form = HTTP_TARGET_ORIGIN_FORM;
+ msg.data.target_path_offset = 0;
+ msg.data.target_path_len = vec_len (target);
+ /* custom headers */
+ msg.data.headers_offset = msg.data.target_path_len;
+ msg.data.headers_len = vec_len (headers_buf);
+ /* no request body because we are doing GET request */
+ msg.data.body_len = 0;
+ /* data type and total length */
+ msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.len = msg.data.target_path_len + msg.data.headers_len + msg.data.body_len;
+
+Finally application sends everything to HTTP layer:
+
+.. code-block:: C
+
+ svm_fifo_seg_t segs[3] = { { (u8 *) &msg, sizeof (msg) }, /* message metadata */
+ { target, vec_len (target) }, /* request target */
+ { headers_buf, vec_len (headers_buf) } }; /* serialized headers */
+ rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 3, 0 /* allow partial */);
+ vec_free (headers_buf);
+ if (rv < 0 || rv != sizeof (msg) + msg.data.len)
+ {
+ clib_warning ("failed app enqueue");
+ return -1;
+ }
+ if (svm_fifo_set_event (as->tx_fifo))
+ session_program_tx_io_evt (as->handle, SESSION_IO_EVT_TX);
+
+Examples above shows how to send buffers by copy, alternatively you could pass them as pointer:
+
+.. code-block:: C
+
+ msg.data.type = HTTP_MSG_DATA_PTR;
+ msg.method_type = HTTP_REQ_POST;
+ msg.data.body_len = vec_len (data);
+ /* code omitted for brevity */
+ uword target = pointer_to_uword (target);
+ uword headers = pointer_to_uword (headers_buf);
+ uword body = pointer_to_uword (data);
+ svm_fifo_seg_t segs[4] = {
+ { (u8 *) &msg, sizeof (msg) },
+ { (u8 *) &target, sizeof (target) },
+ { (u8 *) &headers, sizeof (headers) },
+ { (u8 *) &body, sizeof (body) },
+ };
+ rv = svm_fifo_enqueue_segments (s->tx_fifo, segs, 4, 0 /* allow partial */);
+ ASSERT (rv == (sizeof (msg) + sizeof (target) + sizeof (headers) + sizeof (body)));
+
+In this case you need to free data when you receive response or when session is closed.
+
+Receiving data
+""""""""""""""
+
+HTTP plugin sends message header with metadata for parsing, in form of offset and length, followed by all data bytes as received from transport.
+
+Application will get pre-parsed following items:
+
+* status code
+* header section offset and length
+* body offset and length
+
+The example below reads HTTP message header in ``builtin_app_rx_callback``, which is first step application should do:
+
+.. code-block:: C
+
+ #include <http/http.h>
+ http_msg_t msg;
+ rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
+
+As next step application might validate message type and status code:
+
+.. code-block:: C
+
+ if (msg.type != HTTP_MSG_REPLY)
+ {
+ /* your error handling */
+ }
+ if (msg.code != HTTP_STATUS_OK)
+ {
+ /* your error handling */
+ /* of course you can continue with steps bellow */
+ /* you might be interested in some headers or body content (if any) */
+ }
+
+Headers are parsed using a generic algorithm, independent of the individual header names.
+When header is repeated, its combined value consists of all values separated by comma, concatenated in order as received.
+Following example shows how to parse headers:
+
+.. code-block:: C
+
+ #include <http/http_header_names.h>
+ if (msg.data.headers_len)
+ {
+ u8 *headers = 0;
+ http_header_table_t *ht;
+ vec_validate (headers, msg.data.headers_len - 1);
+ rv = svm_fifo_peek (ts->rx_fifo, msg.data.headers_offset,
+ msg.data.headers_len, headers);
+ ASSERT (rv == msg.data.headers_len);
+ if (http_parse_headers (headers, &ht))
+ {
+ /* your error handling */
+ }
+ /* get Content-Type header */
+ const char *content_type = http_get_header (ht, http_header_name_str (HTTP_HEADER_CONTENT_TYPE));
+ if (content_type)
+ {
+ /* do something interesting */
+ }
+ http_free_header_table (ht);
+ vec_free (headers);
+ }
+
+Finally application reads body, which might be received in multiple pieces (depends on size), so we might need some state machine in ``builtin_app_rx_callback``.
+We will add following members to our session context structure:
+
+.. code-block:: C
+
+ typedef struct
+ {
+ /* ... */
+ u64 to_recv;
+ u8 *resp_body;
+ } session_ctx_t;
+
+First we prepare vector for response body, do it only once when you are reading metadata:
+
+.. code-block:: C
+
+ /* drop everything up to body */
+ svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset);
+ ctx->to_recv = msg.data.body_len;
+ /* prepare vector for response body */
+ vec_validate (ctx->resp_body, msg.data.body_len - 1);
+ vec_reset_length (ctx->resp_body);
+
+Now we can start reading body content, following block of code could be executed multiple times:
+
+.. code-block:: C
+
+ /* dequeue */
+ u32 max_deq = svm_fifo_max_dequeue (ts->rx_fifo);
+ u32 n_deq = clib_min (to_recv, max_deq);
+ /* current offset */
+ u64 curr = vec_len (ctx->resp_body);
+ rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, ctx->resp_body + curr);
+ if (rv < 0 || rv != n_deq)
+ {
+ /* your error handling */
+ }
+ /* update length of the vector */
+ vec_set_len (ctx->resp_body, curr + n_deq);
+ /* update number of remaining bytes to receive */
+ ASSERT (to_recv >= rv);
+ ctx->to_recv -= rv;
+ /* check if all data received */
+ if (ctx->to_recv == 0)
{
- vec_validate (body, msg.data.body_len - 1);
- rv = svm_fifo_peek (ts->rx_fifo, msg.data.body_offset, msg.data.body_len, body);
- ASSERT (rv == msg.data.body_len);
+ /* we are done */
+ /* close the session if you don't want to send another request */
+ /* and update state machine... */
}
diff --git a/src/plugins/http/http_status_codes.h b/src/plugins/http/http_status_codes.h
new file mode 100644
index 00000000000..100095c8f42
--- /dev/null
+++ b/src/plugins/http/http_status_codes.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#ifndef SRC_PLUGINS_HTTP_HTTP_STATUS_CODES_H_
+#define SRC_PLUGINS_HTTP_HTTP_STATUS_CODES_H_
+
+#include <http/http.h>
+
+static const char *http_status_code_str[] = {
+#define _(c, s, str) str,
+ foreach_http_status_code
+#undef _
+};
+
+static inline u8 *
+format_http_status_code (u8 *s, va_list *va)
+{
+ http_status_code_t status_code = va_arg (*va, http_status_code_t);
+ if (status_code < HTTP_N_STATUS)
+ s = format (s, "%s", http_status_code_str[status_code]);
+ else
+ s = format (s, "invalid status code %d", status_code);
+ return s;
+}
+
+#endif /* SRC_PLUGINS_HTTP_HTTP_STATUS_CODES_H_ */
diff --git a/src/plugins/http/http_test.c b/src/plugins/http/http_test.c
new file mode 100644
index 00000000000..1f2f21dd19a
--- /dev/null
+++ b/src/plugins/http/http_test.c
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#include <http/http.h>
+
+static clib_error_t *
+test_http_authority_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ u8 *target = 0;
+ http_uri_t authority;
+ int rv;
+
+ if (!unformat (input, "%v", &target))
+ return clib_error_return (0, "error: no input provided");
+
+ rv = http_parse_authority_form_target (target, &authority);
+ vec_free (target);
+ if (rv)
+ return clib_error_return (0, "error: parsing failed");
+
+ target = http_serialize_authority_form_target (&authority);
+ vlib_cli_output (vm, "%v", target);
+ vec_free (target);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (test_http_authority_command) = {
+ .path = "test http authority-form",
+ .short_help = "test dns authority-form",
+ .function = test_http_authority_command_fn,
+};
diff --git a/src/plugins/http_static/builtinurl/json_urls.c b/src/plugins/http_static/builtinurl/json_urls.c
index 8578be147f3..19c5245e4b2 100644
--- a/src/plugins/http_static/builtinurl/json_urls.c
+++ b/src/plugins/http_static/builtinurl/json_urls.c
@@ -45,6 +45,7 @@ handle_get_version (hss_url_handler_args_t *args)
args->data = s;
args->data_len = vec_len (s);
+ args->ct = HTTP_CONTENT_APP_JSON;
args->free_vec_data = 1;
return HSS_URL_HANDLER_OK;
}
@@ -117,6 +118,7 @@ handle_get_interface_stats (hss_url_handler_args_t *args)
out:
args->data = s;
args->data_len = vec_len (s);
+ args->ct = HTTP_CONTENT_APP_JSON;
args->free_vec_data = 1;
vec_free (sw_if_indices);
vec_free (stats);
@@ -157,6 +159,7 @@ handle_get_interface_list (hss_url_handler_args_t *args)
args->data = s;
args->data_len = vec_len (s);
+ args->ct = HTTP_CONTENT_APP_JSON;
args->free_vec_data = 1;
return HSS_URL_HANDLER_OK;
}
diff --git a/src/plugins/http_static/http_cache.c b/src/plugins/http_static/http_cache.c
index 8b9751b7f78..2e63e335d47 100644
--- a/src/plugins/http_static/http_cache.c
+++ b/src/plugins/http_static/http_cache.c
@@ -17,6 +17,8 @@
#include <vppinfra/bihash_template.c>
#include <vppinfra/unix.h>
#include <vlib/vlib.h>
+#include <sys/stat.h>
+#include <vppinfra/time_range.h>
static void
hss_cache_lock (hss_cache_t *hc)
@@ -153,7 +155,7 @@ lru_update (hss_cache_t *hc, hss_cache_entry_t *ep, f64 now)
static void
hss_cache_attach_entry (hss_cache_t *hc, u32 ce_index, u8 **data,
- u64 *data_len)
+ u64 *data_len, u8 **last_modified)
{
hss_cache_entry_t *ce;
@@ -162,6 +164,7 @@ hss_cache_attach_entry (hss_cache_t *hc, u32 ce_index, u8 **data,
ce->inuse++;
*data = ce->data;
*data_len = vec_len (ce->data);
+ *last_modified = ce->last_modified;
/* Update the cache entry, mark it in-use */
lru_update (hc, ce, vlib_time_now (vlib_get_main ()));
@@ -209,16 +212,15 @@ hss_cache_lookup (hss_cache_t *hc, u8 *path)
u32
hss_cache_lookup_and_attach (hss_cache_t *hc, u8 *path, u8 **data,
- u64 *data_len)
+ u64 *data_len, u8 **last_modified)
{
u32 ce_index;
-
/* Make sure nobody removes the entry while we look it up */
hss_cache_lock (hc);
ce_index = hss_cache_lookup (hc, path);
if (ce_index != ~0)
- hss_cache_attach_entry (hc, ce_index, data, data_len);
+ hss_cache_attach_entry (hc, ce_index, data, data_len, last_modified);
hss_cache_unlock (hc);
@@ -260,6 +262,7 @@ hss_cache_do_evictions (hss_cache_t *hc)
hc->cache_evictions++;
vec_free (ce->filename);
vec_free (ce->data);
+ vec_free (ce->last_modified);
if (hc->debug_level > 1)
clib_warning ("pool put index %d", ce - hc->cache_pool);
@@ -271,13 +274,15 @@ hss_cache_do_evictions (hss_cache_t *hc)
}
u32
-hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len)
+hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len,
+ u8 **last_modified)
{
BVT (clib_bihash_kv) kv;
hss_cache_entry_t *ce;
clib_error_t *error;
u8 *file_data;
u32 ce_index;
+ struct stat dm;
hss_cache_lock (hc);
@@ -298,11 +303,17 @@ hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data, u64 *data_len)
pool_get_zero (hc->cache_pool, ce);
ce->filename = vec_dup (path);
ce->data = file_data;
+ if (stat ((char *) path, &dm) == 0)
+ {
+ ce->last_modified =
+ format (0, "%U GMT", format_clib_timebase_time, (f64) dm.st_mtime);
+ }
/* Attach cache entry without additional lock */
ce->inuse++;
*data = file_data;
*data_len = vec_len (file_data);
+ *last_modified = ce->last_modified;
lru_add (hc, ce, vlib_time_now (vlib_get_main ()));
hc->cache_size += vec_len (ce->data);
@@ -364,6 +375,7 @@ hss_cache_clear (hss_cache_t *hc)
hc->cache_evictions++;
vec_free (ce->filename);
vec_free (ce->data);
+ vec_free (ce->last_modified);
if (hc->debug_level > 1)
clib_warning ("pool put index %d", ce - hc->cache_pool);
pool_put (hc->cache_pool, ce);
@@ -421,19 +433,19 @@ format_hss_cache (u8 *s, va_list *args)
{
s = format (s, "cache size %lld bytes, limit %lld bytes, evictions %lld",
hc->cache_size, hc->cache_limit, hc->cache_evictions);
- return 0;
+ return s;
}
vm = vlib_get_main ();
now = vlib_time_now (vm);
- s = format (s, "%U", format_hss_cache_entry, 0 /* header */, now);
+ s = format (s, "%U\n", format_hss_cache_entry, 0 /* header */, now);
for (index = hc->first_index; index != ~0;)
{
ce = pool_elt_at_index (hc->cache_pool, index);
index = ce->next_index;
- s = format (s, "%U", format_hss_cache_entry, ce, now);
+ s = format (s, "%U\n", format_hss_cache_entry, ce, now);
}
s = format (s, "%40s%12lld", "Total Size", hc->cache_size);
diff --git a/src/plugins/http_static/http_cache.h b/src/plugins/http_static/http_cache.h
index a89ed5e7e94..21f71a924d5 100644
--- a/src/plugins/http_static/http_cache.h
+++ b/src/plugins/http_static/http_cache.h
@@ -22,6 +22,9 @@ typedef struct hss_cache_entry_
{
/** Name of the file */
u8 *filename;
+ /** Last modified date, format:
+ * <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT */
+ u8 *last_modified;
/** Contents of the file, as a u8 * vector */
u8 *data;
/** Last time the cache entry was used */
@@ -58,9 +61,9 @@ typedef struct hss_cache_
} hss_cache_t;
u32 hss_cache_lookup_and_attach (hss_cache_t *hc, u8 *path, u8 **data,
- u64 *data_len);
+ u64 *data_len, u8 **last_modified);
u32 hss_cache_add_and_attach (hss_cache_t *hc, u8 *path, u8 **data,
- u64 *data_len);
+ u64 *data_len, u8 **last_modified);
void hss_cache_detach_entry (hss_cache_t *hc, u32 ce_index);
u32 hss_cache_clear (hss_cache_t *hc);
void hss_cache_init (hss_cache_t *hc, uword cache_size, u8 debug_level);
diff --git a/src/plugins/http_static/http_static.api b/src/plugins/http_static/http_static.api
index 4d6d8bfe9b5..dd4f513a420 100644
--- a/src/plugins/http_static/http_static.api
+++ b/src/plugins/http_static/http_static.api
@@ -2,7 +2,8 @@
/** \file
This file defines static http server control-plane API messages
*/
-option version = "2.1.0";
+
+option version = "2.2.0";
/** \brief Configure and enable the static http server
@param client_index - opaque cookie to identify the sender
@@ -16,6 +17,39 @@ option version = "2.1.0";
*/
autoreply define http_static_enable {
+ option deprecated;
+
+ /* Client identifier, set from api_main.my_client_index */
+ u32 client_index;
+
+ /* Arbitrary context, so client can match reply to request */
+ u32 context;
+ /* Typical options */
+ u32 fifo_size;
+ u32 cache_size_limit;
+ /* Unusual options */
+ u32 prealloc_fifos;
+ u32 private_segment_size;
+
+ /* Root of the html path */
+ string www_root[256];
+ /* The bind URI */
+ string uri[256];
+};
+
+/** \brief Configure and enable the static http server
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param fifo_size - size (in bytes) of the session FIFOs
+ @param cache_size_limit - size (in bytes) of the in-memory file data cache
+ @param max_age - how long a response is considered fresh (in seconds)
+ @param prealloc_fifos - number of preallocated fifos (usually 0)
+ @param private_segment_size - fifo segment size (usually 0)
+ @param www_root - html root path
+ @param uri - bind URI, defaults to "tcp://0.0.0.0/80"
+*/
+
+autoreply define http_static_enable_v2 {
/* Client identifier, set from api_main.my_client_index */
u32 client_index;
@@ -24,6 +58,7 @@ autoreply define http_static_enable {
/* Typical options */
u32 fifo_size;
u32 cache_size_limit;
+ u32 max_age [default=600];
/* Unusual options */
u32 prealloc_fifos;
u32 private_segment_size;
diff --git a/src/plugins/http_static/http_static.c b/src/plugins/http_static/http_static.c
index 8f8fe37b7c1..967b8474af8 100644
--- a/src/plugins/http_static/http_static.c
+++ b/src/plugins/http_static/http_static.c
@@ -66,7 +66,7 @@ hss_register_url_handler (hss_url_handler_fn fp, const char *url,
*/
static int
hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos,
- u32 private_segment_size, u8 *www_root, u8 *uri)
+ u32 private_segment_size, u8 *www_root, u8 *uri, u32 max_age)
{
hss_main_t *hsm = &hss_main;
int rv;
@@ -77,6 +77,7 @@ hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos,
hsm->private_segment_size = private_segment_size;
hsm->www_root = format (0, "%s%c", www_root, 0);
hsm->uri = format (0, "%s%c", uri, 0);
+ hsm->max_age = max_age;
if (vec_len (hsm->www_root) < 2)
return VNET_API_ERROR_INVALID_VALUE;
@@ -84,7 +85,10 @@ hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos,
if (hsm->app_index != ~0)
return VNET_API_ERROR_APP_ALREADY_ATTACHED;
- vnet_session_enable_disable (hsm->vlib_main, 1 /* turn on TCP, etc. */);
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (hsm->vlib_main, &args);
rv = hss_create (hsm->vlib_main);
switch (rv)
@@ -110,14 +114,33 @@ static void vl_api_http_static_enable_t_handler
mp->uri[ARRAY_LEN (mp->uri) - 1] = 0;
mp->www_root[ARRAY_LEN (mp->www_root) - 1] = 0;
- rv =
- hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit),
- ntohl (mp->prealloc_fifos),
- ntohl (mp->private_segment_size), mp->www_root, mp->uri);
+ rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit),
+ ntohl (mp->prealloc_fifos),
+ ntohl (mp->private_segment_size), mp->www_root, mp->uri,
+ HSS_DEFAULT_MAX_AGE);
REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_REPLY);
}
+/* API message handler */
+static void
+vl_api_http_static_enable_v2_t_handler (vl_api_http_static_enable_v2_t *mp)
+{
+ vl_api_http_static_enable_v2_reply_t *rmp;
+ hss_main_t *hsm = &hss_main;
+ int rv;
+
+ mp->uri[ARRAY_LEN (mp->uri) - 1] = 0;
+ mp->www_root[ARRAY_LEN (mp->www_root) - 1] = 0;
+
+ rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit),
+ ntohl (mp->prealloc_fifos),
+ ntohl (mp->private_segment_size), mp->www_root, mp->uri,
+ ntohl (mp->max_age));
+
+ REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V2_REPLY);
+}
+
#include <http_static/http_static.api.c>
static clib_error_t *
hss_api_init (vlib_main_t *vm)
diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h
index 8f336e83d58..bee79090d2b 100644
--- a/src/plugins/http_static/http_static.h
+++ b/src/plugins/http_static/http_static.h
@@ -23,6 +23,8 @@
#include <vppinfra/error.h>
#include <http_static/http_cache.h>
+#define HSS_DEFAULT_MAX_AGE 600
+
/** @file http_static.h
* Static http server definitions
*/
@@ -45,13 +47,15 @@ typedef struct
/** Data length */
u64 data_len;
/** Current data send offset */
- u32 data_offset;
+ u64 data_offset;
/** Need to free data in detach_cache_entry */
int free_data;
/** File cache pool index */
u32 cache_pool_index;
- /** Content type, e.g. text, text/javascript, etc. */
- http_content_type_t content_type;
+ /** Response header list */
+ http_header_t *resp_headers;
+ /** Serialized headers to send */
+ u8 *headers_buf;
} hss_session_t;
typedef struct hss_session_handle_
@@ -91,6 +95,7 @@ typedef struct hss_url_handler_args_
uword data_len;
u8 free_vec_data;
http_status_code_t sc;
+ http_content_type_t ct;
};
};
} hss_url_handler_args_t;
@@ -153,6 +158,10 @@ typedef struct
u8 enable_url_handlers;
/** Max cache size before LRU occurs */
u64 cache_size;
+ /** How long a response is considered fresh (in seconds) */
+ u32 max_age;
+ /** Formatted max_age: "max-age=xyz" */
+ u8 *max_age_formatted;
/** hash table of file extensions to mime types string indices */
uword *mime_type_indices_by_file_extensions;
diff --git a/src/plugins/http_static/http_static_test.c b/src/plugins/http_static/http_static_test.c
index 3503a1b0812..f701c8b9ee7 100644
--- a/src/plugins/http_static/http_static_test.c
+++ b/src/plugins/http_static/http_static_test.c
@@ -18,6 +18,7 @@
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vppinfra/error.h>
+#include <http_static/http_static.h>
uword unformat_sw_if_index (unformat_input_t * input, va_list * args);
@@ -126,6 +127,96 @@ api_http_static_enable (vat_main_t * vam)
return ret;
}
+static int
+api_http_static_enable_v2 (vat_main_t *vam)
+{
+ unformat_input_t *line_input = vam->input;
+ vl_api_http_static_enable_v2_t *mp;
+ u64 tmp;
+ u8 *www_root = 0;
+ u8 *uri = 0;
+ u32 prealloc_fifos = 0;
+ u32 private_segment_size = 0;
+ u32 fifo_size = 8 << 10;
+ u32 cache_size_limit = 1 << 20;
+ u32 max_age = HSS_DEFAULT_MAX_AGE;
+ int ret;
+
+ /* Parse args required to build the message */
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "www-root %s", &www_root))
+ ;
+ else if (unformat (line_input, "prealloc-fifos %d", &prealloc_fifos))
+ ;
+ else if (unformat (line_input, "private-segment-size %U",
+ unformat_memory_size, &tmp))
+ {
+ if (tmp >= 0x100000000ULL)
+ {
+ errmsg ("private segment size %llu, too large", tmp);
+ return -99;
+ }
+ private_segment_size = (u32) tmp;
+ }
+ else if (unformat (line_input, "fifo-size %U", unformat_memory_size,
+ &tmp))
+ {
+ if (tmp >= 0x100000000ULL)
+ {
+ errmsg ("fifo-size %llu, too large", tmp);
+ return -99;
+ }
+ fifo_size = (u32) tmp;
+ }
+ else if (unformat (line_input, "cache-size %U", unformat_memory_size,
+ &tmp))
+ {
+ if (tmp < (128ULL << 10))
+ {
+ errmsg ("cache-size must be at least 128kb");
+ return -99;
+ }
+ cache_size_limit = (u32) tmp;
+ }
+ else if (unformat (line_input, "max-age %d", &max_age))
+ ;
+ else if (unformat (line_input, "uri %s", &uri))
+ ;
+ else
+ {
+ errmsg ("unknown input `%U'", format_unformat_error, line_input);
+ return -99;
+ }
+ }
+
+ if (www_root == 0)
+ {
+ errmsg ("Must specify www-root");
+ return -99;
+ }
+
+ if (uri == 0)
+ uri = format (0, "tcp://0.0.0.0/80%c", 0);
+
+ /* Construct the API message */
+ M (HTTP_STATIC_ENABLE_V2, mp);
+ strncpy_s ((char *) mp->www_root, 256, (const char *) www_root, 256);
+ strncpy_s ((char *) mp->uri, 256, (const char *) uri, 256);
+ mp->fifo_size = ntohl (fifo_size);
+ mp->cache_size_limit = ntohl (cache_size_limit);
+ mp->prealloc_fifos = ntohl (prealloc_fifos);
+ mp->private_segment_size = ntohl (private_segment_size);
+ mp->max_age = ntohl (max_age);
+
+ /* send it... */
+ S (mp);
+
+ /* Wait for a reply... */
+ W (ret);
+ return ret;
+}
+
#include <http_static/http_static.api_test.c>
/*
diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c
index 26224989332..9d9a68f7d02 100644
--- a/src/plugins/http_static/static_server.c
+++ b/src/plugins/http_static/static_server.c
@@ -19,6 +19,9 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <http/http_header_names.h>
+#include <http/http_content_types.h>
+
/** @file static_server.c
* Static http server, sufficient to serve .html / .css / .js content.
*/
@@ -83,48 +86,84 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
{
http_msg_t msg;
session_t *ts;
+ u8 *headers_buf = 0;
+ u32 n_enq;
+ u64 to_send;
int rv;
ts = session_get (hs->vpp_session_index, hs->thread_index);
+ if (vec_len (hs->resp_headers))
+ {
+ headers_buf = http_serialize_headers (hs->resp_headers);
+ vec_free (hs->resp_headers);
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = vec_len (headers_buf);
+ }
+ else
+ {
+ msg.data.headers_offset = 0;
+ msg.data.headers_len = 0;
+ }
+
msg.type = HTTP_MSG_REPLY;
msg.code = status;
- msg.content_type = hs->content_type;
- msg.data.len = hs->data_len;
+ msg.data.body_len = hs->data_len;
+ msg.data.len = msg.data.body_len + msg.data.headers_len;
- if (hs->data_len > hss_main.use_ptr_thresh)
+ if (msg.data.len > hss_main.use_ptr_thresh)
{
msg.data.type = HTTP_MSG_DATA_PTR;
rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
ASSERT (rv == sizeof (msg));
+ if (msg.data.headers_len)
+ {
+ hs->headers_buf = headers_buf;
+ uword headers = pointer_to_uword (hs->headers_buf);
+ rv =
+ svm_fifo_enqueue (ts->tx_fifo, sizeof (headers), (u8 *) &headers);
+ ASSERT (rv == sizeof (headers));
+ }
+
uword data = pointer_to_uword (hs->data);
rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (data), (u8 *) &data);
- ASSERT (rv == sizeof (sizeof (data)));
+ ASSERT (rv == sizeof (data));
goto done;
}
msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.body_offset = msg.data.headers_len;
rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
ASSERT (rv == sizeof (msg));
- if (!msg.data.len)
+ if (msg.data.headers_len)
+ {
+ rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+ ASSERT (rv == msg.data.headers_len);
+ vec_free (headers_buf);
+ }
+
+ if (!msg.data.body_len)
goto done;
- rv = svm_fifo_enqueue (ts->tx_fifo, hs->data_len, hs->data);
+ to_send = hs->data_len;
+ n_enq = clib_min (svm_fifo_size (ts->tx_fifo), to_send);
+
+ rv = svm_fifo_enqueue (ts->tx_fifo, n_enq, hs->data);
- if (rv != hs->data_len)
+ if (rv < to_send)
{
- hs->data_offset = rv;
+ hs->data_offset = (rv > 0) ? rv : 0;
svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
}
done:
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
}
__clib_export void
@@ -142,6 +181,15 @@ hss_session_send_data (hss_url_handler_args_t *args)
hs->data = args->data;
hs->data_len = args->data_len;
hs->free_data = args->free_vec_data;
+
+ /* Set content type only if we have some response data */
+ if (hs->data_len)
+ {
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (args->ct));
+ }
+
start_send_data (hs, args->sc);
}
@@ -217,7 +265,6 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
http_status_code_t sc = HTTP_STATUS_OK;
hss_url_handler_args_t args = {};
uword *p, *url_table;
- http_content_type_t type;
int rv;
if (!hsm->enable_url_handlers || !target_path)
@@ -229,8 +276,6 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
target_path = format (target_path, "index.html");
}
- type = content_type_from_request (target_path);
-
/* Look for built-in GET / POST handlers */
url_table =
(rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers;
@@ -263,17 +308,24 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
{
clib_warning ("builtin handler %llx hit on %s '%s' but failed!", p[0],
(rt == HTTP_REQ_GET) ? "GET" : "POST", target_path);
- sc = HTTP_STATUS_NOT_FOUND;
+ sc = HTTP_STATUS_BAD_GATEWAY;
}
hs->data = args.data;
hs->data_len = args.data_len;
hs->free_data = args.free_vec_data;
- hs->content_type = type;
+
+ /* Set content type only if we have some response data */
+ if (hs->data_len)
+ {
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (args.ct));
+ }
start_send_data (hs, sc);
- if (!hs->data)
+ if (!hs->data_len)
hss_session_disconnect_transport (hs);
return 0;
@@ -337,18 +389,20 @@ try_index_file (hss_main_t *hsm, hss_session_t *hs, u8 *path)
}
redirect =
- format (0,
- "Location: http%s://%U%s%s\r\n\r\n",
- proto == TRANSPORT_PROTO_TLS ? "s" : "", format_ip46_address,
- &endpt.ip, endpt.is_ip4, print_port ? port_str : (u8 *) "", path);
+ format (0, "http%s://%U%s%s", proto == TRANSPORT_PROTO_TLS ? "s" : "",
+ format_ip46_address, &endpt.ip, endpt.is_ip4,
+ print_port ? port_str : (u8 *) "", path);
if (hsm->debug_level > 0)
clib_warning ("redirect: %s", redirect);
vec_free (port_str);
- hs->data = redirect;
- hs->data_len = vec_len (redirect);
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_LOCATION),
+ (const char *) redirect, vec_len (redirect));
+ hs->data = redirect; /* TODO: find better way */
+ hs->data_len = 0;
hs->free_data = 1;
return HTTP_STATUS_MOVED;
@@ -362,13 +416,12 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
u8 *path, *sanitized_path;
u32 ce_index;
http_content_type_t type;
+ u8 *last_modified;
/* Feature not enabled */
if (!hsm->www_root)
return -1;
- type = content_type_from_request (target);
-
/* Remove dot segments to prevent path traversal */
sanitized_path = http_path_remove_dot_segments (target);
@@ -388,8 +441,8 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
hs->data_offset = 0;
- ce_index =
- hss_cache_lookup_and_attach (&hsm->cache, path, &hs->data, &hs->data_len);
+ ce_index = hss_cache_lookup_and_attach (&hsm->cache, path, &hs->data,
+ &hs->data_len, &last_modified);
if (ce_index == ~0)
{
if (!file_path_is_valid (path))
@@ -408,8 +461,8 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
sc = try_index_file (hsm, hs, path);
goto done;
}
- ce_index =
- hss_cache_add_and_attach (&hsm->cache, path, &hs->data, &hs->data_len);
+ ce_index = hss_cache_add_and_attach (&hsm->cache, path, &hs->data,
+ &hs->data_len, &last_modified);
if (ce_index == ~0)
{
sc = HTTP_STATUS_INTERNAL_ERROR;
@@ -420,11 +473,25 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
hs->path = path;
hs->cache_pool_index = ce_index;
+ /* Set following headers only for happy path:
+ * Content-Type
+ * Cache-Control max-age
+ */
+ type = content_type_from_request (target);
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+ http_content_type_token (type));
+ http_add_header (
+ &hs->resp_headers, http_header_name_token (HTTP_HEADER_CACHE_CONTROL),
+ (const char *) hsm->max_age_formatted, vec_len (hsm->max_age_formatted));
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_LAST_MODIFIED),
+ (const char *) last_modified, vec_len (last_modified));
+
done:
vec_free (sanitized_path);
- hs->content_type = type;
start_send_data (hs, sc);
- if (!hs->data)
+ if (!hs->data_len)
hss_session_disconnect_transport (hs);
return 0;
@@ -459,6 +526,8 @@ hss_ts_rx_callback (session_t *ts)
if (hs->free_data)
vec_free (hs->data);
hs->data = 0;
+ hs->resp_headers = 0;
+ vec_free (hs->headers_buf);
/* Read the http message header */
rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
@@ -467,6 +536,9 @@ hss_ts_rx_callback (session_t *ts)
if (msg.type != HTTP_MSG_REQUEST ||
(msg.method_type != HTTP_REQ_GET && msg.method_type != HTTP_REQ_POST))
{
+ http_add_header (&hs->resp_headers,
+ http_header_name_token (HTTP_HEADER_ALLOW),
+ http_token_lit ("GET, POST"));
start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
goto done;
}
@@ -531,7 +603,8 @@ static int
hss_ts_tx_callback (session_t *ts)
{
hss_session_t *hs;
- u32 to_send;
+ u32 n_enq;
+ u64 to_send;
int rv;
hs = hss_session_get (ts->thread_index, ts->opaque);
@@ -539,7 +612,9 @@ hss_ts_tx_callback (session_t *ts)
return 0;
to_send = hs->data_len - hs->data_offset;
- rv = svm_fifo_enqueue (ts->tx_fifo, to_send, hs->data + hs->data_offset);
+ n_enq = clib_min (svm_fifo_size (ts->tx_fifo), to_send);
+
+ rv = svm_fifo_enqueue (ts->tx_fifo, n_enq, hs->data + hs->data_offset);
if (rv <= 0)
{
@@ -554,7 +629,7 @@ hss_ts_tx_callback (session_t *ts)
}
if (svm_fifo_set_event (ts->tx_fifo))
- session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
+ session_program_tx_io_evt (ts->handle, SESSION_IO_EVT_TX);
return 0;
}
@@ -648,6 +723,7 @@ hss_ts_cleanup (session_t *s, session_cleanup_ntf_t ntf)
hs->data = 0;
hs->data_offset = 0;
hs->free_data = 0;
+ vec_free (hs->headers_buf);
vec_free (hs->path);
hss_session_free (hs);
@@ -798,6 +874,8 @@ hss_create (vlib_main_t *vm)
if (hsm->enable_url_handlers)
hss_url_handlers_init (hsm);
+ hsm->max_age_formatted = format (0, "max-age=%d", hsm->max_age);
+
return 0;
}
@@ -818,6 +896,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
hsm->private_segment_size = 0;
hsm->fifo_size = 0;
hsm->cache_size = 10 << 20;
+ hsm->max_age = HSS_DEFAULT_MAX_AGE;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
@@ -849,6 +928,8 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
;
else if (unformat (line_input, "url-handlers"))
hsm->enable_url_handlers = 1;
+ else if (unformat (line_input, "max-age %d", &hsm->max_age))
+ ;
else
{
error = clib_error_return (0, "unknown input `%U'",
@@ -877,7 +958,10 @@ no_input:
goto done;
}
- vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
if ((rv = hss_create (vm)))
{
@@ -906,8 +990,8 @@ VLIB_CLI_COMMAND (hss_create_command, static) = {
.path = "http static server",
.short_help =
"http static server www-root <path> [prealloc-fifos <nn>]\n"
- "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n"
- "[ptr-thresh <nn>] [url-handlers] [debug [nn]]\n",
+ "[private-segment-size <nnMG>] [fifo-size <nbytes>] [max-age <nseconds>]\n"
+ "[uri <uri>] [ptr-thresh <nn>] [url-handlers] [debug [nn]]\n",
.function = hss_create_command_fn,
};
@@ -917,7 +1001,7 @@ format_hss_session (u8 *s, va_list *args)
hss_session_t *hs = va_arg (*args, hss_session_t *);
int __clib_unused verbose = va_arg (*args, int);
- s = format (s, "\n path %s, data length %u, data_offset %u",
+ s = format (s, "\n path %s, data length %llu, data_offset %llu",
hs->path ? hs->path : (u8 *) "[none]", hs->data_len,
hs->data_offset);
return s;
diff --git a/src/plugins/ikev2/CMakeLists.txt b/src/plugins/ikev2/CMakeLists.txt
index 568271ed7d9..dd2b49d6651 100644
--- a/src/plugins/ikev2/CMakeLists.txt
+++ b/src/plugins/ikev2/CMakeLists.txt
@@ -27,6 +27,7 @@ add_vpp_plugin(ikev2
ikev2_crypto.c
ikev2_format.c
ikev2_payload.c
+ ikev2_handoff.c
API_FILES
ikev2_types.api
diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api
index de276e7f3ea..e2ff8fb8268 100644
--- a/src/plugins/ikev2/ikev2.api
+++ b/src/plugins/ikev2/ikev2.api
@@ -658,6 +658,12 @@ counters ikev2 {
units "packets";
description "IKE AUTH SA requests received";
};
+ handoff {
+ severity info;
+ type counter64;
+ units "packets";
+ description "IKE packets handoff";
+ };
};
paths {
"/err/ikev2-ip4" "ike";
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index 9bea2c96d12..f66469a24d1 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -97,6 +97,7 @@ format_ikev2_gen_sa_error (u8 * s, va_list * args)
typedef enum
{
IKEV2_NEXT_IP4_LOOKUP,
+ IKEV2_NEXT_IP4_HANDOFF,
IKEV2_NEXT_IP4_ERROR_DROP,
IKEV2_IP4_N_NEXT,
} ikev2_ip4_next_t;
@@ -104,6 +105,7 @@ typedef enum
typedef enum
{
IKEV2_NEXT_IP6_LOOKUP,
+ IKEV2_NEXT_IP6_HANDOFF,
IKEV2_NEXT_IP6_ERROR_DROP,
IKEV2_IP6_N_NEXT,
} ikev2_ip6_next_t;
@@ -3187,6 +3189,7 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data ();
+ u32 thread_index = vm->thread_index;
ikev2_stats_t _stats, *stats = &_stats;
int res;
@@ -3213,6 +3216,14 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
int ip_hdr_sz = 0;
int is_req = 0;
+ if (PREDICT_TRUE (thread_index != km->handoff_thread))
+ {
+ vlib_node_increment_counter (vm, node->node_index,
+ IKEV2_ERROR_HANDOFF, 1);
+
+ next[0] = is_ip4 ? IKEV2_NEXT_IP4_HANDOFF : IKEV2_NEXT_IP6_HANDOFF;
+ goto out;
+ }
if (natt)
{
u8 *ptr = vlib_buffer_get_current (b0);
@@ -3723,6 +3734,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
ikev2_delete_sa (ptd, sa0);
}
+
+ out:
if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
&& (b0->flags & VLIB_BUFFER_IS_TRACED)))
{
@@ -3775,6 +3788,7 @@ VLIB_REGISTER_NODE (ikev2_node_ip4,static) = {
.n_next_nodes = IKEV2_IP4_N_NEXT,
.next_nodes = {
[IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup",
+ [IKEV2_NEXT_IP4_HANDOFF] = "ikev2-ip4-handoff",
[IKEV2_NEXT_IP4_ERROR_DROP] = "error-drop",
},
};
@@ -3792,6 +3806,7 @@ VLIB_REGISTER_NODE (ikev2_node_ip4_natt,static) = {
.n_next_nodes = IKEV2_IP4_N_NEXT,
.next_nodes = {
[IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup",
+ [IKEV2_NEXT_IP4_HANDOFF] = "ikev2-ip4-natt-handoff",
[IKEV2_NEXT_IP4_ERROR_DROP] = "error-drop",
},
};
@@ -3809,6 +3824,7 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = {
.n_next_nodes = IKEV2_IP6_N_NEXT,
.next_nodes = {
[IKEV2_NEXT_IP6_LOOKUP] = "ip6-lookup",
+ [IKEV2_NEXT_IP4_HANDOFF] = "ikev2-ip6-handoff",
[IKEV2_NEXT_IP6_ERROR_DROP] = "error-drop",
},
};
@@ -5126,6 +5142,8 @@ ikev2_init (vlib_main_t * vm)
km->liveness_period = IKEV2_LIVENESS_PERIOD_CHECK;
km->liveness_max_retries = IKEV2_LIVENESS_RETRIES;
+ km->handoff_thread = vlib_num_workers () ? 1 : 0;
+
return 0;
}
@@ -5133,6 +5151,31 @@ VLIB_INIT_FUNCTION (ikev2_init) = {
.runs_after = VLIB_INITS ("ipsec_init", "ipsec_punt_init"),
};
+static clib_error_t *
+ikev2_config (vlib_main_t *vm, unformat_input_t *input)
+{
+ ikev2_main_t *km = &ikev2_main;
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "handoff-thread %d", &km->handoff_thread))
+ {
+ if (km->handoff_thread > vlib_num_workers ())
+ {
+ return clib_error_return (0, "wrong handoff-thread %d",
+ km->handoff_thread);
+ }
+ }
+ else
+ return clib_error_return (0, "unknown input `%U'", format_unformat_error,
+ input);
+ }
+
+ return 0;
+}
+
+VLIB_CONFIG_FUNCTION (ikev2_config, "ikev2");
+
static u8
ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa,
u8 del_old_ids)
@@ -5447,6 +5490,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa)
}
dp = sa->dst_port ? sa->dst_port : ikev2_get_port (sa);
+
ikev2_send_ike (km->vlib_main, src, dst, bi0, len, ikev2_get_port (sa), dp,
sa->sw_if_index);
}
@@ -5625,6 +5669,15 @@ ikev2_lazy_init (ikev2_main_t *km)
if (!km->dns_resolve_name_ptr)
ikev2_log_error ("cannot load symbols from dns plugin");
+ km->handoff_ip4_fq_index =
+ vlib_frame_queue_main_init (ikev2_node_ip4.index, 0);
+
+ km->handoff_ip4_natt_fq_index =
+ vlib_frame_queue_main_init (ikev2_node_ip4_natt.index, 0);
+
+ km->handoff_ip6_fq_index =
+ vlib_frame_queue_main_init (ikev2_node_ip6.index, 0);
+
/* wake up ikev2 process */
vlib_process_signal_event (vlib_get_first_main (),
ikev2_mngr_process_node.index, 0, 0);
diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c
index c9608aa660b..e09bde3cbe2 100644
--- a/src/plugins/ikev2/ikev2_api.c
+++ b/src/plugins/ikev2/ikev2_api.c
@@ -577,6 +577,7 @@ vl_api_ikev2_child_sa_dump_t_handler (vl_api_ikev2_child_sa_dump_t * mp)
vec_foreach (child, sa->childs)
{
u32 child_sa_index = child - sa->childs;
+ sai = ikev2_encode_sa_index (sai, tkm - im->per_thread_data);
send_child_sa (child, mp, child_sa_index, sai);
}
}
diff --git a/src/plugins/ikev2/ikev2_crypto.c b/src/plugins/ikev2/ikev2_crypto.c
index 3d4ad0a28ed..58167e2322e 100644
--- a/src/plugins/ikev2/ikev2_crypto.c
+++ b/src/plugins/ikev2/ikev2_crypto.c
@@ -481,15 +481,14 @@ ikev2_encrypt_data (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa,
int
BN_bn2binpad (const BIGNUM * a, unsigned char *to, int tolen)
{
- int r = BN_bn2bin (a, to);
+ int r = BN_num_bytes (a);
ASSERT (tolen >= r);
int pad = tolen - r;
if (pad)
{
- vec_insert (to, pad, 0);
clib_memset (to, 0, pad);
- vec_dec_len (to, pad);
}
+ BN_bn2bin (a, to + pad);
return tolen;
}
#endif
diff --git a/src/plugins/ikev2/ikev2_handoff.c b/src/plugins/ikev2/ikev2_handoff.c
new file mode 100644
index 00000000000..8f55985bce8
--- /dev/null
+++ b/src/plugins/ikev2/ikev2_handoff.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vnet/vnet.h>
+#include <ikev2/ikev2_priv.h>
+
+extern ikev2_main_t ikev2_main;
+
+#define foreach_ikev2_handoff_error _ (CONGESTION_DROP, "congestion drop")
+
+typedef enum
+{
+#define _(sym, str) IKEV2_HANDOFF_ERROR_##sym,
+ foreach_ikev2_handoff_error
+#undef _
+ IKEV2_HANDOFF_N_ERROR,
+} ikev2_handoff_error_t;
+
+static char *ikev2_handoff_error_strings[] = {
+#define _(sym, string) string,
+ foreach_ikev2_handoff_error
+#undef _
+};
+
+typedef struct ikev2_handoff_trace_t_
+{
+ u32 current_worker_index;
+ u32 next_worker_index;
+} ikev2_handoff_trace_t;
+
+u8 *
+format_ikev2_handoff_trace (u8 *s, va_list *args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+
+ ikev2_handoff_trace_t *t = va_arg (*args, ikev2_handoff_trace_t *);
+ s = format (s, "ikev2 handoff %d to %d", t->current_worker_index,
+ t->next_worker_index);
+ return s;
+}
+
+static_always_inline uword
+ikev2_handoff_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
+ vlib_frame_t *frame, u32 fq_index)
+{
+ ikev2_main_t *km = &ikev2_main;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u16 thread_indices[VLIB_FRAME_SIZE], *ti;
+ u32 n_enq, n_left_from, *from;
+ u32 this_thread;
+
+ this_thread = vm->thread_index;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+
+ b = bufs;
+ ti = thread_indices;
+
+ while (n_left_from > 0)
+ {
+ ti[0] = km->handoff_thread;
+
+ if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE) &&
+ b[0]->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ ikev2_handoff_trace_t *t =
+ vlib_add_trace (vm, node, b[0], sizeof (*t));
+ t->current_worker_index = this_thread;
+ t->next_worker_index = ti[0];
+ }
+ n_left_from--;
+ ti++;
+ b++;
+ }
+
+ n_enq = vlib_buffer_enqueue_to_thread (vm, node, fq_index, from,
+ thread_indices, frame->n_vectors, 1);
+
+ if (n_enq < frame->n_vectors)
+ vlib_node_increment_counter (vm, node->node_index,
+ IKEV2_HANDOFF_ERROR_CONGESTION_DROP,
+ frame->n_vectors - n_enq);
+ return n_enq;
+}
+
+/* Do worker handoff based on the ikev2's thread_index */
+VLIB_NODE_FN (ikev2_ip4_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ ikev2_main_t *km = &ikev2_main;
+
+ return ikev2_handoff_inline (vm, node, from_frame, km->handoff_ip4_fq_index);
+}
+
+VLIB_NODE_FN (ikev2_ip4_natt_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ ikev2_main_t *km = &ikev2_main;
+
+ return ikev2_handoff_inline (vm, node, from_frame,
+ km->handoff_ip4_natt_fq_index);
+}
+
+VLIB_NODE_FN (ikev2_ip6_handoff)
+(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
+{
+ ikev2_main_t *km = &ikev2_main;
+
+ return ikev2_handoff_inline (vm, node, from_frame, km->handoff_ip6_fq_index);
+}
+
+VLIB_REGISTER_NODE (ikev2_ip4_handoff) = {
+ .name = "ikev2-ip4-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ikev2_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(ikev2_handoff_error_strings),
+ .error_strings = ikev2_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (ikev2_ip4_natt_handoff) = {
+ .name = "ikev2-ip4-natt-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ikev2_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(ikev2_handoff_error_strings),
+ .error_strings = ikev2_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
+
+VLIB_REGISTER_NODE (ikev2_ip6_handoff) = {
+ .name = "ikev2-ip6-handoff",
+ .vector_size = sizeof (u32),
+ .format_trace = format_ikev2_handoff_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = ARRAY_LEN(ikev2_handoff_error_strings),
+ .error_strings = ikev2_handoff_error_strings,
+ .n_next_nodes = 1,
+ .next_nodes = {
+ [0] = "error-drop",
+ },
+};
diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h
index 0639809e9b1..96313182552 100644
--- a/src/plugins/ikev2/ikev2_priv.h
+++ b/src/plugins/ikev2/ikev2_priv.h
@@ -571,6 +571,12 @@ typedef struct
/* punt handle for IPsec NATT IPSEC_PUNT_IP4_SPI_UDP_0 reason */
vlib_punt_hdl_t punt_hdl;
+ /** Worker handoff */
+ u32 handoff_thread;
+ u32 handoff_ip4_fq_index;
+ u32 handoff_ip4_natt_fq_index;
+ u32 handoff_ip6_fq_index;
+
} ikev2_main_t;
extern ikev2_main_t ikev2_main;
diff --git a/src/plugins/linux-cp/lcp_interface.c b/src/plugins/linux-cp/lcp_interface.c
index b1c0ad5a022..61665ad4146 100644
--- a/src/plugins/linux-cp/lcp_interface.c
+++ b/src/plugins/linux-cp/lcp_interface.c
@@ -1001,7 +1001,8 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
clib_max (1, lcp_get_default_num_queues (0 /* is_tx */)),
.num_tx_queues =
clib_max (1, lcp_get_default_num_queues (1 /* is_tx */)),
- .id = hw->hw_if_index,
+ .id = ~0,
+ .auto_id_offset = 4096,
.sw_if_index = ~0,
.rx_ring_sz = 256,
.tx_ring_sz = 256,
diff --git a/src/plugins/mactime/builtins.c b/src/plugins/mactime/builtins.c
index c487d0375bf..f726d3c03ed 100644
--- a/src/plugins/mactime/builtins.c
+++ b/src/plugins/mactime/builtins.c
@@ -147,6 +147,7 @@ handle_get_mactime (hss_url_handler_args_t *args)
args->data = s;
args->data_len = vec_len (s);
+ args->ct = HTTP_CONTENT_APP_JSON;
args->free_vec_data = 1;
return HSS_URL_HANDLER_OK;
}
diff --git a/src/plugins/marvell/CMakeLists.txt b/src/plugins/marvell/CMakeLists.txt
deleted file mode 100644
index b48ac72aa08..00000000000
--- a/src/plugins/marvell/CMakeLists.txt
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (c) 2018 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.
-
-if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)")
- return()
-endif()
-
-find_path(MUSDK_INCLUDE_DIR NAMES mv_std.h)
-find_library(MUSDK_LIB NAMES libmusdk.a)
-
-if(MUSDK_INCLUDE_DIR AND MUSDK_LIB)
- get_filename_component(MUSDK_LIB_DIR ${MUSDK_LIB} DIRECTORY)
- set(MUSDK_LINK_FLAGS "-Wl,--whole-archive,${MUSDK_LIB_DIR}/libmusdk.a,--no-whole-archive")
- add_vpp_plugin(marvell
- SOURCES
- plugin.c
- pp2/cli.c
- pp2/format.c
- pp2/input.c
- pp2/output.c
- pp2/pp2.c
- pp2/pp2_api.c
-
- API_FILES
- pp2/pp2.api
-
- API_TEST_SOURCES
- pp2/pp2_test.c
-
- LINK_FLAGS
- ${MUSDK_LINK_FLAGS}
- )
- include_directories(${MUSDK_INCLUDE_DIR})
- message(STATUS "Found Marvell MUSDK in ${MUSDK_INCLUDE_DIR}")
-else()
- message(WARNING "Marvell MUSDK not found - marvell_plugin disabled")
-endif()
diff --git a/src/plugins/marvell/README.rst b/src/plugins/marvell/README.rst
deleted file mode 100644
index 19cf1c49d0e..00000000000
--- a/src/plugins/marvell/README.rst
+++ /dev/null
@@ -1,85 +0,0 @@
-Marvell device plugin
-=====================
-
-Overview
---------
-
-This plugins provides native device support for Marvell PP2 network
-device, by use of Marvell Usermode SDK
-(`MUSDK <https://github.com/MarvellEmbeddedProcessors/musdk-marvell>`__).
-Code is developed and tested on
-`MACCHIATObin <http://macchiatobin.net>`__ board.
-
-Prerequisites
--------------
-
-Plugins depends on installed MUSDK and Marvell provided linux
-`kernel <https://github.com/MarvellEmbeddedProcessors/linux-marvell>`__
-with MUSDK provided kernel patches (see ``patches/linux`` in musdk repo
-and relevant documentation. Kernel version used: **4.14.22
-armada-18.09.3** MUSDK version used: **armada-18.09.3** Following kernel
-modules from MUSDK must be loaded for plugin to work: \*
-``musdk_cma.ko`` \* ``mv_pp_uio.ko``
-
-Musdk 18.09.3 compilation steps
--------------------------------
-
-::
-
- ./bootstrap
- ./configure --prefix=/opt/vpp/external/aarch64/ CFLAGS="-Wno-error=unused-result -g -fPIC" --enable-shared=no
- sed -i -e 's/marvell,mv-pp-uio/generic-uio/' modules/pp2/mv_pp_uio.c
- sed -i -e 's/O_CREAT/O_CREAT, S_IRUSR | S_IWUSR/' src/lib/file_utils.c
- make
- sudo make install
-
-Usage
------
-
-Interface Creation
-~~~~~~~~~~~~~~~~~~
-
-Interfaces are dynamically created with following CLI:
-
-::
-
- create interface marvell pp2 name eth0
- set interface state mv-ppio-0/0 up
-
-Where ``eth0`` is linux interface name and ``mv-ppio-X/Y`` is VPP
-interface name where X is PP2 device ID and Y is PPIO ID Interface needs
-to be assigned to MUSDK in FDT configuration and linux interface state
-must be up.
-
-Interface Deletion
-~~~~~~~~~~~~~~~~~~
-
-Interface can be deleted with following CLI:
-
-::
-
- delete interface marvell pp2 <interface name>
-
-Interface Statistics
-~~~~~~~~~~~~~~~~~~~~
-
-Interface statistics can be displayed with
-``sh hardware-interface mv-ppio0/0`` command.
-
-Interaction with DPDK plugin
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This plugin doesn’t have any dependency on DPDK or DPDK plugin but it
-can work with DPDK plugin enabled or disabled. It is observed that
-performance is better around 30% when DPDK plugin is disabled, as DPDK
-plugin registers own buffer manager, which needs to deal with additional
-metadata in each packet.
-
-DPKD plugin can be disabled by adding following config to the
-startup.conf.
-
-::
-
- plugins {
- dpdk_plugin.so { disable }
- }
diff --git a/src/plugins/marvell/pp2/cli.c b/src/plugins/marvell/pp2/cli.c
deleted file mode 100644
index 5072a3c035b..00000000000
--- a/src/plugins/marvell/pp2/cli.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-#include <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <inttypes.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <marvell/pp2/pp2.h>
-
-static clib_error_t *
-mrvl_pp2_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- mrvl_pp2_create_if_args_t args = { 0 };
- unsigned int val;
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "name %s", &args.name))
- ;
- else if (unformat (line_input, "rx-queue-size %u", &val))
- args.rx_q_sz = val;
- else if (unformat (line_input, "tx-queue-size %u", &val))
- args.tx_q_sz = val;
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
- }
- unformat_free (line_input);
-
-
- mrvl_pp2_create_if (&args);
-
- vec_free (args.name);
-
- return args.error;
-}
-
-VLIB_CLI_COMMAND (mrvl_pp2_create_command, static) = {
- .path = "create interface marvell pp2",
- .short_help = "create interface marvell pp2 [name <ifname>] [rx-queue-size slots] [tx-queue-size slots]",
- .function = mrvl_pp2_create_command_fn,
-};
-
-static clib_error_t *
-mrvl_pp2_delete_command_fn (vlib_main_t * vm, unformat_input_t * input,
- vlib_cli_command_t * cmd)
-{
- unformat_input_t _line_input, *line_input = &_line_input;
- u32 sw_if_index = ~0;
- vnet_hw_interface_t *hw;
- mrvl_pp2_main_t *mm = &mrvl_pp2_main;
- mrvl_pp2_if_t *dif;
- vnet_main_t *vnm = vnet_get_main ();
-
- /* Get a line of input. */
- if (!unformat_user (input, unformat_line_input, line_input))
- return 0;
-
- while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (line_input, "sw_if_index %d", &sw_if_index))
- ;
- else if (unformat (line_input, "%U", unformat_vnet_sw_interface,
- vnm, &sw_if_index))
- ;
- else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
- }
- unformat_free (line_input);
-
- if (sw_if_index == ~0)
- return clib_error_return (0,
- "please specify interface name or sw_if_index");
-
- hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
- if (hw == NULL || mrvl_pp2_device_class.index != hw->dev_class_index)
- return clib_error_return (0, "not a Marvell PP2 interface");
-
- dif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
-
- mrvl_pp2_delete_if (dif);
-
- return 0;
-}
-
-VLIB_CLI_COMMAND (mrvl_pp2_delete_command, static) = {
- .path = "delete interface marvell pp2",
- .short_help = "delete interface marvell pp2 "
- "{<interface> | sw_if_index <sw_idx>}",
- .function = mrvl_pp2_delete_command_fn,
-};
-
-clib_error_t *
-mrvl_pp2_cli_init (vlib_main_t * vm)
-{
- /* initialize binary API */
- mrvl_pp2_plugin_api_hookup (vm);
-
- return 0;
-}
-
-VLIB_INIT_FUNCTION (mrvl_pp2_cli_init);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/format.c b/src/plugins/marvell/pp2/format.c
deleted file mode 100644
index 877010ea561..00000000000
--- a/src/plugins/marvell/pp2/format.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/plugin/plugin.h>
-#include <marvell/pp2/pp2.h>
-
-static inline u32
-mrvl_get_u32_bits (void *start, int offset, int first, int last)
-{
- u32 value = *(u32 *) (((u8 *) start) + offset);
- if ((last == 0) && (first == 31))
- return value;
- value >>= last;
- value &= (1 << (first - last + 1)) - 1;
- return value;
-}
-
-u8 *
-format_mrvl_pp2_interface_name (u8 * s, va_list * args)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- u32 dev_instance = va_arg (*args, u32);
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, dev_instance);
- return format (s, "mv-ppio-%d/%d", ppif->ppio->pp2_id, ppif->ppio->port_id);
-}
-
-#define foreach_ppio_statistics_entry \
- _(rx_packets) \
- _(rx_fullq_dropped) \
- _(rx_bm_dropped) \
- _(rx_early_dropped) \
- _(rx_fifo_dropped) \
- _(rx_cls_dropped) \
- _(tx_packets)
-
-#define foreach_ppio_inq_statistics_entry \
- _(enq_desc) \
- _(drop_early) \
- _(drop_fullq) \
- _(drop_bm)
-
-#define foreach_ppio_outq_statistics_entry \
- _(enq_desc) \
- _(enq_dec_to_ddr) \
- _(enq_buf_to_ddr) \
- _(deq_desc)
-
-u8 *
-format_mrvl_pp2_interface (u8 * s, va_list * args)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- u32 dev_instance = va_arg (*args, u32);
- u32 indent = format_get_indent (s);
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, dev_instance);
- struct pp2_ppio_statistics stat;
- int i;
- u8 *s2 = 0;
-
- pp2_ppio_get_statistics (ppif->ppio, &stat, 0);
-
-#define _(c) if (stat.c) \
- s2 = format (s2, "\n%U%-25U%16Ld", \
- format_white_space, indent + 2, \
- format_c_identifier, #c, stat.c);
- foreach_ppio_statistics_entry;
-
- if (vec_len (s2))
- s = format (s, "Interface statistics:%v", s2);
- vec_reset_length (s2);
-
- vec_foreach_index (i, ppif->inqs)
- {
- struct pp2_ppio_inq_statistics stat = { 0 };
- pp2_ppio_inq_get_statistics (ppif->ppio, 0, i, &stat, 0);
-
- foreach_ppio_inq_statistics_entry;
-
- if (vec_len (s2))
- s = format (s, "\n%UInput queue %u statistics:%v",
- format_white_space, indent, i, s2);
- vec_reset_length (s2);
- }
- vec_foreach_index (i, ppif->outqs)
- {
- struct pp2_ppio_outq_statistics stat = { 0 };
-
- pp2_ppio_outq_get_statistics (ppif->ppio, i, &stat, 0);
-
- foreach_ppio_outq_statistics_entry;
-
- if (vec_len (s2))
- s = format (s, "\n%UOutput queue %u statistics:%v",
- format_white_space, indent, i, s2);
- vec_reset_length (s2);
- }
-#undef _
- vec_free (s2);
- return s;
-}
-
-#define foreach_pp2_rx_desc_field \
- _(0x00, 6, 0, l3_offset) \
- _(0x00, 12, 8, ip_hdlen) \
- _(0x00, 14, 13, ec) \
- _(0x00, 15, 15, es) \
- _(0x00, 19, 16, pool_id) \
- _(0x00, 21, 21, hwf_sync) \
- _(0x00, 22, 22, l4_chk_ok) \
- _(0x00, 23, 23, ip_frg) \
- _(0x00, 24, 24, ipv4_hdr_err) \
- _(0x00, 27, 25, l4_info) \
- _(0x00, 30, 28, l3_info) \
- _(0x00, 31, 31, buf_header) \
- _(0x04, 5, 0, lookup_id) \
- _(0x04, 8, 6, cpu_code) \
- _(0x04, 9, 9, pppoe) \
- _(0x04, 11, 10, l3_cast_info) \
- _(0x04, 13, 12, l2_cast_info) \
- _(0x04, 15, 14, vlan_info) \
- _(0x04, 31, 16, byte_count) \
- _(0x08, 11, 0, gem_port_id) \
- _(0x08, 13, 12, color) \
- _(0x08, 14, 14, gop_sop_u) \
- _(0x08, 15, 15, key_hash_enable) \
- _(0x08, 31, 16, l4chk) \
- _(0x0c, 31, 0, timestamp) \
- _(0x10, 31, 0, buf_phys_ptr_lo) \
- _(0x14, 7, 0, buf_phys_ptr_hi) \
- _(0x14, 31, 8, key_hash) \
- _(0x18, 31, 0, buf_virt_ptr_lo) \
- _(0x1c, 7, 0, buf_virt_ptr_hi) \
- _(0x1c, 14, 8, buf_qset_no) \
- _(0x1c, 15, 15, buf_type) \
- _(0x1c, 21, 16, mod_dscp) \
- _(0x1c, 24, 22, mod_pri) \
- _(0x1c, 25, 25, mdscp) \
- _(0x1c, 26, 26, mpri) \
- _(0x1c, 27, 27, mgpid) \
- _(0x1c, 31, 29, port_num)
-
-u8 *
-format_mrvl_pp2_input_trace (u8 * s, va_list * args)
-{
- vlib_main_t *vm = va_arg (*args, vlib_main_t *);
- vlib_node_t *node = va_arg (*args, vlib_node_t *);
- mrvl_pp2_input_trace_t *t = va_arg (*args, mrvl_pp2_input_trace_t *);
- vnet_main_t *vnm = vnet_get_main ();
- vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, t->hw_if_index);
- u32 indent = format_get_indent (s);
- struct pp2_ppio_desc *d = &t->desc;
- u32 r32;
-
- s = format (s, "pp2: %v (%d) next-node %U",
- hi->name, t->hw_if_index, format_vlib_next_node_name, vm,
- node->index, t->next_index);
- s = format (s, "\n%U", format_white_space, indent + 2);
-
-#define _(a, b, c, n) \
- r32 = mrvl_get_u32_bits (d, a, b, c); \
- if (r32 > 9) \
- s = format (s, "%s %u (0x%x)", #n, r32, r32); \
- else \
- s = format (s, "%s %u", #n,r32); \
- if (format_get_indent (s) > 72) \
- s = format (s, "\n%U", format_white_space, indent + 2); \
- else s = format (s, " ");
-
- foreach_pp2_rx_desc_field;
-#undef _
- return s;
-}
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/input.c b/src/plugins/marvell/pp2/input.c
deleted file mode 100644
index 2545f91becb..00000000000
--- a/src/plugins/marvell/pp2/input.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 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.
- *------------------------------------------------------------------
- */
-
-#define _GNU_SOURCE
-#include <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/devices/devices.h>
-#include <vnet/interface/rx_queue_funcs.h>
-
-#include <marvell/pp2/pp2.h>
-
-#define foreach_mrvl_pp2_input_error \
- _(PPIO_RECV, "pp2_ppio_recv error") \
- _(BPOOL_GET_NUM_BUFFS, "pp2_bpool_get_num_buffs error") \
- _(BPOOL_PUT_BUFFS, "pp2_bpool_put_buffs error") \
- _(BUFFER_ALLOC, "buffer alloc error") \
- _(MAC_CE, "MAC error (CRC error)") \
- _(MAC_OR, "overrun error") \
- _(MAC_RSVD, "unknown MAC error") \
- _(MAC_RE, "resource error") \
- _(IP_HDR, "ip4 header error")
-
-typedef enum
-{
-#define _(f,s) MRVL_PP2_INPUT_ERROR_##f,
- foreach_mrvl_pp2_input_error
-#undef _
- MRVL_PP2_INPUT_N_ERROR,
-} mrvl_pp2_input_error_t;
-
-static __clib_unused char *mrvl_pp2_input_error_strings[] = {
-#define _(n,s) s,
- foreach_mrvl_pp2_input_error
-#undef _
-};
-
-static_always_inline void
-mrvl_pp2_input_trace (vlib_main_t * vm, vlib_node_runtime_t * node, u32 next0,
- vlib_buffer_t * b0, uword * n_trace,
- mrvl_pp2_if_t * ppif, struct pp2_ppio_desc *d)
-{
- if (PREDICT_TRUE (
- vlib_trace_buffer (vm, node, next0, b0, /* follow_chain */ 0)))
- {
- mrvl_pp2_input_trace_t *tr;
- vlib_set_trace_count (vm, node, --(*n_trace));
- tr = vlib_add_trace (vm, node, b0, sizeof (*tr));
- tr->next_index = next0;
- tr->hw_if_index = ppif->hw_if_index;
- clib_memcpy_fast (&tr->desc, d, sizeof (struct pp2_ppio_desc));
- }
-}
-
-static_always_inline u16
-mrvl_pp2_set_buf_data_len_flags (vlib_buffer_t * b, struct pp2_ppio_desc *d,
- u32 add_flags)
-{
- u16 len;
- len = pp2_ppio_inq_desc_get_pkt_len (d);
- b->total_length_not_including_first_buffer = 0;
- b->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID | add_flags;
-
- if (add_flags & VNET_BUFFER_F_L2_HDR_OFFSET_VALID)
- vnet_buffer (b)->l2_hdr_offset = 2;
-
- if (add_flags & VNET_BUFFER_F_L3_HDR_OFFSET_VALID)
- {
- u16 offset = DM_RXD_GET_L3_OFF (d);
- vnet_buffer (b)->l3_hdr_offset = offset;
- b->current_data = offset;
- b->current_length = len - offset + 2;
- }
- else
- {
- b->current_data = 2;
- b->current_length = len;
- }
-
- if (add_flags & VNET_BUFFER_F_L3_HDR_OFFSET_VALID)
- vnet_buffer (b)->l4_hdr_offset = vnet_buffer (b)->l3_hdr_offset +
- DM_RXD_GET_IPHDR_LEN (d) * 4;
-
- return len;
-}
-
-static_always_inline u16
-mrvl_pp2_next_from_desc (vlib_node_runtime_t * node, struct pp2_ppio_desc * d,
- vlib_buffer_t * b, u32 * next)
-{
- u8 l3_info;
- /* ES bit set means MAC error - drop and count */
- if (PREDICT_FALSE (DM_RXD_GET_ES (d)))
- {
- *next = VNET_DEVICE_INPUT_NEXT_DROP;
- u8 ec = DM_RXD_GET_EC (d);
- if (ec == 0)
- b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_CE];
- else if (ec == 1)
- b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_OR];
- else if (ec == 2)
- b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_RSVD];
- else if (ec == 3)
- b->error = node->errors[MRVL_PP2_INPUT_ERROR_MAC_RE];
- return mrvl_pp2_set_buf_data_len_flags (b, d, 0);
- }
- l3_info = DM_RXD_GET_L3_PRS_INFO (d);
-
- /* ipv4 packet can be value 1, 2 or 3 */
- if (PREDICT_TRUE ((l3_info - 1) < 3))
- {
- if (PREDICT_FALSE (DM_RXD_GET_L3_IP4_HDR_ERR (d) != 0))
- {
- *next = VNET_DEVICE_INPUT_NEXT_DROP;
- b->error = node->errors[MRVL_PP2_INPUT_ERROR_IP_HDR];
- return mrvl_pp2_set_buf_data_len_flags (b, d, 0);
- }
- *next = VNET_DEVICE_INPUT_NEXT_IP4_NCS_INPUT;
- return mrvl_pp2_set_buf_data_len_flags
- (b, d,
- VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
- VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
- VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP4);
- }
-
- /* ipv4 packet can be value 4 or 5 */
- if (PREDICT_TRUE ((l3_info - 4) < 2))
- {
- *next = VNET_DEVICE_INPUT_NEXT_IP6_INPUT;
- return mrvl_pp2_set_buf_data_len_flags
- (b, d,
- VNET_BUFFER_F_L2_HDR_OFFSET_VALID |
- VNET_BUFFER_F_L3_HDR_OFFSET_VALID |
- VNET_BUFFER_F_L4_HDR_OFFSET_VALID | VNET_BUFFER_F_IS_IP6);
- }
-
- *next = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
- return mrvl_pp2_set_buf_data_len_flags (b, d,
- VNET_BUFFER_F_L2_HDR_OFFSET_VALID);
-}
-
-static_always_inline uword
-mrvl_pp2_device_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame, mrvl_pp2_if_t * ppif,
- u16 qid)
-{
- vnet_main_t *vnm = vnet_get_main ();
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- u32 thread_index = vm->thread_index;
- mrvl_pp2_inq_t *inq = vec_elt_at_index (ppif->inqs, qid);
- uword n_trace = vlib_get_trace_count (vm, node);
- mrvl_pp2_per_thread_data_t *ptd =
- vec_elt_at_index (ppm->per_thread_data, thread_index);
- u32 next_index = VNET_DEVICE_INPUT_NEXT_ETHERNET_INPUT;
- u32 sw_if_index[VLIB_N_RX_TX];
- u32 n_rx_packets = 0;
- u32 n_rx_bytes = 0;
- u32 *to_next = 0;
- struct pp2_ppio_desc *d;
- u16 n_desc = VLIB_FRAME_SIZE;
- u32 n_bufs;
- u32 *buffers;
- int i;
-
- vec_validate_aligned (ptd->descs, n_desc, CLIB_CACHE_LINE_BYTES);
- if (PREDICT_FALSE (pp2_ppio_recv (ppif->ppio, 0, qid, ptd->descs, &n_desc)))
- {
- vlib_error_count (vm, node->node_index, MRVL_PP2_INPUT_ERROR_PPIO_RECV,
- 1);
- n_desc = 0;
- }
- n_rx_packets = n_desc;
-
- for (i = 0; i < n_desc; i++)
- ptd->buffers[i] = pp2_ppio_inq_desc_get_cookie (&ptd->descs[i]);
-
- d = ptd->descs;
- buffers = ptd->buffers;
- sw_if_index[VLIB_RX] = ppif->sw_if_index;
- sw_if_index[VLIB_TX] = (u32) ~ 0;
- while (n_desc)
- {
- u32 n_left_to_next;
- vlib_buffer_t *b0, *b1;
- u32 bi0, bi1;
- u32 next0, next1;
- vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
- while (n_desc >= 4 && n_left_to_next >= 2)
- {
- /* prefetch */
- bi0 = buffers[0];
- bi1 = buffers[1];
- to_next[0] = bi0;
- to_next[1] = bi1;
- b0 = vlib_get_buffer (vm, bi0);
- b1 = vlib_get_buffer (vm, bi1);
-
- if (PREDICT_TRUE (ppif->per_interface_next_index == ~0))
- {
- n_rx_bytes += mrvl_pp2_next_from_desc (node, d, b0, &next0);
- n_rx_bytes += mrvl_pp2_next_from_desc (node, d + 1, b1, &next1);
- vnet_feature_start_device_input (ppif->sw_if_index, &next0, b0);
- vnet_feature_start_device_input (ppif->sw_if_index, &next1, b1);
- }
- else
- {
- n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b0, d, 0);
- n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b1, d + 1, 0);
- next0 = next1 = ppif->per_interface_next_index;
- }
-
- clib_memcpy_fast (vnet_buffer (b0)->sw_if_index, sw_if_index,
- sizeof (sw_if_index));
- clib_memcpy_fast (vnet_buffer (b1)->sw_if_index, sw_if_index,
- sizeof (sw_if_index));
-
- if (PREDICT_FALSE (n_trace > 0))
- {
- mrvl_pp2_input_trace (vm, node, next0, b0, &n_trace, ppif, d);
- if (n_trace > 0)
- mrvl_pp2_input_trace (vm, node, next1, b1, &n_trace, ppif,
- d + 1);
- }
-
- to_next += 2;
- n_left_to_next -= 2;
- d += 2;
- buffers += 2;
- n_desc -= 2;
-
- /* enqueue */
- vlib_validate_buffer_enqueue_x2 (vm, node, next_index, to_next,
- n_left_to_next, bi0, bi1, next0,
- next1);
-
- }
- while (n_desc && n_left_to_next)
- {
- u32 bi0 = buffers[0];
- to_next[0] = bi0;
- b0 = vlib_get_buffer (vm, bi0);
-
- if (PREDICT_TRUE (ppif->per_interface_next_index == ~0))
- {
- n_rx_bytes += mrvl_pp2_next_from_desc (node, d, b0, &next0);
- vnet_feature_start_device_input (ppif->sw_if_index, &next0, b0);
- }
- else
- {
- n_rx_bytes += mrvl_pp2_set_buf_data_len_flags (b0, d, 0);
- next0 = ppif->per_interface_next_index;
- }
-
- clib_memcpy_fast (vnet_buffer (b0)->sw_if_index, sw_if_index,
- sizeof (sw_if_index));
-
- if (PREDICT_FALSE (n_trace > 0))
- mrvl_pp2_input_trace (vm, node, next0, b0, &n_trace, ppif, d);
-
- to_next += 1;
- n_left_to_next--;
- d++;
- buffers++;
- n_desc--;
-
- /* enqueue */
- vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
- n_left_to_next, bi0, next0);
- }
- vlib_put_next_frame (vm, node, next_index, n_left_to_next);
- }
- vlib_increment_combined_counter (vnm->
- interface_main.combined_sw_if_counters +
- VNET_INTERFACE_COUNTER_RX, thread_index,
- ppif->hw_if_index, n_rx_packets,
- n_rx_bytes);
-
- if (PREDICT_FALSE (pp2_bpool_get_num_buffs (inq->bpool, &n_bufs)))
- {
- vlib_error_count (vm, node->node_index,
- MRVL_PP2_INPUT_ERROR_BPOOL_GET_NUM_BUFFS, 1);
- goto done;
- }
-
- n_bufs = inq->size - n_bufs;
- while (n_bufs >= MRVL_PP2_BUFF_BATCH_SZ)
- {
- u16 n_alloc, i;
- struct buff_release_entry *e = ptd->bre;
- u32 *buffers = ptd->buffers;
-
- n_alloc = vlib_buffer_alloc (vm, ptd->buffers, MRVL_PP2_BUFF_BATCH_SZ);
- i = n_alloc;
-
- if (PREDICT_FALSE (n_alloc == 0))
- {
- vlib_error_count (vm, node->node_index,
- MRVL_PP2_INPUT_ERROR_BUFFER_ALLOC, 1);
- goto done;
- }
-
- while (i--)
- {
- u32 bi = buffers[0];
- vlib_buffer_t *b = vlib_get_buffer (vm, bi);
- e->buff.addr = vlib_buffer_get_pa (vm, b) - 64;
- e->buff.cookie = bi;
- e->bpool = inq->bpool;
- e++;
- buffers++;
- }
-
- i = n_alloc;
- if (PREDICT_FALSE (pp2_bpool_put_buffs (ptd->hif, ptd->bre, &i)))
- {
- vlib_error_count (vm, node->node_index,
- MRVL_PP2_INPUT_ERROR_BPOOL_PUT_BUFFS, 1);
- vlib_buffer_free (vm, ptd->buffers, n_alloc);
- goto done;
- }
-
- if (PREDICT_FALSE (i != n_alloc))
- vlib_buffer_free (vm, ptd->buffers + i, n_alloc - i);
-
- n_bufs -= i;
- }
-
-done:
- return n_rx_packets;
-}
-
-uword
-mrvl_pp2_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame)
-{
- u32 n_rx = 0;
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- vnet_hw_if_rxq_poll_vector_t *pv;
-
- pv = vnet_hw_if_get_rxq_poll_vector (vm, node);
-
- for (int i = 0; i < vec_len (pv); i++)
- {
- mrvl_pp2_if_t *ppif;
- ppif = vec_elt_at_index (ppm->interfaces, pv[i].dev_instance);
- if (ppif->flags & MRVL_PP2_IF_F_ADMIN_UP)
- n_rx +=
- mrvl_pp2_device_input_inline (vm, node, frame, ppif, pv[i].queue_id);
- }
- return n_rx;
-}
-
-VLIB_REGISTER_NODE (mrvl_pp2_input_node) = {
- .function = mrvl_pp2_input_fn,
- .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
- .name = "mrvl-pp2-input",
- .sibling_of = "device-input",
- .format_trace = format_mrvl_pp2_input_trace,
- .type = VLIB_NODE_TYPE_INPUT,
- .state = VLIB_NODE_STATE_POLLING,
- .n_errors = MRVL_PP2_INPUT_N_ERROR,
- .error_strings = mrvl_pp2_input_error_strings,
-};
-
-
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/output.c b/src/plugins/marvell/pp2/output.c
deleted file mode 100644
index 911b2f55a17..00000000000
--- a/src/plugins/marvell/pp2/output.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <stdint.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-#include <vnet/devices/devices.h>
-
-#include <marvell/pp2/pp2.h>
-
-uword
-mrvl_pp2_interface_tx (vlib_main_t * vm,
- vlib_node_runtime_t * node, vlib_frame_t * frame)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- vnet_interface_output_runtime_t *rd = (void *) node->runtime_data;
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, rd->dev_instance);
- u32 thread_index = vm->thread_index;
- mrvl_pp2_per_thread_data_t *ptd =
- vec_elt_at_index (ppm->per_thread_data, thread_index);
- u8 qid = thread_index;
- mrvl_pp2_outq_t *outq = vec_elt_at_index (ppif->outqs, qid);
- u32 *buffers = vlib_frame_vector_args (frame);
- u16 n_desc = frame->n_vectors, n_left = n_desc, n_sent = n_desc, n_done;
- struct pp2_ppio_desc *d;
- u16 mask = outq->size - 1;
-
- if (PREDICT_FALSE (pp2_ppio_get_num_outq_done (ppif->ppio, ptd->hif, qid,
- &n_done)))
- {
- n_done = 0;
- vlib_error_count (vm, node->node_index,
- MRVL_PP2_TX_ERROR_PPIO_GET_NUM_OUTQ_DONE, 1);
- }
-
- if (n_done)
- {
- u16 n_free = clib_min (n_done, outq->size - (outq->tail & mask));
- vlib_buffer_free (vm, outq->buffers + (outq->tail & mask), n_free);
- if (PREDICT_FALSE (n_free < n_done))
- vlib_buffer_free (vm, outq->buffers, n_done - n_free);
- outq->tail += n_done;
- }
-
- vec_validate_aligned (ptd->descs, n_left, CLIB_CACHE_LINE_BYTES);
- d = ptd->descs;
- while (n_left)
- {
- u32 bi0 = buffers[0];
- vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0);
- u64 paddr = vlib_buffer_get_pa (vm, b0);
-
- pp2_ppio_outq_desc_reset (d);
- pp2_ppio_outq_desc_set_phys_addr (d, paddr + b0->current_data);
- pp2_ppio_outq_desc_set_pkt_offset (d, 0);
- pp2_ppio_outq_desc_set_pkt_len (d, b0->current_length);
- d++;
- buffers++;
- n_left--;
- }
-
- if (pp2_ppio_send (ppif->ppio, ptd->hif, qid, ptd->descs, &n_sent))
- {
- n_sent = 0;
- vlib_error_count (vm, node->node_index, MRVL_PP2_TX_ERROR_PPIO_SEND, 1);
- }
-
- /* free unsent buffers */
- if (PREDICT_FALSE (n_sent != n_desc))
- {
- vlib_buffer_free (vm, vlib_frame_vector_args (frame) + n_sent,
- frame->n_vectors - n_sent);
- vlib_error_count (vm, node->node_index, MRVL_PP2_TX_ERROR_NO_FREE_SLOTS,
- frame->n_vectors - n_sent);
- }
-
- /* store buffer index for each enqueued packet into the ring
- so we can know what to free after packet is sent */
- if (n_sent)
- {
- u16 slot = outq->head & mask;
- buffers = vlib_frame_vector_args (frame);
- u16 n_copy = clib_min (outq->size - slot, n_sent);
-
- vlib_buffer_copy_indices (outq->buffers + slot, buffers, n_copy);
- if (PREDICT_FALSE (n_copy < n_sent))
- clib_memcpy_fast (outq->buffers, buffers + n_copy,
- (n_sent - n_copy) * sizeof (u32));
-
- outq->head += n_sent;
- }
-
- return n_sent;
-}
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/pp2.c b/src/plugins/marvell/pp2/pp2.c
deleted file mode 100644
index 030ab9b4496..00000000000
--- a/src/plugins/marvell/pp2/pp2.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 Cisco and/or its affiliates.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/plugin/plugin.h>
-#include <marvell/pp2/pp2.h>
-#include <vnet/interface/rx_queue_funcs.h>
-
-/* size of DMA memory used by musdk (not used for buffers) */
-#define MV_SYS_DMA_MEM_SZ (2 << 20)
-/* number of HIFs reserved (first X) */
-#define NUM_HIFS_RSVD 4
-/* number of buffer pools reserved (first X) */
-#define NUM_BPOOLS_RSVD 7
-
-mrvl_pp2_main_t mrvl_pp2_main;
-extern vnet_device_class_t ppa2_device_class;
-
-static void
-mrvl_pp2_main_deinit ()
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- int i;
- vec_foreach_index (i, ppm->per_thread_data)
- {
- mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
- i);
- if (ptd->hif)
- pp2_hif_deinit (ptd->hif);
- vec_free (ptd->descs);
- }
- vec_free (ppm->per_thread_data);
- pp2_deinit ();
- mv_sys_dma_mem_destroy ();
-}
-
-static clib_error_t *
-mrvl_pp2_main_init ()
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- vlib_thread_main_t *tm = vlib_get_thread_main ();
- clib_error_t *err = 0;
- struct pp2_init_params init_params = { 0 };
- int i, rv;
- u8 *s = 0;
-
- rv = mv_sys_dma_mem_init (MV_SYS_DMA_MEM_SZ);
- if (rv)
- return clib_error_return (0, "mv_sys_dma_mem_init failed, rv = %u", rv);
-
- init_params.hif_reserved_map = ((1 << NUM_HIFS_RSVD) - 1);
- init_params.bm_pool_reserved_map = ((1 << NUM_BPOOLS_RSVD) - 1);
- rv = pp2_init (&init_params);
- if (rv)
- {
- err = clib_error_return (0, "mrvl_pp2_init failed, rv = %u", rv);
- goto done;
- }
-
- vec_validate_aligned (ppm->per_thread_data, tm->n_vlib_mains - 1,
- CLIB_CACHE_LINE_BYTES);
-
- vec_foreach_index (i, ppm->per_thread_data)
- {
- mrvl_pp2_per_thread_data_t *ptd = vec_elt_at_index (ppm->per_thread_data,
- i);
- struct pp2_hif_params hif_params = { 0 };
- vec_reset_length (s);
- s = format (s, "hif-%d%c", NUM_HIFS_RSVD + i, 0);
- hif_params.match = (char *) s;
- hif_params.out_size = 2048; /* FIXME */
- if (pp2_hif_init (&hif_params, &ptd->hif))
- {
- err = clib_error_return (0, "hif '%s' init failed", s);
- goto done;
- }
- }
-
-done:
- if (err)
- mrvl_pp2_main_deinit ();
- vec_free (s);
- return err;
-}
-
-static u32
-mrvl_pp2_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
- u32 flags)
-{
- /* nothing for now */
- return 0;
-}
-
-void
-mrvl_pp2_delete_if (mrvl_pp2_if_t * ppif)
-{
- vlib_main_t *vm = vlib_get_main ();
- vnet_main_t *vnm = vnet_get_main ();
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- mrvl_pp2_outq_t *outq;
- mrvl_pp2_inq_t *inq;
-
- if (ppif->hw_if_index != ~0)
- ethernet_delete_interface (vnm, ppif->hw_if_index);
-
- if (ppif->ppio)
- {
- pp2_ppio_disable (ppif->ppio);
- pp2_ppio_deinit (ppif->ppio);
- }
-
- /* free buffers hanging in the tx ring */
- vec_foreach (outq, ppif->outqs)
- {
- while (outq->tail < outq->head)
- {
- u16 slot = outq->tail & (outq->size - 1);
- vlib_buffer_free (vm, outq->buffers + slot, 1);
- outq->tail++;
- }
- vec_free (outq->buffers);
- }
- vec_free (ppif->outqs);
-
- /* free buffers hangin in the rx buffer pool */
- vec_foreach (inq, ppif->inqs)
- if (inq->bpool)
- {
- u32 n_bufs = 0;
- pp2_bpool_get_num_buffs (inq->bpool, &n_bufs);
- while (n_bufs--)
- {
- struct pp2_buff_inf binf;
- if (pp2_bpool_get_buff (ppm->per_thread_data[0].hif, inq->bpool,
- &binf) == 0)
- {
- u32 bi = binf.cookie;
- vlib_buffer_free (vm, &bi, 1);
- }
- }
- pp2_bpool_deinit (inq->bpool);
- }
- vec_free (ppif->inqs);
-
-
- pool_put (ppm->interfaces, ppif);
-
- if (pool_elts (ppm->interfaces) == 0)
- mrvl_pp2_main_deinit ();
-}
-
-void
-mrvl_pp2_create_if (mrvl_pp2_create_if_args_t * args)
-{
- vlib_main_t *vm = vlib_get_main ();
- vnet_main_t *vnm = vnet_get_main ();
- vlib_thread_main_t *tm = vlib_get_thread_main ();
- vnet_eth_interface_registration_t eir = {};
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- struct pp2_bpool_params bpool_params = { 0 };
- struct pp2_ppio_params ppio_params = { 0 };
- struct pp2_ppio_inq_params inq_params = { 0 };
- vnet_sw_interface_t *sw;
- mrvl_pp2_if_t *ppif = 0;
- u8 pp2_id, port_id, *s = 0;
- eth_addr_t mac_addr;
- u8 n_outqs, n_inqs = 1;
- int i;
-
- if (tm->n_vlib_mains > PP2_PPIO_MAX_NUM_OUTQS)
- {
- args->rv = VNET_API_ERROR_INIT_FAILED;
- args->error = clib_error_return (0, "number of threads (main + workers)"
- " is bigger than number of output "
- "queues (%u)", PP2_PPIO_MAX_NUM_OUTQS);
- return;
- }
- n_outqs = tm->n_vlib_mains;
-
- /* defaults */
- args->tx_q_sz = args->tx_q_sz ? args->tx_q_sz : 2 * VLIB_FRAME_SIZE;
- args->rx_q_sz = args->rx_q_sz ? args->rx_q_sz : 2 * VLIB_FRAME_SIZE;
-
- if (vec_len (ppm->per_thread_data) == 0)
- {
- if ((args->error = mrvl_pp2_main_init ()) != 0)
- {
- args->rv = VNET_API_ERROR_INIT_FAILED;
- return;
- }
- }
-
- pool_get_zero (ppm->interfaces, ppif);
- ppif->dev_instance = ppif - ppm->interfaces;
- ppif->hw_if_index = ~0;
- vec_validate_aligned (ppif->inqs, n_inqs - 1, CLIB_CACHE_LINE_BYTES);
- vec_validate_aligned (ppif->outqs, n_outqs - 1, CLIB_CACHE_LINE_BYTES);
-
- for (i = 0; i < n_inqs; i++)
- {
- mrvl_pp2_inq_t *inq = vec_elt_at_index (ppif->inqs, i);
- inq->size = args->rx_q_sz;
- }
- for (i = 0; i < n_outqs; i++)
- {
- mrvl_pp2_outq_t *outq = vec_elt_at_index (ppif->outqs, i);
- outq->size = args->tx_q_sz;
- vec_validate_aligned (outq->buffers, outq->size, CLIB_CACHE_LINE_BYTES);
- }
-
- if (pp2_netdev_get_ppio_info ((char *) args->name, &pp2_id, &port_id))
- {
- args->rv = VNET_API_ERROR_INVALID_INTERFACE;
- args->error = clib_error_return (0, "Invalid interface '%s'",
- args->name);
- goto error;
- }
-
- /* FIXME bpool bit select per pp */
- s = format (s, "pool-%d:%d%c", pp2_id, pp2_id + 8, 0);
- bpool_params.match = (char *) s;
- bpool_params.buff_len = vlib_buffer_get_default_data_size (vm);
- /* FIXME +64 ? */
- if (pp2_bpool_init (&bpool_params, &ppif->inqs[0].bpool))
- {
- args->rv = VNET_API_ERROR_INIT_FAILED;
- args->error = clib_error_return (0, "bpool '%s' init failed", s);
- goto error;
- }
- vec_reset_length (s);
-
- s = format (s, "ppio-%d:%d%c", pp2_id, port_id, 0);
- ppio_params.match = (char *) s;
- ppio_params.type = PP2_PPIO_T_NIC;
- inq_params.size = args->rx_q_sz;
- ppio_params.inqs_params.num_tcs = 1;
- ppio_params.inqs_params.tcs_params[0].pkt_offset = 0;
- ppio_params.inqs_params.tcs_params[0].num_in_qs = n_inqs;
- ppio_params.inqs_params.tcs_params[0].inqs_params = &inq_params;
- ppio_params.inqs_params.tcs_params[0].pools[0][0] = ppif->inqs[0].bpool;
- ppio_params.outqs_params.num_outqs = n_outqs;
- for (i = 0; i < n_outqs; i++)
- {
- ppio_params.outqs_params.outqs_params[i].weight = 1;
- ppio_params.outqs_params.outqs_params[i].size = args->tx_q_sz;
- }
- if (pp2_ppio_init (&ppio_params, &ppif->ppio))
- {
- args->rv = VNET_API_ERROR_INIT_FAILED;
- args->error = clib_error_return (0, "ppio '%s' init failed", s);
- goto error;
- }
- vec_reset_length (s);
-
- if (pp2_ppio_get_mac_addr (ppif->ppio, mac_addr))
- {
- args->rv = VNET_API_ERROR_INIT_FAILED;
- args->error =
- clib_error_return (0, "%s: pp2_ppio_get_mac_addr failed", s);
- goto error;
- }
-
- eir.dev_class_index = mrvl_pp2_device_class.index;
- eir.dev_instance = ppif->dev_instance;
- eir.address = mac_addr;
- eir.cb.flag_change = mrvl_pp2_eth_flag_change;
- ppif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
-
- sw = vnet_get_hw_sw_interface (vnm, ppif->hw_if_index);
- ppif->sw_if_index = sw->sw_if_index;
- ppif->per_interface_next_index = ~0;
- args->sw_if_index = sw->sw_if_index;
- vnet_hw_if_set_input_node (vnm, ppif->hw_if_index,
- mrvl_pp2_input_node.index);
- /* FIXME: only one RX queue ? */
- ppif->inqs[0].queue_index = vnet_hw_if_register_rx_queue (
- vnm, ppif->hw_if_index, 0, VNET_HW_IF_RXQ_THREAD_ANY);
-
- vnet_hw_if_set_rx_queue_mode (vnm, ppif->inqs[0].queue_index,
- VNET_HW_IF_RX_MODE_POLLING);
- vnet_hw_if_update_runtime_data (vnm, ppif->hw_if_index);
- vnet_hw_interface_set_flags (vnm, ppif->hw_if_index,
- VNET_HW_INTERFACE_FLAG_LINK_UP);
- goto done;
-
-error:
- mrvl_pp2_delete_if (ppif);
-done:
- vec_free (s);
-}
-
-static clib_error_t *
-mrvl_pp2_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
- u32 flags)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
- static clib_error_t *error = 0;
- int is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
- int rv;
-
- if (is_up)
- rv = pp2_ppio_enable (ppif->ppio);
- else
- rv = pp2_ppio_disable (ppif->ppio);
-
- if (rv)
- return clib_error_return (0, "failed to %s interface",
- is_up ? "enable" : "disable");
-
- if (is_up)
- ppif->flags |= MRVL_PP2_IF_F_ADMIN_UP;
- else
- ppif->flags &= ~MRVL_PP2_IF_F_ADMIN_UP;
-
- return error;
-}
-
-static void
-mrvl_pp2_clear_interface_counters (u32 instance)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, instance);
- struct pp2_ppio_statistics stats;
-
- pp2_ppio_get_statistics (ppif->ppio, &stats, 1);
-}
-
-static void
-mrvl_pp2_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
- u32 node_index)
-{
- mrvl_pp2_main_t *ppm = &mrvl_pp2_main;
- vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
- mrvl_pp2_if_t *ppif = pool_elt_at_index (ppm->interfaces, hw->dev_instance);
-
- /* Shut off redirection */
- if (node_index == ~0)
- {
- ppif->per_interface_next_index = node_index;
- return;
- }
-
- ppif->per_interface_next_index =
- vlib_node_add_next (vlib_get_main (), mrvl_pp2_input_node.index,
- node_index);
-}
-
-static char *mrvl_pp2_tx_func_error_strings[] = {
-#define _(n,s) s,
- foreach_mrvl_pp2_tx_func_error
-#undef _
-};
-
-VNET_DEVICE_CLASS (mrvl_pp2_device_class,) =
-{
- .name = "Marvell PPv2 interface",
- .format_device_name = format_mrvl_pp2_interface_name,
- .format_device = format_mrvl_pp2_interface,
- .tx_function = mrvl_pp2_interface_tx,
- .tx_function_n_errors = MRVL_PP2_TX_N_ERROR,
- .tx_function_error_strings = mrvl_pp2_tx_func_error_strings,
- .admin_up_down_function = mrvl_pp2_interface_admin_up_down,
- .clear_counters = mrvl_pp2_clear_interface_counters,
- .rx_redirect_to_node = mrvl_pp2_set_interface_next_node,
-};
-
-static clib_error_t *
-mrvl_pp2_init (vlib_main_t * vm)
-{
- return 0;
-}
-
-VLIB_INIT_FUNCTION (mrvl_pp2_init);
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/pp2.h b/src/plugins/marvell/pp2/pp2.h
deleted file mode 100644
index abb8e573a37..00000000000
--- a/src/plugins/marvell/pp2/pp2.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 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.
- *------------------------------------------------------------------
- */
-
-#define MVCONF_DBG_LEVEL 0
-#define MVCONF_PP2_BPOOL_COOKIE_SIZE 32
-#define MVCONF_PP2_BPOOL_DMA_ADDR_SIZE 64
-#define MVCONF_DMA_PHYS_ADDR_T_SIZE 64
-#define MVCONF_SYS_DMA_UIO
-#define MVCONF_TYPES_PUBLIC
-#define MVCONF_DMA_PHYS_ADDR_T_PUBLIC
-
-#include <vlib/vlib.h>
-
-#include "mv_std.h"
-#include "env/mv_sys_dma.h"
-#include "drivers/mv_pp2.h"
-#include <drivers/mv_pp2_bpool.h>
-#include <drivers/mv_pp2_ppio.h>
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- u16 size;
- u32 queue_index;
- struct pp2_bpool *bpool;
-} mrvl_pp2_inq_t;
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- u16 size;
- u32 *buffers;
- u16 head;
- u16 tail;
-} mrvl_pp2_outq_t;
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- u32 flags;
-#define MRVL_PP2_IF_F_ADMIN_UP (1 << 0)
- struct pp2_ppio *ppio;
- u32 per_interface_next_index;
-
- mrvl_pp2_inq_t *inqs;
- mrvl_pp2_outq_t *outqs;
-
- u32 dev_instance;
- u32 sw_if_index;
- u32 hw_if_index;
-} mrvl_pp2_if_t;
-
-#define MRVL_PP2_BUFF_BATCH_SZ VLIB_FRAME_SIZE
-
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- struct pp2_hif *hif;
- struct pp2_ppio_desc *descs;
- struct buff_release_entry bre[MRVL_PP2_BUFF_BATCH_SZ];
- u32 buffers[VLIB_FRAME_SIZE];
-} mrvl_pp2_per_thread_data_t;
-
-typedef struct
-{
- mrvl_pp2_if_t *interfaces;
- mrvl_pp2_per_thread_data_t *per_thread_data;
-
- /* API message ID base */
- u16 msg_id_base;
-} mrvl_pp2_main_t;
-
-extern vnet_device_class_t mrvl_pp2_device_class;
-extern mrvl_pp2_main_t mrvl_pp2_main;
-
-typedef struct
-{
- u8 *name;
- u16 rx_q_sz;
- u16 tx_q_sz;
-
- /* return */
- i32 rv;
- u32 sw_if_index;
- clib_error_t *error;
-} mrvl_pp2_create_if_args_t;
-
-void mrvl_pp2_create_if (mrvl_pp2_create_if_args_t * args);
-void mrvl_pp2_delete_if (mrvl_pp2_if_t * dfif);
-clib_error_t *mrvl_pp2_plugin_api_hookup (vlib_main_t * vm);
-
-/* output.c */
-
-#define foreach_mrvl_pp2_tx_func_error \
- _(NO_FREE_SLOTS, "no free tx slots") \
- _(PPIO_SEND, "pp2_ppio_send errors") \
- _(PPIO_GET_NUM_OUTQ_DONE, "pp2_ppio_get_num_outq_done errors")
-
-typedef enum
-{
-#define _(f,s) MRVL_PP2_TX_ERROR_##f,
- foreach_mrvl_pp2_tx_func_error
-#undef _
- MRVL_PP2_TX_N_ERROR,
-} mrvl_pp2_tx_func_error_t;
-
-uword mrvl_pp2_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
- vlib_frame_t * frame);
-
-/* input.c */
-
-typedef struct
-{
- u32 next_index;
- u32 hw_if_index;
- struct pp2_ppio_desc desc;
-} mrvl_pp2_input_trace_t;
-
-extern vlib_node_registration_t mrvl_pp2_input_node;
-
-/* format.c */
-format_function_t format_mrvl_pp2_input_trace;
-format_function_t format_mrvl_pp2_interface;
-format_function_t format_mrvl_pp2_interface_name;
-
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/pp2_api.c b/src/plugins/marvell/pp2/pp2_api.c
deleted file mode 100644
index c1f3a9e1d1d..00000000000
--- a/src/plugins/marvell/pp2/pp2_api.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2019 Arm Limited.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <marvell/pp2/pp2.h>
-
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-
-/* define message IDs */
-#include <marvell/pp2/pp2.api_enum.h>
-#include <marvell/pp2/pp2.api_types.h>
-
-#define REPLY_MSG_ID_BASE (pp2->msg_id_base)
-#include <vlibapi/api_helper_macros.h>
-
-static void
-vl_api_mrvl_pp2_create_t_handler (vl_api_mrvl_pp2_create_t * mp)
-{
- mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
- mrvl_pp2_create_if_args_t args = { 0 };
- vl_api_mrvl_pp2_create_reply_t *rmp;
- int rv;
-
- args.name = format (0, "%s", mp->if_name);
- args.rx_q_sz = ntohs (mp->rx_q_sz);
- args.tx_q_sz = ntohs (mp->tx_q_sz);
- mrvl_pp2_create_if (&args);
- rv = args.rv;
- vec_free (args.name);
- if (args.error)
- {
- clib_error_free (args.error);
- }
- REPLY_MACRO2 (VL_API_MRVL_PP2_CREATE_REPLY,
- ({ rmp->sw_if_index = ntohl (args.sw_if_index); }));
-}
-
-static void
-vl_api_mrvl_pp2_delete_t_handler (vl_api_mrvl_pp2_delete_t * mp)
-{
- vnet_main_t *vnm = vnet_get_main ();
- vnet_hw_interface_t *hw;
- mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
- vl_api_mrvl_pp2_delete_reply_t *rmp;
- mrvl_pp2_if_t *dif;
- int rv = 0;
- mp->sw_if_index = ntohl (mp->sw_if_index);
- hw = vnet_get_sup_hw_interface (vnm, mp->sw_if_index);
- if (hw == NULL || mrvl_pp2_device_class.index != hw->dev_class_index)
- {
- rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
- goto reply;
- }
-
- dif = pool_elt_at_index (pp2->interfaces, hw->dev_instance);
-
- mrvl_pp2_delete_if (dif);
-
-reply:
- REPLY_MACRO (VL_API_MRVL_PP2_DELETE_REPLY);
-}
-
-#include <marvell/pp2/pp2.api.c>
-/* set up the API message handling tables */
-clib_error_t *
-mrvl_pp2_plugin_api_hookup (vlib_main_t * vm)
-{
- mrvl_pp2_main_t *pp2 = &mrvl_pp2_main;
-
- /* ask for a correctly-sized block of API message decode slots */
- pp2->msg_id_base = setup_message_id_table ();
-
- return 0;
-}
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/marvell/pp2/pp2_test.c b/src/plugins/marvell/pp2/pp2_test.c
deleted file mode 100644
index 26a9e9a6e34..00000000000
--- a/src/plugins/marvell/pp2/pp2_test.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *------------------------------------------------------------------
- * Copyright (c) 2019 Arm Limited.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *------------------------------------------------------------------
- */
-
-#include <vlib/vlib.h>
-#include <vlib/unix/unix.h>
-#include <vnet/ethernet/ethernet.h>
-
-#include <vat/vat.h>
-#include <vlibapi/api.h>
-#include <vlibmemory/api.h>
-
-#include <vppinfra/error.h>
-#include <marvell/pp2/pp2.h>
-
-#define __plugin_msg_base pp2_test_main.msg_id_base
-#include <vlibapi/vat_helper_macros.h>
-
-/* declare message IDs */
-#include <marvell/pp2/pp2.api_enum.h>
-#include <marvell/pp2/pp2.api_types.h>
-
-typedef struct
-{
- /* API message ID base */
- u16 msg_id_base;
- vat_main_t *vat_main;
-} pp2_test_main_t;
-
-pp2_test_main_t pp2_test_main;
-
-/* mrvl_pp2 create API */
-static int
-api_mrvl_pp2_create (vat_main_t * vam)
-{
- unformat_input_t *i = vam->input;
- vl_api_mrvl_pp2_create_t *mp;
- mrvl_pp2_create_if_args_t args;
- int ret;
- u16 size;
-
- clib_memset (&args, 0, sizeof (mrvl_pp2_create_if_args_t));
- while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (i, "name %s", &args.name))
- ;
- else if (unformat (i, "rx-queue-size %u", &size))
- args.rx_q_sz = size;
- else if (unformat (i, "tx-queue-size %u", &size))
- args.tx_q_sz = size;
- else
- {
- clib_warning ("unknown input '%U'", format_unformat_error, i);
- return -99;
- }
- }
-
- M (MRVL_PP2_CREATE, mp);
-
- strncpy_s ((char *) mp->if_name, ARRAY_LEN (mp->if_name),
- (char *) (args.name), strlen ((char *) args.name));
- mp->rx_q_sz = clib_host_to_net_u16 (args.rx_q_sz);
- mp->tx_q_sz = clib_host_to_net_u16 (args.tx_q_sz);
-
- S (mp);
- W (ret);
-
- vec_free (args.name);
-
- return ret;
-}
-
-/* mrvl_pp2 create reply handler */
-static void
-vl_api_mrvl_pp2_create_reply_t_handler (vl_api_mrvl_pp2_create_reply_t * mp)
-{
- vat_main_t *vam = pp2_test_main.vat_main;
- i32 retval = ntohl (mp->retval);
-
- if (retval == 0)
- {
- fformat (vam->ofp, "created mrvl_pp2 with sw_if_index %d\n",
- ntohl (mp->sw_if_index));
- }
-
- vam->retval = retval;
- vam->result_ready = 1;
- vam->regenerate_interface_table = 1;
-}
-
-
-/* mrvl_pp2 delete API */
-static int
-api_mrvl_pp2_delete (vat_main_t * vam)
-{
- unformat_input_t *i = vam->input;
- //vnet_main_t *vnm = vnet_get_main ();
- vl_api_mrvl_pp2_delete_t *mp;
- u32 sw_if_index = 0;
- int ret;
-
- while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
- {
- if (unformat (i, "sw_if_index %d", &sw_if_index))
- ;
- else
- {
- clib_warning ("unknown input '%U'", format_unformat_error, i);
- return -99;
- }
- }
-
- M (MRVL_PP2_DELETE, mp);
-
- mp->sw_if_index = clib_host_to_net_u32 (sw_if_index);
-
- S (mp);
- W (ret);
-
- return ret;
-}
-
-#include <marvell/pp2/pp2.api_test.c>
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
diff --git a/src/plugins/npt66/npt66.api b/src/plugins/npt66/npt66.api
index 63640ac2097..dab09cda31f 100644
--- a/src/plugins/npt66/npt66.api
+++ b/src/plugins/npt66/npt66.api
@@ -36,5 +36,16 @@ counters npt66 {
units "packets";
description "packet translation failed";
};
-
+ icmp6_checksum {
+ severity error;
+ type counter64;
+ units "packets";
+ description "ICMP6 checksum validation failed";
+ };
+ icmp6_truncated {
+ severity error;
+ type counter64;
+ units "packets";
+ description "ICMP6 packet truncated";
+ };
}; \ No newline at end of file
diff --git a/src/plugins/npt66/npt66_node.c b/src/plugins/npt66/npt66_node.c
index f74f9143998..0d0c475f2c3 100644
--- a/src/plugins/npt66/npt66_node.c
+++ b/src/plugins/npt66/npt66_node.c
@@ -127,10 +127,7 @@ npt66_translate (ip6_header_t *ip, npt66_binding_t *binding, int dir)
if (!ip6_prefix_cmp (ip->src_address, binding->internal,
binding->internal_plen))
{
- clib_warning (
- "npt66_translate: src address is not internal (%U -> %U)",
- format_ip6_address, &ip->src_address, format_ip6_address,
- &ip->dst_address);
+ /* Packet is not for us */
goto done;
}
ip->src_address = ip6_prefix_copy (ip->src_address, binding->external,
@@ -144,10 +141,7 @@ npt66_translate (ip6_header_t *ip, npt66_binding_t *binding, int dir)
if (!ip6_prefix_cmp (ip->dst_address, binding->external,
binding->external_plen))
{
- clib_warning (
- "npt66_translate: dst address is not external (%U -> %U)",
- format_ip6_address, &ip->src_address, format_ip6_address,
- &ip->dst_address);
+ /* Packet is not for us */
goto done;
}
ip->dst_address = ip6_prefix_copy (ip->dst_address, binding->internal,
@@ -162,7 +156,7 @@ done:
static int
npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
icmp46_header_t *icmp, npt66_binding_t *binding,
- int dir)
+ int dir, u32 *error)
{
ip6_header_t *ip = (ip6_header_t *) (icmp + 2);
int rv = 0;
@@ -171,7 +165,7 @@ npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
if (clib_net_to_host_u16 (outer_ip->payload_length) <
sizeof (icmp46_header_t) + 4 + sizeof (ip6_header_t))
{
- clib_warning ("ICMP6 payload too short");
+ *error = NPT66_ERROR_ICMP6_TRUNCATED;
return -1;
}
@@ -181,7 +175,7 @@ npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
sum16 = ip6_tcp_udp_icmp_compute_checksum (vm, b, outer_ip, &bogus_length);
if (sum16 != 0 && sum16 != 0xffff)
{
- clib_warning ("ICMP6 checksum failed");
+ *error = NPT66_ERROR_ICMP6_CHECKSUM;
return -1;
}
if (dir == VLIB_RX)
@@ -189,10 +183,7 @@ npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
if (!ip6_prefix_cmp (ip->src_address, binding->external,
binding->external_plen))
{
- clib_warning (
- "npt66_icmp6_translate: src address is not internal (%U -> %U)",
- format_ip6_address, &ip->src_address, format_ip6_address,
- &ip->dst_address);
+ /* Not for us */
goto done;
}
ip->src_address = ip6_prefix_copy (ip->src_address, binding->internal,
@@ -206,10 +197,7 @@ npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
if (!ip6_prefix_cmp (ip->dst_address, binding->external,
binding->external_plen))
{
- clib_warning (
- "npt66_icmp6_translate: dst address is not external (%U -> %U)",
- format_ip6_address, &ip->src_address, format_ip6_address,
- &ip->dst_address);
+ /* Not for us */
goto done;
}
ip->dst_address = ip6_prefix_copy (ip->dst_address, binding->internal,
@@ -217,8 +205,8 @@ npt66_icmp6_translate (vlib_buffer_t *b, ip6_header_t *outer_ip,
rv = npt66_adjust_checksum (binding->internal_plen, false,
binding->delta, &ip->dst_address);
}
-done:
+done:
return rv;
}
@@ -243,10 +231,12 @@ npt66_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
n_left_from = frame->n_vectors;
vlib_get_buffers (vm, from, b, n_left_from);
npt66_binding_t *binding;
+ u32 translated = 0;
/* Stage 1: build vector of flow hash (based on lookup mask) */
while (n_left_from > 0)
{
+ u32 error = NPT66_ERROR_TRANSLATION;
u32 sw_if_index = vnet_buffer (b[0])->sw_if_index[dir];
u32 iph_offset =
dir == VLIB_TX ? vnet_buffer (b[0])->ip.save_rewrite_length : 0;
@@ -261,28 +251,26 @@ npt66_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
icmp46_header_t *icmp = (icmp46_header_t *) (ip + 1);
if (ip->protocol == IP_PROTOCOL_ICMP6 && icmp->type < 128)
{
- rv = npt66_icmp6_translate (b[0], ip, icmp, binding, dir);
+ rv = npt66_icmp6_translate (b[0], ip, icmp, binding, dir, &error);
if (rv < 0)
{
- clib_warning ("ICMP6 npt66_translate failed");
*next = NPT66_NEXT_DROP;
+ b[0]->error = node->errors[error];
goto next;
}
}
- rv = npt66_translate (ip, binding, dir);
+ rv = npt66_translate (ip, binding, dir);
if (rv < 0)
{
- vlib_node_increment_counter (vm, node->node_index,
- NPT66_ERROR_TRANSLATION, 1);
+ b[0]->error = node->errors[error];
*next = NPT66_NEXT_DROP;
goto next;
}
- else if (dir == VLIB_TX)
- vlib_node_increment_counter (vm, node->node_index, NPT66_ERROR_TX, 1);
else
- vlib_node_increment_counter (vm, node->node_index, NPT66_ERROR_RX, 1);
-
+ {
+ translated++;
+ }
next:
next += 1;
n_left_from -= 1;
@@ -321,6 +309,9 @@ npt66_node_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
break;
}
}
+ vlib_node_increment_counter (
+ vm, node->node_index, dir == VLIB_TX ? NPT66_ERROR_TX : NPT66_ERROR_RX,
+ translated);
vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
return frame->n_vectors;
@@ -338,17 +329,17 @@ VLIB_NODE_FN (npt66_output_node)
}
VLIB_REGISTER_NODE(npt66_input_node) = {
- .name = "npt66-input",
- .vector_size = sizeof(u32),
- .format_trace = format_npt66_trace,
- .type = VLIB_NODE_TYPE_INTERNAL,
- .n_errors = NPT66_N_ERROR,
- .error_counters = npt66_error_counters,
- .n_next_nodes = NPT66_N_NEXT,
- .next_nodes =
- {
- [NPT66_NEXT_DROP] = "error-drop",
- },
+ .name = "npt66-input",
+ .vector_size = sizeof(u32),
+ .format_trace = format_npt66_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = NPT66_N_ERROR,
+ .error_counters = npt66_error_counters,
+ .n_next_nodes = NPT66_N_NEXT,
+ .next_nodes =
+ {
+ [NPT66_NEXT_DROP] = "error-drop",
+ },
};
VLIB_REGISTER_NODE (npt66_output_node) = {
diff --git a/src/plugins/builtinurl/CMakeLists.txt b/src/plugins/osi/CMakeLists.txt
index ddbca5e50f1..8ab014770ea 100644
--- a/src/plugins/builtinurl/CMakeLists.txt
+++ b/src/plugins/osi/CMakeLists.txt
@@ -1,5 +1,4 @@
-
-# Copyright (c) <current-year> <your-organization>
+# Copyright (c) 2023 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:
@@ -12,15 +11,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-add_vpp_plugin(builtinurl
- SOURCES
- builtins.c
- builtinurl.c
- builtinurl.h
+add_vpp_plugin(osi
- API_FILES
- builtinurl.api
+ SOURCES
+ osi.c
+ node.c
+ pg.c
+ plugin.c
- API_TEST_SOURCES
- builtinurl_test.c
+ INSTALL_HEADERS
+ osi.h
)
diff --git a/src/plugins/osi/FEATURE.yaml b/src/plugins/osi/FEATURE.yaml
new file mode 100644
index 00000000000..337be1c7146
--- /dev/null
+++ b/src/plugins/osi/FEATURE.yaml
@@ -0,0 +1,11 @@
+---
+name: OSI plugin
+maintainer:
+ - community <vpp-dev@lists.fd.io>
+features:
+ - Adds support for OSI protocols (SAP types)
+ - Registered as input protocol for PPP, HDLC, and LLC
+missing:
+ - No tests for this feature currently exist
+description: ""
+state: experimental
diff --git a/src/vnet/osi/node.c b/src/plugins/osi/node.c
index 9edc354cda7..a36b1525e0e 100644
--- a/src/vnet/osi/node.c
+++ b/src/plugins/osi/node.c
@@ -39,7 +39,7 @@
#include <vlib/vlib.h>
#include <vnet/pg/pg.h>
-#include <vnet/osi/osi.h>
+#include <osi/osi.h>
#include <vnet/ppp/ppp.h>
#include <vnet/hdlc/hdlc.h>
#include <vnet/llc/llc.h>
diff --git a/src/vnet/osi/osi.c b/src/plugins/osi/osi.c
index 9556481448a..67c7053f388 100644
--- a/src/vnet/osi/osi.c
+++ b/src/plugins/osi/osi.c
@@ -38,7 +38,7 @@
*/
#include <vnet/vnet.h>
-#include <vnet/osi/osi.h>
+#include <osi/osi.h>
/* Global main structure. */
osi_main_t osi_main;
@@ -169,13 +169,8 @@ add_protocol (osi_main_t * pm, osi_protocol_t protocol, char *protocol_name)
static clib_error_t *
osi_init (vlib_main_t * vm)
{
- clib_error_t *error = 0;
osi_main_t *pm = &osi_main;
- /* init order dependency: llc_init -> osi_init */
- if ((error = vlib_call_init_function (vm, llc_init)))
- return error;
-
clib_memset (pm, 0, sizeof (pm[0]));
pm->vlib_main = vm;
@@ -189,8 +184,11 @@ osi_init (vlib_main_t * vm)
return vlib_call_init_function (vm, osi_input_init);
}
-VLIB_INIT_FUNCTION (osi_init);
-
+/* init order dependency: llc_init -> osi_init -> snap_init*/
+/* Otherwise, osi_input_init will wipe out e.g. the snap init */
+VLIB_INIT_FUNCTION (osi_init) = {
+ .init_order = VLIB_INITS ("llc_init", "osi_init", "snap_init"),
+};
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/osi/osi.h b/src/plugins/osi/osi.h
index fb248ed9cc5..fb248ed9cc5 100644
--- a/src/vnet/osi/osi.h
+++ b/src/plugins/osi/osi.h
diff --git a/src/vnet/osi/pg.c b/src/plugins/osi/pg.c
index c87a869b28d..3bac693c127 100644
--- a/src/vnet/osi/pg.c
+++ b/src/plugins/osi/pg.c
@@ -39,7 +39,7 @@
#include <vlib/vlib.h>
#include <vnet/pg/pg.h>
-#include <vnet/osi/osi.h>
+#include <osi/osi.h>
typedef struct
{
diff --git a/src/plugins/marvell/plugin.c b/src/plugins/osi/plugin.c
index ed90776ba95..5fc412e093e 100644
--- a/src/plugins/marvell/plugin.c
+++ b/src/plugins/osi/plugin.c
@@ -1,6 +1,7 @@
/*
- *------------------------------------------------------------------
- * Copyright (c) 2018 Cisco and/or its affiliates.
+ * plugin.c: osi
+ *
+ * Copyright (c) 2023 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:
@@ -12,22 +13,11 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- *------------------------------------------------------------------
*/
-
#include <vlib/vlib.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
-
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
- .description = "Marvell PP2 Device Driver",
-};
-
-/*
- * fd.io coding-style-patch-verification: ON
- *
- * Local Variables:
- * eval: (c-set-style "gnu")
- * End:
- */
+ .description = "OSI plugin",
+}; \ No newline at end of file
diff --git a/src/plugins/prom/prom.c b/src/plugins/prom/prom.c
index 934e8480d3c..475e98b1038 100644
--- a/src/plugins/prom/prom.c
+++ b/src/plugins/prom/prom.c
@@ -191,6 +191,7 @@ send_data_to_hss (hss_session_handle_t sh)
args.sh = sh;
args.data = vec_dup (pm->stats);
args.data_len = vec_len (pm->stats);
+ args.ct = HTTP_CONTENT_TEXT_PLAIN;
args.sc = HTTP_STATUS_OK;
args.free_vec_data = 1;
@@ -207,7 +208,7 @@ static uword
prom_scraper_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
vlib_frame_t *f)
{
- uword *event_data = 0, event_type;
+ uword *event_data = 0, event_type, *sh_as_uword;
prom_main_t *pm = &prom_main;
hss_session_handle_t sh;
f64 timeout = 10000.0;
@@ -222,12 +223,15 @@ prom_scraper_process (vlib_main_t *vm, vlib_node_runtime_t *rt,
/* timeout, do nothing */
break;
case PROM_SCRAPER_EVT_RUN:
- sh.as_u64 = event_data[0];
vec_reset_length (pm->stats);
pm->stats = scrape_stats_segment (pm->stats, pm->stats_patterns,
pm->used_only);
- session_send_rpc_evt_to_thread_force (sh.thread_index,
- send_data_to_hss_rpc, &sh);
+ vec_foreach (sh_as_uword, event_data)
+ {
+ sh.as_u64 = (u64) *sh_as_uword;
+ session_send_rpc_evt_to_thread_force (
+ sh.thread_index, send_data_to_hss_rpc, sh_as_uword);
+ }
pm->last_scrape = vlib_time_now (vm);
break;
default:
diff --git a/src/plugins/tlsopenssl/tls_openssl.c b/src/plugins/tlsopenssl/tls_openssl.c
index 5d172a0adcf..19aae3ffadc 100644
--- a/src/plugins/tlsopenssl/tls_openssl.c
+++ b/src/plugins/tlsopenssl/tls_openssl.c
@@ -1286,7 +1286,10 @@ tls_openssl_set_command_fn (vlib_main_t * vm, unformat_input_t * input,
}
else
{
- vnet_session_enable_disable (vm, 1);
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
if (openssl_engine_register (engine_name, engine_alg, async) < 0)
{
return clib_error_return (0, "Failed to register %s polling",
diff --git a/src/plugins/unittest/segment_manager_test.c b/src/plugins/unittest/segment_manager_test.c
index a106470ee48..29da662e007 100644
--- a/src/plugins/unittest/segment_manager_test.c
+++ b/src/plugins/unittest/segment_manager_test.c
@@ -739,8 +739,11 @@ segment_manager_test (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd_arg)
{
int res = 0;
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
- vnet_session_enable_disable (vm, 1);
+ vnet_session_enable_disable (vm, &args);
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
diff --git a/src/plugins/unittest/session_test.c b/src/plugins/unittest/session_test.c
index 6d28b2d25ec..a70a6ea88bf 100644
--- a/src/plugins/unittest/session_test.c
+++ b/src/plugins/unittest/session_test.c
@@ -13,13 +13,11 @@
* limitations under the License.
*/
-#include <vnet/session/application_namespace.h>
-#include <vnet/session/application_interface.h>
+#include <arpa/inet.h>
#include <vnet/session/application.h>
#include <vnet/session/session.h>
-#include <vnet/session/session_rules_table.h>
-#include <vnet/tcp/tcp.h>
#include <sys/epoll.h>
+#include <vnet/session/session_rules_table.h>
#define SESSION_TEST_I(_cond, _comment, _args...) \
({ \
@@ -775,10 +773,37 @@ session_test_namespace (vlib_main_t * vm, unformat_input_t * input)
return 0;
}
+static void
+session_test_disable_rt_backend_engine (vlib_main_t *vm)
+{
+ session_enable_disable_args_t args = { .is_en = 0,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_DISABLE };
+ vnet_session_enable_disable (vm, &args);
+}
+
+static void
+session_test_enable_rule_table_engine (vlib_main_t *vm)
+{
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
+}
+
+static void
+session_test_enable_sdl_engine (vlib_main_t *vm)
+{
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_SDL };
+ vnet_session_enable_disable (vm, &args);
+}
+
static int
session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
{
- session_rules_table_t _srt, *srt = &_srt;
+ session_table_t *st = session_table_alloc ();
u16 lcl_port = 1234, rmt_port = 4321;
u32 action_index = 1, res;
ip4_address_t lcl_lkup, rmt_lkup;
@@ -796,8 +821,11 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
}
}
- clib_memset (srt, 0, sizeof (*srt));
- session_rules_table_init (srt);
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_rule_table_engine (vm);
+
+ session_table_init (st, FIB_PROTOCOL_MAX);
+ session_rules_table_init (st, FIB_PROTOCOL_MAX);
ip4_address_t lcl_ip = {
.as_u32 = clib_host_to_net_u32 (0x01020304),
@@ -836,12 +864,13 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
.action_index = action_index++,
.is_add = 1,
};
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/16 1234 5.6.7.8/16 4321 action %d",
action_index - 1);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 1),
"Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 1: %d",
res);
@@ -852,13 +881,15 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl.fp_addr.ip4 = lcl_ip;
args.lcl.fp_len = 24;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/16 4321 action %d",
action_index - 1);
args.rmt.fp_addr.ip4 = rmt_ip;
args.rmt.fp_len = 24;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1234 5.6.7.8/24 4321 action %d",
action_index - 1);
@@ -870,13 +901,15 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.rmt.fp_addr.ip4 = rmt_ip2;
args.rmt.fp_len = 16;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 2.2.2.2/24 1234 6.6.6.6/16 4321 action %d",
action_index - 1);
args.lcl.fp_addr.ip4 = lcl_ip3;
args.rmt.fp_addr.ip4 = rmt_ip3;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 3.3.3.3/24 1234 7.7.7.7/16 4321 action %d",
action_index - 1);
@@ -886,7 +919,8 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl.fp_addr.ip4 = lcl_ip3;
args.rmt.fp_addr.ip4 = rmt_ip3;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "overwrite 3.3.3.3/24 1234 7.7.7.7/16 4321 "
"action %d", action_index - 1);
@@ -894,23 +928,22 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
* Lookup 1.2.3.4/32 1234 5.6.7.8/32 4321, 1.2.2.4/32 1234 5.6.7.9/32 4321
* and 3.3.3.3 1234 7.7.7.7 4321
*/
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 3),
"Lookup 1.2.3.4 1234 5.6.7.8 4321 action " "should be 3: %d",
res);
lcl_lkup.as_u32 = clib_host_to_net_u32 (0x01020204);
rmt_lkup.as_u32 = clib_host_to_net_u32 (0x05060709);
- res =
- session_rules_table_lookup4 (srt, &lcl_lkup,
- &rmt_lkup, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_lkup, &rmt_lkup, lcl_port, rmt_port);
SESSION_TEST ((res == 1),
"Lookup 1.2.2.4 1234 5.6.7.9 4321, action " "should be 1: %d",
res);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip3, &rmt_ip3, lcl_port, rmt_port);
SESSION_TEST ((res == 6),
"Lookup 3.3.3.3 1234 7.7.7.7 4321, action "
"should be 6 (updated): %d", res);
@@ -926,17 +959,17 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl_port = 0;
args.rmt_port = 0;
args.action_index = action_index++;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/24 * 5.6.7.8/24 * action %d",
action_index - 1);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 7),
"Lookup 1.2.3.4 1234 5.6.7.8 4321, action should"
" be 7 (lpm dst): %d", res);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
- lcl_port + 1, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port + 1, rmt_port);
SESSION_TEST ((res == 7),
"Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 7: %d",
res);
@@ -948,7 +981,8 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
* 1.2.3.4 1235 5.6.7.8 4322
*/
args.is_add = 0;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Del 1.2.3.4/24 * 5.6.7.8/24 *");
args.lcl.fp_addr.ip4 = lcl_ip;
@@ -959,7 +993,8 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.rmt_port = 0;
args.action_index = action_index++;
args.is_add = 1;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/16 * 5.6.7.8/16 * action %d",
action_index - 1);
@@ -971,27 +1006,28 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.rmt_port = rmt_port;
args.action_index = action_index++;
args.is_add = 1;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Add 1.2.3.4/24 1235 5.6.7.8/24 4321 action %d",
action_index - 1);
if (verbose)
- session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
+ session_rules_table_cli_dump (vm, st->srtg_handle, TRANSPORT_PROTO_TCP,
+ FIB_PROTOCOL_IP4);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 3),
"Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
res);
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
- lcl_port + 1, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port + 1, rmt_port);
SESSION_TEST ((res == 9),
"Lookup 1.2.3.4 1235 5.6.7.8 4321, action should " "be 9: %d",
res);
res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip,
- lcl_port + 1, rmt_port + 1);
+ session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP, &lcl_ip,
+ &rmt_ip, lcl_port + 1, rmt_port + 1);
SESSION_TEST ((res == 8),
"Lookup 1.2.3.4 1235 5.6.7.8 4322, action should " "be 8: %d",
res);
@@ -1005,10 +1041,11 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl.fp_len = 16;
args.rmt.fp_len = 16;
args.is_add = 0;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Del 1.2.0.0/16 1234 5.6.0.0/16 4321");
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 3),
"Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
res);
@@ -1016,10 +1053,11 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl_port = 0;
args.rmt_port = 0;
args.is_add = 0;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Del 1.2.0.0/16 * 5.6.0.0/16 *");
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 3),
"Lookup 1.2.3.4 1234 5.6.7.8 4321, action should " "be 3: %d",
res);
@@ -1034,12 +1072,15 @@ session_test_rule_table (vlib_main_t * vm, unformat_input_t * input)
args.lcl_port = 1234;
args.rmt_port = 4321;
args.is_add = 0;
- error = session_rules_table_add_del (srt, &args);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
SESSION_TEST ((error == 0), "Del 1.2.3.4/24 1234 5.6.7.5/24");
- res =
- session_rules_table_lookup4 (srt, &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
SESSION_TEST ((res == 2), "Action should be 2: %d", res);
+ session_table_free (st, FIB_PROTOCOL_MAX);
+
return 0;
}
@@ -1075,6 +1116,9 @@ session_test_rules (vlib_main_t * vm, unformat_input_t * input)
}
}
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_rule_table_engine (vm);
+
server_sep.is_ip4 = 1;
server_sep.port = placeholder_port;
clib_memset (options, 0, sizeof (options));
@@ -2115,15 +2159,19 @@ session_test_enable_disable (vlib_main_t *vm, unformat_input_t *input)
/* warm up */
for (i = 0; i < 10; i++)
{
- vnet_session_enable_disable (vm, 0);
- vnet_session_enable_disable (vm, 1);
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_sdl_engine (vm);
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_rule_table_engine (vm);
}
was_using = session_get_memory_usage ();
for (i = 0; i < iteration; i++)
{
- vnet_session_enable_disable (vm, 0);
- vnet_session_enable_disable (vm, 1);
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_sdl_engine (vm);
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_rule_table_engine (vm);
}
now_using = session_get_memory_usage ();
@@ -2134,13 +2182,220 @@ session_test_enable_disable (vlib_main_t *vm, unformat_input_t *input)
return 0;
}
+static int
+session_test_sdl (vlib_main_t *vm, unformat_input_t *input)
+{
+ session_table_t *st = session_table_alloc ();
+ u16 lcl_port = 0, rmt_port = 0;
+ u32 action_index = 1, res;
+ int verbose = 0, error;
+ ip4_address_t lcl_ip;
+ const char ip_str_1234[] = "1.2.3.4";
+ inet_pton (AF_INET, ip_str_1234, &lcl_ip);
+ ip4_address_t rmt_ip = {
+ .as_u32 = clib_host_to_net_u32 (0x0),
+ };
+ ip6_address_t rmt_ip6 = {
+ .as_u64 = { 0, 0 },
+ };
+ fib_prefix_t lcl_pref = {
+ .fp_addr.ip4.as_u32 = lcl_ip.as_u32,
+ .fp_len = 16,
+ .fp_proto = FIB_PROTOCOL_IP4,
+ };
+ fib_prefix_t rmt_pref = {
+ .fp_addr.ip4.as_u32 = rmt_ip.as_u32,
+ .fp_len = 0,
+ .fp_proto = 0,
+ };
+ session_rule_table_add_del_args_t args = {
+ .lcl = lcl_pref,
+ .rmt = rmt_pref,
+ .lcl_port = lcl_port,
+ .rmt_port = rmt_port,
+ .action_index = action_index++,
+ .is_add = 1,
+ };
+ const char ip_str_1200[] = "1.2.0.0";
+ const char ip_str_1230[] = "1.2.3.0";
+ const char ip_str_1111[] = "1.1.1.1";
+ const char ip6_str[] = "2501:0db8:85a3:0000:0000:8a2e:0371:1";
+ const char ip6_str2[] = "2501:0db8:85a3:0000:0000:8a2e:0372:1";
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "verbose"))
+ verbose = 1;
+ else
+ {
+ vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
+ input);
+ return -1;
+ }
+ }
+
+ session_test_disable_rt_backend_engine (vm);
+ session_test_enable_sdl_engine (vm);
+
+ session_table_init (st, FIB_PROTOCOL_MAX);
+ session_rules_table_init (st, FIB_PROTOCOL_MAX);
+
+ /* Add 1.2.0.0/16 */
+ args.lcl.fp_len = 16;
+ inet_pton (AF_INET, ip_str_1200, &args.lcl.fp_addr.ip4.as_u32);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "Add %s/%d action %d", ip_str_1200,
+ args.lcl.fp_len, action_index - 1);
+
+ /* Lookup 1.2.3.4 */
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ SESSION_TEST ((res == action_index - 1),
+ "Lookup %s, action should "
+ "be 1: %d",
+ ip_str_1234, action_index - 1);
+
+ /*
+ * Add 1.2.3.0/24
+ */
+ args.lcl.fp_len = 24;
+ inet_pton (AF_INET, ip_str_1230, &args.lcl.fp_addr.ip4.as_u32);
+ args.action_index = action_index++;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "Add %s/%d action %d", ip_str_1230,
+ args.lcl.fp_len, action_index - 1);
+
+ /* Lookup 1.2.3.4 */
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ SESSION_TEST ((res == action_index - 1),
+ "Lookup %s, action should "
+ "be 2: %d",
+ ip_str_1234, action_index - 1);
+
+ /* look up 1.1.1.1, should be -1 (invalid index) */
+ inet_pton (AF_INET, ip_str_1111, &lcl_ip);
+ res = session_rules_table_lookup4 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_ip, &rmt_ip, lcl_port, rmt_port);
+ SESSION_TEST ((res == SESSION_TABLE_INVALID_INDEX),
+ "Lookup %s, action should "
+ "be -1: %d",
+ ip_str_1111, res);
+
+ /* Add again 1.2.0.0/16, should be rejected */
+ args.lcl.fp_len = 16;
+ inet_pton (AF_INET, ip_str_1200, &args.lcl.fp_addr.ip4.as_u32);
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == SESSION_E_IPINUSE), "Add %s/%d action %d",
+ ip_str_1200, args.lcl.fp_len, error);
+ /*
+ * Add 0.0.0.0/0, should get an error
+ */
+ args.lcl.fp_len = 0;
+ args.lcl.fp_addr.ip4.as_u32 = 0;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == SESSION_E_IPINUSE), "Add 0.0.0.0/%d action %d",
+ args.lcl.fp_len, error);
+
+ /* delete 0.0.0.0 should be rejected */
+ args.is_add = 0;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == SESSION_E_NOROUTE), "Del 0.0.0.0/%d action %d",
+ args.lcl.fp_len, error);
+ if (verbose)
+ session_rules_table_cli_dump (vm, st->srtg_handle, TRANSPORT_PROTO_TCP,
+ FIB_PROTOCOL_IP4);
+
+ /*
+ * Clean up
+ * Delete 1.2.0.0/16
+ * Delete 1.2.3.0/24
+ */
+ inet_pton (AF_INET, ip_str_1200, &args.lcl.fp_addr.ip4.as_u32);
+ args.lcl.fp_len = 16;
+ args.is_add = 0;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "Del %s/%d should 0: %d", ip_str_1200,
+ args.lcl.fp_len, error);
+
+ inet_pton (AF_INET, ip_str_1230, &args.lcl.fp_addr.ip4.as_u32);
+ args.lcl.fp_len = 24;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "Del %s/%d, should be 0: %d", ip_str_1230,
+ args.lcl.fp_len, error);
+ if (verbose)
+ session_rules_table_cli_dump (vm, st->srtg_handle, TRANSPORT_PROTO_TCP,
+ FIB_PROTOCOL_IP4);
+
+ /* ip6 tests */
+
+ /*
+ * Add ip6 2001:0db8:85a3:0000:0000:8a2e:0371:1/124
+ */
+ ip6_address_t lcl_lkup;
+ inet_pton (AF_INET6, ip6_str, &args.lcl.fp_addr.ip6);
+ args.lcl.fp_len = 124;
+ args.lcl.fp_proto = FIB_PROTOCOL_IP6;
+ args.action_index = action_index++;
+ args.is_add = 1;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "Add %s/%d action %d", ip6_str, args.lcl.fp_len,
+ action_index - 1);
+ if (verbose)
+ session_rules_table_cli_dump (vm, st->srtg_handle, TRANSPORT_PROTO_TCP,
+ FIB_PROTOCOL_IP6);
+
+ /* Lookup 2001:0db8:85a3:0000:0000:8a2e:0371:1 */
+ res = session_rules_table_lookup6 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &args.lcl.fp_addr.ip6, &rmt_ip6, lcl_port,
+ rmt_port);
+ SESSION_TEST ((res == action_index - 1),
+ "Lookup %s action should "
+ "be 3: %d",
+ ip6_str, action_index - 1);
+
+ /* Lookup 2001:0db8:85a3:0000:0000:8a2e:0372:1 */
+ inet_pton (AF_INET6, ip6_str2, &lcl_lkup);
+ res = session_rules_table_lookup6 (st->srtg_handle, TRANSPORT_PROTO_TCP,
+ &lcl_lkup, &rmt_ip6, lcl_port, rmt_port);
+ SESSION_TEST ((res == SESSION_TABLE_INVALID_INDEX),
+ "Lookup %s action should "
+ "be -1: %d",
+ ip6_str2, res);
+
+ /*
+ * del ip6 2001:0db8:85a3:0000:0000:8a2e:0371:1/124
+ */
+ args.is_add = 0;
+ args.lcl.fp_len = 124;
+ error =
+ session_rules_table_add_del (st->srtg_handle, TRANSPORT_PROTO_TCP, &args);
+ SESSION_TEST ((error == 0), "del %s/%d, should be 0: %d", ip6_str,
+ args.lcl.fp_len, error);
+ if (verbose)
+ session_rules_table_cli_dump (vm, st->srtg_handle, TRANSPORT_PROTO_TCP,
+ FIB_PROTOCOL_IP6);
+
+ session_table_free (st, FIB_PROTOCOL_MAX);
+
+ return 0;
+}
+
static clib_error_t *
session_test (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd_arg)
{
int res = 0;
- vnet_session_enable_disable (vm, 1);
+ session_test_enable_rule_table_engine (vm);
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
@@ -2162,6 +2417,8 @@ session_test (vlib_main_t * vm,
res = session_test_mq_basic (vm, input);
else if (unformat (input, "enable-disable"))
res = session_test_enable_disable (vm, input);
+ else if (unformat (input, "sdl"))
+ res = session_test_sdl (vm, input);
else if (unformat (input, "all"))
{
if ((res = session_test_basic (vm, input)))
@@ -2180,6 +2437,8 @@ session_test (vlib_main_t * vm,
goto done;
if ((res = session_test_mq_basic (vm, input)))
goto done;
+ if ((res = session_test_sdl (vm, input)))
+ goto done;
if ((res = session_test_enable_disable (vm, input)))
goto done;
}
diff --git a/src/plugins/unittest/tcp_test.c b/src/plugins/unittest/tcp_test.c
index 34033a0b622..bd39474ce93 100644
--- a/src/plugins/unittest/tcp_test.c
+++ b/src/plugins/unittest/tcp_test.c
@@ -1550,8 +1550,11 @@ tcp_test (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd_arg)
{
int res = 0;
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
- vnet_session_enable_disable (vm, 1);
+ vnet_session_enable_disable (vm, &args);
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
diff --git a/src/plugins/unittest/util_test.c b/src/plugins/unittest/util_test.c
index 53384e55494..5b7e30bc21f 100644
--- a/src/plugins/unittest/util_test.c
+++ b/src/plugins/unittest/util_test.c
@@ -101,6 +101,36 @@ VLIB_CLI_COMMAND (test_hash_command, static) =
.function = test_hash_command_fn,
};
+static void *
+leak_memory_fn (void *args)
+{
+ u8 *p = 0;
+ vec_validate (p, 100);
+ p = 0;
+ return 0;
+}
+
+static clib_error_t *
+test_mem_leak_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ /* do memory leak from thread, so no 'unix_cli' in traceback */
+ pthread_t thread;
+ int rv = pthread_create (&thread, NULL, leak_memory_fn, 0);
+ if (rv)
+ {
+ return clib_error_return (0, "pthread_create failed");
+ }
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (test_mem_leak_command, static) = {
+ .path = "test mem-leak",
+ .short_help = "leak some memory",
+ .function = test_mem_leak_command_fn,
+};
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/svm/svmdb.c b/src/svm/svmdb.c
index 3c69dbf45ba..98bb96f3dd4 100644
--- a/src/svm/svmdb.c
+++ b/src/svm/svmdb.c
@@ -436,7 +436,7 @@ svmdb_local_serialize_strings (svmdb_client_t * client, char *filename)
u8 *sanitized_name = 0;
int fd = 0;
- if (strstr (filename, "..") || index (filename, '/'))
+ if (strstr (filename, "..") || strchr (filename, '/'))
{
error = clib_error_return (0, "Illegal characters in filename '%s'",
filename);
diff --git a/src/tools/vppapigen/vppapigen_c.py b/src/tools/vppapigen/vppapigen_c.py
index c2e1e7da7b7..3cd52df1ad0 100755
--- a/src/tools/vppapigen/vppapigen_c.py
+++ b/src/tools/vppapigen/vppapigen_c.py
@@ -171,14 +171,10 @@ class ToJSON:
write(" {\n")
# What is length field doing here?
write(
- ' u8 *s = format(0, "0x%U", format_hex_bytes, '
+ ' char *s = format_c_string(0, "0x%U", format_hex_bytes_no_wrap, '
"&a->{n}, {lfield});\n".format(n=o.fieldname, lfield=lfield)
)
- write(
- ' cJSON_AddStringToObject(o, "{n}", (char *)s);\n'.format(
- n=o.fieldname
- )
- )
+ write(' cJSON_AddStringToObject(o, "{n}", s);\n'.format(n=o.fieldname))
write(" vec_free(s);\n")
write(" }\n")
return
@@ -275,8 +271,12 @@ class ToJSON:
"(vl_api_{name}_t *a) {{\n".format(name=o.name)
)
- write(' u8 *s = format(0, "%U", format_vl_api_{}_t, a);\n'.format(o.name))
- write(" cJSON *o = cJSON_CreateString((char *)s);\n")
+ write(
+ ' char *s = format_c_string(0, "%U", format_vl_api_{}_t, a);\n'.format(
+ o.name
+ )
+ )
+ write(" cJSON *o = cJSON_CreateString(s);\n")
write(" vec_free(s);\n")
write(" return o;\n")
write("}\n")
@@ -1143,12 +1143,20 @@ ENDIAN_STRINGS = {
}
-def get_endian_string(o, fieldtype):
+def get_endian_string(fieldtype):
"""Return proper endian string conversion function"""
return ENDIAN_STRINGS[fieldtype]
-def endianfun_array(o):
+def get_lengthfield_type(fieldname, block):
+ """Return the type of the length field"""
+ for o in block:
+ if o.fieldname == fieldname:
+ return o.fieldtype
+ return None
+
+
+def endianfun_array(o, block):
"""Generate endian functions for arrays"""
forloop = """\
ASSERT((u32){length} <= (u32)VL_API_MAX_ARRAY_SIZE);
@@ -1167,12 +1175,16 @@ def endianfun_array(o):
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
+ # 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"
- )
+ fieldtype = get_lengthfield_type(o.lengthfield, block)
+ if fieldtype == "u8":
+ output += f" u32 count = a->{o.lengthfield};\n"
+ else:
+ output += (
+ f" u32 count = to_net ? {get_endian_string(fieldtype)}(a->{o.lengthfield}) : "
+ f"a->{o.lengthfield};\n"
+ )
lfield = "count"
else:
lfield = o.length
@@ -1180,7 +1192,7 @@ def endianfun_array(o):
if o.fieldtype in ENDIAN_STRINGS:
output += forloop.format(
length=lfield,
- format=get_endian_string(o, o.fieldtype),
+ format=get_endian_string(o.fieldtype),
name=o.fieldname,
)
else:
@@ -1193,11 +1205,11 @@ def endianfun_array(o):
NO_ENDIAN_CONVERSION = {"client_index": None}
-def endianfun_obj(o):
+def endianfun_obj(o, block):
"""Generate endian conversion function for type"""
output = ""
if o.type == "Array":
- return endianfun_array(o)
+ return endianfun_array(o, block)
if o.type != "Field":
output += ' s = format(s, "\\n{} {} {} (print not implemented");\n'.format(
o.type, o.fieldtype, o.fieldname
@@ -1208,7 +1220,7 @@ def endianfun_obj(o):
return output
if o.fieldtype in ENDIAN_STRINGS:
output += " a->{name} = {format}(a->{name});\n".format(
- name=o.fieldname, format=get_endian_string(o, o.fieldtype)
+ name=o.fieldname, format=get_endian_string(o.fieldtype)
)
elif o.fieldtype.startswith("vl_api_"):
output += " {type}_endian(&a->{name}, to_net);\n".format(
@@ -1252,7 +1264,7 @@ static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a, bool to_net)
if t.__class__.__name__ == "Enum" or t.__class__.__name__ == "EnumFlag":
output += signature.format(name=t.name)
if t.enumtype in ENDIAN_STRINGS:
- output += " *a = {}(*a);\n".format(get_endian_string(t, t.enumtype))
+ output += " *a = {}(*a);\n".format(get_endian_string(t.enumtype))
else:
output += " /* a->{name} = a->{name} (no-op) */\n".format(
name=t.name
@@ -1273,7 +1285,7 @@ static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a, bool to_net)
)
elif t.alias["type"] in FORMAT_STRINGS:
output += " *a = {}(*a);\n".format(
- get_endian_string(t, t.alias["type"])
+ get_endian_string(t.alias["type"])
)
else:
output += " /* Not Implemented yet {} */".format(t.name)
@@ -1283,7 +1295,7 @@ static inline void vl_api_{name}_t_endian (vl_api_{name}_t *a, bool to_net)
output += signature.format(name=t.name)
for o in t.block:
- output += endianfun_obj(o)
+ output += endianfun_obj(o, t.block)
output += "}\n\n"
output += "\n#endif"
@@ -1349,7 +1361,7 @@ static inline uword vl_api_{name}_t_calc_size (vl_api_{name}_t *a)
)
lf = m[0]
if lf.fieldtype in ENDIAN_STRINGS:
- output += f" + {get_endian_string(b, lf.fieldtype)}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
+ output += f" + {get_endian_string(lf.fieldtype)}(a->{b.lengthfield}) * sizeof(a->{b.fieldname}[0])"
elif lf.fieldtype == "u8":
output += (
f" + a->{b.lengthfield} * sizeof(a->{b.fieldname}[0])"
diff --git a/src/vat/api_format.c b/src/vat/api_format.c
index 45ba025f191..48c1ccaa820 100644
--- a/src/vat/api_format.c
+++ b/src/vat/api_format.c
@@ -2151,7 +2151,7 @@ elog_save (vat_main_t * vam)
}
/* It's fairly hard to get "../oopsie" through unformat; just in case */
- if (strstr (file, "..") || index (file, '/'))
+ if (strstr (file, "..") || strchr (file, '/'))
{
errmsg ("illegal characters in filename '%s'", file);
return 0;
diff --git a/src/vcl/vcl_locked.c b/src/vcl/vcl_locked.c
index 69dd15b0ef4..93ece0027ff 100644
--- a/src/vcl/vcl_locked.c
+++ b/src/vcl/vcl_locked.c
@@ -374,6 +374,12 @@ vls_worker_get_current (void)
return pool_elt_at_index (vlsm->workers, vls_get_worker_index ());
}
+static inline u8
+vls_n_workers (void)
+{
+ return pool_elts (vlsm->workers);
+}
+
static void
vls_worker_alloc (void)
{
@@ -1298,7 +1304,7 @@ vls_mp_checks (vcl_locked_session_t * vls, int is_add)
vcl_session_t *s;
u32 owner_wrk;
- if (vls_mt_wrk_supported ())
+ if (vls_mt_wrk_supported () && vls_n_workers () <= 1)
return;
ASSERT (wrk->wrk_index == vls->vcl_wrk_index);
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index a557093e897..5408fb79186 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -2345,6 +2345,75 @@ vppcom_session_write_inline (vcl_worker_t *wrk, vcl_session_t *s, void *buf,
}
int
+vppcom_session_write_segments (uint32_t session_handle,
+ vppcom_data_segment_t *ds, uint32_t n_segments)
+{
+ vcl_worker_t *wrk = vcl_worker_get_current ();
+ int n_write = 0, n_bytes = 0, is_nonblocking;
+ vcl_session_t *s = 0;
+ svm_fifo_t *tx_fifo;
+ svm_msg_q_t *mq;
+ u8 is_ct;
+ u32 i;
+
+ if (PREDICT_FALSE (!ds))
+ return VPPCOM_EFAULT;
+
+ /* Accept zero length writes but just return */
+ if (PREDICT_FALSE (ds[0].len == 0))
+ return VPPCOM_OK;
+
+ s = vcl_session_get_w_handle (wrk, session_handle);
+ if (PREDICT_FALSE (!s || (s->flags & VCL_SESSION_F_IS_VEP)))
+ return VPPCOM_EBADFD;
+
+ if (PREDICT_FALSE (!vcl_session_is_open (s)))
+ return vcl_session_closed_error (s);
+
+ if (PREDICT_FALSE (s->flags & VCL_SESSION_F_WR_SHUTDOWN))
+ return VPPCOM_EPIPE;
+
+ is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
+ is_ct = vcl_session_is_ct (s);
+ mq = wrk->app_event_queue;
+ tx_fifo = is_ct ? s->ct_tx_fifo : s->tx_fifo;
+
+ for (i = 0; i < n_segments; i++)
+ n_bytes += ds[i].len;
+
+ if (svm_fifo_max_enqueue_prod (tx_fifo) < n_bytes)
+ {
+ if (is_nonblocking)
+ {
+ return VPPCOM_EWOULDBLOCK;
+ }
+ while (svm_fifo_max_enqueue_prod (tx_fifo) < n_bytes)
+ {
+ svm_fifo_add_want_deq_ntf (tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
+ if (vcl_session_is_closing (s))
+ return vcl_session_closing_error (s);
+
+ svm_msg_q_wait (mq, SVM_MQ_WAIT_EMPTY);
+ vcl_worker_flush_mq_events (wrk);
+ }
+ }
+
+ n_write = svm_fifo_enqueue_segments (tx_fifo, (svm_fifo_seg_t *) ds,
+ n_segments, 0 /* allow_partial */);
+
+ /* The underlying fifo segment can run out of memory */
+ if (PREDICT_FALSE (n_write < 0))
+ return VPPCOM_EAGAIN;
+
+ if (svm_fifo_set_event (s->tx_fifo))
+ app_send_io_evt_to_vpp (s->vpp_evt_q,
+ s->tx_fifo->shr->master_session_index,
+ SESSION_IO_EVT_TX, SVM_Q_WAIT);
+
+ return n_write;
+}
+
+int
vppcom_session_write (uint32_t session_handle, void *buf, size_t n)
{
vcl_worker_t *wrk = vcl_worker_get_current ();
@@ -2619,6 +2688,7 @@ vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits,
vcl_mq_evt_conn_t *mqc;
int __clib_unused n_read;
int n_mq_evts, i;
+ double end = -1;
u64 buf;
if (PREDICT_FALSE (wrk->api_client_handle == ~0))
@@ -2628,23 +2698,45 @@ vppcom_select_eventfd (vcl_worker_t * wrk, int n_bits,
}
vec_validate (wrk->mq_events, pool_elts (wrk->mq_evt_conns));
- n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
- vec_len (wrk->mq_events), time_to_wait);
- for (i = 0; i < n_mq_evts; i++)
+ if (time_to_wait > 0)
+ end = clib_time_now (&wrk->clib_time) + (time_to_wait / 1e3);
+
+ do
{
- if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0))
+ n_mq_evts = epoll_wait (wrk->mqs_epfd, wrk->mq_events,
+ vec_len (wrk->mq_events), time_to_wait);
+ if (n_mq_evts < 0)
{
- vcl_api_handle_disconnect (wrk);
- continue;
+ if (errno == EINTR)
+ continue;
+
+ VDBG (0, "epoll_wait error %u", errno);
+ return 0;
+ }
+
+ if (n_mq_evts == 0)
+ return 0;
+
+ for (i = 0; i < n_mq_evts; i++)
+ {
+ if (PREDICT_FALSE (wrk->mq_events[i].data.u32 == ~0))
+ {
+ vcl_api_handle_disconnect (wrk);
+ continue;
+ }
+
+ mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
+ n_read = read (mqc->mq_fd, &buf, sizeof (buf));
+ vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map,
+ except_map, 0, bits_set);
}
- mqc = vcl_mq_evt_conn_get (wrk, wrk->mq_events[i].data.u32);
- n_read = read (mqc->mq_fd, &buf, sizeof (buf));
- vcl_select_handle_mq (wrk, mqc->mq, n_bits, read_map, write_map,
- except_map, 0, bits_set);
+ if (*bits_set || !time_to_wait)
+ return (int) *bits_set;
}
+ while (end == -1 || clib_time_now (&wrk->clib_time) < end);
- return (n_mq_evts > 0 ? (int) *bits_set : 0);
+ return 0;
}
int
@@ -3407,6 +3499,9 @@ vppcom_epoll_wait_eventfd (vcl_worker_t *wrk, struct epoll_event *events,
vec_len (wrk->mq_events), timeout_ms);
if (n_mq_evts < 0)
{
+ if (errno == EINTR)
+ continue;
+
VDBG (0, "epoll_wait error %u", errno);
return n_evts;
}
diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h
index 386d7d0c3f7..3de2934adc1 100644
--- a/src/vcl/vppcom.h
+++ b/src/vcl/vppcom.h
@@ -259,6 +259,9 @@ extern int vppcom_session_read_segments (uint32_t session_handle,
vppcom_data_segment_t * ds,
uint32_t n_segments,
uint32_t max_bytes);
+extern int vppcom_session_write_segments (uint32_t session_handle,
+ vppcom_data_segment_t * ds,
+ uint32_t n_segments);
extern void vppcom_session_free_segments (uint32_t session_handle,
uint32_t n_bytes);
extern int vppcom_add_cert_key_pair (vppcom_cert_key_pair_t *ckpair);
diff --git a/src/vlib/buffer.c b/src/vlib/buffer.c
index 5ba42270b1a..a7952d93c21 100644
--- a/src/vlib/buffer.c
+++ b/src/vlib/buffer.c
@@ -663,6 +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 default_buffers_per_numa = bm->default_buffers_per_numa;
u32 buffers_per_numa = bm->buffers_per_numa[numa_node];
clib_error_t *error;
u32 buffer_size;
@@ -679,12 +680,13 @@ vlib_buffer_main_init_numa_alloc (struct vlib_main_t *vm, u32 numa_node,
return clib_error_return (0, "buffer size (%llu) is greater than page "
"size (%llu)", buffer_size, pagesize);
- if (buffers_per_numa == 0)
- buffers_per_numa = bm->default_buffers_per_numa;
+ if (default_buffers_per_numa == 0)
+ default_buffers_per_numa = unpriv ?
+ VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA_UNPRIV :
+ VLIB_BUFFER_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;
+ if (buffers_per_numa == ~0)
+ buffers_per_numa = default_buffers_per_numa;
name = format (0, "buffers-numa-%d%c", numa_node, 0);
n_pages = (buffers_per_numa - 1) / (pagesize / buffer_size) + 1;
@@ -824,7 +826,7 @@ clib_error_t *
vlib_buffer_main_init (struct vlib_main_t * vm)
{
vlib_buffer_main_t *bm;
- clib_error_t *err;
+ clib_error_t *err = 0;
clib_bitmap_t *bmp = 0, *bmp_has_memory = 0;
u32 numa_node;
vlib_buffer_pool_t *bp;
@@ -856,6 +858,10 @@ vlib_buffer_main_init (struct vlib_main_t * vm)
{
u8 *index = bm->default_buffer_pool_index_for_numa + numa_node;
index[0] = ~0;
+
+ if (bm->buffers_per_numa[numa_node] == 0)
+ continue;
+
if ((err = vlib_buffer_main_init_numa_node (vm, numa_node, index)))
{
clib_error_report (err);
@@ -912,7 +918,7 @@ static clib_error_t *
vlib_buffers_numa_configure (vlib_buffer_main_t *bm, u32 numa_node,
unformat_input_t *input)
{
- u32 buffers = 0;
+ u32 buffers = ~0;
if (numa_node >= VLIB_BUFFER_MAX_NUMA_NODES)
return clib_error_return (0, "invalid numa node");
@@ -945,7 +951,7 @@ vlib_buffers_configure (vlib_main_t * vm, unformat_input_t * input)
bm = vm->buffer_main;
bm->log2_page_size = CLIB_MEM_PAGE_SZ_UNKNOWN;
- memset (bm->buffers_per_numa, 0, sizeof (bm->buffers_per_numa));
+ memset (bm->buffers_per_numa, ~0, sizeof (bm->buffers_per_numa));
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
diff --git a/src/vlib/cli.c b/src/vlib/cli.c
index 98d57c6ccb0..4198b4b0976 100644
--- a/src/vlib/cli.c
+++ b/src/vlib/cli.c
@@ -43,6 +43,7 @@
#include <vppinfra/callback.h>
#include <vppinfra/cpu.h>
#include <vppinfra/elog.h>
+#include <vppinfra/cJSON.h>
#include <unistd.h>
#include <ctype.h>
@@ -1115,6 +1116,111 @@ VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
};
static clib_error_t *
+save_memory_trace (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ char *file, *chroot_file;
+ uword was_enabled;
+ mheap_trace_t *t, *mem_traces = 0;
+ u8 *tmp;
+ cJSON *traces, *trace, *traceback, *symbol;
+ int i;
+ FILE *fp;
+ char *json_str = 0;
+
+ cJSON_Hooks cjson_hooks = {
+ .malloc_fn = clib_mem_alloc,
+ .free_fn = clib_mem_free,
+ .realloc_fn = clib_mem_realloc,
+ };
+ cJSON_InitHooks (&cjson_hooks);
+
+ if (!unformat (input, "%s", &file))
+ {
+ vlib_cli_output (vm, "expected file name, got `%U'",
+ format_unformat_error, input);
+ return 0;
+ }
+
+ /* It's fairly hard to get "../oopsie" through unformat; just in case */
+ if (strstr (file, "..") || strchr (file, '/'))
+ {
+ vlib_cli_output (vm, "illegal characters in filename '%s'", file);
+ return 0;
+ }
+ chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
+ vec_free (file);
+ fp = fopen ((char *) chroot_file, "w");
+ if (fp == NULL)
+ {
+ vlib_cli_output (vm, "couldn't open output file %s '%s'", chroot_file);
+ vec_free (chroot_file);
+ return 0;
+ }
+
+ was_enabled = clib_mem_trace_enable_disable (0);
+ vlib_cli_output (vm, "Saving trace to '%s'", chroot_file);
+ mem_traces = clib_mem_trace_dup (current_traced_heap);
+ traces = cJSON_CreateArray ();
+ vec_foreach (t, mem_traces)
+ {
+ /* Skip over free elements. */
+ if (t->n_allocations == 0)
+ continue;
+
+ trace = cJSON_CreateObject ();
+ cJSON_AddNumberToObject (trace, "count", t->n_allocations);
+ cJSON_AddNumberToObject (trace, "bytes", t->n_bytes);
+ tmp = format (0, "%p%c", t->offset, 0);
+ cJSON_AddStringToObject (trace, "sample", (char *) tmp);
+ vec_free (tmp);
+ traceback = cJSON_AddArrayToObject (trace, "traceback");
+ for (i = 0; i < ARRAY_LEN (t->callers) && t->callers[i]; i++)
+ {
+#if defined(CLIB_UNIX) && !defined(__APPLE__)
+ tmp = format (0, "%U%c\n", format_clib_elf_symbol_with_address,
+ t->callers[i], 0);
+ symbol = cJSON_CreateString ((char *) tmp);
+ cJSON_AddItemToArray (traceback, symbol);
+ vec_free (tmp);
+#else
+ tmp = format (0, "%p%c\n", t->callers[i], 0);
+ symbol = cJSON_CreateString ((char *) tmp);
+ cJSON_AddItemToArray (traceback, symbol);
+ vec_free (tmp);
+#endif
+ }
+
+ cJSON_AddItemToArray (traces, trace);
+ }
+ json_str = cJSON_PrintUnformatted (traces);
+ cJSON_Delete (traces);
+ fputs (json_str, fp);
+ fclose (fp);
+ clib_mem_free (json_str);
+
+ vec_free (mem_traces);
+ clib_mem_trace_enable_disable (was_enabled);
+
+ vec_free (chroot_file);
+
+ return 0;
+}
+
+/*?
+ * Save memory traces of the currently traced heap in JSON format to file.
+ * Only filename can be specified, path is fixed (/tmp/<filename>).
+ *
+ * @cliexpar
+ * @cliexcmd{save memory-trace mem_trace.json}
+?*/
+VLIB_CLI_COMMAND (save_memory_trace_command, static) = {
+ .path = "save memory-trace",
+ .short_help = "save memory-trace <filename>",
+ .function = save_memory_trace,
+};
+
+static clib_error_t *
restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
diff --git a/src/vlib/format.c b/src/vlib/format.c
index 7de6417be69..98010620a5d 100644
--- a/src/vlib/format.c
+++ b/src/vlib/format.c
@@ -198,7 +198,7 @@ unformat_vlib_tmpfile (unformat_input_t * input, va_list * args)
return 0;
/* Brain-police user path input */
- if (strstr ((char *) filename, "..") || index ((char *) filename, '/'))
+ if (strstr ((char *) filename, "..") || strchr ((char *) filename, '/'))
{
vec_free (filename);
return 0;
diff --git a/src/vlib/main.c b/src/vlib/main.c
index 04b58762646..bf840324b64 100644
--- a/src/vlib/main.c
+++ b/src/vlib/main.c
@@ -569,6 +569,9 @@ vlib_node_sync_stats (vlib_main_t * vm, vlib_node_t * n)
uword i;
for (i = 0; i < rt->n_next_nodes; i++)
{
+ if (n->flags & VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES &&
+ n->next_nodes[i] == VLIB_INVALID_NODE_INDEX)
+ continue;
nf = vlib_node_runtime_get_next_frame (vm, rt, i);
vec_elt (n->n_vectors_by_next_node, i) +=
nf->vectors_since_last_overflow;
@@ -655,7 +658,7 @@ elog_save_buffer (vlib_main_t * vm,
}
/* It's fairly hard to get "../oopsie" through unformat; just in case */
- if (strstr (file, "..") || index (file, '/'))
+ if (strstr (file, "..") || strchr (file, '/'))
{
vlib_cli_output (vm, "illegal characters in filename '%s'", file);
return 0;
diff --git a/src/vlib/node.c b/src/vlib/node.c
index 8f6c852188b..c0572f3cf83 100644
--- a/src/vlib/node.c
+++ b/src/vlib/node.c
@@ -805,7 +805,8 @@ vlib_node_main_init (vlib_main_t * vm)
if (!a)
continue;
- if (~0 == vlib_node_add_named_next_with_slot (vm, n->index, a, i))
+ if (~0 == vlib_node_add_named_next_with_slot (vm, n->index, a, i) &&
+ !(n->flags & VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES))
{
error = clib_error_create
("node `%v' refers to unknown node `%s'", n->name, a);
@@ -813,7 +814,8 @@ vlib_node_main_init (vlib_main_t * vm)
}
}
- vec_free (n->next_node_names);
+ if (!(n->flags & VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES))
+ vec_free (n->next_node_names);
}
/* Set previous node pointers. */
@@ -851,14 +853,18 @@ vlib_node_main_init (vlib_main_t * vm)
for (i = 0; i < vec_len (n->next_nodes); i++)
{
- next = vlib_get_node (vm, n->next_nodes[i]);
+ if (n->flags & VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES &&
+ n->next_nodes[i] >= vec_len (nm->nodes))
+ continue;
- /* Validate node runtime indices are correctly initialized. */
- ASSERT (nf[i].node_runtime_index == next->runtime_index);
+ next = vlib_get_node (vm, n->next_nodes[i]);
- nf[i].flags = 0;
- if (next->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH)
- nf[i].flags |= VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
+ /* Validate node runtime indices are correctly initialized. */
+ ASSERT (nf[i].node_runtime_index == next->runtime_index);
+
+ nf[i].flags = 0;
+ if (next->flags & VLIB_NODE_FLAG_FRAME_NO_FREE_AFTER_DISPATCH)
+ nf[i].flags |= VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
}
}
}
@@ -927,6 +933,33 @@ vlib_node_set_march_variant (vlib_main_t *vm, u32 node_index,
}
return -1;
}
+
+clib_error_t *
+vlib_node_main_lazy_next_update (vlib_main_t *vm)
+{
+ vlib_node_main_t *nm = &vm->node_main;
+ uword ni;
+ vlib_node_t *n;
+ for (ni = 0; ni < vec_len (nm->nodes); ni++)
+ {
+ uword nni;
+ n = vec_elt (nm->nodes, ni);
+
+ if (!(n->flags & VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES))
+ continue;
+
+ for (nni = 0; nni < vec_len (n->next_node_names); nni++)
+ {
+ char *a = n->next_node_names[nni];
+
+ if (!a)
+ continue;
+
+ vlib_node_add_named_next_with_slot (vm, n->index, a, nni);
+ }
+ }
+ return 0;
+}
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vlib/node.h b/src/vlib/node.h
index 68813c2c3e1..651a39e3119 100644
--- a/src/vlib/node.h
+++ b/src/vlib/node.h
@@ -297,6 +297,7 @@ typedef struct vlib_node_t
#define VLIB_NODE_FLAG_SWITCH_FROM_POLLING_TO_INTERRUPT_MODE (1 << 7)
#define VLIB_NODE_FLAG_TRACE_SUPPORTED (1 << 8)
#define VLIB_NODE_FLAG_ADAPTIVE_MODE (1 << 9)
+#define VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES (1 << 10)
/* State for input nodes. */
u8 state;
diff --git a/src/vlib/node_funcs.h b/src/vlib/node_funcs.h
index 1beac33cf9b..4c7020d6a42 100644
--- a/src/vlib/node_funcs.h
+++ b/src/vlib/node_funcs.h
@@ -1338,6 +1338,10 @@ void vlib_node_runtime_sync_stats_node (vlib_node_t *n, vlib_node_runtime_t *r,
/* Node graph initialization function. */
clib_error_t *vlib_node_main_init (vlib_main_t * vm);
+/* Refresh graph after the creation of a node that was potentially mentionned
+ * as a named next for a node with VLIB_NODE_FLAG_ALLOW_LAZY_NEXT_NODES */
+clib_error_t *vlib_node_main_lazy_next_update (vlib_main_t *vm);
+
format_function_t format_vlib_node_graph;
format_function_t format_vlib_node_name;
format_function_t format_vlib_next_node_name;
diff --git a/src/vlib/unix/cli.c b/src/vlib/unix/cli.c
index 90cf61d811d..051c5730aed 100644
--- a/src/vlib/unix/cli.c
+++ b/src/vlib/unix/cli.c
@@ -3329,6 +3329,12 @@ VLIB_CLI_COMMAND (unix_cli_q_command, static) = {
.function = unix_cli_quit,
};
+VLIB_CLI_COMMAND (unix_cli_exit_command, static) = {
+ .path = "exit",
+ .short_help = "Exit CLI",
+ .function = unix_cli_quit,
+};
+
/** CLI command to execute a VPP command script. */
static clib_error_t *
unix_cli_exec (vlib_main_t * vm,
diff --git a/src/vlibapi/api_shared.c b/src/vlibapi/api_shared.c
index 79064b292c9..1f02aefe88a 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, 1);
+ m->endian_handler (tmpmem, 0 /* host endian */);
}
if (m && m->tojson_handler)
diff --git a/src/vnet/CMakeLists.txt b/src/vnet/CMakeLists.txt
index 01958225343..6262e803057 100644
--- a/src/vnet/CMakeLists.txt
+++ b/src/vnet/CMakeLists.txt
@@ -78,8 +78,8 @@ list(APPEND VNET_HEADERS
dev/args.h
dev/bus/pci.h
dev/counters.h
- dev/dev.h
dev/dev_funcs.h
+ dev/dev.h
dev/errors.h
dev/log.h
dev/mgmt.h
@@ -607,19 +607,6 @@ list(APPEND VNET_HEADERS
)
##############################################################################
-# Layer 3 protocol: osi
-##############################################################################
-list(APPEND VNET_SOURCES
- osi/node.c
- osi/osi.c
- osi/pg.c
-)
-
-list(APPEND VNET_HEADERS
- osi/osi.h
-)
-
-##############################################################################
# Layer 4 protocol: tcp
##############################################################################
list(APPEND VNET_SOURCES
@@ -973,12 +960,14 @@ list(APPEND VNET_API_FILES
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
list(APPEND VNET_SOURCES
+ dev/bus/platform.c
devices/tap/cli.c
devices/tap/tap.c
devices/tap/tapv2_api.c
)
list(APPEND VNET_HEADERS
+ dev/bus/platform.h
devices/tap/tap.h
)
@@ -1023,6 +1012,7 @@ list(APPEND VNET_SOURCES
session/application_namespace.c
session/segment_manager.c
session/session_api.c
+ session/session_sdl.c
)
list(APPEND VNET_HEADERS
@@ -1053,10 +1043,13 @@ list(APPEND VNET_API_FILES session/session.api)
list(APPEND VNET_SOURCES
tls/tls.c
+ tls/tls_record.c
)
list(APPEND VNET_HEADERS
tls/tls.h
+ tls/tls_inlines.h
+ tls/tls_record.h
tls/tls_test.h
)
diff --git a/src/vnet/dev/bus/platform.c b/src/vnet/dev/bus/platform.c
new file mode 100644
index 00000000000..56a1f9c762c
--- /dev/null
+++ b/src/vnet/dev/bus/platform.c
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/dev/dev.h>
+#include <vnet/dev/bus/platform.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
+ .class_name = "dev",
+ .subclass_name = "platform",
+};
+
+#define log_debug(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_DEBUG, dev_log.class, "%U" f, format_vnet_dev_log, \
+ dev, \
+ clib_string_skip_prefix (__func__, "vnet_dev_bus_platform_dt_"), \
+ ##__VA_ARGS__)
+#define log_err(dev, f, ...) \
+ vlib_log (VLIB_LOG_LEVEL_ERR, dev_log.class, "%U" f, format_vnet_dev_log, \
+ dev, 0, ##__VA_ARGS__)
+
+#define PLATFORM_DEV_PATH "/sys/bus/platform/devices"
+
+clib_dt_main_t vnet_dev_bus_platform_dt_main;
+
+vnet_dev_rv_t
+vnet_dev_bus_platform_dt_node_from_device_id (clib_dt_node_t **nodep,
+ char *device_id)
+{
+ clib_dt_main_t *dm = &vnet_dev_bus_platform_dt_main;
+ clib_dt_node_t *n;
+ char *name = device_id + sizeof (PLATFORM_BUS_NAME);
+ char path[PATH_MAX];
+ int r;
+ u8 *link;
+
+ if (dm->root == 0)
+ {
+ clib_error_t *err;
+ err = clib_dt_read_from_sysfs (&vnet_dev_bus_platform_dt_main);
+ if (err)
+ {
+ log_err (0, "cannot read devicetree: %U", format_clib_error, err);
+ clib_error_free (err);
+ return VNET_DEV_ERR_NOT_FOUND;
+ }
+ }
+
+ link = format (0, PLATFORM_DEV_PATH "/%s/of_node%c", name, 0);
+ r = readlink ((char *) link, path, sizeof (path) - 1);
+
+ if (r < 1)
+ {
+ log_err (0, "of_node doesn't exist for '%s'", name);
+ vec_free (link);
+ return VNET_DEV_ERR_NOT_FOUND;
+ }
+
+ path[r] = 0;
+ vec_reset_length (link);
+ link = format (link, PLATFORM_DEV_PATH "/%s/%s%c", name, path, 0);
+ if (!realpath ((char *) link, path))
+ {
+ log_err (0, "cannot find realpath for '%s'", link);
+ vec_free (link);
+ return VNET_DEV_ERR_NOT_FOUND;
+ }
+
+ vec_free (link);
+
+ if (strncmp (CLIB_DT_LINUX_PREFIX, path,
+ sizeof (CLIB_DT_LINUX_PREFIX) - 1) != 0)
+ return VNET_DEV_ERR_BUG;
+
+ n = clib_dt_get_node_with_path (dm, "%s",
+ path + sizeof (CLIB_DT_LINUX_PREFIX) - 1);
+
+ if (n)
+ {
+ *nodep = n;
+ return VNET_DEV_OK;
+ }
+
+ return VNET_DEV_ERR_NOT_FOUND;
+}
+
+static void *
+vnet_dev_bus_platform_get_device_info (vlib_main_t *vm, char *device_id)
+{
+ clib_dt_node_t *n = 0;
+ vnet_dev_bus_platform_device_info_t *di;
+
+ vnet_dev_bus_platform_dt_node_from_device_id (&n, device_id);
+
+ if (n)
+ {
+ clib_dt_property_t *compatible;
+ compatible = clib_dt_get_node_property_by_name (n, "compatible");
+ log_debug (0, "node found, is compatible %U",
+ format_clib_dt_property_data, compatible);
+ di = clib_mem_alloc (sizeof (*di));
+ di->node = n;
+ return di;
+ }
+
+ return 0;
+}
+
+static void
+vnet_dev_bus_platform_free_device_info (vlib_main_t *vm, void *p)
+{
+ clib_mem_free (p);
+}
+
+static void
+vnet_dev_bus_platform_close (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ log_debug (dev, "");
+}
+
+static vnet_dev_rv_t
+vnet_dev_bus_platform_open (vlib_main_t *vm, vnet_dev_t *dev)
+{
+ clib_dt_node_t *n = 0;
+ vnet_dev_bus_platform_device_data_t *dd = vnet_dev_get_bus_data (dev);
+ vnet_dev_rv_t rv;
+
+ log_debug (dev, "");
+
+ rv = vnet_dev_bus_platform_dt_node_from_device_id (&n, dev->device_id);
+ if (rv != VNET_DEV_OK)
+ return rv;
+
+ dd->node = n;
+ return VNET_DEV_OK;
+}
+
+static u8 *
+format_dev_bus_platform_device_info (u8 *s, va_list *args)
+{
+ vnet_dev_format_args_t __clib_unused *a =
+ va_arg (*args, vnet_dev_format_args_t *);
+ vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
+ vnet_dev_bus_platform_device_data_t *dd = vnet_dev_get_bus_data (dev);
+ return format (s, "device-tree path is '%v'", dd->node->path);
+}
+
+static u8 *
+format_dev_bus_platform_device_addr (u8 *s, va_list *args)
+{
+ vnet_dev_t *dev = va_arg (*args, vnet_dev_t *);
+ return format (s, "%s", dev->device_id + sizeof (PLATFORM_BUS_NAME));
+}
+
+VNET_DEV_REGISTER_BUS (pp2) = {
+ .name = PLATFORM_BUS_NAME,
+ .device_data_size = sizeof (vnet_dev_bus_platform_device_info_t),
+ .ops = {
+ .get_device_info = vnet_dev_bus_platform_get_device_info,
+ .free_device_info = vnet_dev_bus_platform_free_device_info,
+ .device_open = vnet_dev_bus_platform_open,
+ .device_close = vnet_dev_bus_platform_close,
+ .format_device_info = format_dev_bus_platform_device_info,
+ .format_device_addr = format_dev_bus_platform_device_addr,
+ },
+};
diff --git a/src/vnet/dev/bus/platform.h b/src/vnet/dev/bus/platform.h
new file mode 100644
index 00000000000..3492aad57ed
--- /dev/null
+++ b/src/vnet/dev/bus/platform.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2023 Cisco Systems, Inc.
+ */
+
+#ifndef _VNET_DEV_BUS_PLATFORM_H_
+#define _VNET_DEV_BUS_PLATFORM_H_
+
+#include <vppinfra/clib.h>
+#include <vppinfra/devicetree.h>
+#include <vlib/vlib.h>
+#include <vnet/dev/dev.h>
+
+#define PLATFORM_BUS_NAME "platform"
+
+extern clib_dt_main_t vnet_dev_bus_platform_dt_main;
+
+typedef struct
+{
+ clib_dt_node_t *node;
+} vnet_dev_bus_platform_device_info_t;
+
+typedef struct
+{
+ clib_dt_node_t *node;
+} vnet_dev_bus_platform_device_data_t;
+
+#endif /* _VNET_DEV_BUS_PLATFORM_H_ */
diff --git a/src/vnet/dev/errors.h b/src/vnet/dev/errors.h
index 430a6aef282..6ececad12ec 100644
--- a/src/vnet/dev/errors.h
+++ b/src/vnet/dev/errors.h
@@ -41,6 +41,7 @@
_ (UNSUPPORTED_DEVICE, "unsupported device") \
_ (UNSUPPORTED_DEVICE_VER, "unsupported device version") \
_ (ALREADY_DONE, "already done") \
- _ (NO_SUCH_INTERFACE, "no such interface")
+ _ (NO_SUCH_INTERFACE, "no such interface") \
+ _ (INIT_FAILED, "init failed")
#endif /* _VNET_DEV_ERRORS_H_ */
diff --git a/src/vnet/dev/port.c b/src/vnet/dev/port.c
index 5b4b8cdc7b8..df7805c1ff2 100644
--- a/src/vnet/dev/port.c
+++ b/src/vnet/dev/port.c
@@ -305,7 +305,8 @@ vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
switch (req->type)
{
case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
- if (req->max_rx_frame_size > port->attr.max_supported_rx_frame_size)
+ if ((req->max_rx_frame_size > port->attr.max_supported_rx_frame_size) ||
+ (req->max_rx_frame_size < ETHERNET_MIN_PACKET_BYTES))
return VNET_DEV_ERR_INVALID_VALUE;
if (req->max_rx_frame_size == port->max_rx_frame_size)
return VNET_DEV_ERR_NO_CHANGE;
diff --git a/src/vnet/devices/tap/tap.c b/src/vnet/devices/tap/tap.c
index 1e2ee87041d..b0b0a3af13f 100644
--- a/src/vnet/devices/tap/tap.c
+++ b/src/vnet/devices/tap/tap.c
@@ -85,7 +85,7 @@ virtio_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
return 0;
}
-#define TAP_MAX_INSTANCE 1024
+#define TAP_MAX_INSTANCE 8192
static void
tap_free (vlib_main_t * vm, virtio_if_t * vif)
@@ -162,7 +162,8 @@ tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
}
else
{
- args->id = clib_bitmap_first_clear (tm->tap_ids);
+ args->id = clib_bitmap_next_clear (tm->tap_ids, args->auto_id_offset %
+ TAP_MAX_INSTANCE);
}
if (args->id > TAP_MAX_INSTANCE)
diff --git a/src/vnet/devices/tap/tap.h b/src/vnet/devices/tap/tap.h
index 6b88c34fe41..1df2fb7e1ad 100644
--- a/src/vnet/devices/tap/tap.h
+++ b/src/vnet/devices/tap/tap.h
@@ -42,6 +42,7 @@ typedef enum
typedef struct
{
u32 id;
+ u32 auto_id_offset;
u8 mac_addr_set;
mac_address_t mac_addr;
u16 num_rx_queues;
diff --git a/src/vnet/devices/virtio/FEATURE.yaml b/src/vnet/devices/virtio/FEATURE.yaml
index 446a45b61a3..870023861de 100644
--- a/src/vnet/devices/virtio/FEATURE.yaml
+++ b/src/vnet/devices/virtio/FEATURE.yaml
@@ -13,6 +13,7 @@ features:
- Support virtio 1.1 packed ring in vhost
- Support for tx queue size configuration (tested on host kernel 5.15
and qemu version 6.2.0)
+ - Support RSS (tested on ubuntu 23.10)
description: "Virtio implementation"
missing:
- API dump filtering by sw_if_index
diff --git a/src/vnet/devices/virtio/cli.c b/src/vnet/devices/virtio/cli.c
index c1b6c8be065..c4364600722 100644
--- a/src/vnet/devices/virtio/cli.c
+++ b/src/vnet/devices/virtio/cli.c
@@ -62,6 +62,8 @@ virtio_pci_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
args.bind = VIRTIO_BIND_FORCE;
else if (unformat (line_input, "bind"))
args.bind = VIRTIO_BIND_DEFAULT;
+ else if (unformat (line_input, "rss-enabled"))
+ args.rss_enabled = 1;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
@@ -77,7 +79,7 @@ VLIB_CLI_COMMAND (virtio_pci_create_command, static) = {
.path = "create interface virtio",
.short_help = "create interface virtio <pci-address> "
"[feature-mask <hex-mask>] [tx-queue-size <size>] "
- "[gso-enabled] [csum-enabled] "
+ "[gso-enabled] [csum-enabled] [rss-enabled] "
"[buffering [size <buffering-szie>]] [packed] [bind [force]]",
.function = virtio_pci_create_command_fn,
};
diff --git a/src/vnet/devices/virtio/pci.c b/src/vnet/devices/virtio/pci.c
index 6234f64fcfb..140cdb94153 100644
--- a/src/vnet/devices/virtio/pci.c
+++ b/src/vnet/devices/virtio/pci.c
@@ -37,6 +37,13 @@
#define PCI_MSIX_ENABLE 0x8000
+static const u8 virtio_rss_key[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {
+ 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67,
+ 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb,
+ 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30,
+ 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa,
+};
+
static pci_device_id_t virtio_pci_device_ids[] = {
{
.vendor_id = PCI_VENDOR_ID_VIRTIO,
@@ -584,6 +591,35 @@ virtio_pci_enable_multiqueue (vlib_main_t * vm, virtio_if_t * vif,
return status;
}
+static int
+virtio_pci_enable_multiqueue_rss (vlib_main_t *vm, virtio_if_t *vif,
+ u16 num_queues)
+{
+ virtio_ctrl_msg_t mq_hdr;
+ virtio_net_rss_config *rss = (virtio_net_rss_config *) mq_hdr.data;
+ virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
+
+ STATIC_ASSERT (sizeof (*rss) <= sizeof (mq_hdr.data),
+ "virtio_net_rss_config size too big");
+ mq_hdr.ctrl.class = VIRTIO_NET_CTRL_MQ;
+ mq_hdr.ctrl.cmd = VIRTIO_NET_CTRL_MQ_RSS_CONFIG;
+ mq_hdr.status = VIRTIO_NET_ERR;
+
+ rss->hash_types = VIRTIO_NET_HASH_TYPE_SUPPORTED;
+ rss->indirection_table_mask = VIRTIO_NET_RSS_MAX_TABLE_LEN - 1;
+ rss->unclassified_queue = 0;
+ for (int i = 0; i < VIRTIO_NET_RSS_MAX_TABLE_LEN; i++)
+ rss->indirection_table[i] = i % num_queues;
+ rss->max_tx_vq = num_queues;
+ rss->hash_key_length = VIRTIO_NET_RSS_MAX_KEY_SIZE;
+ clib_memcpy (rss->hash_key_data, virtio_rss_key,
+ VIRTIO_NET_RSS_MAX_KEY_SIZE);
+
+ status = virtio_pci_send_ctrl_msg (vm, vif, &mq_hdr, sizeof (*rss));
+ virtio_log_debug (vif, "multi-queue with rss enable %u queues", num_queues);
+ return status;
+}
+
static u8
virtio_pci_queue_size_valid (u16 qsz)
{
@@ -933,6 +969,9 @@ virtio_negotiate_features (vlib_main_t * vm, virtio_if_t * vif,
| VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)
| VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
+ if (vif->rss_enabled)
+ supported_features |= VIRTIO_FEATURE (VIRTIO_NET_F_RSS);
+
if (vif->is_modern)
supported_features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
@@ -1375,6 +1414,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
vif->dev_instance = vif - vim->interfaces;
vif->per_interface_next_index = ~0;
vif->pci_addr.as_u32 = args->addr;
+ vif->rss_enabled = args->rss_enabled;
if (args->virtio_flags & VIRTIO_FLAG_PACKED)
vif->is_packed = 1;
@@ -1536,8 +1576,16 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) &&
(vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ)))
{
- if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs))
- virtio_log_warning (vif, "multiqueue is not set");
+ if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_RSS))
+ {
+ if (virtio_pci_enable_multiqueue_rss (vm, vif, vif->max_queue_pairs))
+ virtio_log_warning (vif, "multiqueue with rss is not set");
+ }
+ else
+ {
+ if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs))
+ virtio_log_warning (vif, "multiqueue is not set");
+ }
}
return;
diff --git a/src/vnet/devices/virtio/pci.h b/src/vnet/devices/virtio/pci.h
index 5eb80f823be..745ad6fce87 100644
--- a/src/vnet/devices/virtio/pci.h
+++ b/src/vnet/devices/virtio/pci.h
@@ -60,6 +60,9 @@ typedef enum
/* If multiqueue is provided by host, then we support it. */
#define VIRTIO_NET_CTRL_MQ 4
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0
+#define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1
+#define VIRTIO_NET_CTRL_MQ_HASH_CONFIG 2
+
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000
@@ -139,14 +142,77 @@ typedef struct
u64 queue_device; /* read-write */
} virtio_pci_common_cfg_t;
+#define foreach_virtio_net_hash_report_type \
+ _ (NONE, 0) \
+ _ (IPV4, 1) \
+ _ (TCPV4, 2) \
+ _ (UDPV4, 3) \
+ _ (IPV6, 4) \
+ _ (TCPV6, 5) \
+ _ (UDPV6, 6) \
+ _ (IPV6_EX, 7) \
+ _ (TCPV6_EX, 8) \
+ _ (UDPV6_EX, 9)
+
+typedef enum
+{
+#define _(n, i) VIRTIO_NET_HASH_REPORT_##n = i,
+ foreach_virtio_net_hash_report_type
+#undef _
+} virtio_net_hash_report_type_t;
+
typedef struct
{
u8 mac[6];
u16 status;
u16 max_virtqueue_pairs;
u16 mtu;
+ u32 speed;
+ u8 duplex;
+ u8 rss_max_key_size;
+ u16 rss_max_indirection_table_length;
+ u32 supported_hash_types;
} virtio_net_config_t;
+#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
+
+#define foreach_virtio_net_hash_type \
+ _ (IPV4, 0) \
+ _ (TCPV4, 1) \
+ _ (UDPV4, 2) \
+ _ (IPV6, 3) \
+ _ (TCPV6, 4) \
+ _ (UDPV6, 5) \
+ _ (IPV6_EX, 6) \
+ _ (TCPV6_EX, 7) \
+ _ (UDPV6_EX, 8)
+
+typedef enum
+{
+#define _(n, i) VIRTIO_NET_HASH_TYPE_##n = (1 << i),
+ foreach_virtio_net_hash_type
+#undef _
+} virtio_net_hash_type_t;
+
+#define VIRTIO_NET_HASH_TYPE_SUPPORTED \
+ (VIRTIO_NET_HASH_TYPE_IPV4 | VIRTIO_NET_HASH_TYPE_TCPV4 | \
+ VIRTIO_NET_HASH_TYPE_UDPV4 | VIRTIO_NET_HASH_TYPE_IPV6 | \
+ VIRTIO_NET_HASH_TYPE_TCPV6 | VIRTIO_NET_HASH_TYPE_UDPV6 | \
+ VIRTIO_NET_HASH_TYPE_IPV6_EX | VIRTIO_NET_HASH_TYPE_TCPV6_EX | \
+ VIRTIO_NET_HASH_TYPE_UDPV6_EX)
+
+typedef struct
+{
+ u32 hash_types;
+ u16 indirection_table_mask;
+ u16 unclassified_queue;
+ u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+ u16 max_tx_vq;
+ u8 hash_key_length;
+ u8 hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+} virtio_net_rss_config;
+
/*
* Control virtqueue data structures
*
@@ -210,13 +276,14 @@ typedef struct _virtio_pci_func
void (*device_debug_config_space) (vlib_main_t * vm, virtio_if_t * vif);
} virtio_pci_func_t;
-#define foreach_virtio_flags \
- _ (GSO, 0) \
- _ (CSUM_OFFLOAD, 1) \
- _ (GRO_COALESCE, 2) \
- _ (PACKED, 3) \
- _ (IN_ORDER, 4) \
- _ (BUFFERING, 5)
+#define foreach_virtio_flags \
+ _ (GSO, 0) \
+ _ (CSUM_OFFLOAD, 1) \
+ _ (GRO_COALESCE, 2) \
+ _ (PACKED, 3) \
+ _ (IN_ORDER, 4) \
+ _ (BUFFERING, 5) \
+ _ (RSS, 6)
typedef enum
{
@@ -243,6 +310,7 @@ typedef struct
u64 features;
u8 gso_enabled;
u8 checksum_offload_enabled;
+ u8 rss_enabled;
u32 tx_queue_size;
virtio_bind_t bind;
u32 buffering_size;
diff --git a/src/vnet/devices/virtio/virtio.api b/src/vnet/devices/virtio/virtio.api
index a11492ec258..14a58491282 100644
--- a/src/vnet/devices/virtio/virtio.api
+++ b/src/vnet/devices/virtio/virtio.api
@@ -63,6 +63,7 @@ enumflag virtio_flags {
VIRTIO_API_FLAG_PACKED = 8, /* enable packed ring support, provided it is available from backend */
VIRTIO_API_FLAG_IN_ORDER = 16, /* enable in order support, provided it is available from backend */
VIRTIO_API_FLAG_BUFFERING = 32 [backwards_compatible], /* enable buffering to handle backend jitter/delays */
+ VIRTIO_API_FLAG_RSS = 64 [backwards_compatible], /* enable rss support */
};
/** \brief Initialize a new virtio pci interface with the given parameters
diff --git a/src/vnet/devices/virtio/virtio.c b/src/vnet/devices/virtio/virtio.c
index d2302fa1dc4..840936a43ff 100644
--- a/src/vnet/devices/virtio/virtio.c
+++ b/src/vnet/devices/virtio/virtio.c
@@ -404,6 +404,7 @@ virtio_show (vlib_main_t *vm, u32 *hw_if_indices, u8 show_descr,
vlib_cli_output (vm, " csum-enabled %d", vif->csum_offload_enabled);
vlib_cli_output (vm, " packet-coalesce %d", vif->packet_coalesce);
vlib_cli_output (vm, " packet-buffering %d", vif->packet_buffering);
+ vlib_cli_output (vm, " rss-enabled %d", vif->rss_enabled);
if (type & (VIRTIO_IF_TYPE_TAP | VIRTIO_IF_TYPE_PCI))
vlib_cli_output (vm, " Mac Address: %U", format_ethernet_address,
vif->mac_addr);
diff --git a/src/vnet/devices/virtio/virtio.h b/src/vnet/devices/virtio/virtio.h
index 431b1d25c26..a8e258884a4 100644
--- a/src/vnet/devices/virtio/virtio.h
+++ b/src/vnet/devices/virtio/virtio.h
@@ -140,6 +140,7 @@ typedef struct
vnet_virtio_vring_t *txq_vrings;
int gso_enabled;
int csum_offload_enabled;
+ int rss_enabled;
union
{
int *tap_fds;
diff --git a/src/vnet/devices/virtio/virtio_api.c b/src/vnet/devices/virtio/virtio_api.c
index 3197a2fab6d..2e25efff29e 100644
--- a/src/vnet/devices/virtio/virtio_api.c
+++ b/src/vnet/devices/virtio/virtio_api.c
@@ -111,18 +111,18 @@ vl_api_virtio_pci_create_v2_t_handler (vl_api_virtio_pci_create_v2_t * mp)
STATIC_ASSERT (((int) VIRTIO_API_FLAG_BUFFERING ==
(int) VIRTIO_FLAG_BUFFERING),
"virtio buffering api flag mismatch");
+ STATIC_ASSERT (((int) VIRTIO_API_FLAG_RSS == (int) VIRTIO_FLAG_RSS),
+ "virtio rss api flag mismatch");
ap->virtio_flags = clib_net_to_host_u32 (mp->virtio_flags);
ap->features = clib_net_to_host_u64 (mp->features);
if (ap->virtio_flags & VIRTIO_API_FLAG_GSO)
ap->gso_enabled = 1;
- else
- ap->gso_enabled = 0;
if (ap->virtio_flags & VIRTIO_API_FLAG_CSUM_OFFLOAD)
ap->checksum_offload_enabled = 1;
- else
- ap->checksum_offload_enabled = 0;
+ if (ap->virtio_flags & VIRTIO_API_FLAG_RSS)
+ ap->rss_enabled = 1;
virtio_pci_create_if (vm, ap);
diff --git a/src/vnet/devices/virtio/virtio_std.h b/src/vnet/devices/virtio/virtio_std.h
index ec988c08dbb..66b8bac092c 100644
--- a/src/vnet/devices/virtio/virtio_std.h
+++ b/src/vnet/devices/virtio/virtio_std.h
@@ -15,49 +15,61 @@
#ifndef __VIRTIO_STD_H__
#define __VIRTIO_STD_H__
-#define foreach_virtio_net_features \
- _ (VIRTIO_NET_F_CSUM, 0) /* Host handles pkts w/ partial csum */ \
- _ (VIRTIO_NET_F_GUEST_CSUM, 1) /* Guest handles pkts w/ partial csum */ \
- _ (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, 2) /* Dynamic offload configuration. */ \
- _ (VIRTIO_NET_F_MTU, 3) /* Initial MTU advice. */ \
- _ (VIRTIO_NET_F_MAC, 5) /* Host has given MAC address. */ \
- _ (VIRTIO_NET_F_GSO, 6) /* Host handles pkts w/ any GSO. */ \
- _ (VIRTIO_NET_F_GUEST_TSO4, 7) /* Guest can handle TSOv4 in. */ \
- _ (VIRTIO_NET_F_GUEST_TSO6, 8) /* Guest can handle TSOv6 in. */ \
- _ (VIRTIO_NET_F_GUEST_ECN, 9) /* Guest can handle TSO[6] w/ ECN in. */ \
- _ (VIRTIO_NET_F_GUEST_UFO, 10) /* Guest can handle UFO in. */ \
- _ (VIRTIO_NET_F_HOST_TSO4, 11) /* Host can handle TSOv4 in. */ \
- _ (VIRTIO_NET_F_HOST_TSO6, 12) /* Host can handle TSOv6 in. */ \
- _ (VIRTIO_NET_F_HOST_ECN, 13) /* Host can handle TSO[6] w/ ECN in. */ \
- _ (VIRTIO_NET_F_HOST_UFO, 14) /* Host can handle UFO in. */ \
- _ (VIRTIO_NET_F_MRG_RXBUF, 15) /* Host can merge receive buffers. */ \
- _ (VIRTIO_NET_F_STATUS, 16) /* virtio_net_config.status available */ \
- _ (VIRTIO_NET_F_CTRL_VQ, 17) /* Control channel available */ \
- _ (VIRTIO_NET_F_CTRL_RX, 18) /* Control channel RX mode support */ \
- _ (VIRTIO_NET_F_CTRL_VLAN, 19) /* Control channel VLAN filtering */ \
- _ (VIRTIO_NET_F_CTRL_RX_EXTRA, 20) /* Extra RX mode control support */ \
- _ (VIRTIO_NET_F_GUEST_ANNOUNCE, 21) /* Guest can announce device on the network */ \
- _ (VIRTIO_NET_F_MQ, 22) /* Device supports Receive Flow Steering */ \
- _ (VIRTIO_NET_F_CTRL_MAC_ADDR, 23) /* Set MAC address */ \
- _ (VIRTIO_F_NOTIFY_ON_EMPTY, 24) \
- _ (VHOST_F_LOG_ALL, 26) /* Log all write descriptors */ \
- _ (VIRTIO_F_ANY_LAYOUT, 27) /* Can the device handle any descriptor layout */ \
- _ (VIRTIO_RING_F_INDIRECT_DESC, 28) /* Support indirect buffer descriptors */ \
- _ (VIRTIO_RING_F_EVENT_IDX, 29) /* The Guest publishes the used index for which it expects an interrupt \
- * at the end of the avail ring. Host should ignore the avail->flags field. */ \
-/* The Host publishes the avail index for which it expects a kick \
- * at the end of the used ring. Guest should ignore the used->flags field. */ \
- _ (VHOST_USER_F_PROTOCOL_FEATURES, 30) \
- _ (VIRTIO_F_VERSION_1, 32) /* v1.0 compliant. */ \
- _ (VIRTIO_F_IOMMU_PLATFORM, 33) \
- _ (VIRTIO_F_RING_PACKED, 34) \
- _ (VIRTIO_F_IN_ORDER, 35) /* all buffers are used by the device in the */ \
- /* same order in which they have been made available */ \
+#define foreach_virtio_net_features \
+ _ (VIRTIO_NET_F_CSUM, 0) /* Host handles pkts w/ partial csum */ \
+ _ (VIRTIO_NET_F_GUEST_CSUM, 1) /* Guest handles pkts w/ partial csum */ \
+ _ (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, \
+ 2) /* Dynamic offload configuration. */ \
+ _ (VIRTIO_NET_F_MTU, 3) /* Initial MTU advice. */ \
+ _ (VIRTIO_NET_F_MAC, 5) /* Host has given MAC address. */ \
+ _ (VIRTIO_NET_F_GSO, 6) /* Host handles pkts w/ any GSO. */ \
+ _ (VIRTIO_NET_F_GUEST_TSO4, 7) /* Guest can handle TSOv4 in. */ \
+ _ (VIRTIO_NET_F_GUEST_TSO6, 8) /* Guest can handle TSOv6 in. */ \
+ _ (VIRTIO_NET_F_GUEST_ECN, 9) /* Guest can handle TSO[6] w/ ECN in. */ \
+ _ (VIRTIO_NET_F_GUEST_UFO, 10) /* Guest can handle UFO in. */ \
+ _ (VIRTIO_NET_F_HOST_TSO4, 11) /* Host can handle TSOv4 in. */ \
+ _ (VIRTIO_NET_F_HOST_TSO6, 12) /* Host can handle TSOv6 in. */ \
+ _ (VIRTIO_NET_F_HOST_ECN, 13) /* Host can handle TSO[6] w/ ECN in. */ \
+ _ (VIRTIO_NET_F_HOST_UFO, 14) /* Host can handle UFO in. */ \
+ _ (VIRTIO_NET_F_MRG_RXBUF, 15) /* Host can merge receive buffers. */ \
+ _ (VIRTIO_NET_F_STATUS, 16) /* virtio_net_config.status available */ \
+ _ (VIRTIO_NET_F_CTRL_VQ, 17) /* Control channel available */ \
+ _ (VIRTIO_NET_F_CTRL_RX, 18) /* Control channel RX mode support */ \
+ _ (VIRTIO_NET_F_CTRL_VLAN, 19) /* Control channel VLAN filtering */ \
+ _ (VIRTIO_NET_F_CTRL_RX_EXTRA, 20) /* Extra RX mode control support */ \
+ _ (VIRTIO_NET_F_GUEST_ANNOUNCE, \
+ 21) /* Guest can announce device on the network */ \
+ _ (VIRTIO_NET_F_MQ, 22) /* Device supports Receive Flow Steering */ \
+ _ (VIRTIO_NET_F_CTRL_MAC_ADDR, 23) /* Set MAC address */ \
+ _ (VIRTIO_F_NOTIFY_ON_EMPTY, 24) \
+ _ (VHOST_F_LOG_ALL, 26) /* Log all write descriptors */ \
+ _ (VIRTIO_F_ANY_LAYOUT, \
+ 27) /* Can the device handle any descriptor layout */ \
+ _ (VIRTIO_RING_F_INDIRECT_DESC, \
+ 28) /* Support indirect buffer descriptors */ \
+ _ (VIRTIO_RING_F_EVENT_IDX, \
+ 29) /* The Guest publishes the used index for which it expects an \
+ * interrupt at the end of the avail ring. Host should ignore the \
+ * avail->flags field. */ \
+ /* The Host publishes the avail index for which it expects a kick \
+ * at the end of the used ring. Guest should ignore the used->flags field. \
+ */ \
+ _ (VHOST_USER_F_PROTOCOL_FEATURES, 30) \
+ _ (VIRTIO_F_VERSION_1, 32) /* v1.0 compliant. */ \
+ _ (VIRTIO_F_IOMMU_PLATFORM, 33) \
+ _ (VIRTIO_F_RING_PACKED, 34) \
+ _ (VIRTIO_F_IN_ORDER, 35) /* all buffers are used by the device in the */ \
+ /* same order in which they have been made available */ \
_ (VIRTIO_F_ORDER_PLATFORM, 36) /* memory accesses by the driver and the */ \
- /* device are ordered in a way described by the platfor */ \
- _ (VIRTIO_F_NOTIFICATION_DATA, 38) /* the driver passes extra data (besides */ \
- /* identifying the virtqueue) in its device notifications. */ \
- _ (VIRTIO_NET_F_SPEED_DUPLEX, 63) /* Device set linkspeed and duplex */
+ /* device are ordered in a way described by the platfor */ \
+ _ (VIRTIO_F_NOTIFICATION_DATA, \
+ 38) /* the driver passes extra data (besides */ \
+ /* identifying the virtqueue) in its device notifications. */ \
+ _ (VIRTIO_NET_F_RING_RESET, 40) /* Device supports individual ring reset */ \
+ _ (VIRTIO_NET_F_HASH_REPORT, \
+ 57) /* Device supports per packet hash value */ \
+ _ (VIRTIO_NET_F_RSS, 60) /* Device supports RSS */ \
+ _ (VIRTIO_NET_F_SPEED_DUPLEX, 63) /* Device set linkspeed and duplex */
typedef enum
{
diff --git a/src/vnet/error.c b/src/vnet/error.c
index 473d11135f1..7ae32962132 100644
--- a/src/vnet/error.c
+++ b/src/vnet/error.c
@@ -37,6 +37,10 @@ u8 *
format_vnet_api_errno (u8 *s, va_list *args)
{
vnet_api_error_t api_error = va_arg (*args, vnet_api_error_t);
+
+ if (0 == api_error)
+ return format (s, "Success");
+
#ifdef _
#undef _
#endif
diff --git a/src/vnet/interface/runtime.c b/src/vnet/interface/runtime.c
index a88a23bd4c9..6428d5ab75b 100644
--- a/src/vnet/interface/runtime.c
+++ b/src/vnet/interface/runtime.c
@@ -72,6 +72,9 @@ vnet_hw_if_update_runtime_data (vnet_main_t *vnm, u32 hw_if_index)
clib_bitmap_t *pending_int = 0;
int last_int = -1;
+ if (node_index == 0)
+ return;
+
log_debug ("update node '%U' triggered by interface %v",
format_vlib_node_name, vm, node_index, hi->name);
diff --git a/src/vnet/ip/ip6_input.h b/src/vnet/ip/ip6_input.h
index 49e37ec1808..25eae62723d 100644
--- a/src/vnet/ip/ip6_input.h
+++ b/src/vnet/ip/ip6_input.h
@@ -53,11 +53,9 @@ typedef enum
} ip6_input_next_t;
always_inline void
-ip6_input_check_x2 (vlib_main_t * vm,
- vlib_node_runtime_t * error_node,
- vlib_buffer_t * p0, vlib_buffer_t * p1,
- ip6_header_t * ip0, ip6_header_t * ip1,
- u32 * next0, u32 * next1)
+ip6_input_check_x2 (vlib_main_t *vm, vlib_node_runtime_t *error_node,
+ vlib_buffer_t *p0, vlib_buffer_t *p1, ip6_header_t *ip0,
+ ip6_header_t *ip1, u32 *next0, u32 *next1)
{
u8 error0, error1;
@@ -65,13 +63,15 @@ ip6_input_check_x2 (vlib_main_t * vm,
/* Version != 6? Drop it. */
error0 =
- (clib_net_to_host_u32
- (ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
- 6 ? IP6_ERROR_VERSION : error0;
+ (clib_net_to_host_u32 (ip0->ip_version_traffic_class_and_flow_label) >>
+ 28) != 6 ?
+ IP6_ERROR_VERSION :
+ error0;
error1 =
- (clib_net_to_host_u32
- (ip1->ip_version_traffic_class_and_flow_label) >> 28) !=
- 6 ? IP6_ERROR_VERSION : error1;
+ (clib_net_to_host_u32 (ip1->ip_version_traffic_class_and_flow_label) >>
+ 28) != 6 ?
+ IP6_ERROR_VERSION :
+ error1;
/* hop limit < 1? Drop it. for link-local broadcast packets,
* like dhcpv6 packets from client has hop-limit 1, which should not
@@ -81,18 +81,18 @@ ip6_input_check_x2 (vlib_main_t * vm,
error1 = ip1->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error1;
/* L2 length must be at least minimal IP header. */
- error0 =
- p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
- error1 =
- p1->current_length < sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
+ error0 = p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
+ error1 = p1->current_length < sizeof (ip1[0]) ? IP6_ERROR_TOO_SHORT : error1;
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
{
+ p0->error = error_node->errors[error0];
+
if (error0 == IP6_ERROR_TIME_EXPIRED)
{
- icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
- ICMP6_time_exceeded_ttl_exceeded_in_transit,
- 0);
+ icmp6_error_set_vnet_buffer (
+ p0, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
*next0 = IP6_INPUT_NEXT_ICMP_ERROR;
}
else
@@ -102,11 +102,13 @@ ip6_input_check_x2 (vlib_main_t * vm,
}
if (PREDICT_FALSE (error1 != IP6_ERROR_NONE))
{
+ p1->error = error_node->errors[error1];
+
if (error1 == IP6_ERROR_TIME_EXPIRED)
{
- icmp6_error_set_vnet_buffer (p1, ICMP6_time_exceeded,
- ICMP6_time_exceeded_ttl_exceeded_in_transit,
- 0);
+ icmp6_error_set_vnet_buffer (
+ p1, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
*next1 = IP6_INPUT_NEXT_ICMP_ERROR;
}
else
@@ -117,9 +119,8 @@ ip6_input_check_x2 (vlib_main_t * vm,
}
always_inline void
-ip6_input_check_x1 (vlib_main_t * vm,
- vlib_node_runtime_t * error_node,
- vlib_buffer_t * p0, ip6_header_t * ip0, u32 * next0)
+ip6_input_check_x1 (vlib_main_t *vm, vlib_node_runtime_t *error_node,
+ vlib_buffer_t *p0, ip6_header_t *ip0, u32 *next0)
{
u8 error0;
@@ -127,9 +128,10 @@ ip6_input_check_x1 (vlib_main_t * vm,
/* Version != 6? Drop it. */
error0 =
- (clib_net_to_host_u32
- (ip0->ip_version_traffic_class_and_flow_label) >> 28) !=
- 6 ? IP6_ERROR_VERSION : error0;
+ (clib_net_to_host_u32 (ip0->ip_version_traffic_class_and_flow_label) >>
+ 28) != 6 ?
+ IP6_ERROR_VERSION :
+ error0;
/* hop limit < 1? Drop it. for link-local broadcast packets,
* like dhcpv6 packets from client has hop-limit 1, which should not
@@ -138,16 +140,16 @@ ip6_input_check_x1 (vlib_main_t * vm,
error0 = ip0->hop_limit < 1 ? IP6_ERROR_TIME_EXPIRED : error0;
/* L2 length must be at least minimal IP header. */
- error0 =
- p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
+ error0 = p0->current_length < sizeof (ip0[0]) ? IP6_ERROR_TOO_SHORT : error0;
if (PREDICT_FALSE (error0 != IP6_ERROR_NONE))
{
+ p0->error = error_node->errors[error0];
if (error0 == IP6_ERROR_TIME_EXPIRED)
{
- icmp6_error_set_vnet_buffer (p0, ICMP6_time_exceeded,
- ICMP6_time_exceeded_ttl_exceeded_in_transit,
- 0);
+ icmp6_error_set_vnet_buffer (
+ p0, ICMP6_time_exceeded,
+ ICMP6_time_exceeded_ttl_exceeded_in_transit, 0);
*next0 = IP6_INPUT_NEXT_ICMP_ERROR;
}
else
diff --git a/src/vnet/ip/ip_sas.c b/src/vnet/ip/ip_sas.c
index 0fc261724f1..01f6c90baf8 100644
--- a/src/vnet/ip/ip_sas.c
+++ b/src/vnet/ip/ip_sas.c
@@ -54,6 +54,8 @@ ip6_sas_commonlen (const ip6_address_t *a1, const ip6_address_t *a2)
static int
ip4_sas_commonlen (const ip4_address_t *a1, const ip4_address_t *a2)
{
+ if (!a1 || !a2)
+ return 0;
u64 a =
clib_net_to_host_u32 (a1->as_u32) ^ clib_net_to_host_u32 (a2->as_u32);
if (a == 0)
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index 4f73f1eab0f..640d9288a42 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -486,7 +486,7 @@ ipsec_sa_anti_replay_and_sn_advance (const ipsec_sa_t *sa, u32 seq,
return 0;
}
- if (PREDICT_TRUE (sa->seq >= window_size - 1))
+ if (PREDICT_TRUE (window_size > 0 && sa->seq >= window_size - 1))
{
/*
* the last sequence number VPP received is more than one
diff --git a/src/vnet/ipsec/ipsec_tun_in.c b/src/vnet/ipsec/ipsec_tun_in.c
index c82de3ebaff..3dde084cb24 100644
--- a/src/vnet/ipsec/ipsec_tun_in.c
+++ b/src/vnet/ipsec/ipsec_tun_in.c
@@ -60,8 +60,8 @@ format_ipsec_tun_protect_input_trace (u8 * s, va_list * args)
s = format (s, "IPSec: %U seq %u",
format_ipsec6_tunnel_kv, &t->kv6, t->seq);
else
- s = format (s, "IPSec: %U seq %u sa %d",
- format_ipsec4_tunnel_kv, &t->kv4, t->seq);
+ s =
+ format (s, "IPSec: %U seq %u", format_ipsec4_tunnel_kv, &t->kv4, t->seq);
return s;
}
diff --git a/src/vnet/llc/llc.c b/src/vnet/llc/llc.c
index 4cbf17d48df..e17eaa6fd25 100644
--- a/src/vnet/llc/llc.c
+++ b/src/vnet/llc/llc.c
@@ -208,7 +208,6 @@ add_protocol (llc_main_t * pm, llc_protocol_t protocol, char *protocol_name)
static clib_error_t *
llc_init (vlib_main_t * vm)
{
- clib_error_t *error;
llc_main_t *pm = &llc_main;
clib_memset (pm, 0, sizeof (pm[0]));
@@ -221,9 +220,6 @@ llc_init (vlib_main_t * vm)
foreach_llc_protocol;
#undef _
- if ((error = vlib_call_init_function (vm, snap_init)))
- return error;
-
return vlib_call_init_function (vm, llc_input_init);
}
diff --git a/src/vnet/llc/node.c b/src/vnet/llc/node.c
index d1ee6948269..dee0e060460 100644
--- a/src/vnet/llc/node.c
+++ b/src/vnet/llc/node.c
@@ -313,10 +313,6 @@ llc_register_input_protocol (vlib_main_t * vm,
clib_error_t *error = vlib_call_init_function (vm, llc_input_init);
if (error)
clib_error_report (error);
- /* Otherwise, osi_input_init will wipe out e.g. the snap init */
- error = vlib_call_init_function (vm, osi_input_init);
- if (error)
- clib_error_report (error);
}
pi = llc_get_protocol_info (lm, protocol);
diff --git a/src/vnet/pg/output.c b/src/vnet/pg/output.c
index 042591a7709..fa1a14cc4af 100644
--- a/src/vnet/pg/output.c
+++ b/src/vnet/pg/output.c
@@ -88,7 +88,13 @@ pg_output (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
pcap_add_buffer (&pif->pcap_main, vm, bi0, ETHERNET_MAX_PACKET_BYTES);
}
if (pif->pcap_file_name != 0)
- pcap_write (&pif->pcap_main);
+ {
+ pcap_packet_type_t pm_pt = pif->pcap_main.packet_type;
+ pif->pcap_main.packet_type =
+ pg_intf_mode_to_pcap_packet_type (pif->mode);
+ pcap_write (&pif->pcap_main);
+ pif->pcap_main.packet_type = pm_pt;
+ }
if ((pif->pcap_main.flags & PCAP_MAIN_INIT_DONE)
&& pif->pcap_main.n_packets_captured >=
pif->pcap_main.n_packets_to_capture)
diff --git a/src/vnet/pg/pg.h b/src/vnet/pg/pg.h
index 6d5b25ba25a..bede747428c 100644
--- a/src/vnet/pg/pg.h
+++ b/src/vnet/pg/pg.h
@@ -306,6 +306,15 @@ typedef enum pg_interface_mode_t_
PG_MODE_IP6,
} pg_interface_mode_t;
+always_inline pcap_packet_type_t
+pg_intf_mode_to_pcap_packet_type (pg_interface_mode_t mode)
+{
+ if ((mode == PG_MODE_IP4) || (mode == PG_MODE_IP6))
+ return PCAP_PACKET_TYPE_ip;
+ else
+ return PCAP_PACKET_TYPE_ethernet;
+}
+
typedef struct
{
/* TX lock */
diff --git a/src/vnet/session/application_namespace.c b/src/vnet/session/application_namespace.c
index 2520188d88c..8b06331d803 100644
--- a/src/vnet/session/application_namespace.c
+++ b/src/vnet/session/application_namespace.c
@@ -22,12 +22,6 @@
#include <vppinfra/format_table.h>
#include <vlib/unix/unix.h>
-/*
- * fib source when locking the fib table
- */
-static fib_source_t app_namespace_fib_src = FIB_SOURCE_INVALID;
-static u32 *fib_index_to_lock_count[FIB_PROTOCOL_IP6 + 1];
-
/**
* Hash table of application namespaces by app ns ids
*/
@@ -40,6 +34,17 @@ static app_namespace_t *app_namespace_pool;
static u8 app_sapi_enabled;
+void
+app_namespace_walk (app_namespace_walk_fn_t fn, void *ctx)
+{
+ app_namespace_t *app_ns;
+
+ pool_foreach (app_ns, app_namespace_pool)
+ {
+ fn (app_ns, ctx);
+ }
+}
+
app_namespace_t *
app_namespace_get (u32 index)
{
@@ -87,50 +92,6 @@ app_namespace_alloc (const u8 *ns_id)
return app_ns;
}
-static void
-app_namespace_fib_table_lock (u32 fib_index, u32 protocol)
-{
- fib_table_lock (fib_index, protocol, app_namespace_fib_src);
- vec_validate (fib_index_to_lock_count[protocol], fib_index);
- fib_index_to_lock_count[protocol][fib_index]++;
- ASSERT (fib_index_to_lock_count[protocol][fib_index] > 0);
-}
-
-static void
-app_namespace_fib_table_unlock (u32 fib_index, u32 protocol)
-{
- fib_table_unlock (fib_index, protocol, app_namespace_fib_src);
- ASSERT (fib_index_to_lock_count[protocol][fib_index] > 0);
- fib_index_to_lock_count[protocol][fib_index]--;
-}
-
-static void
-app_namespace_del_global_table (app_namespace_t *app_ns)
-{
- session_table_t *st;
- u32 table_index;
-
- app_namespace_fib_table_unlock (app_ns->ip4_fib_index, FIB_PROTOCOL_IP4);
- if (fib_index_to_lock_count[FIB_PROTOCOL_IP4][app_ns->ip4_fib_index] == 0)
- {
- table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP4,
- app_ns->ip4_fib_index);
- st = session_table_get (table_index);
- if (st)
- session_table_free (st, FIB_PROTOCOL_IP4);
- }
-
- app_namespace_fib_table_unlock (app_ns->ip6_fib_index, FIB_PROTOCOL_IP6);
- if (fib_index_to_lock_count[FIB_PROTOCOL_IP6][app_ns->ip6_fib_index] == 0)
- {
- table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP6,
- app_ns->ip6_fib_index);
- st = session_table_get (table_index);
- if (st)
- session_table_free (st, FIB_PROTOCOL_IP6);
- }
-}
-
session_error_t
vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t *a)
{
@@ -188,11 +149,7 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t *a)
app_ns->sw_if_index = a->sw_if_index;
app_ns->ip4_fib_index = fib_table_find (FIB_PROTOCOL_IP4, a->ip4_fib_id);
- app_namespace_fib_table_lock (app_ns->ip4_fib_index, FIB_PROTOCOL_IP4);
-
app_ns->ip6_fib_index = fib_table_find (FIB_PROTOCOL_IP6, a->ip6_fib_id);
- app_namespace_fib_table_lock (app_ns->ip6_fib_index, FIB_PROTOCOL_IP6);
-
session_lookup_set_tables_appns (app_ns);
}
else
@@ -216,7 +173,8 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t *a)
if (app_ns->sock_name)
vec_free (app_ns->sock_name);
- app_namespace_del_global_table (app_ns);
+ session_lookup_table_cleanup (FIB_PROTOCOL_IP4, app_ns->ip4_fib_index);
+ session_lookup_table_cleanup (FIB_PROTOCOL_IP6, app_ns->ip6_fib_index);
app_namespace_free (app_ns);
}
@@ -290,15 +248,6 @@ app_namespaces_init (void)
{
u8 *ns_id = format (0, "default");
- /* We are not contributing any route to the fib. But we allocate a fib source
- * so that when we lock the fib table, we can view that we have a lock on the
- * particular fib table in case we wonder why the fib table is not free after
- * "ip table del"
- */
- if (app_namespace_fib_src == FIB_SOURCE_INVALID)
- app_namespace_fib_src = fib_source_allocate (
- "application namespace", FIB_SOURCE_PRIORITY_LOW, FIB_SOURCE_BH_SIMPLE);
-
if (!app_namespace_lookup_table)
app_namespace_lookup_table =
hash_create_vec (0, sizeof (u8), sizeof (uword));
diff --git a/src/vnet/session/application_namespace.h b/src/vnet/session/application_namespace.h
index 261325cbe0e..b441e3c48f2 100644
--- a/src/vnet/session/application_namespace.h
+++ b/src/vnet/session/application_namespace.h
@@ -15,6 +15,7 @@
#include <vppinfra/socket.h>
#include <vnet/vnet.h>
+#include <vnet/session/session_types.h>
#include <vnet/session/session_table.h>
#ifndef SRC_VNET_SESSION_APPLICATION_NAMESPACE_H_
@@ -87,6 +88,9 @@ vnet_app_namespace_add_del (vnet_app_namespace_add_del_args_t *a);
u32 app_namespace_get_fib_index (app_namespace_t * app_ns, u8 fib_proto);
session_table_t *app_namespace_get_local_table (app_namespace_t * app_ns);
+typedef void (*app_namespace_walk_fn_t) (app_namespace_t *app_ns, void *ctx);
+extern void app_namespace_walk (app_namespace_walk_fn_t fn, void *ctx);
+
always_inline app_namespace_t *
app_namespace_get_default (void)
{
diff --git a/src/vnet/session/session.api b/src/vnet/session/session.api
index 6affae4112d..26346eaa466 100644
--- a/src/vnet/session/session.api
+++ b/src/vnet/session/session.api
@@ -13,12 +13,19 @@
* limitations under the License.
*/
-option version = "4.0.0";
+option version = "4.0.1";
import "vnet/interface_types.api";
import "vnet/ip/ip_types.api";
+typedef sdl_rule
+{
+ vl_api_prefix_t lcl;
+ u32 action_index;
+ string tag[64];
+};
+
enum transport_proto : u8
{
TRANSPORT_PROTO_API_TCP,
@@ -28,6 +35,14 @@ enum transport_proto : u8
TRANSPORT_PROTO_API_QUIC,
};
+enum rt_backend_engine : u8
+{
+ RT_BACKEND_ENGINE_API_DISABLE = 0,
+ RT_BACKEND_ENGINE_API_RULE_TABLE,
+ RT_BACKEND_ENGINE_API_NONE,
+ RT_BACKEND_ENGINE_API_SDL,
+};
+
/** \brief Application attach to session layer
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
@@ -166,11 +181,18 @@ define app_worker_add_del_reply
@param is_enable - disable session layer if 0, enable otherwise
*/
autoreply define session_enable_disable {
+ option deprecated;
u32 client_index;
u32 context;
bool is_enable [default=true];
};
+autoreply define session_enable_disable_v2 {
+ u32 client_index;
+ u32 context;
+ vl_api_rt_backend_engine_t rt_engine_type;
+};
+
/** \brief enable/disable session layer socket api
@param client_index - opaque cookie to identify the sender
client to vpp direction only
@@ -417,6 +439,42 @@ define session_rules_details
string tag[64];
};
+autoreply define session_sdl_add_del {
+ u32 client_index;
+ u32 context;
+ u32 appns_index;
+ bool is_add;
+ u32 count;
+ vl_api_sdl_rule_t r[count];
+};
+
+/** \brief Dump session sdl
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ */
+define session_sdl_dump
+{
+ u32 client_index;
+ u32 context;
+};
+
+/** \brief Session sdl details
+ @param context - sender context, to match reply w/ request
+ @param lcl - local prefix
+ @param action_index - the only action defined now is forward to
+ application with index action_index
+ @param appns_index - application namespace where rule is to be applied to
+ @param tag - tag
+ */
+define session_sdl_details
+{
+ u32 context;
+ vl_api_prefix_t lcl;
+ u32 action_index;
+ u32 appns_index;
+ string tag[64];
+};
+
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c
index c1becf2c5ea..ac02281cf5c 100644
--- a/src/vnet/session/session.c
+++ b/src/vnet/session/session.c
@@ -24,6 +24,7 @@
#include <vnet/fib/ip4_fib.h>
#include <vlib/stats/stats.h>
#include <vlib/dma/dma.h>
+#include <vnet/session/session_rules_table.h>
session_main_t session_main;
@@ -1996,7 +1997,8 @@ session_stats_collector_init (void)
}
static clib_error_t *
-session_manager_main_enable (vlib_main_t * vm)
+session_manager_main_enable (vlib_main_t *vm,
+ session_rt_engine_type_t rt_engine_type)
{
session_main_t *smm = &session_main;
vlib_thread_main_t *vtm = vlib_get_thread_main ();
@@ -2004,6 +2006,9 @@ session_manager_main_enable (vlib_main_t * vm)
session_worker_t *wrk;
int i;
+ if (session_rt_backend_enable_disable (rt_engine_type))
+ return clib_error_return (0, "error on enable backend engine");
+
/* We only initialize once and do not de-initialized on disable */
if (smm->is_initialized)
goto done;
@@ -2082,9 +2087,11 @@ done:
}
static void
-session_manager_main_disable (vlib_main_t * vm)
+session_manager_main_disable (vlib_main_t *vm,
+ session_rt_engine_type_t rt_engine_type)
{
transport_enable_disable (vm, 0 /* is_en */ );
+ session_rt_backend_enable_disable (rt_engine_type);
}
/* in this new callback, cookie hint the index */
@@ -2221,22 +2228,24 @@ session_node_enable_disable (u8 is_en)
}
clib_error_t *
-vnet_session_enable_disable (vlib_main_t * vm, u8 is_en)
+vnet_session_enable_disable (vlib_main_t *vm,
+ session_enable_disable_args_t *args)
{
clib_error_t *error = 0;
- if (is_en)
+
+ if (args->is_en)
{
if (session_main.is_enabled)
return 0;
- error = session_manager_main_enable (vm);
- session_node_enable_disable (is_en);
+ error = session_manager_main_enable (vm, args->rt_engine_type);
+ session_node_enable_disable (1);
}
else
{
session_main.is_enabled = 0;
- session_manager_main_disable (vm);
- session_node_enable_disable (is_en);
+ session_manager_main_disable (vm, args->rt_engine_type);
+ session_node_enable_disable (0);
}
return error;
@@ -2263,10 +2272,15 @@ static clib_error_t *
session_main_loop_init (vlib_main_t * vm)
{
session_main_t *smm = &session_main;
+
if (smm->session_enable_asap)
{
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ smm->rt_engine_type };
+
vlib_worker_thread_barrier_sync (vm);
- vnet_session_enable_disable (vm, 1 /* is_en */ );
+ vnet_session_enable_disable (vm, &args);
vlib_worker_thread_barrier_release (vm);
}
return 0;
@@ -2356,8 +2370,22 @@ session_config_fn (vlib_main_t * vm, unformat_input_t * input)
smm->port_allocator_min_src_port = tmp;
else if (unformat (input, "max-src-port %d", &tmp))
smm->port_allocator_max_src_port = tmp;
+ else if (unformat (input, "enable rt-backend rule-table"))
+ {
+ smm->rt_engine_type = RT_BACKEND_ENGINE_RULE_TABLE;
+ smm->session_enable_asap = 1;
+ }
+ else if (unformat (input, "enable rt-backend sdl"))
+ {
+ smm->rt_engine_type = RT_BACKEND_ENGINE_SDL;
+ smm->session_enable_asap = 1;
+ }
else if (unformat (input, "enable"))
- smm->session_enable_asap = 1;
+ {
+ /* enable session without rt-backend */
+ smm->rt_engine_type = RT_BACKEND_ENGINE_NONE;
+ smm->session_enable_asap = 1;
+ }
else if (unformat (input, "use-app-socket-api"))
(void) appns_sapi_enable_disable (1 /* is_enable */);
else if (unformat (input, "poll-main"))
diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h
index 67a182573e4..24150fbbcd1 100644
--- a/src/vnet/session/session.h
+++ b/src/vnet/session/session.h
@@ -184,6 +184,19 @@ typedef void (*nat44_original_dst_lookup_fn) (
u16 i2o_dst_port, ip_protocol_t proto, u32 *original_dst,
u16 *original_dst_port);
+#define foreach_rt_engine \
+ _ (DISABLE, "disable") \
+ _ (RULE_TABLE, "enable with rt-backend rule table") \
+ _ (NONE, "enable without rt-backend") \
+ _ (SDL, "enable with rt-backend sdl")
+
+typedef enum
+{
+#define _(v, s) RT_BACKEND_ENGINE_##v,
+ foreach_rt_engine
+#undef _
+} session_rt_engine_type_t;
+
typedef struct session_main_
{
/** Worker contexts */
@@ -235,6 +248,9 @@ typedef struct session_main_
/** Enable session manager at startup */
u8 session_enable_asap;
+ /** Session engine type */
+ session_rt_engine_type_t rt_engine_type;
+
/** Poll session node in main thread */
u8 poll_main;
@@ -292,6 +308,12 @@ typedef enum session_q_process_evt_
SESSION_Q_PROCESS_STOP
} session_q_process_evt_t;
+typedef struct _session_enable_disable_args_t
+{
+ session_rt_engine_type_t rt_engine_type;
+ u8 is_en;
+} session_enable_disable_args_t;
+
#define TRANSPORT_PROTO_INVALID (session_main.last_transport_proto_type + 1)
#define TRANSPORT_N_PROTOS (session_main.last_transport_proto_type + 1)
@@ -812,7 +834,9 @@ session_wrk_update_time (session_worker_t *wrk, f64 now)
void session_wrk_enable_adaptive_mode (session_worker_t *wrk);
fifo_segment_t *session_main_get_wrk_mqs_segment (void);
void session_node_enable_disable (u8 is_en);
-clib_error_t *vnet_session_enable_disable (vlib_main_t * vm, u8 is_en);
+clib_error_t *
+vnet_session_enable_disable (vlib_main_t *vm,
+ session_enable_disable_args_t *args);
void session_wrk_handle_evts_main_rpc (void *);
void session_wrk_program_app_wrk_evts (session_worker_t *wrk,
u32 app_wrk_index);
@@ -921,6 +945,30 @@ pool_program_safe_realloc (void **p, u32 elt_size, u32 align)
} \
while (0)
+always_inline u8
+session_is_enabled_without_rt_backend (void)
+{
+ session_main_t *smm = vnet_get_session_main ();
+
+ return (smm->rt_engine_type == RT_BACKEND_ENGINE_NONE);
+}
+
+always_inline u8
+session_sdl_is_enabled (void)
+{
+ session_main_t *smm = vnet_get_session_main ();
+
+ return (smm->rt_engine_type == RT_BACKEND_ENGINE_SDL);
+}
+
+always_inline u8
+session_rule_table_is_enabled (void)
+{
+ session_main_t *smm = vnet_get_session_main ();
+
+ return (smm->rt_engine_type == RT_BACKEND_ENGINE_RULE_TABLE);
+}
+
#endif /* __included_session_h__ */
/*
diff --git a/src/vnet/session/session_api.c b/src/vnet/session/session_api.c
index 7110029b5dc..a729baaae29 100644
--- a/src/vnet/session/session_api.c
+++ b/src/vnet/session/session_api.c
@@ -18,9 +18,10 @@
#include <vnet/session/application.h>
#include <vnet/session/application_interface.h>
#include <vnet/session/application_local.h>
-#include <vnet/session/session_rules_table.h>
-#include <vnet/session/session_table.h>
#include <vnet/session/session.h>
+#include <vnet/session/session_table.h>
+#include <vnet/session/session_rules_table.h>
+#include <vnet/session/session_sdl.h>
#include <vnet/ip/ip_types_api.h>
#include <vnet/format_fns.h>
@@ -30,6 +31,105 @@
#define REPLY_MSG_ID_BASE session_main.msg_id_base
#include <vlibapi/api_helper_macros.h>
+VLIB_REGISTER_LOG_CLASS (session_api_log, static) = { .class_name = "session",
+ .subclass_name = "api" };
+
+#define log_debug(fmt, ...) \
+ vlib_log_debug (session_api_log.class, "%s: " fmt, __func__, __VA_ARGS__)
+#define log_warn(fmt, ...) \
+ vlib_log_warn (session_api_log.class, fmt, __VA_ARGS__)
+#define log_err(fmt, ...) \
+ vlib_log_err (session_api_log.class, fmt, __VA_ARGS__)
+
+static int
+verify_message_len (void *mp, u64 expected_len, char *where)
+{
+ u32 supplied_len = vl_msg_api_get_msg_length (mp);
+
+ if (supplied_len < expected_len)
+ {
+ log_err ("%s: Supplied message length %d is less than expected %d",
+ where, supplied_len, expected_len);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+static void
+vl_api_session_sdl_add_del_t_handler (vl_api_session_sdl_add_del_t *mp)
+{
+ vl_api_session_sdl_add_del_reply_t *rmp;
+ session_rule_add_del_args_t args;
+ session_rule_table_add_del_args_t *table_args = &args.table_args;
+ int rv = 0;
+ u32 count = clib_net_to_host_u32 (mp->count);
+ u64 expected_len = sizeof (*mp) + count * sizeof (mp->r[0]);
+
+ if ((session_main.is_enabled == 0) || (session_sdl_is_enabled () == 0))
+ {
+ rv = VNET_API_ERROR_FEATURE_DISABLED;
+ goto done;
+ }
+
+ if (!verify_message_len (mp, expected_len, "session_sdl_add_del"))
+ {
+ rv = VNET_API_ERROR_INVALID_VALUE;
+ goto done;
+ }
+
+ clib_memset (&args, 0, sizeof (args));
+ table_args->is_add = mp->is_add;
+ args.scope = SESSION_RULE_SCOPE_GLOBAL;
+ args.appns_index = clib_net_to_host_u32 (mp->appns_index);
+ for (int i = 0; i < count; i++)
+ {
+ mp->r[i].tag[sizeof (mp->r[i].tag) - 1] = 0;
+ table_args->tag = format (0, "%s", mp->r[i].tag);
+ ip_prefix_decode (&mp->r[i].lcl, &table_args->lcl);
+ /*
+ * Need to set fp_proto for vnet_session_rule_add_del to find the
+ * correct table
+ */
+ table_args->rmt.fp_proto = table_args->lcl.fp_proto;
+ table_args->action_index = clib_net_to_host_u32 (mp->r[i].action_index);
+
+ rv = vnet_session_rule_add_del (&args);
+ vec_free (table_args->tag);
+ if (rv)
+ {
+ log_err ("session_sdl add del returned on %U @index %d: %U",
+ format_ip46_address, &table_args->lcl.fp_addr,
+ IP46_TYPE_ANY, i, format_session_error, rv);
+
+ /* roll back */
+ table_args->is_add = !mp->is_add;
+ for (int j = i - 1; j >= 0; j--)
+ {
+ mp->r[j].tag[sizeof (mp->r[j].tag) - 1] = 0;
+ table_args->tag = format (0, "%s", mp->r[j].tag);
+ ip_prefix_decode (&mp->r[j].lcl, &table_args->lcl);
+ table_args->rmt.fp_proto = table_args->lcl.fp_proto;
+ table_args->action_index =
+ clib_net_to_host_u32 (mp->r[j].action_index);
+ int rv2 = vnet_session_rule_add_del (&args);
+ vec_free (table_args->tag);
+ if (rv2)
+ log_err ("rollback session_sdl add del returned on %U "
+ "@index %d: %U",
+ format_ip46_address, &table_args->lcl.fp_addr,
+ IP46_TYPE_ANY, j, format_session_error, rv2);
+ }
+ break;
+ }
+ }
+
+done:
+ REPLY_MACRO (VL_API_SESSION_SDL_ADD_DEL_REPLY);
+}
+
static transport_proto_t
api_session_transport_proto_decode (const vl_api_transport_proto_t * api_tp)
{
@@ -520,12 +620,54 @@ vl_api_session_enable_disable_t_handler (vl_api_session_enable_disable_t * mp)
vl_api_session_enable_disable_reply_t *rmp;
vlib_main_t *vm = vlib_get_main ();
int rv = 0;
+ session_enable_disable_args_t args;
+
+ args.is_en = mp->is_enable;
+ if (mp->is_enable)
+ args.rt_engine_type = RT_BACKEND_ENGINE_RULE_TABLE;
+ else
+ args.rt_engine_type = RT_BACKEND_ENGINE_DISABLE;
- vnet_session_enable_disable (vm, mp->is_enable);
+ if (vnet_session_enable_disable (vm, &args))
+ rv = VNET_API_ERROR_INVALID_ARGUMENT;
REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_REPLY);
}
static void
+vl_api_session_enable_disable_v2_t_handler (
+ vl_api_session_enable_disable_v2_t *mp)
+{
+ vl_api_session_enable_disable_v2_reply_t *rmp;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+ session_enable_disable_args_t args;
+
+ STATIC_ASSERT ((session_rt_engine_type_t) RT_BACKEND_ENGINE_API_DISABLE ==
+ RT_BACKEND_ENGINE_DISABLE,
+ "API value mismatch");
+ STATIC_ASSERT ((session_rt_engine_type_t) RT_BACKEND_ENGINE_API_NONE ==
+ RT_BACKEND_ENGINE_NONE,
+ "API value mismatch");
+ STATIC_ASSERT ((session_rt_engine_type_t) RT_BACKEND_ENGINE_API_RULE_TABLE ==
+ RT_BACKEND_ENGINE_RULE_TABLE,
+ "API value mismatch");
+ STATIC_ASSERT ((session_rt_engine_type_t) RT_BACKEND_ENGINE_API_SDL ==
+ RT_BACKEND_ENGINE_SDL,
+ "API value mismatch");
+
+ args.rt_engine_type = (session_rt_engine_type_t) mp->rt_engine_type;
+ if (args.rt_engine_type == RT_BACKEND_ENGINE_DISABLE)
+ args.is_en = 0;
+ else
+ args.is_en = 1;
+
+ if (vnet_session_enable_disable (vm, &args))
+ rv = VNET_API_ERROR_INVALID_VALUE;
+
+ REPLY_MACRO (VL_API_SESSION_ENABLE_DISABLE_V2_REPLY);
+}
+
+static void
vl_api_session_sapi_enable_disable_t_handler (
vl_api_session_sapi_enable_disable_t *mp)
{
@@ -1019,6 +1161,8 @@ send_session_rule_details4 (mma_rule_16_t * rule, u8 is_local,
ip_set (&rmt.fp_addr, &match->rmt_ip, 1);
lcl.fp_len = ip4_mask_to_preflen (&mask->lcl_ip);
rmt.fp_len = ip4_mask_to_preflen (&mask->rmt_ip);
+ lcl.fp_proto = FIB_PROTOCOL_IP4;
+ rmt.fp_proto = FIB_PROTOCOL_IP4;
ip_prefix_encode (&lcl, &rmp->lcl);
ip_prefix_encode (&rmt, &rmp->rmt);
@@ -1061,6 +1205,8 @@ send_session_rule_details6 (mma_rule_40_t * rule, u8 is_local,
ip_set (&rmt.fp_addr, &match->rmt_ip, 0);
lcl.fp_len = ip6_mask_to_preflen (&mask->lcl_ip);
rmt.fp_len = ip6_mask_to_preflen (&mask->rmt_ip);
+ lcl.fp_proto = FIB_PROTOCOL_IP6;
+ rmt.fp_proto = FIB_PROTOCOL_IP6;
ip_prefix_encode (&lcl, &rmp->lcl);
ip_prefix_encode (&rmt, &rmp->rmt);
@@ -1127,14 +1273,89 @@ vl_api_session_rules_dump_t_handler (vl_api_session_rules_dump_t * mp)
return;
session_table_foreach (st, ({
- for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
- {
- send_session_rules_table_details (&st->session_rules[tp],
- st->active_fib_proto, tp,
- st->is_local, st->appns_index, reg,
- mp->context);
- }
- }));
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+ for (tp = 0; tp < TRANSPORT_N_PROTOS; tp++)
+ {
+ session_rules_table_t *srt =
+ srtg_handle_to_srt (st->srtg_handle, tp);
+ send_session_rules_table_details (
+ srt, st->active_fib_proto, tp, st->is_local,
+ st->appns_index, reg, mp->context);
+ }
+ }));
+}
+
+typedef struct session_sdl_table_walk_ctx_
+{
+ vl_api_registration_t *reg;
+ u32 mp_context;
+ u32 appns_index;
+} session_sdl_table_walk_ctx;
+
+static void
+send_session_sdl_details (u32 fei, ip46_address_t *lcl_ip, u16 fp_len,
+ u32 action_index, u32 fp_proto, u8 *tag, void *args)
+{
+ session_sdl_table_walk_ctx *ctx = args;
+ vl_api_registration_t *reg = ctx->reg;
+ u32 appns_index = ctx->appns_index;
+ u32 context = ctx->mp_context;
+ vl_api_session_sdl_details_t *rmp = 0;
+ fib_prefix_t lcl;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ clib_memset (rmp, 0, sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_DETAILS);
+ rmp->context = context;
+
+ clib_memset (&lcl, 0, sizeof (lcl));
+ if (fp_proto == FIB_PROTOCOL_IP4)
+ ip_set (&lcl.fp_addr, &lcl_ip->ip4, 1);
+ else
+ ip_set (&lcl.fp_addr, &lcl_ip->ip6, 0);
+ lcl.fp_len = fp_len;
+ lcl.fp_proto = fp_proto,
+
+ ip_prefix_encode (&lcl, &rmp->lcl);
+ rmp->action_index = clib_host_to_net_u32 (action_index);
+ rmp->appns_index = clib_host_to_net_u32 (appns_index);
+ if (tag)
+ {
+ clib_memcpy_fast (rmp->tag, tag, vec_len (tag));
+ rmp->tag[vec_len (tag)] = 0;
+ }
+
+ vl_api_send_msg (reg, (u8 *) rmp);
+}
+
+static void
+vl_api_session_sdl_dump_t_handler (vl_api_session_rules_dump_t *mp)
+{
+ vl_api_registration_t *reg;
+ session_table_t *st;
+ session_sdl_table_walk_ctx ctx;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ ctx.reg = reg;
+ ctx.mp_context = mp->context;
+
+ session_table_foreach (
+ st, ({
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+ {
+ ctx.appns_index = st->appns_index;
+
+ if (st->active_fib_proto == FIB_PROTOCOL_IP4)
+ session_sdl_table_walk4 (st->srtg_handle, send_session_sdl_details,
+ &ctx);
+ else
+ session_sdl_table_walk6 (st->srtg_handle, send_session_sdl_details,
+ &ctx);
+ }
+ }));
}
static void
@@ -1832,11 +2053,21 @@ appns_sapi_add_ns_socket (app_namespace_t * app_ns)
static clib_error_t *
session_api_hookup (vlib_main_t *vm)
{
+ api_main_t *am = vlibapi_get_main ();
+
/*
* Set up the (msg_name, crc, message-id) table
*/
REPLY_MSG_ID_BASE = setup_message_id_table ();
+ vl_api_set_msg_thread_safe (
+ am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_ADD_DEL, 1);
+ vl_api_set_msg_thread_safe (
+ am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_ADD_DEL_REPLY, 1);
+ vl_api_set_msg_thread_safe (am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_DUMP,
+ 1);
+ vl_api_set_msg_thread_safe (
+ am, REPLY_MSG_ID_BASE + VL_API_SESSION_SDL_DETAILS, 1);
return 0;
}
diff --git a/src/vnet/session/session_cli.c b/src/vnet/session/session_cli.c
index 569a77bccc1..c29a465d056 100644
--- a/src/vnet/session/session_cli.c
+++ b/src/vnet/session/session_cli.c
@@ -237,6 +237,27 @@ done:
return rv;
}
+static uword
+unformat_ip_port (unformat_input_t *input, va_list *args)
+{
+ ip46_address_t *ip = va_arg (*args, ip46_address_t *);
+ u16 *port = va_arg (*args, u16 *);
+
+ if (unformat (input, "%U:%d", unformat_ip46_address, ip, IP46_TYPE_ANY,
+ port))
+ ;
+ else if (unformat (input, "%U", unformat_ip46_address, ip, IP46_TYPE_ANY))
+ {
+ *port = 0;
+ }
+ else
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
uword
unformat_session (unformat_input_t * input, va_list * args)
{
@@ -360,30 +381,80 @@ session_cli_show_all_sessions (vlib_main_t * vm, int verbose)
}
}
+typedef enum
+{
+ SESSION_CLI_FILTER_FORCE_PRINT = 1 << 0,
+} session_cli_filter_flags_t;
+
+typedef enum
+{
+ SESSION_CLI_FILTER_ENDPT_LOCAL = 1 << 0,
+ SESSION_CLI_FILTER_ENDPT_REMOTE = 1 << 1,
+} session_cli_endpt_flags_t;
+
+typedef struct session_cli_filter_
+{
+ session_cli_filter_flags_t flags;
+ struct
+ {
+ u32 start;
+ u32 end;
+ } range;
+ transport_endpoint_t endpt;
+ session_cli_endpt_flags_t endpt_flags;
+ session_state_t *states;
+ transport_proto_t transport_proto;
+ u32 thread_index;
+ u32 verbose;
+} session_cli_filter_t;
+
static int
-session_cli_filter_check (session_t * s, session_state_t * states,
- transport_proto_t tp)
+session_cli_filter_check (session_t *s, session_cli_filter_t *sf)
{
- if (states)
+ transport_connection_t *tc;
+
+ if (sf->states)
{
session_state_t *state;
- vec_foreach (state, states) if (s->session_state == *state)
+ vec_foreach (state, sf->states)
+ if (s->session_state == *state)
goto check_transport;
return 0;
}
check_transport:
- if (tp != TRANSPORT_PROTO_INVALID && session_get_transport_proto (s) != tp)
+ if (sf->transport_proto != TRANSPORT_PROTO_INVALID &&
+ session_get_transport_proto (s) != sf->transport_proto)
return 0;
- return 1;
+ if (s->session_state >= SESSION_STATE_TRANSPORT_DELETED)
+ return 0;
+
+ /* No explicit ip:port match requested */
+ if (!sf->endpt_flags)
+ return 1;
+
+ tc = session_get_transport (s);
+ if (sf->endpt_flags & SESSION_CLI_FILTER_ENDPT_LOCAL)
+ {
+ if (!ip46_address_cmp (&sf->endpt.ip, &tc->lcl_ip) &&
+ (sf->endpt.port == 0 ||
+ sf->endpt.port == clib_net_to_host_u16 (tc->lcl_port)))
+ return 1;
+ }
+ if (sf->endpt_flags & SESSION_CLI_FILTER_ENDPT_REMOTE)
+ {
+ if (!ip46_address_cmp (&sf->endpt.ip, &tc->rmt_ip) &&
+ (sf->endpt.port == 0 ||
+ sf->endpt.port == clib_net_to_host_u16 (tc->rmt_port)))
+ return 1;
+ }
+ return 0;
}
static void
-session_cli_show_session_filter (vlib_main_t * vm, u32 thread_index,
- u32 start, u32 end, session_state_t * states,
- transport_proto_t tp, int verbose)
+session_cli_show_session_filter (vlib_main_t *vm, session_cli_filter_t *sf)
{
u8 output_suppressed = 0;
session_worker_t *wrk;
@@ -391,54 +462,62 @@ session_cli_show_session_filter (vlib_main_t * vm, u32 thread_index,
u32 count = 0, max_index;
int i;
- wrk = session_main_get_worker_if_valid (thread_index);
+ if (sf->range.end < sf->range.start)
+ {
+ vlib_cli_output (vm, "invalid range start: %u end: %u", sf->range.start,
+ sf->range.end);
+ return;
+ }
+
+ wrk = session_main_get_worker_if_valid (sf->thread_index);
if (!wrk)
{
- vlib_cli_output (vm, "invalid thread index %u", thread_index);
+ vlib_cli_output (vm, "invalid thread index %u", sf->thread_index);
return;
}
pool = wrk->sessions;
- if (tp == TRANSPORT_PROTO_INVALID && states == 0 && !verbose
- && (start == 0 && end == ~0))
+ if (sf->transport_proto == TRANSPORT_PROTO_INVALID && sf->states == 0 &&
+ !sf->verbose && (sf->range.start == 0 && sf->range.end == ~0))
{
- vlib_cli_output (vm, "Thread %d: %u sessions", thread_index,
+ vlib_cli_output (vm, "Thread %d: %u sessions", sf->thread_index,
pool_elts (pool));
return;
}
max_index = pool_len (pool) ? pool_len (pool) - 1 : 0;
- for (i = start; i <= clib_min (end, max_index); i++)
+ for (i = sf->range.start; i <= clib_min (sf->range.end, max_index); i++)
{
if (pool_is_free_index (pool, i))
continue;
s = pool_elt_at_index (pool, i);
- if (session_cli_filter_check (s, states, tp))
+ if (!session_cli_filter_check (s, sf))
+ continue;
+
+ count += 1;
+ if (sf->verbose)
{
- count += 1;
- if (verbose)
- {
- if (count > 50 || (verbose > 1 && count > 10))
- {
- output_suppressed = 1;
- continue;
- }
- if (s->session_state < SESSION_STATE_TRANSPORT_DELETED)
- vlib_cli_output (vm, "%U", format_session, s, verbose);
- }
+ if (!(sf->flags & SESSION_CLI_FILTER_FORCE_PRINT) &&
+ (count > 50 || (sf->verbose > 1 && count > 10)))
+ {
+ output_suppressed = 1;
+ continue;
+ }
+ vlib_cli_output (vm, "%U", format_session, s, sf->verbose);
}
}
if (!output_suppressed)
vlib_cli_output (vm, "Thread %d: %u sessions matched filter",
- thread_index, count);
+ sf->thread_index, count);
else
- vlib_cli_output (vm, "Thread %d: %u sessions matched filter. Not all"
- " shown. Use finer grained filter.", thread_index,
- count);
+ vlib_cli_output (vm,
+ "Thread %d: %u sessions matched filter. Not all"
+ " shown. Use finer grained filter.",
+ sf->thread_index, count);
}
void
@@ -482,14 +561,33 @@ session_cli_print_session_states (vlib_main_t * vm)
#undef _
}
+static u8 *
+format_rt_backend (u8 *s, va_list *args)
+{
+ u32 i = va_arg (*args, u32);
+ u8 *t = 0;
+
+ switch (i)
+ {
+#define _(v, s) \
+ case RT_BACKEND_ENGINE_##v: \
+ t = (u8 *) s; \
+ break;
+ foreach_rt_engine
+#undef _
+ default : return format (s, "unknown");
+ }
+ return format (s, "%s", t);
+}
+
static clib_error_t *
show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
u8 one_session = 0, do_listeners = 0, sst, do_elog = 0, do_filter = 0;
- u32 track_index, thread_index = 0, start = 0, end = ~0, session_index;
+ u32 track_index, thread_index = 0, session_index;
transport_proto_t transport_proto = TRANSPORT_PROTO_INVALID;
- session_state_t state = SESSION_N_STATES, *states = 0;
+ session_state_t state = SESSION_N_STATES;
session_main_t *smm = &session_main;
clib_error_t *error = 0;
app_worker_t *app_wrk;
@@ -498,18 +596,51 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
u8 do_events = 0;
int verbose = 0;
session_t *s;
+ session_cli_filter_t sf = {
+ .transport_proto = TRANSPORT_PROTO_INVALID,
+ .range = { 0, ~0 },
+ };
session_cli_return_if_not_enabled ();
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (input, "verbose %d", &verbose))
+ /*
+ * helpers
+ */
+ if (unformat (input, "protos"))
+ {
+ vlib_cli_output (vm, "%U", format_transport_protos);
+ goto done;
+ }
+ else if (unformat (input, "rt-backend"))
+ {
+ vlib_cli_output (vm, "%U", format_rt_backend, smm->rt_engine_type);
+ goto done;
+ }
+ else if (unformat (input, "states"))
+ {
+ session_cli_print_session_states (vm);
+ goto done;
+ }
+ else if (unformat (input, "verbose %d", &verbose))
;
else if (unformat (input, "verbose"))
verbose = 1;
+ /*
+ * listeners
+ */
else if (unformat (input, "listeners %U", unformat_transport_proto,
&transport_proto))
do_listeners = 1;
+ /*
+ * session events
+ */
+ else if (unformat (input, "events"))
+ do_events = 1;
+ /*
+ * single session filter
+ */
else if (unformat (input, "%U", unformat_session, &s))
{
one_session = 1;
@@ -525,17 +656,9 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
}
one_session = 1;
}
- else if (unformat (input, "thread %u", &thread_index))
- {
- do_filter = 1;
- }
- else if (unformat (input, "state %U", unformat_session_state, &state))
- {
- vec_add1 (states, state);
- do_filter = 1;
- }
- else if (unformat (input, "proto %U index %u", unformat_transport_proto,
- &transport_proto, &transport_index))
+ else if (unformat (input, "thread %u proto %U index %u", &thread_index,
+ unformat_transport_proto, &transport_proto,
+ &transport_index))
{
transport_connection_t *tc;
tc = transport_get_connection (transport_proto, transport_index,
@@ -556,30 +679,54 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
}
one_session = 1;
}
+ else if (unformat (input, "elog"))
+ do_elog = 1;
+ /*
+ * session filter
+ */
+ else if (unformat (input, "thread %u", &sf.thread_index))
+ {
+ do_filter = 1;
+ }
+ else if (unformat (input, "state %U", unformat_session_state, &state))
+ {
+ vec_add1 (sf.states, state);
+ do_filter = 1;
+ }
else if (unformat (input, "proto %U", unformat_transport_proto,
- &transport_proto))
+ &sf.transport_proto))
do_filter = 1;
- else if (unformat (input, "range %u %u", &start, &end))
+ else if (unformat (input, "range %u %u", &sf.range.start, &sf.range.end))
do_filter = 1;
- else if (unformat (input, "range %u", &start))
+ else if (unformat (input, "range %u", &sf.range.start))
{
- end = start + 50;
+ sf.range.end = sf.range.start + 50;
do_filter = 1;
}
- else if (unformat (input, "elog"))
- do_elog = 1;
- else if (unformat (input, "protos"))
+ else if (unformat (input, "lcl %U", unformat_ip_port, &sf.endpt.ip,
+ &sf.endpt.port))
{
- vlib_cli_output (vm, "%U", format_transport_protos);
- goto done;
+ sf.endpt_flags |= SESSION_CLI_FILTER_ENDPT_LOCAL;
+ do_filter = 1;
}
- else if (unformat (input, "states"))
+ else if (unformat (input, "rmt %U", unformat_ip_port, &sf.endpt.ip,
+ &sf.endpt.port))
{
- session_cli_print_session_states (vm);
- goto done;
+ sf.endpt_flags |= SESSION_CLI_FILTER_ENDPT_REMOTE;
+ do_filter = 1;
+ }
+ else if (unformat (input, "ep %U", unformat_ip_port, &sf.endpt.ip,
+ &sf.endpt.port))
+ {
+ sf.endpt_flags |=
+ SESSION_CLI_FILTER_ENDPT_REMOTE | SESSION_CLI_FILTER_ENDPT_LOCAL;
+ do_filter = 1;
+ }
+ else if (unformat (input, "force-print"))
+ {
+ sf.flags |= SESSION_CLI_FILTER_FORCE_PRINT;
+ do_filter = 1;
}
- else if (unformat (input, "events"))
- do_events = 1;
else
{
error = clib_error_return (0, "unknown input `%U'",
@@ -636,31 +783,26 @@ show_session_command_fn (vlib_main_t * vm, unformat_input_t * input,
if (do_filter)
{
- if (end < start)
- {
- error = clib_error_return (0, "invalid range start: %u end: %u",
- start, end);
- goto done;
- }
- session_cli_show_session_filter (vm, thread_index, start, end, states,
- transport_proto, verbose);
+ sf.verbose = verbose;
+ session_cli_show_session_filter (vm, &sf);
goto done;
}
session_cli_show_all_sessions (vm, verbose);
done:
- vec_free (states);
+ vec_free (sf.states);
return error;
}
-VLIB_CLI_COMMAND (vlib_cli_show_session_command) =
-{
+VLIB_CLI_COMMAND (vlib_cli_show_session_command) = {
.path = "show session",
- .short_help = "show session [verbose [n]] [listeners <proto>] "
- "[<session-id> [elog]] [thread <n> [index <n>] "
- "[proto <proto>] [state <state>] [range <min> [<max>]] "
- "[protos] [states] ",
+ .short_help =
+ "show session [protos][states][rt-backend][verbose [n]] "
+ "[events][listeners <proto>] "
+ "[<session-id>][thread <n> [[proto <p>] index <n>]][elog] "
+ "[thread <n>][proto <proto>][state <state>][range <min> [<max>]] "
+ "[lcl|rmt|ep <ip>[:<port>]][force-print]",
.function = show_session_command_fn,
};
@@ -829,29 +971,47 @@ static clib_error_t *
session_enable_disable_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
- u8 is_en = 2;
+ session_enable_disable_args_t args;
+ session_main_t *smm = &session_main;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "enable"))
- is_en = 1;
+ {
+ args.is_en = 1;
+ if (unformat (input, "rt-backend"))
+ if (unformat (input, "sdl"))
+ args.rt_engine_type = RT_BACKEND_ENGINE_SDL;
+ else if (unformat (input, "rule-table"))
+ args.rt_engine_type = RT_BACKEND_ENGINE_RULE_TABLE;
+ else
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ else
+ args.rt_engine_type = RT_BACKEND_ENGINE_NONE;
+ }
else if (unformat (input, "disable"))
- is_en = 0;
+ {
+ args.rt_engine_type = RT_BACKEND_ENGINE_DISABLE;
+ args.is_en = 0;
+ }
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
}
- if (is_en > 1)
- return clib_error_return (0, "expected enable | disable");
+ if (smm->is_enabled && args.is_en)
+ if (args.rt_engine_type != smm->rt_engine_type)
+ return clib_error_return (
+ 0, "session is already enable. Must disable first");
- return vnet_session_enable_disable (vm, is_en);
+ return vnet_session_enable_disable (vm, &args);
}
-VLIB_CLI_COMMAND (session_enable_disable_command, static) =
-{
+VLIB_CLI_COMMAND (session_enable_disable_command, static) = {
.path = "session",
- .short_help = "session [enable|disable]",
+ .short_help =
+ "session { enable [ rt-backend sdl | rule-table ] } | { disable }",
.function = session_enable_disable_fn,
};
diff --git a/src/vnet/session/session_lookup.c b/src/vnet/session/session_lookup.c
index ff20bc2d835..0d580ba35c6 100644
--- a/src/vnet/session/session_lookup.c
+++ b/src/vnet/session/session_lookup.c
@@ -28,6 +28,7 @@
#include <vnet/session/session_lookup.h>
#include <vnet/session/session.h>
#include <vnet/session/application.h>
+#include <vnet/session/session_rules_table.h>
static session_lookup_main_t sl_main;
@@ -37,6 +38,8 @@ static session_lookup_main_t sl_main;
*/
static u32 *fib_index_to_table_index[2];
+static u32 *fib_index_to_lock_count[2];
+
/* 16 octets */
typedef CLIB_PACKED (struct {
union
@@ -239,7 +242,7 @@ session_table_get_for_connection (transport_connection_t * tc)
session_table_get (fib_index_to_table_index[fib_proto][tc->fib_index]);
}
-static session_table_t *
+session_table_t *
session_table_get_for_fib_index (u32 fib_proto, u32 fib_index)
{
if (vec_len (fib_index_to_table_index[fib_proto]) <= fib_index)
@@ -476,10 +479,10 @@ session_lookup_rules_table_session4 (session_table_t * st, u8 proto,
ip4_address_t * lcl, u16 lcl_port,
ip4_address_t * rmt, u16 rmt_port)
{
- session_rules_table_t *srt = &st->session_rules[proto];
u32 action_index, app_index;
- action_index = session_rules_table_lookup4 (srt, lcl, rmt, lcl_port,
- rmt_port);
+
+ action_index = session_rules_table_lookup4 (st->srtg_handle, proto, lcl, rmt,
+ lcl_port, rmt_port);
app_index = session_lookup_action_to_handle (action_index);
/* Nothing sophisticated for now, action index is app index */
return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP4,
@@ -492,10 +495,10 @@ session_lookup_rules_table_session6 (session_table_t * st, u8 proto,
ip6_address_t * lcl, u16 lcl_port,
ip6_address_t * rmt, u16 rmt_port)
{
- session_rules_table_t *srt = &st->session_rules[proto];
u32 action_index, app_index;
- action_index = session_rules_table_lookup6 (srt, lcl, rmt, lcl_port,
- rmt_port);
+
+ action_index = session_rules_table_lookup6 (st->srtg_handle, proto, lcl, rmt,
+ lcl_port, rmt_port);
app_index = session_lookup_action_to_handle (action_index);
return session_lookup_app_listen_session (app_index, FIB_PROTOCOL_IP6,
proto);
@@ -515,7 +518,6 @@ u64
session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep,
u8 use_rules)
{
- session_rules_table_t *srt;
session_table_t *st;
u32 ai;
int rv;
@@ -535,10 +537,12 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep,
return kv4.value;
if (use_rules)
{
+ if (st->srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return SESSION_INVALID_HANDLE;
clib_memset (&lcl4, 0, sizeof (lcl4));
- srt = &st->session_rules[sep->transport_proto];
- ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
- sep->port);
+ ai =
+ session_rules_table_lookup4 (st->srtg_handle, sep->transport_proto,
+ &lcl4, &sep->ip.ip4, 0, sep->port);
if (session_lookup_action_index_is_valid (ai))
return session_lookup_action_to_handle (ai);
}
@@ -556,10 +560,12 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep,
if (use_rules)
{
+ if (st->srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return SESSION_INVALID_HANDLE;
clib_memset (&lcl6, 0, sizeof (lcl6));
- srt = &st->session_rules[sep->transport_proto];
- ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
- sep->port);
+ ai =
+ session_rules_table_lookup6 (st->srtg_handle, sep->transport_proto,
+ &lcl6, &sep->ip.ip6, 0, sep->port);
if (session_lookup_action_index_is_valid (ai))
return session_lookup_action_to_handle (ai);
}
@@ -586,14 +592,13 @@ session_lookup_endpoint_listener (u32 table_index, session_endpoint_t * sep,
u64
session_lookup_local_endpoint (u32 table_index, session_endpoint_t * sep)
{
- session_rules_table_t *srt;
session_table_t *st;
u32 ai;
int rv;
st = session_table_get (table_index);
if (!st)
- return SESSION_INVALID_INDEX;
+ return SESSION_INVALID_HANDLE;
ASSERT (st->is_local);
if (sep->is_ip4)
@@ -601,15 +606,18 @@ session_lookup_local_endpoint (u32 table_index, session_endpoint_t * sep)
session_kv4_t kv4;
ip4_address_t lcl4;
- /*
- * Check if endpoint has special rules associated
- */
- clib_memset (&lcl4, 0, sizeof (lcl4));
- srt = &st->session_rules[sep->transport_proto];
- ai = session_rules_table_lookup4 (srt, &lcl4, &sep->ip.ip4, 0,
- sep->port);
- if (session_lookup_action_index_is_valid (ai))
- return session_lookup_action_to_handle (ai);
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+ {
+ /*
+ * Check if endpoint has special rules associated
+ */
+ clib_memset (&lcl4, 0, sizeof (lcl4));
+ ai =
+ session_rules_table_lookup4 (st->srtg_handle, sep->transport_proto,
+ &lcl4, &sep->ip.ip4, 0, sep->port);
+ if (session_lookup_action_index_is_valid (ai))
+ return session_lookup_action_to_handle (ai);
+ }
/*
* Check if session endpoint is a listener
@@ -649,12 +657,15 @@ session_lookup_local_endpoint (u32 table_index, session_endpoint_t * sep)
session_kv6_t kv6;
ip6_address_t lcl6;
- clib_memset (&lcl6, 0, sizeof (lcl6));
- srt = &st->session_rules[sep->transport_proto];
- ai = session_rules_table_lookup6 (srt, &lcl6, &sep->ip.ip6, 0,
- sep->port);
- if (session_lookup_action_index_is_valid (ai))
- return session_lookup_action_to_handle (ai);
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+ {
+ clib_memset (&lcl6, 0, sizeof (lcl6));
+ ai =
+ session_rules_table_lookup6 (st->srtg_handle, sep->transport_proto,
+ &lcl6, &sep->ip.ip6, 0, sep->port);
+ if (session_lookup_action_index_is_valid (ai))
+ return session_lookup_action_to_handle (ai);
+ }
make_v6_listener_kv (&kv6, &sep->ip.ip6, sep->port,
sep->transport_proto);
@@ -982,22 +993,25 @@ session_lookup_connection_wt4 (u32 fib_index, ip4_address_t * lcl,
if (rv == 0)
return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
- /*
- * Check the session rules table
- */
- action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ /*
+ * Check the session rules table
+ */
+ action_index = session_rules_table_lookup4 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
{
- *result = SESSION_LOOKUP_RESULT_FILTERED;
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ {
+ *result = SESSION_LOOKUP_RESULT_FILTERED;
+ return 0;
+ }
+ if ((s = session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP4, proto)))
+ return transport_get_listener (proto, s->connection_index);
return 0;
}
- if ((s = session_lookup_action_to_session (action_index,
- FIB_PROTOCOL_IP4, proto)))
- return transport_get_listener (proto, s->connection_index);
- return 0;
}
/*
@@ -1059,19 +1073,22 @@ session_lookup_connection4 (u32 fib_index, ip4_address_t * lcl,
if (rv == 0)
return transport_get_half_open (proto, kv4.value & 0xFFFFFFFF);
- /*
- * Check the session rules table
- */
- action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
- return 0;
- if ((s = session_lookup_action_to_session (action_index,
- FIB_PROTOCOL_IP4, proto)))
- return transport_get_listener (proto, s->connection_index);
- return 0;
+ /*
+ * Check the session rules table
+ */
+ action_index = session_rules_table_lookup4 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
+ {
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ return 0;
+ if ((s = session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP4, proto)))
+ return transport_get_listener (proto, s->connection_index);
+ return 0;
+ }
}
/*
@@ -1117,17 +1134,20 @@ session_lookup_safe4 (u32 fib_index, ip4_address_t * lcl, ip4_address_t * rmt,
if (rv == 0)
return session_get_from_handle_safe (kv4.value);
- /*
- * Check the session rules table
- */
- action_index = session_rules_table_lookup4 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
- return 0;
- return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP4,
- proto);
+ /*
+ * Check the session rules table
+ */
+ action_index = session_rules_table_lookup4 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
+ {
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ return 0;
+ return session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP4, proto);
+ }
}
/*
@@ -1199,20 +1219,23 @@ session_lookup_connection_wt6 (u32 fib_index, ip6_address_t * lcl,
if (rv == 0)
return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
- /* Check the session rules table */
- action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ /* Check the session rules table */
+ action_index = session_rules_table_lookup6 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
{
- *result = SESSION_LOOKUP_RESULT_FILTERED;
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ {
+ *result = SESSION_LOOKUP_RESULT_FILTERED;
+ return 0;
+ }
+ if ((s = session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP6, proto)))
+ return transport_get_listener (proto, s->connection_index);
return 0;
}
- if ((s = session_lookup_action_to_session (action_index,
- FIB_PROTOCOL_IP6, proto)))
- return transport_get_listener (proto, s->connection_index);
- return 0;
}
/* If nothing is found, check if any listener is available */
@@ -1268,17 +1291,20 @@ session_lookup_connection6 (u32 fib_index, ip6_address_t * lcl,
if (rv == 0)
return transport_get_half_open (proto, kv6.value & 0xFFFFFFFF);
- /* Check the session rules table */
- action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
- return 0;
- if ((s = session_lookup_action_to_session (action_index,
- FIB_PROTOCOL_IP6, proto)))
- return transport_get_listener (proto, s->connection_index);
- return 0;
+ /* Check the session rules table */
+ action_index = session_rules_table_lookup6 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
+ {
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ return 0;
+ if ((s = session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP6, proto)))
+ return transport_get_listener (proto, s->connection_index);
+ return 0;
+ }
}
/* If nothing is found, check if any listener is available */
@@ -1321,15 +1347,18 @@ session_lookup_safe6 (u32 fib_index, ip6_address_t * lcl, ip6_address_t * rmt,
if (rv == 0)
return session_get_from_handle_safe (kv6.value);
- /* Check the session rules table */
- action_index = session_rules_table_lookup6 (&st->session_rules[proto], lcl,
- rmt, lcl_port, rmt_port);
- if (session_lookup_action_index_is_valid (action_index))
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
{
- if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
- return 0;
- return session_lookup_action_to_session (action_index, FIB_PROTOCOL_IP6,
- proto);
+ /* Check the session rules table */
+ action_index = session_rules_table_lookup6 (st->srtg_handle, proto, lcl,
+ rmt, lcl_port, rmt_port);
+ if (session_lookup_action_index_is_valid (action_index))
+ {
+ if (action_index == SESSION_RULES_TABLE_ACTION_DROP)
+ return 0;
+ return session_lookup_action_to_session (action_index,
+ FIB_PROTOCOL_IP6, proto);
+ }
}
/* If nothing is found, check if any listener is available */
@@ -1355,7 +1384,6 @@ session_error_t
vnet_session_rule_add_del (session_rule_add_del_args_t *args)
{
app_namespace_t *app_ns = app_namespace_get (args->appns_index);
- session_rules_table_t *srt;
session_table_t *st;
u32 fib_index;
u8 fib_proto;
@@ -1376,8 +1404,9 @@ vnet_session_rule_add_del (session_rule_add_del_args_t *args)
fib_proto = args->table_args.rmt.fp_proto;
fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
st = session_table_get_for_fib_index (fib_proto, fib_index);
- srt = &st->session_rules[args->transport_proto];
- if ((rv = session_rules_table_add_del (srt, &args->table_args)))
+ session_rules_table_init (st, fib_proto);
+ if ((rv = session_rules_table_add_del (
+ st->srtg_handle, args->transport_proto, &args->table_args)))
return rv;
}
if (args->scope & SESSION_RULE_SCOPE_LOCAL)
@@ -1386,12 +1415,30 @@ vnet_session_rule_add_del (session_rule_add_del_args_t *args)
args->table_args.lcl.fp_proto = args->table_args.rmt.fp_proto;
args->table_args.lcl_port = 0;
st = app_namespace_get_local_table (app_ns);
- srt = &st->session_rules[args->transport_proto];
- rv = session_rules_table_add_del (srt, &args->table_args);
+ session_rules_table_init (st, args->table_args.rmt.fp_proto);
+ rv = session_rules_table_add_del (st->srtg_handle, args->transport_proto,
+ &args->table_args);
}
return rv;
}
+static void
+session_lookup_fib_table_lock (u32 fib_index, u32 protocol)
+{
+ fib_table_lock (fib_index, protocol, sl_main.fib_src);
+ vec_validate (fib_index_to_lock_count[protocol], fib_index);
+ fib_index_to_lock_count[protocol][fib_index]++;
+ ASSERT (fib_index_to_lock_count[protocol][fib_index] > 0);
+}
+
+static void
+session_lookup_fib_table_unlock (u32 fib_index, u32 protocol)
+{
+ fib_table_unlock (fib_index, protocol, sl_main.fib_src);
+ ASSERT (fib_index_to_lock_count[protocol][fib_index] > 0);
+ fib_index_to_lock_count[protocol][fib_index]--;
+}
+
/**
* Mark (global) tables as pertaining to app ns
*/
@@ -1407,7 +1454,10 @@ session_lookup_set_tables_appns (app_namespace_t * app_ns)
fib_index = app_namespace_get_fib_index (app_ns, fp);
st = session_table_get_or_alloc (fp, fib_index);
if (st)
- st->appns_index = app_namespace_index (app_ns);
+ {
+ st->appns_index = app_namespace_index (app_ns);
+ session_lookup_fib_table_lock (fib_index, fp);
+ }
}
}
@@ -1501,6 +1551,9 @@ session_rule_command_fn (vlib_main_t * vm, unformat_input_t * input,
session_cli_return_if_not_enabled ();
+ if (session_rule_table_is_enabled () == 0)
+ return clib_error_return (0, "session rule table engine is not enabled");
+
clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
clib_memset (&rmt_ip, 0, sizeof (rmt_ip));
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
@@ -1622,11 +1675,12 @@ session_lookup_dump_rules_table (u32 fib_index, u8 fib_proto,
u8 transport_proto)
{
vlib_main_t *vm = vlib_get_main ();
- session_rules_table_t *srt;
session_table_t *st;
st = session_table_get_for_fib_index (fib_index, fib_proto);
- srt = &st->session_rules[transport_proto];
- session_rules_table_cli_dump (vm, srt, fib_proto);
+ if (st == 0)
+ return;
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ fib_proto);
}
void
@@ -1634,11 +1688,12 @@ session_lookup_dump_local_rules_table (u32 table_index, u8 fib_proto,
u8 transport_proto)
{
vlib_main_t *vm = vlib_get_main ();
- session_rules_table_t *srt;
session_table_t *st;
st = session_table_get (table_index);
- srt = &st->session_rules[transport_proto];
- session_rules_table_cli_dump (vm, srt, fib_proto);
+ if (st == 0)
+ return;
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ fib_proto);
}
static clib_error_t *
@@ -1650,7 +1705,6 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
ip46_address_t lcl_ip, rmt_ip;
u8 is_ip4 = 1, show_one = 0;
app_namespace_t *app_ns;
- session_rules_table_t *srt;
session_table_t *st;
u8 *ns_id = 0, fib_proto;
@@ -1665,9 +1719,9 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
else if (unformat (input, "appns %_%v%_", &ns_id))
;
else if (unformat (input, "scope global"))
- scope = 1;
+ scope = SESSION_RULE_SCOPE_GLOBAL;
else if (unformat (input, "scope local"))
- scope = 2;
+ scope = SESSION_RULE_SCOPE_LOCAL;
else if (unformat (input, "%U/%d %d %U/%d %d", unformat_ip4_address,
&lcl_ip.ip4, &lcl_plen, &lcl_port,
unformat_ip4_address, &rmt_ip.ip4, &rmt_plen,
@@ -1685,14 +1739,17 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
show_one = 1;
}
else
- return clib_error_return (0, "unknown input `%U'",
- format_unformat_error, input);
+ {
+ vec_free (ns_id);
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
}
if (transport_proto == ~0)
{
vlib_cli_output (vm, "transport proto must be set");
- return 0;
+ goto done;
}
if (ns_id)
@@ -1701,7 +1758,7 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
if (!app_ns)
{
vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
- return 0;
+ goto done;
}
}
else
@@ -1709,7 +1766,7 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
app_ns = app_namespace_get_default ();
}
- if (scope == 1 || scope == 0)
+ if (scope == SESSION_RULE_SCOPE_GLOBAL || scope == 0)
{
fib_proto = is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
fib_index = is_ip4 ? app_ns->ip4_fib_index : app_ns->ip6_fib_index;
@@ -1720,20 +1777,51 @@ show_session_rules_command_fn (vlib_main_t * vm, unformat_input_t * input,
st = app_namespace_get_local_table (app_ns);
}
+ if (session_rule_table_is_enabled () == 0)
+ {
+ vlib_cli_output (vm, "session rule table engine is not enabled");
+ goto done;
+ }
+
if (show_one)
{
- srt = &st->session_rules[transport_proto];
- session_rules_table_show_rule (vm, srt, &lcl_ip, lcl_port, &rmt_ip,
- rmt_port, is_ip4);
- return 0;
+ if (st)
+ session_rules_table_show_rule (vm, st->srtg_handle, transport_proto,
+ &lcl_ip, lcl_port, &rmt_ip, rmt_port,
+ is_ip4);
+ goto done;
}
vlib_cli_output (vm, "%U rules table", format_transport_proto,
transport_proto);
- srt = &st->session_rules[transport_proto];
- session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP4);
- session_rules_table_cli_dump (vm, srt, FIB_PROTOCOL_IP6);
+ if (scope == SESSION_RULE_SCOPE_LOCAL)
+ {
+ if (st)
+ {
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ FIB_PROTOCOL_IP4);
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ FIB_PROTOCOL_IP6);
+ }
+ }
+ else
+ {
+ /*
+ * 2 separate session tables for global entries, 1 for ip4 and 1 for ip6
+ */
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4,
+ app_ns->ip4_fib_index);
+ if (st)
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ FIB_PROTOCOL_IP4);
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6,
+ app_ns->ip6_fib_index);
+ if (st)
+ session_rules_table_cli_dump (vm, st->srtg_handle, transport_proto,
+ FIB_PROTOCOL_IP6);
+ }
+done:
vec_free (ns_id);
return 0;
}
@@ -1832,6 +1920,14 @@ session_lookup_init (void)
clib_spinlock_init (&slm->st_alloc_lock);
+ /* We are not contributing any route to the fib. But we allocate a fib source
+ * so that when we lock the fib table, we can view that we have a lock on the
+ * particular fib table in case we wonder why the fib table is not free after
+ * "ip table del"
+ */
+ slm->fib_src = fib_source_allocate (
+ "session lookup", FIB_SOURCE_PRIORITY_LOW, FIB_SOURCE_BH_SIMPLE);
+
/*
* Allocate default table and map it to fib_index 0
*/
@@ -1847,6 +1943,26 @@ session_lookup_init (void)
session_table_init (st, FIB_PROTOCOL_IP6);
}
+void
+session_lookup_table_cleanup (u32 fib_proto, u32 fib_index)
+{
+ session_table_t *st;
+ u32 table_index;
+
+ session_lookup_fib_table_unlock (fib_index, fib_proto);
+ if (fib_index_to_lock_count[fib_proto][fib_index] == 0)
+ {
+ table_index = session_lookup_get_index_for_fib (fib_proto, fib_index);
+ st = session_table_get (table_index);
+ if (st)
+ {
+ session_table_free (st, fib_proto);
+ if (vec_len (fib_index_to_table_index[fib_proto]) > fib_index)
+ fib_index_to_table_index[fib_proto][fib_index] = ~0;
+ }
+ }
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/session/session_lookup.h b/src/vnet/session/session_lookup.h
index f9ffc15165a..9f56af20a87 100644
--- a/src/vnet/session/session_lookup.h
+++ b/src/vnet/session/session_lookup.h
@@ -19,6 +19,8 @@
#include <vnet/session/session_table.h>
#include <vnet/session/session_types.h>
#include <vnet/session/application_namespace.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_source.h>
#define HALF_OPEN_LOOKUP_INVALID_VALUE ((u64)~0)
@@ -32,6 +34,7 @@ typedef enum session_lookup_result_
typedef struct session_lookup_main_
{
clib_spinlock_t st_alloc_lock;
+ fib_source_t fib_src;
} session_lookup_main_t;
session_t *session_lookup_safe4 (u32 fib_index, ip4_address_t * lcl,
@@ -114,6 +117,17 @@ typedef enum _session_rule_scope
SESSION_RULE_SCOPE_LOCAL = 2,
} session_rule_scope_e;
+typedef struct _session_rules_table_add_del_args
+{
+ fib_prefix_t lcl;
+ fib_prefix_t rmt;
+ u16 lcl_port;
+ u16 rmt_port;
+ u32 action_index;
+ u8 *tag;
+ u8 is_add;
+} session_rule_table_add_del_args_t;
+
typedef struct _session_rule_add_del_args
{
/**
@@ -139,6 +153,8 @@ session_error_t vnet_session_rule_add_del (session_rule_add_del_args_t *args);
void session_lookup_set_tables_appns (app_namespace_t * app_ns);
void session_lookup_init (void);
+session_table_t *session_table_get_for_fib_index (u32 fib_proto,
+ u32 fib_index);
#endif /* SRC_VNET_SESSION_SESSION_LOOKUP_H_ */
diff --git a/src/vnet/session/session_rules_table.c b/src/vnet/session/session_rules_table.c
index d15df48d7b5..acb575b0f7c 100644
--- a/src/vnet/session/session_rules_table.c
+++ b/src/vnet/session/session_rules_table.c
@@ -17,8 +17,23 @@
#include <vnet/session/mma_template.c>
#include <vnet/session/mma_40.h>
#include <vnet/session/mma_template.c>
-#include <vnet/session/session_rules_table.h>
#include <vnet/session/transport.h>
+#include <vnet/session/session.h>
+#include <vnet/session/session_table.h>
+#include <vnet/session/session_rules_table.h>
+#include <vnet/session/session_sdl.h>
+
+VLIB_REGISTER_LOG_CLASS (session_rt_log, static) = { .class_name = "session",
+ .subclass_name = "rt" };
+
+#define log_debug(fmt, ...) \
+ vlib_log_debug (session_rt_log.class, "%s: " fmt, __func__, __VA_ARGS__)
+#define log_warn(fmt, ...) \
+ vlib_log_warn (session_rt_log.class, fmt, __VA_ARGS__)
+#define log_err(fmt, ...) vlib_log_err (session_rt_log.class, fmt, __VA_ARGS__)
+
+static session_rules_table_group_t *srt_instances;
+const session_rt_engine_vft_t *session_rt_engine_vft;
u32
session_rule_tag_key_index (u32 ri, u8 is_ip4)
@@ -119,13 +134,25 @@ fib_pref_normalize (fib_prefix_t * pref)
}
u8 *
+format_session_rule_tag (u8 *s, va_list *args)
+{
+ static u8 *null_tag = 0;
+ u8 *tag = va_arg (*args, u8 *);
+
+ if (!null_tag)
+ null_tag = format (0, "none");
+ s = format (s, "%v", (tag != 0) ? tag : null_tag);
+ return s;
+}
+
+u8 *
format_session_rule4 (u8 * s, va_list * args)
{
session_rules_table_t *srt = va_arg (*args, session_rules_table_t *);
mma_rule_16_t *sr = va_arg (*args, mma_rule_16_t *);
session_mask_or_match_4_t *mask, *match;
mma_rules_table_16_t *srt4;
- u8 *tag = 0, *null_tag = format (0, "none");
+ u8 *tag = 0;
u32 ri;
int i;
@@ -135,20 +162,18 @@ format_session_rule4 (u8 * s, va_list * args)
match = (session_mask_or_match_4_t *) & sr->match;
mask = (session_mask_or_match_4_t *) & sr->mask;
- s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d tag: %v", ri,
+ s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d tag: %U", ri,
format_ip4_address, &match->lcl_ip,
- ip4_mask_to_preflen (&mask->lcl_ip),
- clib_net_to_host_u16 (match->lcl_port), format_ip4_address,
- &match->rmt_ip, ip4_mask_to_preflen (&mask->rmt_ip),
- clib_net_to_host_u16 (match->rmt_port), sr->action_index,
- tag ? tag : null_tag);
+ ip4_mask_to_preflen (&mask->lcl_ip), match->lcl_port,
+ format_ip4_address, &match->rmt_ip,
+ ip4_mask_to_preflen (&mask->rmt_ip), match->rmt_port,
+ sr->action_index, format_session_rule_tag, tag);
if (vec_len (sr->next_indices))
{
s = format (s, "\n children: ");
for (i = 0; i < vec_len (sr->next_indices); i++)
s = format (s, "%d ", sr->next_indices[i]);
}
- vec_free (null_tag);
return s;
}
@@ -159,7 +184,7 @@ format_session_rule6 (u8 * s, va_list * args)
mma_rule_40_t *sr = va_arg (*args, mma_rule_40_t *);
session_mask_or_match_6_t *mask, *match;
mma_rules_table_40_t *srt6;
- u8 *tag = 0, *null_tag = format (0, "none");
+ u8 *tag = 0;
u32 ri;
int i;
@@ -169,20 +194,18 @@ format_session_rule6 (u8 * s, va_list * args)
match = (session_mask_or_match_6_t *) & sr->match;
mask = (session_mask_or_match_6_t *) & sr->mask;
- s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d tag: %v", ri,
+ s = format (s, "[%d] rule: %U/%d %d %U/%d %d action: %d tag: %U", ri,
format_ip6_address, &match->lcl_ip,
- ip6_mask_to_preflen (&mask->lcl_ip),
- clib_net_to_host_u16 (match->lcl_port), format_ip6_address,
- &match->rmt_ip, ip6_mask_to_preflen (&mask->rmt_ip),
- clib_net_to_host_u16 (match->rmt_port), sr->action_index,
- tag ? tag : null_tag);
+ ip6_mask_to_preflen (&mask->lcl_ip), match->lcl_port,
+ format_ip6_address, &match->rmt_ip,
+ ip6_mask_to_preflen (&mask->rmt_ip), match->rmt_port,
+ sr->action_index, format_session_rule_tag, tag);
if (vec_len (sr->next_indices))
{
s = format (s, "\n children: ");
for (i = 0; i < vec_len (sr->next_indices); i++)
s = format (s, "%d ", sr->next_indices[i]);
}
- vec_free (null_tag);
return s;
}
@@ -313,11 +336,10 @@ session_rules_table_alloc_rule_40 (mma_rules_table_40_t * srt,
return rule;
}
-u32
-session_rules_table_lookup_rule4 (session_rules_table_t * srt,
- ip4_address_t * lcl_ip,
- ip4_address_t * rmt_ip, u16 lcl_port,
- u16 rmt_port)
+static u32
+session_rules_table_lookup_rule4 (session_rules_table_t *srt,
+ ip4_address_t *lcl_ip, ip4_address_t *rmt_ip,
+ u16 lcl_port, u16 rmt_port)
{
mma_rules_table_16_t *srt4 = &srt->session_rules_tables_16;
session_mask_or_match_4_t key = {
@@ -326,16 +348,20 @@ session_rules_table_lookup_rule4 (session_rules_table_t * srt,
.lcl_port = lcl_port,
.rmt_port = rmt_port,
};
+
+ if (srt4->rules == 0)
+ return SESSION_TABLE_INVALID_INDEX;
return mma_rules_table_lookup_rule_16 (srt4,
(mma_mask_or_match_16_t *) & key,
srt4->root_index);
}
u32
-session_rules_table_lookup4 (session_rules_table_t * srt,
- ip4_address_t * lcl_ip, ip4_address_t * rmt_ip,
- u16 lcl_port, u16 rmt_port)
+session_rules_table_lookup4_ (u32 srtg_handle, u32 proto,
+ ip4_address_t *lcl_ip, ip4_address_t *rmt_ip,
+ u16 lcl_port, u16 rmt_port)
{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, proto);
mma_rules_table_16_t *srt4 = &srt->session_rules_tables_16;
session_mask_or_match_4_t key = {
.lcl_ip.as_u32 = lcl_ip->as_u32,
@@ -343,21 +369,36 @@ session_rules_table_lookup4 (session_rules_table_t * srt,
.lcl_port = lcl_port,
.rmt_port = rmt_port,
};
+
+ if (srt4->rules == 0)
+ return SESSION_TABLE_INVALID_INDEX;
return mma_rules_table_lookup_16 (srt4, (mma_mask_or_match_16_t *) & key,
srt4->root_index);
}
-u32
-session_rules_table_lookup_rule6 (session_rules_table_t * srt,
- ip6_address_t * lcl_ip,
- ip6_address_t * rmt_ip, u16 lcl_port,
- u16 rmt_port)
+session_rules_table_t *
+srtg_handle_to_srt (u32 srtg_handle, u32 proto)
+{
+ session_rules_table_group_t *srtg =
+ pool_elt_at_index (srt_instances, srtg_handle);
+ session_rules_table_t *srt = &srtg->session_rules[proto];
+
+ return srt;
+}
+
+static u32
+session_rules_table_lookup_rule6 (session_rules_table_t *srt,
+ ip6_address_t *lcl_ip, ip6_address_t *rmt_ip,
+ u16 lcl_port, u16 rmt_port)
{
mma_rules_table_40_t *srt6 = &srt->session_rules_tables_40;
session_mask_or_match_6_t key = {
.lcl_port = lcl_port,
.rmt_port = rmt_port,
};
+
+ if (srt6->rules == 0)
+ return SESSION_TABLE_INVALID_INDEX;
clib_memcpy_fast (&key.lcl_ip, lcl_ip, sizeof (*lcl_ip));
clib_memcpy_fast (&key.rmt_ip, rmt_ip, sizeof (*rmt_ip));
return mma_rules_table_lookup_rule_40 (srt6,
@@ -366,15 +407,19 @@ session_rules_table_lookup_rule6 (session_rules_table_t * srt,
}
u32
-session_rules_table_lookup6 (session_rules_table_t * srt,
- ip6_address_t * lcl_ip, ip6_address_t * rmt_ip,
- u16 lcl_port, u16 rmt_port)
+session_rules_table_lookup6_ (u32 srtg_handle, u32 proto,
+ ip6_address_t *lcl_ip, ip6_address_t *rmt_ip,
+ u16 lcl_port, u16 rmt_port)
{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, proto);
mma_rules_table_40_t *srt6 = &srt->session_rules_tables_40;
session_mask_or_match_6_t key = {
.lcl_port = lcl_port,
.rmt_port = rmt_port,
};
+
+ if (srt6->rules == 0)
+ return SESSION_TABLE_INVALID_INDEX;
clib_memcpy_fast (&key.lcl_ip, lcl_ip, sizeof (*lcl_ip));
clib_memcpy_fast (&key.rmt_ip, rmt_ip, sizeof (*rmt_ip));
return mma_rules_table_lookup_40 (srt6, (mma_mask_or_match_40_t *) & key,
@@ -390,9 +435,10 @@ session_rules_table_lookup6 (session_rules_table_t * srt,
* @return 0 if success, session_error_t error otherwise
*/
session_error_t
-session_rules_table_add_del (session_rules_table_t *srt,
- session_rule_table_add_del_args_t *args)
+session_rules_table_add_del_ (u32 srtg_handle, u32 proto,
+ session_rule_table_add_del_args_t *args)
{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, proto);
u8 fib_proto = args->rmt.fp_proto, *rt;
u32 ri_from_tag, ri;
int rv;
@@ -515,50 +561,90 @@ session_rules_table_add_del (session_rules_table_t *srt,
}
void
-session_rules_table_free (session_rules_table_t *srt)
+session_rules_table_free_ (session_table_t *st, u8 fib_proto)
+{
+ session_rules_table_group_t *srtg =
+ pool_elt_at_index (srt_instances, st->srtg_handle);
+ session_rules_table_t *srt;
+
+ vec_foreach (srt, srtg->session_rules)
+ {
+ mma_rules_table_free_16 (&srt->session_rules_tables_16);
+ mma_rules_table_free_40 (&srt->session_rules_tables_40);
+
+ hash_free (srt->tags_by_rules);
+ hash_free (srt->rules_by_tag);
+ }
+ srtg_instance_free (st);
+}
+
+void
+srtg_instance_free (session_table_t *st)
{
- mma_rules_table_free_16 (&srt->session_rules_tables_16);
- mma_rules_table_free_40 (&srt->session_rules_tables_40);
+ session_rules_table_group_t *srtg =
+ pool_elt_at_index (srt_instances, st->srtg_handle);
- hash_free (srt->tags_by_rules);
- hash_free (srt->rules_by_tag);
+ vec_free (srtg->session_rules);
+ pool_put (srt_instances, srtg);
+ st->srtg_handle = SESSION_SRTG_HANDLE_INVALID;
+}
+
+session_rules_table_group_t *
+srtg_instance_alloc (session_table_t *st, u32 n_proto)
+{
+ session_rules_table_group_t *srtg;
+
+ pool_get (srt_instances, srtg);
+ vec_validate (srtg->session_rules, n_proto);
+ st->srtg_handle = srtg - srt_instances;
+ return (srtg);
}
void
-session_rules_table_init (session_rules_table_t * srt)
+session_rules_table_init_ (session_table_t *st, u8 fib_proto)
{
mma_rules_table_16_t *srt4;
mma_rules_table_40_t *srt6;
mma_rule_16_t *rule4;
mma_rule_40_t *rule6;
fib_prefix_t null_prefix;
+ session_rules_table_t *srt;
+ session_rules_table_group_t *srtg;
- clib_memset (&null_prefix, 0, sizeof (null_prefix));
+ srtg = srtg_instance_alloc (st, TRANSPORT_N_PROTOS - 1);
- srt4 = &srt->session_rules_tables_16;
- rule4 = session_rules_table_alloc_rule_16 (srt4, &null_prefix, 0,
- &null_prefix, 0);
- rule4->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
- srt4->root_index = mma_rules_table_rule_index_16 (srt4, rule4);
- srt4->rule_cmp_fn = rule_cmp_16;
+ clib_memset (&null_prefix, 0, sizeof (null_prefix));
+ vec_foreach (srt, srtg->session_rules)
+ {
+ srt4 = &srt->session_rules_tables_16;
- srt6 = &srt->session_rules_tables_40;
- rule6 = session_rules_table_alloc_rule_40 (srt6, &null_prefix, 0,
- &null_prefix, 0);
- rule6->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
- srt6->root_index = mma_rules_table_rule_index_40 (srt6, rule6);
- srt6->rule_cmp_fn = rule_cmp_40;
+ ASSERT (srt4->rules == 0);
+ rule4 = session_rules_table_alloc_rule_16 (srt4, &null_prefix, 0,
+ &null_prefix, 0);
+ rule4->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
+ srt4->root_index = mma_rules_table_rule_index_16 (srt4, rule4);
+ srt4->rule_cmp_fn = rule_cmp_16;
- srt->rules_by_tag = hash_create_vec (0, sizeof (u8), sizeof (uword));
- srt->tags_by_rules = hash_create (0, sizeof (uword));
+ srt6 = &srt->session_rules_tables_40;
+ ASSERT (srt6->rules == 0);
+ rule6 = session_rules_table_alloc_rule_40 (srt6, &null_prefix, 0,
+ &null_prefix, 0);
+ rule6->action_index = SESSION_RULES_TABLE_INVALID_INDEX;
+ srt6->root_index = mma_rules_table_rule_index_40 (srt6, rule6);
+ srt6->rule_cmp_fn = rule_cmp_40;
+
+ srt->rules_by_tag = hash_create_vec (0, sizeof (u8), sizeof (uword));
+ srt->tags_by_rules = hash_create (0, sizeof (uword));
+ }
}
void
-session_rules_table_show_rule (vlib_main_t * vm, session_rules_table_t * srt,
- ip46_address_t * lcl_ip, u16 lcl_port,
- ip46_address_t * rmt_ip, u16 rmt_port,
- u8 is_ip4)
+session_rules_table_show_rule_ (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ ip46_address_t *lcl_ip, u16 lcl_port,
+ ip46_address_t *rmt_ip, u16 rmt_port,
+ u8 is_ip4)
{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, proto);
mma_rules_table_16_t *srt4;
mma_rules_table_40_t *srt6;
mma_rule_16_t *sr4;
@@ -599,9 +685,10 @@ session_rules_table_show_rule (vlib_main_t * vm, session_rules_table_t * srt,
}
void
-session_rules_table_cli_dump (vlib_main_t * vm, session_rules_table_t * srt,
- u8 fib_proto)
+session_rules_table_cli_dump_ (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ u8 fib_proto)
{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, proto);
if (fib_proto == FIB_PROTOCOL_IP4)
{
mma_rules_table_16_t *srt4;
@@ -628,6 +715,108 @@ session_rules_table_cli_dump (vlib_main_t * vm, session_rules_table_t * srt,
}
}
+static const session_rt_engine_vft_t session_rules_table_vft = {
+ .backend_engine = RT_BACKEND_ENGINE_RULE_TABLE,
+ .table_lookup4 = session_rules_table_lookup4_,
+ .table_lookup6 = session_rules_table_lookup6_,
+ .table_cli_dump = session_rules_table_cli_dump_,
+ .table_show_rule = session_rules_table_show_rule_,
+ .table_add_del = session_rules_table_add_del_,
+ .table_init = session_rules_table_init_,
+ .table_free = session_rules_table_free_,
+};
+
+static void
+session_rules_table_app_namespace_walk_cb (app_namespace_t *app_ns, void *ctx)
+{
+ u32 fib_index, table_index;
+ session_table_t *st;
+
+ log_debug ("disable app_ns %s", app_ns->ns_id);
+ st = session_table_get (app_ns->local_table_index);
+ if (st)
+ session_rules_table_free (st, FIB_PROTOCOL_MAX);
+
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP4);
+ table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP4, fib_index);
+ st = session_table_get (table_index);
+ if (st)
+ session_rules_table_free (st, FIB_PROTOCOL_IP4);
+
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP6);
+ table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP6, fib_index);
+ st = session_table_get (table_index);
+ if (st)
+ session_rules_table_free (st, FIB_PROTOCOL_IP6);
+}
+
+clib_error_t *
+session_rules_table_enable_disable (int enable)
+{
+ clib_error_t *error;
+
+ if (enable)
+ error = session_rule_table_register_engine (&session_rules_table_vft);
+ else
+ {
+ app_namespace_walk (session_rules_table_app_namespace_walk_cb, 0);
+ error = session_rule_table_deregister_engine (&session_rules_table_vft);
+ }
+
+ return error;
+}
+
+clib_error_t *
+session_rt_backend_enable_disable (session_rt_engine_type_t rt_engine_type)
+{
+ session_main_t *smm = &session_main;
+ clib_error_t *error = 0;
+
+ if (rt_engine_type < RT_BACKEND_ENGINE_DISABLE ||
+ rt_engine_type > RT_BACKEND_ENGINE_SDL)
+ return clib_error_return (0, "invalid rt-backend %d", rt_engine_type);
+
+ if (rt_engine_type == RT_BACKEND_ENGINE_SDL)
+ error = session_sdl_enable_disable (1);
+ else if (rt_engine_type == RT_BACKEND_ENGINE_RULE_TABLE)
+ error = session_rules_table_enable_disable (1);
+ else if (rt_engine_type == RT_BACKEND_ENGINE_DISABLE)
+ {
+ if (session_sdl_is_enabled ())
+ error = session_sdl_enable_disable (0);
+ else if (session_rule_table_is_enabled ())
+ error = session_rules_table_enable_disable (0);
+ }
+
+ if (!error)
+ smm->rt_engine_type = rt_engine_type;
+ return error;
+}
+
+clib_error_t *
+session_rule_table_register_engine (const session_rt_engine_vft_t *vft)
+{
+ if (session_rt_engine_vft == vft)
+ return 0;
+ if (session_rt_engine_vft)
+ return clib_error_return (0, "session rule engine is already registered");
+
+ session_rt_engine_vft = vft;
+ return 0;
+}
+
+clib_error_t *
+session_rule_table_deregister_engine (const session_rt_engine_vft_t *vft)
+{
+ if (session_rt_engine_vft == vft)
+ session_rt_engine_vft = 0;
+ else
+ return clib_error_return (
+ 0, "session rule engine is not registered to this engine");
+
+ return 0;
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/src/vnet/session/session_rules_table.h b/src/vnet/session/session_rules_table.h
index 010d50a6398..a61438bb9fd 100644
--- a/src/vnet/session/session_rules_table.h
+++ b/src/vnet/session/session_rules_table.h
@@ -22,6 +22,10 @@
#include <vnet/session/transport.h>
#include <vnet/session/mma_16.h>
#include <vnet/session/mma_40.h>
+#include <vnet/session/session_lookup.h>
+#include <vnet/session/session_table.h>
+
+#define SESSION_SRTG_HANDLE_INVALID ~0
typedef CLIB_PACKED (struct
{
@@ -58,29 +62,36 @@ typedef CLIB_PACKED (struct
#define SESSION_RULES_TABLE_ACTION_DROP (MMA_TABLE_INVALID_INDEX - 1)
#define SESSION_RULES_TABLE_ACTION_ALLOW (MMA_TABLE_INVALID_INDEX - 2)
-typedef struct _session_rules_table_add_del_args
-{
- fib_prefix_t lcl;
- fib_prefix_t rmt;
- u16 lcl_port;
- u16 rmt_port;
- u32 action_index;
- u8 *tag;
- u8 is_add;
-} session_rule_table_add_del_args_t;
-
typedef struct _rule_tag
{
u8 *tag;
} session_rule_tag_t;
+typedef struct session_sdl_block
+{
+ u32 ip_table_id;
+ u32 ip6_table_id;
+ u32 ip_fib_index;
+ u32 ip6_fib_index;
+} session_sdl_block_t;
+
typedef struct _session_rules_table_t
{
- /**
- * Per fib proto session rules tables
- */
- mma_rules_table_16_t session_rules_tables_16;
- mma_rules_table_40_t session_rules_tables_40;
+ union
+ {
+ /**
+ * Per fib proto session rules tables
+ */
+ struct
+ {
+ mma_rules_table_16_t session_rules_tables_16;
+ mma_rules_table_40_t session_rules_tables_40;
+ };
+ /**
+ * sdl table
+ */
+ struct session_sdl_block sdl_block;
+ };
/**
* Hash table that maps tags to rules
*/
@@ -95,28 +106,163 @@ typedef struct _session_rules_table_t
uword *tags_by_rules;
} session_rules_table_t;
-u32 session_rules_table_lookup4 (session_rules_table_t * srt,
- ip4_address_t * lcl_ip,
- ip4_address_t * rmt_ip, u16 lcl_port,
- u16 rmt_port);
-u32 session_rules_table_lookup6 (session_rules_table_t * srt,
- ip6_address_t * lcl_ip,
- ip6_address_t * rmt_ip, u16 lcl_port,
- u16 rmt_port);
-void session_rules_table_cli_dump (vlib_main_t * vm,
- session_rules_table_t * srt, u8 fib_proto);
-void session_rules_table_show_rule (vlib_main_t * vm,
- session_rules_table_t * srt,
- ip46_address_t * lcl_ip, u16 lcl_port,
- ip46_address_t * rmt_ip, u16 rmt_port,
- u8 is_ip4);
+typedef struct _session_rules_table_group_t
+{
+ session_rules_table_t *session_rules;
+} session_rules_table_group_t;
+
session_error_t
-session_rules_table_add_del (session_rules_table_t *srt,
- session_rule_table_add_del_args_t *args);
+session_rules_table_add_del_ (u32 srtg_handle, u32 proto,
+ session_rule_table_add_del_args_t *args);
u8 *session_rules_table_rule_tag (session_rules_table_t * srt, u32 ri,
u8 is_ip4);
-void session_rules_table_init (session_rules_table_t * srt);
-void session_rules_table_free (session_rules_table_t *srt);
+void session_rules_table_init_ (struct _session_lookup_table *st,
+ u8 fib_proto);
+void session_rules_table_free_ (struct _session_lookup_table *st,
+ u8 fib_proto);
+
+typedef u32 (*rules_table_lookup4) (u32 srtg_handle, u32 proto,
+ ip4_address_t *lcl_ip,
+ ip4_address_t *rmt_ip, u16 lcl_port,
+ u16 rmt_port);
+typedef u32 (*rules_table_lookup6) (u32 srtg_handle, u32 proto,
+ ip6_address_t *lcl_ip,
+ ip6_address_t *rmt_ip, u16 lcl_port,
+ u16 rmt_port);
+typedef void (*rules_table_cli_dump) (vlib_main_t *vm, u32 srtg_handle,
+ u32 proto, u8 fib_proto);
+typedef void (*rules_table_show_rule) (vlib_main_t *vm, u32 srtg_handle,
+ u32 proto, ip46_address_t *lcl_ip,
+ u16 lcl_port, ip46_address_t *rmt_ip,
+ u16 rmt_port, u8 is_ip4);
+typedef session_error_t (*rules_table_add_del) (
+ u32 srtg_handle, u32 proto, session_rule_table_add_del_args_t *args);
+typedef void (*rules_table_init) (struct _session_lookup_table *st,
+ u8 fib_proto);
+typedef void (*rules_table_free) (struct _session_lookup_table *st,
+ u8 fib_proto);
+
+#define foreach_session_rt_engine_vft_method_name \
+ _ (lookup4) \
+ _ (lookup6) \
+ _ (cli_dump) \
+ _ (show_rule) \
+ _ (add_del) \
+ _ (init) \
+ _ (free)
+
+#define _(name) rules_table_##name table_##name;
+typedef struct session_rt_engine_vft
+{
+ u32 backend_engine;
+ foreach_session_rt_engine_vft_method_name
+} session_rt_engine_vft_t;
+#undef _
+
+extern u8 *format_session_rule_tag (u8 *s, va_list *args);
+extern u8 *session_rules_table_rule_tag (session_rules_table_t *srt, u32 ri,
+ u8 is_ip4);
+extern u32 session_rules_table_rule_for_tag (session_rules_table_t *srt,
+ u8 *tag);
+extern void session_rules_table_add_tag (session_rules_table_t *srt, u8 *tag,
+ u32 rule_index, u8 is_ip4);
+extern void session_rules_table_del_tag (session_rules_table_t *srt, u8 *tag,
+ u8 is_ip4);
+
+extern const session_rt_engine_vft_t *session_rt_engine_vft;
+extern clib_error_t *session_rules_table_enable_disable (int enable);
+extern clib_error_t *
+session_rt_backend_enable_disable (session_rt_engine_type_t rt_engine_type);
+
+static_always_inline void
+session_rules_table_init (struct _session_lookup_table *st, u8 fib_proto)
+{
+ if (!session_rt_engine_vft)
+ return;
+ if (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID)
+ return;
+ session_rt_engine_vft->table_init (st, fib_proto);
+}
+
+static_always_inline void
+session_rules_table_free (struct _session_lookup_table *st, u8 fib_proto)
+{
+ if (!session_rt_engine_vft)
+ return;
+ if (st->srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return;
+ session_rt_engine_vft->table_free (st, fib_proto);
+}
+
+static_always_inline void
+session_rules_table_show_rule (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ ip46_address_t *lcl_ip, u16 lcl_port,
+ ip46_address_t *rmt_ip, u16 rmt_port, u8 is_ip4)
+{
+ if (!session_rt_engine_vft)
+ return;
+ if (srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return;
+ session_rt_engine_vft->table_show_rule (vm, srtg_handle, proto, lcl_ip,
+ lcl_port, rmt_ip, rmt_port, is_ip4);
+}
+
+static_always_inline u32
+session_rules_table_lookup6 (u32 srtg_handle, u32 proto, ip6_address_t *lcl_ip,
+ ip6_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
+{
+ if (!session_rt_engine_vft)
+ return SESSION_RULES_TABLE_ACTION_ALLOW;
+ if (srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return SESSION_RULES_TABLE_ACTION_ALLOW;
+ return session_rt_engine_vft->table_lookup6 (srtg_handle, proto, lcl_ip,
+ rmt_ip, lcl_port, rmt_port);
+}
+
+static_always_inline void
+session_rules_table_cli_dump (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ u8 fib_proto)
+{
+ if (!session_rt_engine_vft)
+ return;
+ if (srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return;
+ session_rt_engine_vft->table_cli_dump (vm, srtg_handle, proto, fib_proto);
+}
+
+static_always_inline u32
+session_rules_table_lookup4 (u32 srtg_handle, u32 proto, ip4_address_t *lcl_ip,
+ ip4_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
+{
+ if (!session_rt_engine_vft)
+ return SESSION_RULES_TABLE_ACTION_ALLOW;
+ if (srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return SESSION_RULES_TABLE_ACTION_ALLOW;
+ return session_rt_engine_vft->table_lookup4 (srtg_handle, proto, lcl_ip,
+ rmt_ip, lcl_port, rmt_port);
+}
+
+static_always_inline session_error_t
+session_rules_table_add_del (u32 srtg_handle, u32 proto,
+ session_rule_table_add_del_args_t *args)
+{
+ if (!session_rt_engine_vft)
+ return SESSION_E_NOSUPPORT;
+ if (srtg_handle == SESSION_SRTG_HANDLE_INVALID)
+ return SESSION_E_NOSUPPORT;
+ return session_rt_engine_vft->table_add_del (srtg_handle, proto, args);
+}
+
+clib_error_t *
+session_rule_table_register_engine (const session_rt_engine_vft_t *vft);
+clib_error_t *
+session_rule_table_deregister_engine (const session_rt_engine_vft_t *vft);
+
+extern session_rules_table_t *srtg_handle_to_srt (u32 srtg_handle, u32 proto);
+extern session_rules_table_group_t *srtg_instance_alloc (session_table_t *st,
+ u32 n_proto);
+extern void srtg_instance_free (session_table_t *st);
+
#endif /* SRC_VNET_SESSION_SESSION_RULES_TABLE_H_ */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/session/session_sdl.c b/src/vnet/session/session_sdl.c
new file mode 100644
index 00000000000..45ab705fb62
--- /dev/null
+++ b/src/vnet/session/session_sdl.c
@@ -0,0 +1,768 @@
+/*
+ * 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.
+ */
+
+#include <vnet/session/session.h>
+#include <vnet/ip/ip4_forward.h>
+#include <vnet/ip/ip6_forward.h>
+#include <vnet/session/session_rules_table.h>
+#include <vnet/session/session_sdl.h>
+
+VLIB_REGISTER_LOG_CLASS (session_sdl_log, static) = { .class_name = "session",
+ .subclass_name = "sdl" };
+
+#define log_debug(fmt, ...) \
+ vlib_log_debug (session_sdl_log.class, "%s: " fmt, __func__, __VA_ARGS__)
+#define log_warn(fmt, ...) \
+ vlib_log_warn (session_sdl_log.class, fmt, __VA_ARGS__)
+#define log_err(fmt, ...) \
+ vlib_log_err (session_sdl_log.class, fmt, __VA_ARGS__)
+
+static fib_source_t sdl_fib_src;
+static dpo_type_t sdl_dpo_type;
+
+const static char *const *const session_sdl_dpo_nodes[DPO_PROTO_NUM] = {
+ [DPO_PROTO_IP4] = (const char *const[]){ "ip4-drop", 0 },
+ [DPO_PROTO_IP6] = (const char *const[]){ "ip6-drop", 0 },
+};
+
+static fib_route_path_t *
+session_sdl_fib_create_route_paths (u32 fib_index, dpo_proto_t dpo_proto)
+{
+ fib_route_path_t *paths = 0;
+ fib_route_path_t path = {
+ .frp_proto = dpo_proto,
+ .frp_flags = FIB_ROUTE_PATH_EXCLUSIVE,
+ .frp_fib_index = fib_index,
+ .frp_sw_if_index = ~0,
+ .frp_weight = 1,
+ };
+ vec_add1 (paths, path);
+ return paths;
+}
+
+static void
+session_sdl_dpo_lock (dpo_id_t *dpo)
+{
+}
+
+static void
+session_sdl_dpo_unlock (dpo_id_t *dpo)
+{
+}
+
+static u8 *
+format_session_sdl_dpo (u8 *s, va_list *va)
+{
+ index_t index = va_arg (*va, index_t);
+
+ return format (s, "sdl: [index: %u, deny]", index);
+}
+
+static const dpo_vft_t session_sdl_dpo_vft = {
+ .dv_lock = session_sdl_dpo_lock,
+ .dv_unlock = session_sdl_dpo_unlock,
+ .dv_format = format_session_sdl_dpo,
+};
+
+static u32
+session_sdl_lookup6 (u32 srtg_handle, u32 proto, ip6_address_t *lcl_ip,
+ ip6_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+ index_t lbi;
+ const dpo_id_t *dpo;
+
+ if (sdlb->ip6_fib_index == ~0)
+ return SESSION_TABLE_INVALID_INDEX;
+ lbi = ip6_fib_table_fwding_lookup (sdlb->ip6_fib_index, lcl_ip);
+ dpo = load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+ if (dpo->dpoi_type != sdl_dpo_type)
+ return SESSION_TABLE_INVALID_INDEX;
+ return (dpo->dpoi_index);
+}
+
+static u32
+session_sdl_lookup4 (u32 srtg_handle, u32 proto, ip4_address_t *lcl_ip,
+ ip4_address_t *rmt_ip, u16 lcl_port, u16 rmt_port)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+ index_t lbi;
+ const dpo_id_t *dpo;
+
+ if (sdlb->ip_fib_index == ~0)
+ return SESSION_TABLE_INVALID_INDEX;
+ lbi = ip4_fib_forwarding_lookup (sdlb->ip_fib_index, lcl_ip);
+ dpo = load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+ if (dpo->dpoi_type != sdl_dpo_type)
+ return SESSION_TABLE_INVALID_INDEX;
+ return (dpo->dpoi_index);
+}
+
+typedef struct session_sdl4_fib_show_walk_ctx_t_
+{
+ fib_node_index_t *ifsw_indicies;
+} session_sdl4_fib_show_walk_ctx_t;
+
+static fib_table_walk_rc_t
+session_sdl4_fib_show_walk_cb (fib_node_index_t fei, void *arg)
+{
+ session_sdl4_fib_show_walk_ctx_t *ctx = arg;
+
+ vec_add1 (ctx->ifsw_indicies, fei);
+
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+typedef struct session_sdl6_fib_show_ctx_t_
+{
+ fib_node_index_t *entries;
+} session_sdl6_fib_show_ctx_t;
+
+static fib_table_walk_rc_t
+session_sdl6_fib_table_show_walk (fib_node_index_t fei, void *arg)
+{
+ session_sdl6_fib_show_ctx_t *ctx = arg;
+
+ vec_add1 (ctx->entries, fei);
+
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+static void
+session_sdl_fib_table_show (u32 fei, ip46_address_t *lcl_ip, u16 fp_len,
+ u32 action_index, u32 fp_proto, u8 *tag,
+ void *args)
+{
+ vlib_main_t *vm = args;
+ u32 type = (fp_proto == FIB_PROTOCOL_IP4) ? IP46_TYPE_IP4 : IP46_TYPE_IP6;
+
+ vlib_cli_output (vm, "[%d] rule: %U/%d action: %d tag %U", fei,
+ format_ip46_address, lcl_ip, type, fp_len, action_index,
+ format_session_rule_tag, tag);
+}
+
+static void
+session_sdl_cli_dump (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ u8 fib_proto)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+
+ if (fib_proto == FIB_PROTOCOL_IP4)
+ {
+ vlib_cli_output (vm, "IP4 rules, fib index %d", sdlb->ip_fib_index);
+ session_sdl_table_walk4 (srtg_handle, session_sdl_fib_table_show, vm);
+ }
+ else if (fib_proto == FIB_PROTOCOL_IP6)
+ {
+ vlib_cli_output (vm, "IP6 rules, fib index %d", sdlb->ip6_fib_index);
+ session_sdl_table_walk6 (srtg_handle, session_sdl_fib_table_show, vm);
+ }
+}
+
+static void
+session_sdl4_fib_table_show_one (session_rules_table_t *srt, u32 fib_index,
+ vlib_main_t *vm, ip4_address_t *address,
+ u32 mask_len)
+{
+ ip4_fib_t *fib;
+ fib_node_index_t fei;
+
+ fib = ip4_fib_get (fib_index);
+ fei = ip4_fib_table_lookup (fib, address, mask_len);
+ if (fei != FIB_NODE_INDEX_INVALID && fib_entry_is_sourced (fei, sdl_fib_src))
+ {
+ u8 *tag = session_rules_table_rule_tag (srt, fei, 1);
+ fib_entry_t *fib_entry = fib_entry_get (fei);
+ fib_prefix_t pfx = fib_entry->fe_prefix;
+ index_t lbi = ip4_fib_forwarding_lookup (fib_index, &pfx.fp_addr.ip4);
+ const dpo_id_t *dpo =
+ load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+
+ session_sdl_fib_table_show (fei, &pfx.fp_addr, pfx.fp_len,
+ dpo->dpoi_index, FIB_PROTOCOL_IP4, tag, vm);
+ }
+}
+
+static void
+session_sdl6_fib_table_show_one (session_rules_table_t *srt, u32 fib_index,
+ vlib_main_t *vm, ip6_address_t *address,
+ u32 mask_len)
+{
+ fib_node_index_t fei;
+
+ fei = ip6_fib_table_lookup (fib_index, address, mask_len);
+ if (fei != FIB_NODE_INDEX_INVALID && fib_entry_is_sourced (fei, sdl_fib_src))
+ {
+ u8 *tag = session_rules_table_rule_tag (srt, fei, 0);
+ fib_entry_t *fib_entry = fib_entry_get (fei);
+ fib_prefix_t pfx = fib_entry->fe_prefix;
+ index_t lbi = ip6_fib_table_fwding_lookup (fib_index, &pfx.fp_addr.ip6);
+ const dpo_id_t *dpo =
+ load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+
+ session_sdl_fib_table_show (fei, &pfx.fp_addr, pfx.fp_len,
+ dpo->dpoi_index, FIB_PROTOCOL_IP6, tag, vm);
+ }
+}
+
+static void
+session_sdl_show_rule (vlib_main_t *vm, u32 srtg_handle, u32 proto,
+ ip46_address_t *lcl_ip, u16 lcl_port,
+ ip46_address_t *rmt_ip, u16 rmt_port, u8 is_ip4)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb;
+
+ sdlb = &srt->sdl_block;
+ if (is_ip4)
+ session_sdl4_fib_table_show_one (srt, sdlb->ip_fib_index, vm, &lcl_ip->ip4,
+ 32);
+ else
+ session_sdl6_fib_table_show_one (srt, sdlb->ip6_fib_index, vm,
+ &lcl_ip->ip6, 128);
+}
+
+static void
+session_sdl_table_init (session_table_t *st, u8 fib_proto)
+{
+ session_rules_table_t *srt;
+ session_sdl_block_t *sdlb;
+ u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
+ char name[80];
+ app_namespace_t *app_ns = app_namespace_get (st->appns_index);
+ session_rules_table_group_t *srtg;
+
+ /* Don't support local table */
+ if (st->is_local == 1)
+ return;
+
+ srtg = srtg_instance_alloc (st, 0);
+ srt = srtg->session_rules;
+ sdlb = &srt->sdl_block;
+
+ if (fib_proto == FIB_PROTOCOL_IP4 || all)
+ {
+ snprintf (name, sizeof (name), "sdl4 %s", app_ns->ns_id);
+ sdlb->ip_table_id = ip_table_get_unused_id (FIB_PROTOCOL_IP4);
+ sdlb->ip_fib_index = fib_table_find_or_create_and_lock_w_name (
+ FIB_PROTOCOL_IP4, sdlb->ip_table_id, sdl_fib_src, (const u8 *) name);
+ }
+
+ if (fib_proto == FIB_PROTOCOL_IP6 || all)
+ {
+ snprintf (name, sizeof (name), "sdl6 %s", app_ns->ns_id);
+ sdlb->ip6_table_id = ip_table_get_unused_id (FIB_PROTOCOL_IP6);
+ sdlb->ip6_fib_index = fib_table_find_or_create_and_lock_w_name (
+ FIB_PROTOCOL_IP6, sdlb->ip6_table_id, sdl_fib_src, (const u8 *) name);
+ }
+
+ srt->rules_by_tag = hash_create_vec (0, sizeof (u8), sizeof (uword));
+ srt->tags_by_rules = hash_create (0, sizeof (uword));
+}
+
+static void
+session_sdl_table_free (session_table_t *st, u8 fib_proto)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (st->srtg_handle, 0);
+ session_sdl_block_t *sdlb;
+ u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
+
+ ASSERT (st->is_local == 0);
+ sdlb = &srt->sdl_block;
+ if ((fib_proto == FIB_PROTOCOL_IP4 || all) && (sdlb->ip_fib_index != ~0))
+ {
+ fib_table_flush (sdlb->ip_fib_index, FIB_PROTOCOL_IP4, sdl_fib_src);
+ fib_table_unlock (sdlb->ip_fib_index, FIB_PROTOCOL_IP4, sdl_fib_src);
+ }
+ if ((fib_proto == FIB_PROTOCOL_IP6 || all) && (sdlb->ip6_fib_index != ~0))
+ {
+ fib_table_flush (sdlb->ip6_fib_index, FIB_PROTOCOL_IP6, sdl_fib_src);
+ fib_table_unlock (sdlb->ip6_fib_index, FIB_PROTOCOL_IP6, sdl_fib_src);
+ }
+
+ hash_free (srt->tags_by_rules);
+ hash_free (srt->rules_by_tag);
+
+ srtg_instance_free (st);
+}
+
+static session_error_t
+session_sdl_add_del (u32 srtg_handle, u32 proto,
+ session_rule_table_add_del_args_t *args)
+{
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+ u32 fib_index;
+ dpo_proto_t dpo_proto;
+ fib_route_path_t *paths = 0;
+ fib_prefix_t pfx = args->lcl;
+ session_error_t err = SESSION_E_NONE;
+ fib_node_index_t fei;
+ int is_ip4;
+
+ if (!(args->lcl_port == 0 && args->rmt_port == 0 &&
+ args->rmt.fp_addr.ip4.as_u32 == 0))
+ return SESSION_E_NOSUPPORT;
+
+ fei = session_rules_table_rule_for_tag (srt, args->tag);
+ if (args->is_add && fei != SESSION_RULES_TABLE_INVALID_INDEX)
+ return SESSION_E_INVALID;
+
+ if (args->lcl.fp_proto == FIB_PROTOCOL_IP4)
+ {
+ fib_index = sdlb->ip_fib_index;
+ dpo_proto = DPO_PROTO_IP4;
+ is_ip4 = 1;
+ }
+ else
+ {
+ fib_index = sdlb->ip6_fib_index;
+ dpo_proto = DPO_PROTO_IP6;
+ is_ip4 = 0;
+ }
+
+ paths = session_sdl_fib_create_route_paths (fib_index, dpo_proto);
+ if (args->is_add)
+ {
+ fei = fib_table_lookup_exact_match (fib_index, &pfx);
+ if (fei != FIB_NODE_INDEX_INVALID)
+ {
+ err = SESSION_E_IPINUSE;
+ goto done;
+ }
+ dpo_set (&paths->dpo, sdl_dpo_type, dpo_proto, args->action_index);
+ fei = fib_table_entry_path_add2 (fib_index, &pfx, sdl_fib_src,
+ FIB_ENTRY_FLAG_EXCLUSIVE, paths);
+ session_rules_table_add_tag (srt, args->tag, fei, is_ip4);
+ dpo_reset (&paths->dpo);
+ }
+ else
+ {
+ if (fei == SESSION_RULES_TABLE_INVALID_INDEX)
+ {
+ fei = fib_table_lookup_exact_match (fib_index, &pfx);
+
+ if (fei == FIB_NODE_INDEX_INVALID)
+ {
+ err = SESSION_E_NOROUTE;
+ goto done;
+ }
+ }
+
+ if (!fib_entry_is_sourced (fei, sdl_fib_src))
+ {
+ err = SESSION_E_NOROUTE;
+ goto done;
+ }
+
+ fib_entry_t *fib_entry = fib_entry_get (fei);
+ pfx = fib_entry->fe_prefix;
+ fib_table_entry_special_remove (fib_index, &pfx, sdl_fib_src);
+ session_rules_table_del_tag (srt, args->tag, is_ip4);
+ }
+done:
+ vec_free (paths);
+
+ return err;
+}
+
+static const session_rt_engine_vft_t session_sdl_vft = {
+ .backend_engine = RT_BACKEND_ENGINE_SDL,
+ .table_lookup4 = session_sdl_lookup4,
+ .table_lookup6 = session_sdl_lookup6,
+ .table_cli_dump = session_sdl_cli_dump,
+ .table_show_rule = session_sdl_show_rule,
+ .table_add_del = session_sdl_add_del,
+ .table_init = session_sdl_table_init,
+ .table_free = session_sdl_table_free,
+};
+
+static void
+session_sdl_fib_init (void)
+{
+ static u32 session_fib_inited = 0;
+
+ if (session_fib_inited)
+ return;
+ session_fib_inited = 1;
+ sdl_fib_src = fib_source_allocate ("session sdl", FIB_SOURCE_PRIORITY_LOW,
+ FIB_SOURCE_BH_SIMPLE);
+ sdl_dpo_type =
+ dpo_register_new_type (&session_sdl_dpo_vft, session_sdl_dpo_nodes);
+}
+
+static void
+session_sdl_app_namespace_walk_cb (app_namespace_t *app_ns, void *ctx)
+{
+ u32 fib_index, table_index;
+ session_table_t *st;
+
+ log_debug ("disable app_ns %s", app_ns->ns_id);
+
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP4);
+ table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP4, fib_index);
+ st = session_table_get (table_index);
+ if (st)
+ session_rules_table_free (st, FIB_PROTOCOL_IP4);
+
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP6);
+ table_index = session_lookup_get_index_for_fib (FIB_PROTOCOL_IP6, fib_index);
+ st = session_table_get (table_index);
+ if (st)
+ session_rules_table_free (st, FIB_PROTOCOL_IP6);
+}
+
+clib_error_t *
+session_sdl_enable_disable (int enable)
+{
+ clib_error_t *error = 0;
+
+ if (enable)
+ {
+ error = session_rule_table_register_engine (&session_sdl_vft);
+ if (error)
+ {
+ log_err ("error in enabling sdl: %U", format_clib_error, error);
+ return error;
+ }
+ session_sdl_fib_init ();
+ }
+ else
+ {
+ app_namespace_walk (session_sdl_app_namespace_walk_cb, 0);
+
+ error = session_rule_table_deregister_engine (&session_sdl_vft);
+ if (error)
+ log_err ("error in disabling sdl: %U", format_clib_error, error);
+ }
+
+ return error;
+}
+
+/*
+ * Source Deny List
+ */
+static clib_error_t *
+session_sdl_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ u32 appns_index;
+ app_namespace_t *app_ns;
+ u32 lcl_plen = 0, action = 0;
+ clib_error_t *error = 0;
+ ip46_address_t lcl_ip;
+ u8 conn_set = 0;
+ u8 fib_proto = -1, is_add = 1, *ns_id = 0;
+ u8 *tag = 0, tag_only = 0;
+ int rv;
+ session_rule_add_del_args_t args;
+
+ session_cli_return_if_not_enabled ();
+
+ if (session_sdl_is_enabled () == 0)
+ return clib_error_return (0, "session sdl engine is not enabled");
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "del"))
+ is_add = 0;
+ else if (unformat (input, "add"))
+ ;
+ else if (unformat (input, "appns %_%v%_", &ns_id))
+ ;
+ else if (unformat (input, "%U/%d", unformat_ip4_address, &lcl_ip.ip4,
+ &lcl_plen))
+ {
+ fib_proto = FIB_PROTOCOL_IP4;
+ conn_set = 1;
+ }
+ else if (unformat (input, "%U/%d", unformat_ip6_address, &lcl_ip.ip6,
+ &lcl_plen))
+ {
+ fib_proto = FIB_PROTOCOL_IP6;
+ conn_set = 1;
+ }
+ else if (unformat (input, "action %d", &action))
+ ;
+ else if (unformat (input, "tag %_%v%_", &tag))
+ ;
+ else
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ }
+
+ if (ns_id)
+ {
+ app_ns = app_namespace_get_from_id (ns_id);
+ if (!app_ns)
+ {
+ vlib_cli_output (vm, "namespace %v does not exist", ns_id);
+ goto done;
+ }
+ }
+ else
+ {
+ app_ns = app_namespace_get_default ();
+ }
+ appns_index = app_namespace_index (app_ns);
+
+ if (is_add && !conn_set && action == 0)
+ {
+ vlib_cli_output (vm, "connection and action must be set for add");
+ goto done;
+ }
+ if (!is_add && !tag && !conn_set)
+ {
+ vlib_cli_output (vm, "connection or tag must be set for delete");
+ goto done;
+ }
+ if (vec_len (tag) > SESSION_RULE_TAG_MAX_LEN)
+ {
+ vlib_cli_output (vm, "tag too long (max u64)");
+ goto done;
+ }
+
+ /* Delete with only tag entered. Try v4 first and then v6 if failed */
+ if ((is_add == 0) && (fib_proto == (u8) ~0))
+ {
+ fib_proto = FIB_PROTOCOL_IP4;
+ tag_only = 1;
+ }
+
+ memset (&args, 0, sizeof (args));
+ args.transport_proto = TRANSPORT_PROTO_TCP;
+ args.table_args.lcl.fp_addr = lcl_ip;
+ args.table_args.lcl.fp_len = lcl_plen;
+ args.table_args.lcl.fp_proto = fib_proto;
+ args.table_args.rmt.fp_proto = fib_proto;
+ args.table_args.action_index = action;
+ args.table_args.is_add = is_add;
+ args.table_args.tag = tag;
+ args.appns_index = appns_index;
+ args.scope = SESSION_RULE_SCOPE_GLOBAL;
+
+ if ((rv = vnet_session_rule_add_del (&args)))
+ {
+ /* Try tag only delete on v6 */
+ if (rv && tag_only)
+ {
+ args.table_args.rmt.fp_proto = FIB_PROTOCOL_IP6;
+ args.table_args.lcl.fp_proto = FIB_PROTOCOL_IP6;
+ if ((rv = vnet_session_rule_add_del (&args)))
+ {
+ error = clib_error_return (0, "sdl add del returned %u", rv);
+ }
+ }
+ else
+ {
+ error = clib_error_return (0, "sdl add del returned %u", rv);
+ }
+ }
+
+done:
+ vec_free (ns_id);
+ vec_free (tag);
+ return error;
+}
+
+VLIB_CLI_COMMAND (session_sdl_command, static) = {
+ .path = "session sdl",
+ .short_help = "session sdl [add|del] [appns <ns_id>] <lcl-ip/plen> action "
+ "<action> [tag <tag>]",
+ .function = session_sdl_command_fn,
+ .is_mp_safe = 1,
+};
+
+static clib_error_t *
+show_session_sdl_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ u32 fib_index;
+ ip46_address_t lcl_ip;
+ u8 show_one = 0;
+ app_namespace_t *app_ns;
+ session_table_t *st;
+ u8 *ns_id = 0, fib_proto = FIB_PROTOCOL_IP4;
+
+ session_cli_return_if_not_enabled ();
+
+ clib_memset (&lcl_ip, 0, sizeof (lcl_ip));
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "appns %_%s%_", &ns_id))
+ ;
+ else if (unformat (input, "%U", unformat_ip4_address, &lcl_ip.ip4))
+ {
+ fib_proto = FIB_PROTOCOL_IP4;
+ show_one = 1;
+ }
+ else if (unformat (input, "%U", unformat_ip6_address, &lcl_ip.ip6))
+ {
+ fib_proto = FIB_PROTOCOL_IP6;
+ show_one = 1;
+ }
+ else
+ {
+ vec_free (ns_id);
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ }
+
+ if (ns_id)
+ {
+ app_ns = app_namespace_get_from_id (ns_id);
+ if (!app_ns)
+ {
+ vlib_cli_output (vm, "appns %v doesn't exist", ns_id);
+ goto done;
+ }
+ }
+ else
+ {
+ app_ns = app_namespace_get_default ();
+ }
+
+ if (session_sdl_is_enabled () == 0)
+ {
+ vlib_cli_output (vm, "session sdl engine is not enabled");
+ goto done;
+ }
+
+ if (show_one)
+ {
+ fib_index = app_namespace_get_fib_index (app_ns, fib_proto);
+ st = session_table_get_for_fib_index (fib_proto, fib_index);
+ if (st && (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID))
+ session_rules_table_show_rule (vm, st->srtg_handle, 0, &lcl_ip, 0, 0,
+ 0, (fib_proto == FIB_PROTOCOL_IP4));
+ goto done;
+ }
+
+ /* 2 separate session tables for global entries, 1 for ip4 and 1 for ip6 */
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP4);
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP4, fib_index);
+ if (st && (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID))
+ session_rules_table_cli_dump (vm, st->srtg_handle, 0, FIB_PROTOCOL_IP4);
+
+ fib_index = app_namespace_get_fib_index (app_ns, FIB_PROTOCOL_IP6);
+ st = session_table_get_for_fib_index (FIB_PROTOCOL_IP6, fib_index);
+ if (st && (st->srtg_handle != SESSION_SRTG_HANDLE_INVALID))
+ session_rules_table_cli_dump (vm, st->srtg_handle, 0, FIB_PROTOCOL_IP6);
+done:
+ vec_free (ns_id);
+ return 0;
+}
+
+void
+session_sdl_table_walk4 (u32 srtg_handle, session_sdl_table_walk_fn_t fn,
+ void *args)
+{
+ ip4_fib_t *fib;
+ session_sdl4_fib_show_walk_ctx_t ctx = {
+ .ifsw_indicies = NULL,
+ };
+ fib_node_index_t *fei;
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+ u32 fib_index = sdlb->ip_fib_index;
+
+ if (fib_index == ~0)
+ return;
+ fib = ip4_fib_get (fib_index);
+ ip4_fib_table_walk (fib, session_sdl4_fib_show_walk_cb, &ctx);
+ vec_sort_with_function (ctx.ifsw_indicies, fib_entry_cmp_for_sort);
+
+ vec_foreach (fei, ctx.ifsw_indicies)
+ {
+ if (*fei != FIB_NODE_INDEX_INVALID &&
+ fib_entry_is_sourced (*fei, sdl_fib_src))
+ {
+ u8 *tag = session_rules_table_rule_tag (srt, *fei, 1);
+ fib_entry_t *fib_entry = fib_entry_get (*fei);
+ fib_prefix_t pfx = fib_entry->fe_prefix;
+ index_t lbi =
+ ip4_fib_forwarding_lookup (fib_index, &pfx.fp_addr.ip4);
+ const dpo_id_t *dpo =
+ load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+
+ fn (*fei, &pfx.fp_addr, pfx.fp_len, dpo->dpoi_index,
+ FIB_PROTOCOL_IP4, tag, args);
+ }
+ }
+
+ vec_free (ctx.ifsw_indicies);
+}
+
+void
+session_sdl_table_walk6 (u32 srtg_handle, session_sdl_table_walk_fn_t fn,
+ void *args)
+{
+ ip6_fib_t *fib;
+ fib_node_index_t *fei;
+ session_sdl6_fib_show_ctx_t ctx = {
+ .entries = NULL,
+ };
+ session_rules_table_t *srt = srtg_handle_to_srt (srtg_handle, 0);
+ session_sdl_block_t *sdlb = &srt->sdl_block;
+ u32 fib_index = sdlb->ip6_fib_index;
+
+ if (fib_index == ~0)
+ return;
+ fib = ip6_fib_get (fib_index);
+ ip6_fib_table_walk (fib->index, session_sdl6_fib_table_show_walk, &ctx);
+ vec_sort_with_function (ctx.entries, fib_entry_cmp_for_sort);
+
+ vec_foreach (fei, ctx.entries)
+ {
+ if (*fei != FIB_NODE_INDEX_INVALID &&
+ fib_entry_is_sourced (*fei, sdl_fib_src))
+ {
+ u8 *tag = session_rules_table_rule_tag (srt, *fei, 0);
+ fib_entry_t *fib_entry = fib_entry_get (*fei);
+ fib_prefix_t pfx = fib_entry->fe_prefix;
+ index_t lbi =
+ ip6_fib_table_fwding_lookup (fib_index, &pfx.fp_addr.ip6);
+ const dpo_id_t *dpo =
+ load_balance_get_fwd_bucket (load_balance_get (lbi), 0);
+
+ fn (*fei, &pfx.fp_addr, pfx.fp_len, dpo->dpoi_index,
+ FIB_PROTOCOL_IP6, tag, args);
+ }
+ }
+
+ vec_free (ctx.entries);
+}
+
+VLIB_CLI_COMMAND (show_session_sdl_command, static) = {
+ .path = "show session sdl",
+ .short_help = "show session sdl [appns <id> <lcl-ip>]",
+ .function = show_session_sdl_command_fn,
+ .is_mp_safe = 1,
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/session_sdl.h b/src/vnet/session/session_sdl.h
new file mode 100644
index 00000000000..8d8b5b2d29e
--- /dev/null
+++ b/src/vnet/session/session_sdl.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_VNET_SESSION_SESSION_SDL_H_
+#define SRC_VNET_SESSION_SESSION_SDL_H_
+
+clib_error_t *session_sdl_enable_disable (int enable);
+
+typedef void (*session_sdl_table_walk_fn_t) (u32 fei, ip46_address_t *lcl_ip,
+ u16 fp_len, u32 action_index,
+ u32 fb_proto, u8 *tag, void *ctx);
+void session_sdl_table_walk4 (u32 srtg_handle, session_sdl_table_walk_fn_t fn,
+ void *args);
+void session_sdl_table_walk6 (u32 srtg_handle, session_sdl_table_walk_fn_t fn,
+ void *args);
+
+#endif /* SRC_VNET_SESSION_SESSION_SDL_H_ */
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/vnet/session/session_table.c b/src/vnet/session/session_table.c
index dbbe771979c..5dafe0e633c 100644
--- a/src/vnet/session/session_table.c
+++ b/src/vnet/session/session_table.c
@@ -15,6 +15,7 @@
#include <vnet/session/session_table.h>
#include <vnet/session/session.h>
+#include <vnet/session/session_rules_table.h>
/**
* Pool of session tables
@@ -64,12 +65,8 @@ void
session_table_free (session_table_t *slt, u8 fib_proto)
{
u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
- int i;
- for (i = 0; i < TRANSPORT_N_PROTOS; i++)
- session_rules_table_free (&slt->session_rules[i]);
-
- vec_free (slt->session_rules);
+ session_rules_table_free (slt, fib_proto);
if (fib_proto == FIB_PROTOCOL_IP4 || all)
{
@@ -92,10 +89,9 @@ session_table_free (session_table_t *slt, u8 fib_proto)
* otherwise it uses defaults above.
*/
void
-session_table_init (session_table_t * slt, u8 fib_proto)
+session_table_init (session_table_t *slt, u8 fib_proto)
{
u8 all = fib_proto > FIB_PROTOCOL_IP6 ? 1 : 0;
- int i;
#define _(af,table,parm,value) \
u32 configured_##af##_##table##_table_##parm = value;
@@ -109,6 +105,7 @@ session_table_init (session_table_t * slt, u8 fib_proto)
foreach_hash_table_parameter;
#undef _
+ slt->srtg_handle = SESSION_SRTG_HANDLE_INVALID;
if (fib_proto == FIB_PROTOCOL_IP4 || all)
{
clib_bihash_init2_args_16_8_t _a, *a = &_a;
@@ -153,10 +150,6 @@ session_table_init (session_table_t * slt, u8 fib_proto)
a->instantiate_immediately = 1;
clib_bihash_init2_48_8 (a);
}
-
- vec_validate (slt->session_rules, TRANSPORT_N_PROTOS - 1);
- for (i = 0; i < TRANSPORT_N_PROTOS; i++)
- session_rules_table_init (&slt->session_rules[i]);
}
typedef struct _ip4_session_table_walk_ctx_t
diff --git a/src/vnet/session/session_table.h b/src/vnet/session/session_table.h
index 636b8d77bee..aae4a1c2af5 100644
--- a/src/vnet/session/session_table.h
+++ b/src/vnet/session/session_table.h
@@ -18,7 +18,6 @@
#include <vppinfra/bihash_16_8.h>
#include <vppinfra/bihash_48_8.h>
-#include <vnet/session/session_rules_table.h>
typedef struct _session_lookup_table
{
@@ -37,7 +36,7 @@ typedef struct _session_lookup_table
/**
* Per fib proto and transport proto session rules tables
*/
- session_rules_table_t *session_rules;
+ u32 srtg_handle;
/** Flag that indicates if table has local scope */
u8 is_local;
@@ -78,6 +77,8 @@ session_table_t *_get_session_tables ();
#define session_table_foreach(VAR, BODY) \
pool_foreach (VAR, _get_session_tables ()) BODY
+void session_lookup_table_cleanup (u32 fib_proto, u32 fib_index);
+
#endif /* SRC_VNET_SESSION_SESSION_TABLE_H_ */
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/session/session_test.c b/src/vnet/session/session_test.c
index 770e7263024..1c865b877b5 100644
--- a/src/vnet/session/session_test.c
+++ b/src/vnet/session/session_test.c
@@ -271,6 +271,12 @@ api_session_enable_disable (vat_main_t *vat)
}
static int
+api_session_enable_disable_v2 (vat_main_t *vat)
+{
+ return -1;
+}
+
+static int
api_app_worker_add_del (vat_main_t *vat)
{
return -1;
@@ -354,6 +360,23 @@ api_session_sapi_enable_disable (vat_main_t *vat)
return -1;
}
+static int
+api_session_sdl_add_del (vat_main_t *vam)
+{
+ return -1;
+}
+
+static void
+vl_api_session_sdl_details_t_handler (vl_api_session_rules_details_t *mp)
+{
+}
+
+static int
+api_session_sdl_dump (vat_main_t *vam)
+{
+ return -1;
+}
+
#include <vnet/session/session.api_test.c>
/*
diff --git a/src/vnet/snap/snap.c b/src/vnet/snap/snap.c
index 9bee415390a..bf5994271a4 100644
--- a/src/vnet/snap/snap.c
+++ b/src/vnet/snap/snap.c
@@ -192,8 +192,9 @@ snap_init (vlib_main_t * vm)
return vlib_call_init_function (vm, snap_input_init);
}
-VLIB_INIT_FUNCTION (snap_init);
-
+VLIB_INIT_FUNCTION (snap_init) = {
+ .runs_after = VLIB_INITS ("llc_init"),
+};
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vnet/srv6/sr_localsid.c b/src/vnet/srv6/sr_localsid.c
index 12349bb95e8..62b1a271576 100644
--- a/src/vnet/srv6/sr_localsid.c
+++ b/src/vnet/srv6/sr_localsid.c
@@ -1471,6 +1471,7 @@ sr_localsid_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
ip6_header_t *ip0, *ip1, *ip2, *ip3;
ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
+ prev0 = prev1 = prev2 = prev3 = 0;
u32 next0, next1, next2, next3;
next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
@@ -1779,6 +1780,7 @@ sr_localsid_un_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
ip6_header_t *ip0, *ip1, *ip2, *ip3;
ip6_sr_header_t *sr0, *sr1, *sr2, *sr3;
ip6_ext_header_t *prev0, *prev1, *prev2, *prev3;
+ prev0 = prev1 = prev2 = prev3 = 0;
u32 next0, next1, next2, next3;
next0 = next1 = next2 = next3 = SR_LOCALSID_NEXT_IP6_LOOKUP;
ip6_sr_localsid_t *ls0, *ls1, *ls2, *ls3;
diff --git a/src/vnet/tcp/tcp.c b/src/vnet/tcp/tcp.c
index 1d164f236a1..1afc07918b7 100644
--- a/src/vnet/tcp/tcp.c
+++ b/src/vnet/tcp/tcp.c
@@ -879,6 +879,8 @@ format_tcp_listener_session (u8 * s, va_list * args)
if (verbose)
s = format (s, "%-" SESSION_CLI_STATE_LEN "U", format_tcp_state,
tc->state);
+ if (verbose == 2)
+ s = format (s, "\n%U", format_tcp_listener_connection, tc);
return s;
}
diff --git a/src/vnet/tcp/tcp.h b/src/vnet/tcp/tcp.h
index 3d678006f70..8676db413a0 100644
--- a/src/vnet/tcp/tcp.h
+++ b/src/vnet/tcp/tcp.h
@@ -45,19 +45,21 @@ typedef struct _tcp_lookup_dispatch
u8 next, error;
} tcp_lookup_dispatch_t;
-#define foreach_tcp_wrk_stat \
- _(timer_expirations, u64, "timer expirations") \
- _(rxt_segs, u64, "segments retransmitted") \
- _(tr_events, u32, "timer retransmit events") \
- _(to_closewait, u32, "timeout close-wait") \
- _(to_closewait2, u32, "timeout close-wait w/data") \
- _(to_finwait1, u32, "timeout fin-wait-1") \
- _(to_finwait2, u32, "timeout fin-wait-2") \
- _(to_lastack, u32, "timeout last-ack") \
- _(to_closing, u32, "timeout closing") \
- _(tr_abort, u32, "timer retransmit abort") \
- _(rst_unread, u32, "reset on close due to unread data") \
- _(no_buffer, u32, "out of buffers") \
+#define foreach_tcp_wrk_stat \
+ _ (timer_expirations, u64, "timer expirations") \
+ _ (rxt_segs, u64, "segments retransmitted") \
+ _ (tr_events, u32, "timer retransmit events") \
+ _ (to_establish, u32, "timeout establish") \
+ _ (to_persist, u32, "timeout persist") \
+ _ (to_closewait, u32, "timeout close-wait") \
+ _ (to_closewait2, u32, "timeout close-wait w/data") \
+ _ (to_finwait1, u32, "timeout fin-wait-1") \
+ _ (to_finwait2, u32, "timeout fin-wait-2") \
+ _ (to_lastack, u32, "timeout last-ack") \
+ _ (to_closing, u32, "timeout closing") \
+ _ (tr_abort, u32, "timer retransmit abort") \
+ _ (rst_unread, u32, "reset on close due to unread data") \
+ _ (no_buffer, u32, "out of buffers")
typedef struct tcp_wrk_stats_
{
@@ -357,6 +359,7 @@ format_function_t format_tcp_flags;
format_function_t format_tcp_sacks;
format_function_t format_tcp_rcv_sacks;
format_function_t format_tcp_connection;
+format_function_t format_tcp_listener_connection;
format_function_t format_tcp_connection_id;
#define tcp_validate_txf_size(_tc, _a) \
diff --git a/src/vnet/tcp/tcp_cli.c b/src/vnet/tcp/tcp_cli.c
index e26488342d2..55bc5764df2 100644
--- a/src/vnet/tcp/tcp_cli.c
+++ b/src/vnet/tcp/tcp_cli.c
@@ -250,6 +250,21 @@ format_tcp_connection_id (u8 * s, va_list * args)
}
u8 *
+format_tcp_listener_connection (u8 *s, va_list *args)
+{
+ tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
+
+ s = format (s, " index: %u cfg_flags: %U cong_algo: %s snd_mss: %u\n",
+ tc->c_c_index, format_tcp_cfg_flags, tc, tc->cc_algo->name,
+ tc->snd_mss);
+ s = format (s, " next_node %u opaque 0x%x fib_index %u sw_if_index %d",
+ tc->next_node_index, tc->next_node_opaque, tc->c_fib_index,
+ tc->sw_if_index);
+
+ return s;
+}
+
+u8 *
format_tcp_connection (u8 * s, va_list * args)
{
tcp_connection_t *tc = va_arg (*args, tcp_connection_t *);
@@ -825,6 +840,74 @@ VLIB_CLI_COMMAND (show_tcp_punt_command, static) =
.function = show_tcp_punt_fn,
};
+static u8 *
+format_tcp_cfg (u8 *s, va_list *args)
+{
+ tcp_configuration_t tm_cfg = va_arg (*args, tcp_configuration_t);
+
+ s = format (s, "max rx fifo size: %U\n", format_memory_size,
+ tm_cfg.max_rx_fifo);
+ s = format (s, "min rx fifo size: %U\n", format_memory_size,
+ tm_cfg.min_rx_fifo);
+ s = format (s, "default mtu: %u\n", tm_cfg.default_mtu);
+ s = format (s, "initial cwnd multiplier: %u\n",
+ tm_cfg.initial_cwnd_multiplier);
+ s = format (s, "tx pacing: %s\n",
+ tm_cfg.enable_tx_pacing ? "enabled" : "disabled");
+ s = format (s, "tso: %s\n", tm_cfg.allow_tso ? "allowed" : "disallowed");
+ s = format (s, "checksum offload: %s\n",
+ tm_cfg.csum_offload ? "enabled" : "disabled");
+ s = format (s, "congestion control algorithm: %s\n",
+ tcp_cc_algo_get (tm_cfg.cc_algo)->name);
+ s = format (s, "min rwnd update ack: %u\n", tm_cfg.rwnd_min_update_ack);
+ s = format (s, "max gso packet size: %U\n", format_memory_size,
+ tm_cfg.max_gso_size);
+ s = format (s, "close_wait time: %u sec\n",
+ (u32) (tm_cfg.closewait_time * TCP_TIMER_TICK));
+ s = format (s, "time_wait time: %u sec\n",
+ (u32) (tm_cfg.timewait_time * TCP_TIMER_TICK));
+ s = format (s, "fin_wait1 time: %u sec\n",
+ (u32) (tm_cfg.finwait1_time * TCP_TIMER_TICK));
+ s = format (s, "fin_wait2 time: %u sec\n",
+ (u32) (tm_cfg.finwait2_time * TCP_TIMER_TICK));
+ s = format (s, "last_ack time: %u sec\n",
+ (u32) (tm_cfg.lastack_time * TCP_TIMER_TICK));
+ s = format (s, "fin_ack time: %u sec\n",
+ (u32) (tm_cfg.closing_time * TCP_TIMER_TICK));
+ s = format (s, "syn_rcvd time: %u sec\n",
+ (u32) (tm_cfg.syn_rcvd_time * TCP_TICK));
+ s = format (s, "tcp allocation error cleanup time: %0.2f sec\n",
+ (f32) (tm_cfg.alloc_err_timeout * TCP_TIMER_TICK));
+ s = format (s, "connection cleanup time: %.2f sec\n", tm_cfg.cleanup_time);
+ s = format (s, "tcp preallocated connections: %u",
+ tm_cfg.preallocated_connections);
+
+ return s;
+}
+
+static clib_error_t *
+show_tcp_cfg_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ tcp_main_t *tm = vnet_get_tcp_main ();
+
+ if (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ return clib_error_return (0, "unknown input `%U'", format_unformat_error,
+ input);
+ vlib_cli_output (vm, "-----------");
+ vlib_cli_output (vm, "tcp config");
+ vlib_cli_output (vm, "-----------");
+ vlib_cli_output (vm, "%U\n", format_tcp_cfg, tm->cfg);
+
+ return 0;
+}
+
+VLIB_CLI_COMMAND (show_tcp_cfg_command, static) = {
+ .path = "show tcp config",
+ .short_help = "show tcp config",
+ .function = show_tcp_cfg_fn,
+};
+
static clib_error_t *
show_tcp_stats_fn (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
diff --git a/src/vnet/tcp/tcp_output.c b/src/vnet/tcp/tcp_output.c
index 373bb2a9e0f..dd1ec555902 100644
--- a/src/vnet/tcp/tcp_output.c
+++ b/src/vnet/tcp/tcp_output.c
@@ -1458,6 +1458,8 @@ tcp_timer_retransmit_syn_handler (tcp_connection_t * tc)
TCP_EVT (TCP_EVT_CC_EVT, tc, 2);
tc->rtt_ts = 0;
+ tcp_worker_stats_inc (wrk, to_establish, 1);
+
/* Active open establish timeout */
if (tc->rto >= TCP_ESTABLISH_TIME >> 1)
{
@@ -1507,6 +1509,8 @@ tcp_timer_persist_handler (tcp_connection_t * tc)
int n_bytes = 0;
u8 *data;
+ tcp_worker_stats_inc (wrk, to_persist, 1);
+
/* Problem already solved or worse */
if (tc->state == TCP_STATE_CLOSED || tc->snd_wnd > tc->snd_mss
|| (tc->flags & TCP_CONN_FINSNT))
diff --git a/src/vnet/tls/tls_record.c b/src/vnet/tls/tls_record.c
new file mode 100644
index 00000000000..af7d54c466b
--- /dev/null
+++ b/src/vnet/tls/tls_record.c
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vnet/tls/tls_record.h>
+
+/*
+ * rfc8446#section-4.1.2
+ * struct {
+ * ProtocolVersion legacy_version = 0x0303; // TLS v1.2
+ * Random random;
+ * opaque legacy_session_id<0..32>;
+ * CipherSuite cipher_suites<2..2^16-2>;
+ * opaque legacy_compression_methods<1..2^8-1>;
+ * Extension extensions<8..2^16-1>;
+ * } ClientHello;
+ */
+tls_handshake_parse_error_t
+tls_handshake_client_hello_parse (u8 *b, int len,
+ tls_handshake_msg_info_t *info)
+{
+ u8 *p = b;
+
+ if (PREDICT_FALSE (len < 2 + 32 + 1 + 2 + 2 + 2))
+ return TLS_HS_PARSE_ERR_INVALID_LEN;
+ /* skip legacy version and random */
+ p += 2 + 32;
+ /* legacy_session_id */
+ info->legacy_session_id_len = *p;
+ info->legacy_session_id = p + 1;
+ p = info->legacy_session_id + info->legacy_session_id_len;
+ if (PREDICT_FALSE (p - b >= len))
+ return TLS_HS_PARSE_ERR_SESSION_ID_LEN;
+ /* cipher_suites */
+ info->cipher_suite_len = clib_net_to_host_u16 (*(u16 *) p);
+ info->cipher_suites = p + 2;
+ p = info->cipher_suites + info->cipher_suite_len;
+ if (PREDICT_FALSE (p - b >= len))
+ return TLS_HS_PARSE_ERR_CIPHER_SUITE_LEN;
+ /* legacy_compression_method, only support null */
+ if (PREDICT_FALSE (*p != 1 || *(p + 1) != 0))
+ return TLS_HS_PARSE_ERR_COMPRESSION_METHOD;
+ p += 2;
+ /* extensions */
+ info->extensions_len = clib_net_to_host_u16 (*(u16 *) p);
+ info->extensions = p + 2;
+ if (PREDICT_FALSE (info->extensions + info->extensions_len - b > len))
+ return TLS_HS_PARSE_ERR_CIPHER_SUITE_LEN;
+
+ return TLS_HS_PARSE_ERR_OK;
+}
+
+typedef tls_handshake_parse_error_t (*tls_handshake_msg_parser) (
+ u8 *b, int len, tls_handshake_msg_info_t *info);
+
+static tls_handshake_msg_parser tls_handshake_msg_parsers[] = {
+ [TLS_HS_CLIENT_HELLO] = tls_handshake_client_hello_parse,
+};
+
+static inline u32
+tls_handshake_ext_requested (const tls_handshake_ext_info_t *req_exts,
+ u32 n_reqs, tls_handshake_ext_type_t ext_type)
+{
+ for (int i = 0; i < n_reqs; i++)
+ {
+ if (req_exts[i].type == ext_type)
+ return i;
+ }
+
+ return ~0;
+}
+
+tls_handshake_parse_error_t
+tls_hanshake_extensions_parse (tls_handshake_msg_info_t *info,
+ tls_handshake_ext_info_t **exts)
+{
+ tls_handshake_ext_info_t *ext;
+ u16 ext_type, ext_len;
+ u8 *b, *b_end;
+
+ ASSERT (info->extensions != 0);
+
+ if (info->extensions_len < 2)
+ return TLS_HS_PARSE_ERR_EXTENSIONS_LEN;
+
+ b = info->extensions;
+ b_end = info->extensions + info->extensions_len;
+
+ while (b < b_end)
+ {
+ ext_type = clib_net_to_host_u16 (*(u16 *) b);
+ b += 2;
+ ext_len = clib_net_to_host_u16 (*(u16 *) b);
+ b += 2;
+
+ if (b + ext_len > b_end)
+ return TLS_HS_PARSE_ERR_EXTENSIONS_LEN;
+
+ vec_add2 (*exts, ext, 1);
+ ext->type = ext_type;
+ ext->len = ext_len;
+ ext->data = b;
+
+ b += ext_len;
+ }
+
+ return TLS_HS_PARSE_ERR_OK;
+}
+
+tls_handshake_parse_error_t
+tls_hanshake_extensions_try_parse (tls_handshake_msg_info_t *info,
+ tls_handshake_ext_info_t *req_exts,
+ u32 n_reqs)
+{
+ u8 *b, *b_end;
+ u16 ext_type, ext_len;
+ u32 n_found = 0, ext_pos;
+
+ ASSERT (info->extensions != 0);
+
+ if (info->extensions_len < 2)
+ return TLS_HS_PARSE_ERR_EXTENSIONS_LEN;
+
+ b = info->extensions;
+ b_end = info->extensions + info->extensions_len;
+
+ while (b < b_end && n_found < n_reqs)
+ {
+ ext_type = clib_net_to_host_u16 (*(u16 *) b);
+ b += 2;
+ ext_len = clib_net_to_host_u16 (*(u16 *) b);
+ b += 2;
+
+ if (b + ext_len > b_end)
+ return TLS_HS_PARSE_ERR_EXTENSIONS_LEN;
+
+ ext_pos = tls_handshake_ext_requested (req_exts, n_reqs, ext_type);
+ if (ext_pos == ~0)
+ {
+ b += ext_len;
+ continue;
+ }
+
+ req_exts[ext_pos].len = ext_len;
+ req_exts[ext_pos].data = b;
+
+ b += ext_len;
+ n_found++;
+ }
+
+ return TLS_HS_PARSE_ERR_OK;
+}
+
+tls_handshake_parse_error_t
+tls_handshake_message_try_parse (u8 *msg, int len,
+ tls_handshake_msg_info_t *info)
+{
+ tls_handshake_msg_t *msg_hdr = (tls_handshake_msg_t *) msg;
+ u8 *b = msg_hdr->message;
+
+ info->len = tls_handshake_message_len (msg_hdr);
+ if (info->len > len)
+ return info->len > TLS_FRAGMENT_MAX_ENC_LEN ?
+ TLS_HS_PARSE_ERR_INVALID_LEN :
+ TLS_HS_PARSE_ERR_WANT_MORE;
+
+ if (msg_hdr->msg_type >= ARRAY_LEN (tls_handshake_msg_parsers) ||
+ !tls_handshake_msg_parsers[msg_hdr->msg_type])
+ return TLS_HS_PARSE_ERR_UNSUPPORTED;
+
+ return tls_handshake_msg_parsers[msg_hdr->msg_type](b, info->len, info);
+}
+
+/**
+ * As per rfc6066#section-3
+ * struct {
+ * NameType name_type;
+ * select (name_type) {
+ * case host_name: HostName;
+ * } name;
+ * } ServerName;
+ *
+ * enum {
+ * host_name(0), (255)
+ * } NameType;
+ *
+ * opaque HostName<1..2^16-1>;
+ *
+ * struct {
+ * ServerName server_name_list<1..2^16-1>
+ * } ServerNameList;
+ */
+tls_handshake_parse_error_t
+tls_handshake_ext_sni_parse (tls_handshake_ext_info_t *ext_info,
+ tls_handshake_ext_t *ext)
+{
+ tls_handshake_ext_sni_t *sni = (tls_handshake_ext_sni_t *) ext;
+ tls_handshake_ext_sni_sn_t *sn;
+ u16 n_names, sn_len;
+ u8 *b, *b_end;
+
+ b = ext_info->data;
+ b_end = b + ext_info->len;
+
+ sni->ext.type = ext_info->type;
+ sni->names = 0;
+ n_names = clib_net_to_host_u16 (*(u16 *) b);
+ b += 2;
+
+ while (b < b_end && vec_len (sni->names) < n_names)
+ {
+ /* only host name supported */
+ if (b[0] != 0)
+ return TLS_HS_PARSE_ERR_EXT_SNI_NAME_TYPE;
+
+ b++;
+ /* server name length */
+ sn_len = clib_net_to_host_u16 (*(u16 *) b);
+ if (sn_len > TLS_EXT_SNI_MAX_LEN)
+ return TLS_HS_PARSE_ERR_EXT_SNI_LEN;
+
+ b += 2;
+
+ vec_add2 (sni->names, sn, 1);
+ sn->name_type = 0;
+ vec_validate (sn->host_name, sn_len - 1);
+ clib_memcpy (sn->host_name, b, sn_len);
+
+ b += sn_len;
+ }
+
+ return TLS_HS_PARSE_ERR_OK;
+}
+
+typedef tls_handshake_parse_error_t (*tls_handshake_ext_parser) (
+ tls_handshake_ext_info_t *ext_info, tls_handshake_ext_t *ext);
+
+static tls_handshake_ext_parser tls_handshake_ext_parsers[] = {
+ [TLS_EXT_SERVER_NAME] = tls_handshake_ext_sni_parse,
+};
+
+tls_handshake_parse_error_t
+tls_handshake_ext_parse (tls_handshake_ext_info_t *ext_info,
+ tls_handshake_ext_t *ext)
+{
+ if (ext_info->type >= ARRAY_LEN (tls_handshake_ext_parsers) ||
+ !tls_handshake_ext_parsers[ext_info->type])
+ return TLS_HS_PARSE_ERR_UNSUPPORTED;
+
+ return tls_handshake_ext_parsers[ext_info->type](ext_info, ext);
+}
+
+static void
+tls_handshake_ext_sni_free (tls_handshake_ext_t *ext)
+{
+ tls_handshake_ext_sni_t *sni = (tls_handshake_ext_sni_t *) ext;
+ tls_handshake_ext_sni_sn_t *sn;
+
+ vec_foreach (sn, sni->names)
+ vec_free (sn->host_name);
+
+ vec_free (sni->names);
+}
+
+typedef void (*tls_handshake_ext_free_fn) (tls_handshake_ext_t *ext);
+
+static tls_handshake_ext_free_fn tls_handshake_ext_free_fns[] = {
+ [TLS_EXT_SERVER_NAME] = tls_handshake_ext_sni_free,
+};
+
+void
+tls_handshake_ext_free (tls_handshake_ext_t *ext)
+{
+ if (ext->type >= ARRAY_LEN (tls_handshake_ext_free_fns) ||
+ !tls_handshake_ext_free_fns[ext->type])
+ return;
+
+ tls_handshake_ext_free_fns[ext->type](ext);
+}
diff --git a/src/vnet/tls/tls_record.h b/src/vnet/tls/tls_record.h
new file mode 100644
index 00000000000..3f7723f06d5
--- /dev/null
+++ b/src/vnet/tls/tls_record.h
@@ -0,0 +1,250 @@
+
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2024 Cisco Systems, Inc.
+ */
+
+#ifndef SRC_VNET_TLS_TLS_RECORD_H__
+#define SRC_VNET_TLS_TLS_RECORD_H__
+
+#include <vppinfra/clib.h>
+#include <vppinfra/error.h>
+
+/**
+ * TLS record types as per rfc8446#appendix-B.1
+ */
+#define foreach_tls_content_type \
+ _ (INVALID, 0) \
+ _ (CHANGE_CIPHER_SPEC, 20) \
+ _ (ALERT, 21) \
+ _ (HANDSHAKE, 22) \
+ _ (APPLICATION_DATA, 23) \
+ _ (HEARTBEAT, 24) /* RFC 6520 */
+
+typedef enum tls_record_type_
+{
+#define _(sym, val) TLS_REC_##sym = val,
+ foreach_tls_content_type
+#undef _
+} __clib_packed tls_record_type_t;
+
+typedef struct tls_protocol_version_
+{
+ u8 major;
+ u8 minor;
+} __clib_packed tls_protocol_version_t;
+
+#define TLS_MAJOR_VERSION 3
+#define TLS_MINOR_VERSION_MIN 0 /**< SSLv3 */
+#define TLS_MINOR_VERSION_MAX 4 /**< TLS1.3 */
+
+typedef struct tls_record_header_
+{
+ tls_record_type_t type; /**< content type */
+ tls_protocol_version_t version; /**< version (deprecated) */
+ u16 length; /**< fragment length */
+ u8 fragment[0]; /**< fragment/payload */
+} __clib_packed tls_record_header_t;
+
+#define TLS_FRAGMENT_MAX_LEN (1 << 14) /**< 16KB rfc8446 */
+/** rfc5246 (TLS1.2) allows 2048 bytes of protection */
+#define TLS12_FRAGMENT_MAX_ENC_LEN (TLS_FRAGMENT_MAX_LEN + (2 << 10))
+#define TLS13_FRAGMENT_MAX_ENC_LEN (TLS_FRAGMENT_MAX_LEN + 256)
+#define TLS_FRAGMENT_MAX_ENC_LEN TLS12_FRAGMENT_MAX_ENC_LEN
+
+/*
+ * Handshake message types as per rfc8446#appendix-B.3
+ */
+#define foreach_tls_handshake_type \
+ _ (HELLO_REQUEST, 0) \
+ _ (CLIENT_HELLO, 1) \
+ _ (SERVER_HELLO, 2) \
+ _ (HELLO_VERIFY_REQUEST, 3) \
+ _ (NEW_SESSION_TICKET, 4) \
+ _ (END_OF_EARLY_DATA, 5) \
+ _ (HELLO_RETRY_REQUEST, 6) \
+ _ (ENCRYPTED_EXTENSIONS, 8) \
+ _ (CERTIFICATE, 11) \
+ _ (SERVER_KEY_EXCHANGE, 12) \
+ _ (CERTIFICATE_REQUEST, 13) \
+ _ (SERVER_HELLO_DONE, 14) \
+ _ (CERTIFICATE_VERIFY, 15) \
+ _ (CLIENT_KEY_EXCHANGE, 16) \
+ _ (FINISHED, 20) \
+ _ (CERTIFICATE_URL, 21) \
+ _ (CERTIFICATE_STATUS, 22) \
+ _ (SUPPLEMENTAL_DATA, 23) \
+ _ (KEY_UPDATE, 24) \
+ _ (MESSAGE_HASH, 254)
+
+typedef enum tls_handshake_type_
+{
+#define _(sym, val) TLS_HS_##sym = val,
+ foreach_tls_handshake_type
+#undef _
+} tls_handshake_type_t;
+
+typedef struct
+{
+ u32 msg_type : 8; /**< message type */
+ u32 length : 24; /**< message length */
+ u8 message[0]; /**< message contents */
+} __clib_packed tls_handshake_msg_t;
+
+static inline u32
+tls_handshake_message_len (tls_handshake_msg_t *msg)
+{
+ u8 *p = (u8 *) msg;
+ return p[1] << 16 | p[2] << 8 | p[3];
+}
+
+/**
+ * https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
+ */
+#define foreach_tls_hanshake_extensions \
+ _ (SERVER_NAME, 0) \
+ _ (MAX_FRAGMENT_LENGTH, 1) \
+ _ (STATUS_REQUEST, 5) \
+ _ (SUPPORTED_GROUPS, 10) \
+ _ (EC_POINT_FORMATS, 11) \
+ _ (SIGNATURE_ALGORITHMS, 13) \
+ _ (APPLICATION_LAYER_PROTOCOL_NEGOTIATION, 16) \
+ _ (SIGNED_CERTIFICATE_TIMESTAMP, 18) \
+ _ (CLIENT_CERTIFICATE_TYPE, 19) \
+ _ (SERVER_CERTIFICATE_TYPE, 20) \
+ _ (PADDING, 21) \
+ _ (TOKEN_BINDING, 24) \
+ _ (RECORD_SIZE_LIMIT, 28) \
+ _ (SESSION_TICKET, 35) \
+ _ (PRE_SHARED_KEY, 41) \
+ _ (EARLY_DATA, 42) \
+ _ (SUPPORTED_VERSIONS, 43) \
+ _ (COOKIE, 44) \
+ _ (PSK_KEY_EXCHANGE_MODES, 45) \
+ _ (CERTIFICATE_AUTHORITIES, 47) \
+ _ (OID_FILTERS, 48) \
+ _ (SIGNATURE_ALGORITHMS_CERT, 50) \
+ _ (POST_HANDSHAKE_AUTH, 49) \
+ _ (KEY_SHARE, 51) \
+ _ (CONNECTION_ID, 54) \
+ _ (QUIC_TRANSPORT_PARAMETERS, 57) \
+ _ (TICKET_REQUEST, 58) \
+ _ (DNSSEC_CHAIN, 59)
+
+typedef enum tls_handshake_extension_type_
+{
+#define _(sym, val) TLS_EXT_##sym = val,
+ foreach_tls_hanshake_extensions
+#undef _
+} tls_handshake_ext_type_t;
+
+/* Base struct for all extensions */
+typedef struct tls_handshake_ext_
+{
+ tls_handshake_ext_type_t type;
+ u8 extension[0];
+} tls_handshake_ext_t;
+
+typedef struct tls_handshake_ext_server_name_
+{
+ u8 name_type;
+ u8 *host_name;
+} tls_handshake_ext_sni_sn_t;
+
+typedef struct tls_handshake_ext_sni_
+{
+ tls_handshake_ext_t ext;
+ tls_handshake_ext_sni_sn_t *names;
+} tls_handshake_ext_sni_t;
+
+/* FQDN length as per rfc1035 */
+#define TLS_EXT_SNI_MAX_LEN 255
+
+#define foreach_tls_handshake_parse_error \
+ _ (OK, "ok") \
+ _ (WANT_MORE, "want_more") \
+ _ (UNSUPPORTED, "unsupported") \
+ _ (INVALID_LEN, "invalid_len") \
+ _ (SESSION_ID_LEN, "session_id_len") \
+ _ (CIPHER_SUITE_LEN, "cipher_suite_len") \
+ _ (COMPRESSION_METHOD, "compression_method") \
+ _ (EXTENSIONS_LEN, "extensions_len") \
+ _ (EXT_SNI_NAME_TYPE, "ext_sni_name_type") \
+ _ (EXT_SNI_LEN, "ext_sni_len")
+
+typedef enum tls_handshake_parse_error_
+{
+#define _(sym, str) TLS_HS_PARSE_ERR_##sym,
+ foreach_tls_handshake_parse_error
+#undef _
+} tls_handshake_parse_error_t;
+
+typedef struct tls_hanshake_ext_info_
+{
+ tls_handshake_ext_type_t type;
+ u16 len;
+ u8 *data;
+} tls_handshake_ext_info_t;
+
+typedef struct tls_handshake_msg_info_
+{
+ tls_handshake_type_t type;
+ u32 len;
+ u8 legacy_session_id_len;
+ u8 *legacy_session_id;
+ u16 cipher_suite_len;
+ u8 *cipher_suites;
+ u16 extensions_len;
+ u8 *extensions;
+} tls_handshake_msg_info_t;
+
+static inline u8
+tls_record_type_is_valid (tls_record_type_t type)
+{
+ switch (type)
+ {
+ case TLS_REC_CHANGE_CIPHER_SPEC:
+ case TLS_REC_ALERT:
+ case TLS_REC_HANDSHAKE:
+ case TLS_REC_APPLICATION_DATA:
+ case TLS_REC_HEARTBEAT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline u8
+tls_record_hdr_is_valid (tls_record_header_t rec_hdr)
+{
+ u16 rec_len;
+
+ if (!tls_record_type_is_valid (rec_hdr.type))
+ return 0;
+
+ /* Support for SSLv3 and TLS1.0 to TLS1.3 */
+ if (rec_hdr.version.major != TLS_MAJOR_VERSION)
+ return 0;
+
+ rec_len = clib_net_to_host_u16 (rec_hdr.length);
+ if (rec_len == 0 || rec_len > TLS_FRAGMENT_MAX_ENC_LEN)
+ return 0;
+
+ return 1;
+}
+
+tls_handshake_parse_error_t
+tls_handshake_message_try_parse (u8 *msg, int len,
+ tls_handshake_msg_info_t *info);
+tls_handshake_parse_error_t
+tls_hanshake_extensions_parse (tls_handshake_msg_info_t *info,
+ tls_handshake_ext_info_t **exts);
+tls_handshake_parse_error_t
+tls_hanshake_extensions_try_parse (tls_handshake_msg_info_t *info,
+ tls_handshake_ext_info_t *req_exts,
+ u32 n_reqs);
+tls_handshake_parse_error_t
+tls_handshake_ext_parse (tls_handshake_ext_info_t *ext_info,
+ tls_handshake_ext_t *ext);
+void tls_handshake_ext_free (tls_handshake_ext_t *ext);
+
+#endif /* SRC_VNET_TLS_TLS_RECORD_H__ */
diff --git a/src/vpp-api/python/pyproject.toml b/src/vpp-api/python/pyproject.toml
new file mode 100644
index 00000000000..638dd9c54fc
--- /dev/null
+++ b/src/vpp-api/python/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
diff --git a/src/vpp/conf/startup.conf b/src/vpp/conf/startup.conf
index 929106a4c8a..a30a15ab2b1 100644
--- a/src/vpp/conf/startup.conf
+++ b/src/vpp/conf/startup.conf
@@ -164,6 +164,11 @@ cpu {
# num-rx-queues 2
# }
+ ## Set interface only in poll mode
+ # dev 0000:02:00.1 {
+ # no-rx-interrupts
+ # }
+
## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci,
## uio_pci_generic or auto (default)
# uio-driver vfio-pci
diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt
index 233e75d6e2a..83a8b2a7e57 100644
--- a/src/vppinfra/CMakeLists.txt
+++ b/src/vppinfra/CMakeLists.txt
@@ -16,15 +16,7 @@ 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()
+list(APPEND VPPINFRA_LIBS ${CMAKE_DL_LIBS})
##############################################################################
# find libunwind
@@ -77,6 +69,7 @@ set(VPPINFRA_SRCS
bitmap.c
bihash_all_vector.c
cpu.c
+ devicetree.c
dlmalloc.c
elf.c
elog.c
@@ -159,6 +152,7 @@ set(VPPINFRA_HEADERS
crypto/aes_ctr.h
crypto/aes_gcm.h
crypto/poly1305.h
+ devicetree.h
dlist.h
dlmalloc.h
elf_clib.h
diff --git a/src/vppinfra/cpu.h b/src/vppinfra/cpu.h
index 7a1b75fcf7d..b3743d4c26d 100644
--- a/src/vppinfra/cpu.h
+++ b/src/vppinfra/cpu.h
@@ -150,6 +150,7 @@ _CLIB_MARCH_FN_REGISTRATION(fn)
_ (movdir64b, 7, ecx, 28) \
_ (enqcmd, 7, ecx, 29) \
_ (avx512_fp16, 7, edx, 23) \
+ _ (aperfmperf, 0x00000006, ecx, 0) \
_ (invariant_tsc, 0x80000007, edx, 8) \
_ (monitorx, 0x80000001, ecx, 29)
diff --git a/src/vppinfra/crypto/aes_cbc.h b/src/vppinfra/crypto/aes_cbc.h
index cb3d0784051..ee9263df260 100644
--- a/src/vppinfra/crypto/aes_cbc.h
+++ b/src/vppinfra/crypto/aes_cbc.h
@@ -539,4 +539,207 @@ clib_aes256_cbc_decrypt (const aes_cbc_key_data_t *kd, const u8 *ciphertext,
clib_aes_cbc_decrypt (kd, ciphertext, len, iv, AES_KEY_256, plaintext);
}
+#if __GNUC__ > 4 && !__clang__ && CLIB_DEBUG == 0
+#pragma GCC optimize("O3")
+#endif
+
+#if defined(__VAES__) && defined(__AVX512F__)
+#define u8xN u8x64
+#define u32xN u32x16
+#define u32xN_min_scalar u32x16_min_scalar
+#define u32xN_is_all_zero u32x16_is_all_zero
+#define u32xN_splat u32x16_splat
+#elif defined(__VAES__)
+#define u8xN u8x32
+#define u32xN u32x8
+#define u32xN_min_scalar u32x8_min_scalar
+#define u32xN_is_all_zero u32x8_is_all_zero
+#define u32xN_splat u32x8_splat
+#else
+#define u8xN u8x16
+#define u32xN u32x4
+#define u32xN_min_scalar u32x4_min_scalar
+#define u32xN_is_all_zero u32x4_is_all_zero
+#define u32xN_splat u32x4_splat
+#endif
+
+static_always_inline u32
+clib_aes_cbc_encrypt_multi (aes_cbc_key_data_t **key_data,
+ const uword *key_indices, u8 **plaintext,
+ const uword *oplen, u8 **iv, aes_key_size_t ks,
+ u8 **ciphertext, uword n_ops)
+{
+ int rounds = AES_KEY_ROUNDS (ks);
+ u8 placeholder[8192];
+ u32 i, j, count, n_left = n_ops;
+ u32xN placeholder_mask = {};
+ u32xN len = {};
+ u32 key_index[4 * N_AES_LANES];
+ u8 *src[4 * N_AES_LANES] = {};
+ u8 *dst[4 * N_AES_LANES] = {};
+ u8xN r[4] = {};
+ u8xN k[15][4] = {};
+
+ for (i = 0; i < 4 * N_AES_LANES; i++)
+ key_index[i] = ~0;
+
+more:
+ for (i = 0; i < 4 * N_AES_LANES; i++)
+ if (len[i] == 0)
+ {
+ if (n_left == 0)
+ {
+ /* no more work to enqueue, so we are enqueueing placeholder buffer
+ */
+ src[i] = dst[i] = placeholder;
+ len[i] = sizeof (placeholder);
+ placeholder_mask[i] = 0;
+ }
+ else
+ {
+ u8x16 t = aes_block_load (iv[0]);
+ ((u8x16 *) r)[i] = t;
+
+ src[i] = plaintext[0];
+ dst[i] = ciphertext[0];
+ len[i] = oplen[0];
+ placeholder_mask[i] = ~0;
+ if (key_index[i] != key_indices[0])
+ {
+ aes_cbc_key_data_t *kd;
+ key_index[i] = key_indices[0];
+ kd = key_data[key_index[i]];
+ for (j = 0; j < rounds + 1; j++)
+ ((u8x16 *) k[j])[i] = kd->encrypt_key[j];
+ }
+ n_left--;
+ iv++;
+ ciphertext++;
+ plaintext++;
+ key_indices++;
+ oplen++;
+ }
+ }
+
+ count = u32xN_min_scalar (len);
+
+ ASSERT (count % 16 == 0);
+
+ for (i = 0; i < count; i += 16)
+ {
+#if defined(__VAES__) && defined(__AVX512F__)
+ r[0] = u8x64_xor3 (r[0], aes_block_load_x4 (src, i), k[0][0]);
+ r[1] = u8x64_xor3 (r[1], aes_block_load_x4 (src + 4, i), k[0][1]);
+ r[2] = u8x64_xor3 (r[2], aes_block_load_x4 (src + 8, i), k[0][2]);
+ r[3] = u8x64_xor3 (r[3], aes_block_load_x4 (src + 12, i), k[0][3]);
+
+ for (j = 1; j < rounds; j++)
+ {
+ r[0] = aes_enc_round_x4 (r[0], k[j][0]);
+ r[1] = aes_enc_round_x4 (r[1], k[j][1]);
+ r[2] = aes_enc_round_x4 (r[2], k[j][2]);
+ r[3] = aes_enc_round_x4 (r[3], k[j][3]);
+ }
+ r[0] = aes_enc_last_round_x4 (r[0], k[j][0]);
+ r[1] = aes_enc_last_round_x4 (r[1], k[j][1]);
+ r[2] = aes_enc_last_round_x4 (r[2], k[j][2]);
+ r[3] = aes_enc_last_round_x4 (r[3], k[j][3]);
+
+ aes_block_store_x4 (dst, i, r[0]);
+ aes_block_store_x4 (dst + 4, i, r[1]);
+ aes_block_store_x4 (dst + 8, i, r[2]);
+ aes_block_store_x4 (dst + 12, i, r[3]);
+#elif defined(__VAES__)
+ r[0] = u8x32_xor3 (r[0], aes_block_load_x2 (src, i), k[0][0]);
+ r[1] = u8x32_xor3 (r[1], aes_block_load_x2 (src + 2, i), k[0][1]);
+ r[2] = u8x32_xor3 (r[2], aes_block_load_x2 (src + 4, i), k[0][2]);
+ r[3] = u8x32_xor3 (r[3], aes_block_load_x2 (src + 6, i), k[0][3]);
+
+ for (j = 1; j < rounds; j++)
+ {
+ r[0] = aes_enc_round_x2 (r[0], k[j][0]);
+ r[1] = aes_enc_round_x2 (r[1], k[j][1]);
+ r[2] = aes_enc_round_x2 (r[2], k[j][2]);
+ r[3] = aes_enc_round_x2 (r[3], k[j][3]);
+ }
+ r[0] = aes_enc_last_round_x2 (r[0], k[j][0]);
+ r[1] = aes_enc_last_round_x2 (r[1], k[j][1]);
+ r[2] = aes_enc_last_round_x2 (r[2], k[j][2]);
+ r[3] = aes_enc_last_round_x2 (r[3], k[j][3]);
+
+ aes_block_store_x2 (dst, i, r[0]);
+ aes_block_store_x2 (dst + 2, i, r[1]);
+ aes_block_store_x2 (dst + 4, i, r[2]);
+ aes_block_store_x2 (dst + 6, i, r[3]);
+#else
+#if __x86_64__
+ r[0] = u8x16_xor3 (r[0], aes_block_load (src[0] + i), k[0][0]);
+ r[1] = u8x16_xor3 (r[1], aes_block_load (src[1] + i), k[0][1]);
+ r[2] = u8x16_xor3 (r[2], aes_block_load (src[2] + i), k[0][2]);
+ r[3] = u8x16_xor3 (r[3], aes_block_load (src[3] + i), k[0][3]);
+
+ for (j = 1; j < rounds; j++)
+ {
+ r[0] = aes_enc_round_x1 (r[0], k[j][0]);
+ r[1] = aes_enc_round_x1 (r[1], k[j][1]);
+ r[2] = aes_enc_round_x1 (r[2], k[j][2]);
+ r[3] = aes_enc_round_x1 (r[3], k[j][3]);
+ }
+
+ r[0] = aes_enc_last_round_x1 (r[0], k[j][0]);
+ r[1] = aes_enc_last_round_x1 (r[1], k[j][1]);
+ r[2] = aes_enc_last_round_x1 (r[2], k[j][2]);
+ r[3] = aes_enc_last_round_x1 (r[3], k[j][3]);
+
+ aes_block_store (dst[0] + i, r[0]);
+ aes_block_store (dst[1] + i, r[1]);
+ aes_block_store (dst[2] + i, r[2]);
+ aes_block_store (dst[3] + i, r[3]);
+#else
+ r[0] ^= aes_block_load (src[0] + i);
+ r[1] ^= aes_block_load (src[1] + i);
+ r[2] ^= aes_block_load (src[2] + i);
+ r[3] ^= aes_block_load (src[3] + i);
+ for (j = 0; j < rounds - 1; j++)
+ {
+ r[0] = vaesmcq_u8 (vaeseq_u8 (r[0], k[j][0]));
+ r[1] = vaesmcq_u8 (vaeseq_u8 (r[1], k[j][1]));
+ r[2] = vaesmcq_u8 (vaeseq_u8 (r[2], k[j][2]));
+ r[3] = vaesmcq_u8 (vaeseq_u8 (r[3], k[j][3]));
+ }
+ r[0] = vaeseq_u8 (r[0], k[j][0]) ^ k[rounds][0];
+ r[1] = vaeseq_u8 (r[1], k[j][1]) ^ k[rounds][1];
+ r[2] = vaeseq_u8 (r[2], k[j][2]) ^ k[rounds][2];
+ r[3] = vaeseq_u8 (r[3], k[j][3]) ^ k[rounds][3];
+ aes_block_store (dst[0] + i, r[0]);
+ aes_block_store (dst[1] + i, r[1]);
+ aes_block_store (dst[2] + i, r[2]);
+ aes_block_store (dst[3] + i, r[3]);
+#endif
+#endif
+ }
+
+ len -= u32xN_splat (count);
+
+ for (i = 0; i < 4 * N_AES_LANES; i++)
+ {
+ src[i] += count;
+ dst[i] += count;
+ }
+
+ if (n_left > 0)
+ goto more;
+
+ if (!u32xN_is_all_zero (len & placeholder_mask))
+ goto more;
+
+ return n_ops;
+}
+
+#undef u8xN
+#undef u32xN
+#undef u32xN_min_scalar
+#undef u32xN_is_all_zero
+#undef u32xN_splat
+
#endif /* __crypto_aes_cbc_h__ */
diff --git a/src/vppinfra/devicetree.c b/src/vppinfra/devicetree.c
new file mode 100644
index 00000000000..9bf8eeeac6c
--- /dev/null
+++ b/src/vppinfra/devicetree.c
@@ -0,0 +1,347 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Cisco Systems, Inc.
+ */
+
+#include <vppinfra/clib.h>
+#include <vppinfra/devicetree.h>
+
+#ifdef __linux
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#endif
+
+static_always_inline clib_dt_node_t *
+clib_dt_node_add_child (clib_dt_main_t *dm, clib_dt_node_t *n, char *name)
+{
+ clib_dt_node_t *cn;
+
+ cn = clib_mem_alloc (sizeof (clib_dt_node_t));
+ *cn = (clib_dt_node_t){ .parent = n, .depth = n ? n->depth + 1 : 0 };
+ vec_add1 (dm->nodes, cn);
+
+ if (n == 0)
+ {
+ ASSERT (dm->root == 0);
+ dm->root = cn;
+ return cn;
+ }
+
+ vec_add1 (n->child_nodes, cn);
+ cn->path = format (0, "%v/%s", n->path, name);
+ cn->dt_main = dm;
+ hash_set_mem (dm->node_by_path, cn->path, cn);
+ if (vec_len (n->child_nodes) > 1)
+ {
+ clib_dt_node_t *prev = n->child_nodes[vec_len (n->child_nodes) - 2];
+ prev->next = cn;
+ cn->prev = prev;
+ }
+
+ return cn;
+}
+
+void
+clib_dt_main_free (clib_dt_main_t *dm)
+{
+ vec_foreach_pointer (n, dm->nodes)
+ {
+ vec_foreach_pointer (p, n->properties)
+ clib_mem_free (p);
+ vec_free (n->child_nodes);
+ vec_free (n->path);
+ vec_free (n->properties);
+ }
+
+ vec_free (dm->nodes);
+ hash_free (dm->node_by_path);
+ hash_free (dm->node_by_phandle);
+}
+
+#ifdef __linux
+__clib_export clib_error_t *
+clib_dt_read_from_sysfs (clib_dt_main_t *dm)
+{
+ DIR *dir, **dir_stack = 0;
+ struct dirent *e;
+ clib_dt_node_t *n;
+ u8 *path = 0;
+ u32 path_prefix_len;
+ clib_error_t *err = 0;
+
+ path = format (0, CLIB_DT_LINUX_PREFIX);
+ path_prefix_len = vec_len (path);
+ vec_add1 (path, 0);
+
+ dir = opendir ((char *) path);
+ if (!dir)
+ {
+ err = clib_error_return (0, "'%s' opendir failed", path);
+ goto done;
+ }
+
+ dm->node_by_path = hash_create_vec (0, sizeof (u8), sizeof (uword));
+ dm->node_by_phandle = hash_create (0, sizeof (uword));
+ vec_set_len (path, path_prefix_len);
+ n = clib_dt_node_add_child (dm, 0, 0);
+
+ while (1)
+ {
+ e = readdir (dir);
+
+ if (!e)
+ {
+ closedir (dir);
+ if (vec_len (dir_stack) == 0)
+ break;
+
+ dir = dir_stack[vec_len (dir_stack) - 1];
+ vec_pop (dir_stack);
+ n = n->parent;
+ continue;
+ }
+
+ if (e->d_type == DT_REG)
+ {
+ path = format (path, "%v/%s%c", n->path, e->d_name, 0);
+ int fd = open ((char *) path, 0);
+ if (fd >= 0)
+ {
+ struct stat st;
+ if (fstat (fd, &st) == 0)
+ {
+ u32 sz = sizeof (clib_dt_property_t) + st.st_size;
+ clib_dt_property_t *p = clib_mem_alloc (sz);
+ clib_memset (p, 0, sz);
+
+ if (read (fd, p->data, st.st_size) == st.st_size)
+ {
+ strncpy (p->name, e->d_name, sizeof (p->name));
+ p->size = st.st_size;
+ vec_add1 (n->properties, p);
+ if (strncmp ("name", p->name, 5) == 0)
+ n->name = p;
+ if ((strncmp ("phandle", p->name, 8) == 0) &&
+ (p->size == 4))
+ {
+ u32 phandle =
+ clib_net_to_host_u32 (*(u32u *) p->data);
+ hash_set (dm->node_by_phandle, phandle, n);
+ }
+ }
+ else
+ {
+ clib_mem_free (p);
+ err = clib_error_return (0, "'%s' read failed", path);
+ close (fd);
+ goto done;
+ }
+ }
+ else
+ {
+ err = clib_error_return (0, "'%s' fstat failed", path);
+ close (fd);
+ goto done;
+ }
+ close (fd);
+ }
+ else
+ {
+ err = clib_error_return (0, "'%s' open failed", path);
+ goto done;
+ }
+
+ vec_set_len (path, path_prefix_len);
+ }
+ else if (e->d_type == DT_DIR)
+ {
+ DIR *subdir;
+ if (strncmp (".", e->d_name, 2) == 0 ||
+ strncmp ("..", e->d_name, 3) == 0)
+ continue;
+
+ path = format (path, "%v/%s%c", n->path, e->d_name, 0);
+ subdir = opendir ((char *) path);
+ vec_set_len (path, path_prefix_len);
+ if (subdir)
+ {
+ vec_add1 (dir_stack, dir);
+ dir = subdir;
+ n = clib_dt_node_add_child (dm, n, e->d_name);
+ }
+ else
+ {
+ err = clib_error_return (0, "'%s' opendir failed", path);
+ goto done;
+ }
+ }
+ else
+ err =
+ clib_error_return (0, "unknown entry %s [%u]", e->d_name, e->d_type);
+ }
+
+done:
+ if (err)
+ clib_dt_main_free (dm);
+ while (vec_len (dir_stack))
+ closedir (vec_pop (dir_stack));
+ vec_free (dir_stack);
+ vec_free (path);
+ return err;
+}
+#endif
+
+clib_dt_node_t *
+clib_dt_get_child_node (clib_dt_node_t *n, char *name)
+{
+ vec_foreach_pointer (cn, n->child_nodes)
+ {
+ u8 *p = cn->path + vec_len (cn->path) - 1;
+ u32 i = 0;
+
+ while (p > cn->path && p[-1] != '/')
+ p--;
+
+ if (p[-1] != '/')
+ continue;
+
+ while (p[i] == name[i] && name[i] != 0)
+ i++;
+
+ if (name[i] != 0)
+ continue;
+
+ return cn;
+ }
+
+ return 0;
+}
+
+__clib_export clib_dt_node_t *
+clib_dt_get_node_with_path (clib_dt_main_t *dm, char *fmt, ...)
+{
+ u8 *s;
+ uword *p;
+
+ va_list va;
+ va_start (va, fmt);
+ s = va_format (0, fmt, &va);
+ va_end (va);
+
+ if (s[0] != '/')
+ return 0;
+
+ p = hash_get_mem (dm->node_by_path, s);
+ if (p)
+ return (clib_dt_node_t *) p[0];
+
+ return 0;
+}
+
+__clib_export clib_dt_property_t *
+clib_dt_get_node_property_by_name (clib_dt_node_t *n, char *name)
+{
+ vec_foreach_pointer (p, n->properties)
+ if (strncmp (name, p->name, sizeof (p->name)) == 0)
+ return p;
+ return 0;
+}
+
+__clib_export int
+clib_dt_node_is_compatible (clib_dt_node_t *n, char *comp)
+{
+ clib_dt_property_t *p;
+ char *s;
+
+ p = clib_dt_get_node_property_by_name (n, "compatible");
+
+ if (!p)
+ return 0;
+
+ s = (char *) p->data;
+ for (u32 i = 1, len = 1; i <= p->size; i++)
+ {
+ if (p->data[i - 1] == 0)
+ {
+ if (strncmp (comp, s, len) == 0)
+ return 1;
+ s = (char *) p->data + i;
+ len = 1;
+ }
+ else
+ len++;
+ }
+
+ return 0;
+}
+
+__clib_export u8 *
+format_clib_dt_property_data (u8 *s, va_list *args)
+{
+ clib_dt_property_t *p = va_arg (*args, clib_dt_property_t *);
+ u32 sz = p->size, is_printable = 0;
+ u32 n_nulls = 0;
+
+ if (sz > 2 && p->data[sz - 1] == 0 && p->data[0] != 0)
+ {
+ is_printable = 1;
+ for (u32 i = 1; i < sz - 1; i++)
+ {
+ u8 c = p->data[i];
+ if (c == 0)
+ {
+ if (p->data[i - 1] == 0)
+ {
+ is_printable = 0;
+ break;
+ }
+ n_nulls++;
+ }
+ else if ((c < 0x20) || (c > 0x7f))
+ {
+ is_printable = 0;
+ break;
+ }
+ }
+ }
+
+ if (is_printable)
+ {
+ s = format (s, "'%s'", p->data);
+ if (n_nulls)
+ {
+ for (u32 i = 2; i < p->size; i++)
+ if (((u8 *) p->data)[i - 1] == 0)
+ s = format (s, ", '%s'", ((u8 *) p->data) + i);
+ }
+ }
+ else
+ {
+ s = format (s, "< %02x", p->data[0]);
+ for (u32 i = 0; i < p->size; i++)
+ s = format (s, " %02x", p->data[i]);
+ s = format (s, " >");
+ }
+ return s;
+}
+
+__clib_export clib_dt_node_t *
+clib_dt_dereference_node (clib_dt_node_t *n, char *name)
+{
+ clib_dt_property_t *p;
+ uword *h;
+
+ p = clib_dt_get_node_property_by_name (n, name);
+ if (!p || (p->size != sizeof (u32)))
+ return 0;
+
+ h = hash_get (n->dt_main->node_by_phandle,
+ clib_net_to_host_u32 (*(u32u *) p->data));
+
+ if (h)
+ return (clib_dt_node_t *) h[0];
+
+ return 0;
+}
diff --git a/src/vppinfra/devicetree.h b/src/vppinfra/devicetree.h
new file mode 100644
index 00000000000..21c2e0f7006
--- /dev/null
+++ b/src/vppinfra/devicetree.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright (c) 2024 Cisco Systems, Inc.
+ */
+
+#ifndef CLIB_DEVICETREE_H_
+#define CLIB_DEVICETREE_H_
+
+#include <vppinfra/clib.h>
+#include <vlib/vlib.h>
+
+#ifdef __linux
+#define CLIB_DT_LINUX_PREFIX "/sys/firmware/devicetree/base"
+#endif
+
+typedef struct
+{
+ char name[32];
+ u32 size;
+ u8 data[];
+} clib_dt_property_t;
+
+typedef struct clib_dt_main clib_dt_main_t;
+
+typedef struct clib_dt_node
+{
+ u8 *path;
+ struct clib_dt_node *parent;
+ struct clib_dt_node *prev;
+ struct clib_dt_node *next;
+ struct clib_dt_node **child_nodes;
+ u8 depth;
+ clib_dt_property_t *name;
+ clib_dt_property_t **properties;
+ clib_dt_main_t *dt_main;
+} clib_dt_node_t;
+
+typedef struct clib_dt_main
+{
+ clib_dt_node_t **nodes;
+ clib_dt_node_t *root;
+ uword *node_by_path;
+ uword *node_by_phandle;
+} clib_dt_main_t;
+
+clib_dt_node_t *clib_dt_get_node_with_path (clib_dt_main_t *dm, char *fmt,
+ ...);
+clib_dt_property_t *clib_dt_get_node_property_by_name (clib_dt_node_t *,
+ char *);
+int clib_dt_node_is_compatible (clib_dt_node_t *, char *);
+clib_dt_node_t *clib_dt_dereference_node (clib_dt_node_t *, char *);
+#ifdef __linux
+clib_error_t *clib_dt_read_from_sysfs (clib_dt_main_t *dm);
+#endif
+
+format_function_t format_clib_dt_desc;
+format_function_t format_clib_dt_property_data;
+
+static_always_inline int
+clib_dt_proprerty_is_u32 (clib_dt_property_t *p)
+{
+ if (p == 0 || p->size != 4)
+ return 0;
+ return 1;
+}
+
+static_always_inline u32
+clib_dt_proprerty_get_u32 (clib_dt_property_t *p)
+{
+ return clib_net_to_host_u32 (*(u32u *) p->data);
+}
+
+#endif /* CLIB_DEVICETREE_H_ */
diff --git a/src/vppinfra/format.c b/src/vppinfra/format.c
index cf17b8a1acb..642d3e20654 100644
--- a/src/vppinfra/format.c
+++ b/src/vppinfra/format.c
@@ -833,6 +833,16 @@ done:
return s;
}
+__clib_export char *
+format_c_string (u8 *s, const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ s = va_format (s, fmt, &args);
+ va_end (args);
+ vec_add1 (s, '\0');
+ return (char *) s;
+}
/*
* fd.io coding-style-patch-verification: ON
diff --git a/src/vppinfra/format.h b/src/vppinfra/format.h
index a1a70a2d64f..14bac869f89 100644
--- a/src/vppinfra/format.h
+++ b/src/vppinfra/format.h
@@ -372,6 +372,8 @@ int test_unformat_main (unformat_input_t * input);
created circular dependency problems. */
int test_vec_main (unformat_input_t * input);
+char *format_c_string (u8 *s, const char *fmt, ...);
+
#endif /* included_format_h */
/*
diff --git a/src/vppinfra/jsonformat.c b/src/vppinfra/jsonformat.c
index 1aa3864be04..73cb94769d8 100644
--- a/src/vppinfra/jsonformat.c
+++ b/src/vppinfra/jsonformat.c
@@ -500,12 +500,13 @@ format_vl_api_mac_address_t (u8 * s, va_list * args)
mac->bytes[0], mac->bytes[1], mac->bytes[2],
mac->bytes[3], mac->bytes[4], mac->bytes[5]);
}
-#define _(T) \
- cJSON *vl_api_ ##T## _t_tojson (vl_api_ ##T## _t *a) { \
- u8 *s = format(0, "%U", format_vl_api_ ##T## _t, a); \
- cJSON *o = cJSON_CreateString((char *)s); \
- vec_free(s); \
- return o; \
+#define _(T) \
+ cJSON *vl_api_##T##_t_tojson (vl_api_##T##_t *a) \
+ { \
+ char *s = format_c_string (0, "%U", format_vl_api_##T##_t, a, 0); \
+ cJSON *o = cJSON_CreateString (s); \
+ vec_free (s); \
+ return o; \
}
foreach_type_tojson
#undef _
diff --git a/src/vppinfra/linux/mem.c b/src/vppinfra/linux/mem.c
index 21aaa55fc00..17b4412e6c9 100644
--- a/src/vppinfra/linux/mem.c
+++ b/src/vppinfra/linux/mem.c
@@ -101,11 +101,13 @@ legacy_get_log2_default_hugepage_size (void)
void
clib_mem_main_init (void)
{
+ unsigned long nodemask = 0, maxnode = CLIB_MAX_NUMAS;
+ unsigned long flags = MPOL_F_MEMS_ALLOWED;
clib_mem_main_t *mm = &clib_mem_main;
long sysconf_page_size;
uword page_size;
- void *va;
- int fd;
+ void *va = 0;
+ int fd, mode;
if (mm->log2_page_sz != CLIB_MEM_PAGE_SZ_UNKNOWN)
return;
@@ -131,23 +133,8 @@ clib_mem_main_init (void)
mm->log2_sys_default_hugepage_sz = mm->log2_default_hugepage_sz;
/* numa nodes */
- va = mmap (0, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE |
- MAP_ANONYMOUS, -1, 0);
- if (va == MAP_FAILED)
- return;
-
- if (mlock (va, page_size))
- goto done;
-
- for (int i = 0; i < CLIB_MAX_NUMAS; i++)
- {
- int status;
- if (syscall (__NR_move_pages, 0, 1, &va, &i, &status, 0) == 0)
- mm->numa_node_bitmap |= 1ULL << i;
- }
-
-done:
- munmap (va, page_size);
+ if (syscall (__NR_get_mempolicy, &mode, &nodemask, maxnode, va, flags) == 0)
+ mm->numa_node_bitmap = nodemask;
}
__clib_export u64
diff --git a/src/vppinfra/mem.h b/src/vppinfra/mem.h
index 75015d59a4a..ab9c5da30ec 100644
--- a/src/vppinfra/mem.h
+++ b/src/vppinfra/mem.h
@@ -299,10 +299,27 @@ void *clib_mem_init_thread_safe (void *memory, uword memory_size);
void clib_mem_exit (void);
+typedef struct
+{
+ /* Address of callers: outer first, inner last. */
+ uword callers[12];
+
+ /* Count of allocations with this traceback. */
+ u32 n_allocations;
+
+ /* Count of bytes allocated with this traceback. */
+ u32 n_bytes;
+
+ /* Offset of this item */
+ uword offset;
+} mheap_trace_t;
+
void clib_mem_trace (int enable);
int clib_mem_is_traced (void);
+mheap_trace_t *clib_mem_trace_dup (clib_mem_heap_t *heap);
+
typedef struct
{
/* Total number of objects allocated. */
diff --git a/src/vppinfra/mem_dlmalloc.c b/src/vppinfra/mem_dlmalloc.c
index e98687fff2a..d5ff21e58c0 100644
--- a/src/vppinfra/mem_dlmalloc.c
+++ b/src/vppinfra/mem_dlmalloc.c
@@ -23,21 +23,6 @@
typedef struct
{
- /* Address of callers: outer first, inner last. */
- uword callers[12];
-
- /* Count of allocations with this traceback. */
- u32 n_allocations;
-
- /* Count of bytes allocated with this traceback. */
- u32 n_bytes;
-
- /* Offset of this item */
- uword offset;
-} mheap_trace_t;
-
-typedef struct
-{
clib_spinlock_t lock;
mheap_trace_t *traces;
@@ -574,6 +559,23 @@ clib_mem_trace_enable_disable (uword enable)
return rv;
}
+__clib_export mheap_trace_t *
+clib_mem_trace_dup (clib_mem_heap_t *heap)
+{
+ mheap_trace_main_t *tm = &mheap_trace_main;
+ mheap_trace_t *traces_copy = 0;
+
+ clib_spinlock_lock (&tm->lock);
+ if (vec_len (tm->traces) > 0 && heap == tm->current_traced_mheap)
+ {
+ traces_copy = vec_dup (tm->traces);
+ qsort (traces_copy, vec_len (traces_copy), sizeof (traces_copy[0]),
+ mheap_trace_sort);
+ }
+ clib_spinlock_unlock (&tm->lock);
+ return traces_copy;
+}
+
__clib_export clib_mem_heap_t *
clib_mem_create_heap (void *base, uword size, int is_locked, char *fmt, ...)
{
diff --git a/src/vppinfra/time.c b/src/vppinfra/time.c
index 5a6aaf182e4..f1736499a0a 100644
--- a/src/vppinfra/time.c
+++ b/src/vppinfra/time.c
@@ -76,8 +76,11 @@ clock_frequency_from_proc_filesystem (void)
f64 ppc_timebase = 0; /* warnings be gone */
unformat_input_t input;
-/* $$$$ aarch64 kernel doesn't report "cpu MHz" */
-#if defined(__aarch64__)
+#if defined(__x86_64__)
+ if (clib_cpu_supports_aperfmperf ())
+ return 0.0;
+#elif defined(__aarch64__)
+ /* $$$$ aarch64 kernel doesn't report "cpu MHz" */
return 0.0;
#endif
diff --git a/src/vppinfra/time_range.c b/src/vppinfra/time_range.c
index 4b5e1303763..54f5629641a 100644
--- a/src/vppinfra/time_range.c
+++ b/src/vppinfra/time_range.c
@@ -264,11 +264,10 @@ format_clib_timebase_time (u8 * s, va_list * args)
clib_timebase_time_to_components (now, cp);
- s = format (s, "%s, %u %s %u %u:%02u:%02u",
- day_names_epoch_order[cp->day_name_index],
- cp->day,
- month_short_names[cp->month],
- cp->year, cp->hour, cp->minute, cp->second);
+ s = format (s, "%s, %02u %s %u %02u:%02u:%02u",
+ day_names_epoch_order[cp->day_name_index], cp->day,
+ month_short_names[cp->month], cp->year, cp->hour, cp->minute,
+ cp->second);
return (s);
}
diff --git a/src/vppinfra/unix-misc.c b/src/vppinfra/unix-misc.c
index 88a56d88afc..05ca2f901c6 100644
--- a/src/vppinfra/unix-misc.c
+++ b/src/vppinfra/unix-misc.c
@@ -67,6 +67,8 @@
__clib_export __thread uword __os_thread_index = 0;
__clib_export __thread uword __os_numa_index = 0;
+__clib_export clib_bitmap_t *os_get_cpu_affinity_bitmap (int pid);
+
clib_error_t *
clib_file_n_bytes (char *file, uword * result)
{
@@ -275,6 +277,8 @@ os_get_online_cpu_core_bitmap ()
{
#if __linux__
return clib_sysfs_read_bitmap ("/sys/devices/system/cpu/online");
+#elif defined(__FreeBSD__)
+ return os_get_cpu_affinity_bitmap (0);
#else
return 0;
#endif
@@ -309,6 +313,9 @@ os_get_cpu_affinity_bitmap (int pid)
cpuset_t mask;
uword *r = NULL;
+ clib_bitmap_alloc (r, sizeof (CPU_SETSIZE));
+ clib_bitmap_zero (r);
+
if (cpuset_getaffinity (CPU_LEVEL_CPUSET, CPU_WHICH_CPUSET, -1,
sizeof (mask), &mask) != 0)
{
@@ -330,21 +337,6 @@ 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 77c95a87424..bc5bc0cf129 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -74,12 +74,13 @@ V=0
endif
PYTHON_VERSION=$(shell $(PYTHON_INTERP) -c 'import sys; print(sys.version_info.major)')
-PIP_VERSION=24.0
+PIP_VERSION=24.2
# Keep in sync with requirements.txt
PIP_TOOLS_VERSION=7.4.1
-PIP_SETUPTOOLS_VERSION=69.2.0
+PIP_SETUPTOOLS_VERSION=71.1.0
PYTHON_DEPENDS=requirements-$(PYTHON_VERSION).txt
SCAPY_SOURCE=$(shell find $(VENV_PATH)/lib/python* -name site-packages)
+SCAPY_VERSION=$(shell grep scapy $(TEST_DIR)/requirements.txt | cut -d'=' -f3 | cut -d';' -f1)
BUILD_COV_DIR=$(BR)/test-coverage
PIP_TOOLS_INSTALL_DONE=$(VENV_RUN_DIR)/pip-tools-install-$(PYTHON_VERSION)-$(PIP_TOOLS_VERSION).done
@@ -118,7 +119,7 @@ $(PIP_INSTALL_DONE): $(PIP_TOOLS_INSTALL_DONE) $(PYTHON_DEPENDS)
$(PIP_PATCH_DONE): $(PIP_INSTALL_DONE)
@echo --- patching ---
@sleep 1 # Ensure python recompiles patched *.py files -> *.pyc
- for f in $(CURDIR)/patches/scapy-2.4.3/*.patch ; do \
+ for f in $(CURDIR)/patches/scapy-$(SCAPY_VERSION)/*.patch ; do \
echo Applying patch: $$(basename $$f) ; \
patch --forward -p1 -d $(SCAPY_SOURCE) < $$f ; \
retCode=$$?; \
@@ -388,8 +389,8 @@ COV_REM_TODO_NO_TEST="*/vpp-api/client/*" "*/plugins/prom/*" \
"*/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"
+COV_REM_ALT_TEST="*/plugins/hs_apps/*" "*/plugins/http/*.h"
+
.PHONY: cov-post
cov-post: wipe-cov $(BUILD_COV_DIR)
@lcov --capture \
diff --git a/test/asf/asfframework.py b/test/asf/asfframework.py
index 0228af82642..bd1b45c6476 100644
--- a/test/asf/asfframework.py
+++ b/test/asf/asfframework.py
@@ -166,25 +166,28 @@ def _is_distro_ubuntu2204():
is_distro_ubuntu2204 = _is_distro_ubuntu2204()
-def _is_distro_debian11():
+def _is_distro_ubuntu2404():
with open("/etc/os-release") as f:
for line in f.readlines():
- if "bullseye" in line:
+ if "noble" in line:
return True
return False
-is_distro_debian11 = _is_distro_debian11()
+is_distro_ubuntu2404 = _is_distro_ubuntu2404()
-def _is_distro_ubuntu2204():
+def _is_distro_debian11():
with open("/etc/os-release") as f:
for line in f.readlines():
- if "jammy" in line:
+ if "bullseye" in line:
return True
return False
+is_distro_debian11 = _is_distro_debian11()
+
+
class KeepAliveReporter(object):
"""
Singleton object which reports test start to parent process
@@ -236,6 +239,8 @@ class TestCaseTag(Enum):
FIXME_DEBIAN11 = 5
# marks suites broken on debug vpp image
FIXME_VPP_DEBUG = 6
+ # marks suites broken on Ubuntu-24.04
+ FIXME_UBUNTU2404 = 7
def create_tag_decorator(e):
@@ -255,6 +260,7 @@ tag_fixme_asan = create_tag_decorator(TestCaseTag.FIXME_ASAN)
tag_fixme_ubuntu2204 = create_tag_decorator(TestCaseTag.FIXME_UBUNTU2204)
tag_fixme_debian11 = create_tag_decorator(TestCaseTag.FIXME_DEBIAN11)
tag_fixme_vpp_debug = create_tag_decorator(TestCaseTag.FIXME_VPP_DEBUG)
+tag_fixme_ubuntu2404 = create_tag_decorator(TestCaseTag.FIXME_UBUNTU2404)
class DummyVpp:
@@ -323,6 +329,12 @@ class VppAsfTestCase(CPUInterface, unittest.TestCase):
cls = unittest.skip("Skipping @tag_fixme_ubuntu2204 tests")(cls)
@classmethod
+ def skip_fixme_ubuntu2404(cls):
+ """if @tag_fixme_ubuntu2404 & is Ubuntu24.04 - mark for skip"""
+ if cls.has_tag(TestCaseTag.FIXME_UBUNTU2404) and is_distro_ubuntu2404 == True:
+ cls = unittest.skip("Skipping @tag_fixme_ubuntu2404 tests")(cls)
+
+ @classmethod
def instance(cls):
"""Return the instance of this testcase"""
return cls.test_instance
@@ -1376,6 +1388,13 @@ class VppTestResult(unittest.TestResult):
test_title = colorize(f"FIXME with Ubuntu 22.04: {test_title}", RED)
test.skip_fixme_ubuntu2204()
+ if (
+ test.has_tag(TestCaseTag.FIXME_UBUNTU2404)
+ and is_distro_ubuntu2404 == True
+ ):
+ test_title = colorize(f"FIXME with Ubuntu 24.04: {test_title}", RED)
+ test.skip_fixme_ubuntu2404()
+
if hasattr(test, "vpp_worker_count"):
if test.vpp_worker_count == 0:
test_title += " [main thread only]"
diff --git a/test/asf/test_api_trace.py b/test/asf/test_api_trace.py
index 8776a79f0ac..04fcf63ca41 100644
--- a/test/asf/test_api_trace.py
+++ b/test/asf/test_api_trace.py
@@ -37,7 +37,7 @@ class TestJsonApiTrace(VppAsfTestCase):
found = True
break
self.assertTrue(found)
- self.assertEquals(o["_msgname"], "show_version")
+ self.assertEqual(o["_msgname"], "show_version")
def test_json_api_trace_replay(self):
fname = "/tmp/create_loop.json"
diff --git a/test/asf/test_http_static.py b/test/asf/test_http_static.py
index 18e8ba56a1e..73a95e992da 100644
--- a/test/asf/test_http_static.py
+++ b/test/asf/test_http_static.py
@@ -63,11 +63,13 @@ class TestHttpStaticVapi(VppAsfTestCase):
"exec",
"HttpStatic",
"curl",
+ "-v",
f"10.10.1.2/{self.temp.name[5:]}",
],
capture_output=True,
)
self.assertIn(b"Hello world", process.stdout)
+ self.assertIn(b"max-age=600", process.stderr)
self.temp2.seek(0)
process = subprocess.run(
diff --git a/test/asf/test_prom.py b/test/asf/test_prom.py
index 3f8fb4c7a44..f536fd19d34 100644
--- a/test/asf/test_prom.py
+++ b/test/asf/test_prom.py
@@ -39,6 +39,7 @@ class TestProm(VppAsfTestCase):
"""Enable HTTP Static server and prometheus exporter, get stats"""
self.vapi.cli("http static server uri tcp://0.0.0.0/80 url-handlers")
self.vapi.cli("prom enable")
+ self.sleep(1, "wait for min-scrape-interval to expire")
process = subprocess.run(
[
diff --git a/test/asf/test_session_sdl.py b/test/asf/test_session_sdl.py
new file mode 100644
index 00000000000..15d696350bc
--- /dev/null
+++ b/test/asf/test_session_sdl.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+
+import unittest
+
+from framework import VppTestCase
+from asfframework import VppTestRunner, tag_fixme_vpp_workers
+from ipaddress import IPv4Network, IPv6Network
+
+from vpp_ip_route import (
+ VppIpRoute,
+ VppRoutePath,
+ VppIpTable,
+)
+
+from vpp_papi import VppEnum
+
+
+from vpp_session_sdl import VppSessionSdl
+from vpp_session_sdl import SessionSdl
+
+
+@tag_fixme_vpp_workers
+class TestSessionSDL(VppTestCase):
+ """Session SDL Test Case"""
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestSessionSDL, cls).setUpClass()
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestSessionSDL, cls).tearDownClass()
+
+ def setUp(self):
+ super(TestSessionSDL, self).setUp()
+ self.create_loopback_interfaces(2)
+
+ table_id = 0
+
+ for i in self.lo_interfaces:
+ i.admin_up()
+
+ if table_id != 0:
+ tbl = VppIpTable(self, table_id)
+ tbl.add_vpp_config()
+ tbl = VppIpTable(self, table_id, is_ip6=1)
+ tbl.add_vpp_config()
+
+ i.set_table_ip4(table_id)
+ i.set_table_ip6(table_id)
+ i.config_ip4()
+ i.config_ip6()
+ table_id += 1
+
+ def tearDown(self):
+ for i in self.lo_interfaces:
+ i.unconfig_ip4()
+ i.set_table_ip4(0)
+ i.unconfig_ip6()
+ i.set_table_ip6(0)
+ i.admin_down()
+ self.loop0.remove_vpp_config()
+ self.loop1.remove_vpp_config()
+ super(TestSessionSDL, self).tearDown()
+
+ def create_rule(self, lcl, action_index, tag):
+ return SessionSdl(lcl=lcl, action_index=action_index, tag=tag)
+
+ def apply_rules(self, rules, is_add, appns_index):
+ r = VppSessionSdl(self, rules, is_add=is_add, appns_index=appns_index)
+ r.add_vpp_config()
+
+ def test_session_sdl_ip4(self):
+ """Session SDL IP4 test"""
+
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_SDL
+ )
+
+ # Configure namespaces
+ self.vapi.app_namespace_add_del_v4(
+ namespace_id="0", sw_if_index=self.loop0.sw_if_index
+ )
+ self.vapi.app_namespace_add_del_v4(
+ namespace_id="1", sw_if_index=self.loop1.sw_if_index
+ )
+
+ # Add inter-table routes
+ uri = "tcp://" + self.loop0.local_ip4 + "/1234"
+ server_cmd = "test echo server appns 0 fifo-size 4k " + "uri " + uri
+ client_cmd = (
+ "test echo client bytes 100000 appns 1 "
+ + "fifo-size 4k "
+ + "syn-timeout 2 uri "
+ + uri
+ )
+ ip_t01 = VppIpRoute(
+ self,
+ self.loop1.local_ip4,
+ 32,
+ [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)],
+ )
+ ip_t10 = VppIpRoute(
+ self,
+ self.loop0.local_ip4,
+ 32,
+ [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)],
+ table_id=1,
+ )
+ ip_t01.add_vpp_config()
+ ip_t10.add_vpp_config()
+
+ # Start builtin server for ip4
+ self.logger.info(self.vapi.cli(server_cmd))
+
+ # Add session filter to block loop0
+ rules = []
+ rules.append(
+ self.create_rule(lcl=self.loop0.local_ip4 + "/32", action_index=0, tag="")
+ )
+ self.apply_rules(rules, is_add=1, appns_index=0)
+
+ filter = self.vapi.session_sdl_dump()
+ self.assertEqual(filter[0].lcl, IPv4Network(self.loop0.local_ip4 + "/32"))
+
+ # irrelevant rules - add 64k entries in one API call
+ rules = []
+ for i in range(255):
+ for j in range(255):
+ prefix = "10.1.{0}.{1}/32".format(i, j)
+ rules.append(self.create_rule(lcl=prefix, action_index=0, tag=""))
+ self.apply_rules(rules, is_add=1, appns_index=0)
+
+ error = self.vapi.cli_return_response(server_cmd)
+ # Expecting an error because loop0 is blocked
+ self.assertEqual(-1, error.retval)
+
+ # Remove the session filter
+ rules = []
+ rules.append(
+ self.create_rule(lcl=self.loop0.local_ip4 + "/32", action_index=0, tag="")
+ )
+ self.apply_rules(rules, is_add=0, appns_index=0)
+
+ # Not expecting an error
+ self.logger.info(self.vapi.cli(client_cmd))
+
+ # Add a session filter not matching loop0
+ rules = []
+ rules.append(self.create_rule(lcl="172.100.1.0/24", action_index=0, tag=""))
+ self.apply_rules(rules, is_add=1, appns_index=0)
+
+ # Not expecting an error
+ self.logger.info(self.vapi.cli(client_cmd))
+
+ self.logger.info(self.vapi.cli(server_cmd + " stop"))
+
+ self.vapi.app_namespace_add_del_v4(
+ is_add=0, namespace_id="0", sw_if_index=self.loop0.sw_if_index
+ )
+ self.vapi.app_namespace_add_del_v4(
+ is_add=0, namespace_id="1", sw_if_index=self.loop1.sw_if_index
+ )
+ # Delete inter-table routes
+ ip_t01.remove_vpp_config()
+ ip_t10.remove_vpp_config()
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+ )
+
+ def test_session_sdl_ip6(self):
+ """Session SDL IP6 test"""
+
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_SDL
+ )
+
+ # Configure namespaces
+ self.vapi.app_namespace_add_del_v4(
+ namespace_id="0", sw_if_index=self.loop0.sw_if_index
+ )
+ self.vapi.app_namespace_add_del_v4(
+ namespace_id="1", sw_if_index=self.loop1.sw_if_index
+ )
+
+ # IP6 Test
+ # Add inter-table routes
+ uri = "tcp://" + self.loop0.local_ip6 + "/1235"
+ client_cmd = (
+ "test echo client bytes 100000 appns 1 "
+ + "fifo-size 4k "
+ + "syn-timeout 2 uri "
+ + uri
+ )
+ server_cmd = "test echo server appns 0 fifo-size 4k " + "uri " + uri
+
+ ip_t01 = VppIpRoute(
+ self,
+ self.loop1.local_ip6,
+ 128,
+ [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=1)],
+ )
+ ip_t10 = VppIpRoute(
+ self,
+ self.loop0.local_ip6,
+ 128,
+ [VppRoutePath("0::0", 0xFFFFFFFF, nh_table_id=0)],
+ table_id=1,
+ )
+ ip_t01.add_vpp_config()
+ ip_t10.add_vpp_config()
+
+ # Start builtin server for ip6
+ self.logger.info(self.vapi.cli(server_cmd))
+
+ # case 1: No filter
+
+ # Not expecting an error
+ self.logger.info(self.vapi.cli(client_cmd))
+
+ # case 2: filter to block
+ # Add session filter to block loop0
+ rules = []
+ rules.append(
+ self.create_rule(lcl=self.loop0.local_ip6 + "/128", action_index=0, tag="")
+ )
+ self.apply_rules(rules, is_add=1, appns_index=0)
+ filter = self.vapi.session_sdl_dump()
+ self.assertEqual(filter[0].lcl, IPv6Network(self.loop0.local_ip6 + "/128"))
+
+ error = self.vapi.cli_return_response(client_cmd)
+ # Expecting an error because loop0 is blocked
+ self.assertEqual(-1, error.retval)
+
+ # case 3: remove to block
+ # Add session filter to block loop0
+ rules = []
+ rules.append(
+ self.create_rule(lcl=self.loop0.local_ip6 + "/128", action_index=0, tag="")
+ )
+ self.apply_rules(rules, is_add=0, appns_index=0)
+ # Not expecting an error
+ self.logger.info(self.vapi.cli(client_cmd))
+
+ # stop the server
+ self.logger.info(self.vapi.cli(server_cmd + " stop"))
+
+ self.vapi.app_namespace_add_del_v4(
+ is_add=0, namespace_id="0", sw_if_index=self.loop0.sw_if_index
+ )
+ self.vapi.app_namespace_add_del_v4(
+ is_add=0, namespace_id="1", sw_if_index=self.loop1.sw_if_index
+ )
+ # Delete inter-table routes
+ ip_t01.remove_vpp_config()
+ ip_t10.remove_vpp_config()
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+ )
+
+ def test_session_enable_disable(self):
+ """Session SDL enable/disable test"""
+
+ for i in range(10):
+ # Enable sdl
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_SDL
+ )
+
+ # Disable
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+ )
+
+ # Enable rule-table
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_RULE_TABLE
+ )
+
+ # Disable
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+ )
+
+ # Enable sdl
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_SDL
+ )
+
+ # Disable
+ self.vapi.session_enable_disable_v2(
+ rt_engine_type=VppEnum.vl_api_rt_backend_engine_t.RT_BACKEND_ENGINE_API_DISABLE
+ )
+
+
+if __name__ == "__main__":
+ unittest.main(testRunner=VppTestRunner)
diff --git a/test/asf/test_vcl.py b/test/asf/test_vcl.py
index a186c6fe8c5..8368a9f922f 100644
--- a/test/asf/test_vcl.py
+++ b/test/asf/test_vcl.py
@@ -7,7 +7,7 @@ import subprocess
import signal
import glob
from config import config
-from asfframework import VppAsfTestCase, VppTestRunner, Worker
+from asfframework import VppAsfTestCase, VppTestRunner, Worker, tag_fixme_ubuntu2404
from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath
iperf3 = "/usr/bin/iperf3"
@@ -311,6 +311,7 @@ class VCLTestCase(VppAsfTestCase):
self.assert_equal(worker_client.result, 0, "Binary test return code")
+@tag_fixme_ubuntu2404
class LDPCutThruTestCase(VCLTestCase):
"""LDP Cut Thru Tests"""
@@ -970,6 +971,7 @@ class VCLThruHostStackNsock(VCLTestCase):
)
+@tag_fixme_ubuntu2404
class LDPThruHostStackIperf(VCLTestCase):
"""LDP Thru Host Stack Iperf"""
@@ -1006,34 +1008,6 @@ class LDPThruHostStackIperf(VCLTestCase):
iperf3, self.server_iperf3_args, iperf3, self.client_iperf3_args
)
-
-class LDPThruHostStackIperfMss(VCLTestCase):
- """LDP Thru Host Stack Iperf with MSS"""
-
- @classmethod
- def setUpClass(cls):
- super(LDPThruHostStackIperfMss, cls).setUpClass()
-
- @classmethod
- def tearDownClass(cls):
- super(LDPThruHostStackIperfMss, cls).tearDownClass()
-
- def setUp(self):
- super(LDPThruHostStackIperfMss, self).setUp()
-
- self.thru_host_stack_setup()
- self.client_iperf3_timeout = 20
- self.client_iperf3_args = ["-4", "-t 2", "-c", self.loop0.local_ip4]
- self.server_iperf3_args = ["-4", "-s"]
-
- def tearDown(self):
- self.thru_host_stack_tear_down()
- super(LDPThruHostStackIperfMss, self).tearDown()
-
- def show_commands_at_teardown(self):
- self.logger.debug(self.vapi.cli("show session verbose 2"))
- self.logger.debug(self.vapi.cli("show app mq"))
-
@unittest.skipUnless(_have_iperf3, "'%s' not found, Skipping.")
def test_ldp_thru_host_stack_iperf3_mss(self):
"""run LDP thru host stack iperf3 test with mss option"""
@@ -1045,6 +1019,7 @@ class LDPThruHostStackIperfMss(VCLTestCase):
)
+@tag_fixme_ubuntu2404
class LDPThruHostStackIperfUdp(VCLTestCase):
"""LDP Thru Host Stack Iperf UDP"""
@@ -1090,6 +1065,7 @@ class LDPThruHostStackIperfUdp(VCLTestCase):
)
+@tag_fixme_ubuntu2404
class LDPIpv6CutThruTestCase(VCLTestCase):
"""LDP IPv6 Cut Thru Tests"""
diff --git a/test/asf/vpp_session_sdl.py b/test/asf/vpp_session_sdl.py
new file mode 100644
index 00000000000..b10c11d1e15
--- /dev/null
+++ b/test/asf/vpp_session_sdl.py
@@ -0,0 +1,75 @@
+from ipaddress import IPv4Network
+
+from vpp_object import VppObject
+from vpp_papi import VppEnum
+from vpp_ip import INVALID_INDEX
+from vpp_papi_provider import UnexpectedApiReturnValueError
+
+
+class SessionSdl:
+ """Session SDL"""
+
+ def __init__(
+ self,
+ lcl,
+ action_index,
+ tag,
+ ):
+
+ self.action_index = action_index
+ self.lcl = lcl
+ self.tag = tag
+
+ def encode(self):
+ return {
+ "lcl": self.lcl,
+ "action_index": self.action_index,
+ "tag": self.tag,
+ }
+
+
+class VppSessionSdl(VppObject):
+ """VPP Session SDL"""
+
+ def __init__(self, test, rules, is_add, appns_index):
+ self._test = test
+ self._rules = rules
+ self.is_add = is_add
+ self.appns_index = appns_index
+
+ @property
+ def rules(self):
+ return self._rules
+
+ @property
+ def count(self):
+ return len(self._rules)
+
+ def encode_rules(self):
+ rules = []
+ for rule in self._rules:
+ rules.append(rule.encode())
+ return rules
+
+ def add_vpp_config(self, expect_error=False):
+ try:
+ reply = self._test.vapi.session_sdl_add_del(
+ is_add=self.is_add,
+ appns_index=self.appns_index,
+ count=self.count,
+ r=self.encode_rules(),
+ )
+ self._test.registry.register(self, self._test.logger)
+ if expect_error:
+ self._test.fail("Unexpected api reply")
+ return self
+ except UnexpectedApiReturnValueError:
+ if not expect_error:
+ self._test.fail("Unexpected api reply")
+ return None
+
+ def query_vpp_config(self):
+ pass
+
+ def remove_vpp_config(self, expect_error=False):
+ pass
diff --git a/test/framework.py b/test/framework.py
index 6ff03d8b073..fc22ad6483c 100644
--- a/test/framework.py
+++ b/test/framework.py
@@ -71,6 +71,9 @@ class _PacketInfo(object):
#: Store the copy of the former packet.
data = None
+ def __repr__(self):
+ return f"_PacketInfo index:{self.index} src:{self.src} dst:{self.dst} ip:{self.ip} proto:{self.proto} data:{self.data}"
+
def __eq__(self, other):
index = self.index == other.index
src = self.src == other.src
diff --git a/test/patches/scapy-2.4.5/cdp.patch b/test/patches/scapy-2.4.5/cdp.patch
new file mode 100644
index 00000000000..8fa9f69cc80
--- /dev/null
+++ b/test/patches/scapy-2.4.5/cdp.patch
@@ -0,0 +1,14 @@
+diff --git a/scapy/contrib/cdp.py b/scapy/contrib/cdp.py
+index a1532b78..83963ff4 100644
+--- a/scapy/contrib/cdp.py
++++ b/scapy/contrib/cdp.py
+@@ -392,7 +392,7 @@ class _CDPChecksum:
+ This padding is only used for checksum computation. The original
+ packet should not be altered."""
+ if len(pkt) % 2:
+- last_chr = orb(pkt[-1])
++ last_chr = orb(pkt[len(pkt)-1:])
+ if last_chr <= 0x80:
+ return pkt[:-1] + b'\x00' + chb(last_chr)
+ else:
+
diff --git a/test/patches/scapy-2.4.5/ikev2.patch b/test/patches/scapy-2.4.5/ikev2.patch
new file mode 100644
index 00000000000..a1dd45ad661
--- /dev/null
+++ b/test/patches/scapy-2.4.5/ikev2.patch
@@ -0,0 +1,22 @@
+diff --git a/scapy/contrib/ikev2.py b/scapy/contrib/ikev2.py
+index 7799fd1e..f81af7ac 100644
+--- a/scapy/contrib/ikev2.py
++++ b/scapy/contrib/ikev2.py
+@@ -607,12 +607,16 @@ class IKEv2_payload_TSr(IKEv2_class):
+
+ class IKEv2_payload_Delete(IKEv2_class):
+ name = "IKEv2 Vendor ID"
++ name = "IKEv2 delete payload"
+ overload_fields = {IKEv2: {"next_payload": 42}}
+ fields_desc = [
+ ByteEnumField("next_payload", None, IKEv2_payload_type),
+ ByteField("res", 0),
+- FieldLenField("length", None, "vendorID", "H", adjust=lambda pkt, x:x + 4), # noqa: E501
+- StrLenField("vendorID", "", length_from=lambda x:x.length - 4),
++ FieldLenField("length", None, "SPIs", "H", adjust=lambda pkt, x:x + 8), # noqa: E501
++ ByteEnumField("proto", 1, {1: "IKEv2", 2: "AH", 3: "ESP"}),
++ ByteField("SPIsize", 0),
++ ShortField("SPInum", 0),
++ StrLenField("SPIs", "", length_from=lambda x: x.length - 8),
+ ]
+
diff --git a/test/patches/scapy-2.4.5/ipsec.patch b/test/patches/scapy-2.4.5/ipsec.patch
new file mode 100644
index 00000000000..46280ce23c4
--- /dev/null
+++ b/test/patches/scapy-2.4.5/ipsec.patch
@@ -0,0 +1,230 @@
+diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
+index 8251dc14..bbb71102 100644
+--- a/scapy/layers/ipsec.py
++++ b/scapy/layers/ipsec.py
+@@ -60,7 +60,7 @@ import scapy.modules.six as six
+ from scapy.modules.six.moves import range
+ from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
+ IPv6ExtHdrRouting
+-
++from scapy.contrib.mpls import MPLS
+
+ ###############################################################################
+ class AH(Packet):
+@@ -360,13 +360,16 @@ class CryptAlgo(object):
+ encryptor = cipher.encryptor()
+
+ if self.is_aead:
+- if esn_en:
+- aad = struct.pack('!LLL', esp.spi, esn, esp.seq)
+- else:
+- aad = struct.pack('!LL', esp.spi, esp.seq)
++ aad = sa.build_aead(esp)
++ if self.name == 'AES-NULL-GMAC':
++ aad = aad + esp.iv + data
++ aes_null_gmac_data = data
++ data = b''
+ encryptor.authenticate_additional_data(aad)
+ data = encryptor.update(data) + encryptor.finalize()
+ data += encryptor.tag[:self.icv_size]
++ if self.name == 'AES-NULL-GMAC':
++ data = aes_null_gmac_data + data
+ else:
+ data = encryptor.update(data) + encryptor.finalize()
+
+@@ -402,16 +405,18 @@ class CryptAlgo(object):
+
+ if self.is_aead:
+ # Tag value check is done during the finalize method
+- if esn_en:
+- decryptor.authenticate_additional_data(
+- struct.pack('!LLL', esp.spi, esn, esp.seq))
+- else:
+- decryptor.authenticate_additional_data(
+- struct.pack('!LL', esp.spi, esp.seq))
++ aad = sa.build_aead(esp)
++ if self.name == 'AES-NULL-GMAC':
++ aad = aad + iv + data
++ aes_null_gmac_data = data
++ data = b''
++ decryptor.authenticate_additional_data(aad)
+ try:
+ data = decryptor.update(data) + decryptor.finalize()
+ except InvalidTag as err:
+ raise IPSecIntegrityError(err)
++ if self.name == 'AES-NULL-GMAC':
++ data = aes_null_gmac_data + data
+
+ # extract padlen and nh
+ padlen = orb(data[-2])
+@@ -458,6 +463,13 @@ if algorithms:
+ iv_size=8,
+ icv_size=16,
+ format_mode_iv=_salt_format_mode_iv)
++ CRYPT_ALGOS['AES-NULL-GMAC'] = CryptAlgo('AES-NULL-GMAC',
++ cipher=algorithms.AES,
++ mode=modes.GCM,
++ salt_size=4,
++ iv_size=8,
++ icv_size=16,
++ format_mode_iv=_salt_format_mode_iv)
+ if hasattr(modes, 'CCM'):
+ CRYPT_ALGOS['AES-CCM'] = CryptAlgo('AES-CCM',
+ cipher=algorithms.AES,
+@@ -546,7 +558,7 @@ class AuthAlgo(object):
+ else:
+ return self.mac(key, self.digestmod(), default_backend())
+
+- def sign(self, pkt, key, esn_en=False, esn=0):
++ def sign(self, pkt, key, trailer=None, esn_en=False, esn=0):
+ """
+ Sign an IPsec (ESP or AH) packet with this algo.
+
+@@ -565,20 +577,20 @@ class AuthAlgo(object):
+
+ if pkt.haslayer(ESP):
+ mac.update(raw(pkt[ESP]))
++ if trailer:
++ mac.update(trailer)
+ pkt[ESP].data += mac.finalize()[:self.icv_size]
+
+ elif pkt.haslayer(AH):
+ clone = zero_mutable_fields(pkt.copy(), sending=True)
+- if esn_en:
+- temp = raw(clone) + struct.pack('!L', esn)
+- else:
+- temp = raw(clone)
+- mac.update(temp)
++ mac.update(raw(clone))
++ if trailer:
++ mac.update(trailer)
+ pkt[AH].icv = mac.finalize()[:self.icv_size]
+
+ return pkt
+
+- def verify(self, pkt, key, esn_en=False, esn=0):
++ def verify(self, pkt, key, trailer, esn_en=False, esn=0):
+ """
+ Check that the integrity check value (icv) of a packet is valid.
+
+@@ -602,7 +614,6 @@ class AuthAlgo(object):
+ pkt_icv = pkt.data[len(pkt.data) - self.icv_size:]
+ clone = pkt.copy()
+ clone.data = clone.data[:len(clone.data) - self.icv_size]
+- temp = raw(clone)
+
+ elif pkt.haslayer(AH):
+ if len(pkt[AH].icv) != self.icv_size:
+@@ -611,12 +622,10 @@ class AuthAlgo(object):
+ pkt[AH].icv = pkt[AH].icv[:self.icv_size]
+ pkt_icv = pkt[AH].icv
+ clone = zero_mutable_fields(pkt.copy(), sending=False)
+- if esn_en:
+- temp = raw(clone) + struct.pack('!L', esn)
+- else:
+- temp = raw(clone)
+
+- mac.update(temp)
++ mac.update(raw(clone))
++ if trailer:
++ mac.update(trailer) # bytearray(4)) #raw(trailer))
+ computed_icv = mac.finalize()[:self.icv_size]
+
+ # XXX: Cannot use mac.verify because the ICV can be truncated
+@@ -805,7 +814,7 @@ class SecurityAssociation(object):
+ This class is responsible of "encryption" and "decryption" of IPsec packets. # noqa: E501
+ """
+
+- SUPPORTED_PROTOS = (IP, IPv6)
++ SUPPORTED_PROTOS = (IP, IPv6, MPLS)
+
+ def __init__(self, proto, spi, seq_num=1, crypt_algo=None, crypt_key=None,
+ auth_algo=None, auth_key=None, tunnel_header=None, nat_t_header=None, esn_en=False, esn=0): # noqa: E501
+@@ -880,6 +889,23 @@ class SecurityAssociation(object):
+ raise TypeError('nat_t_header must be %s' % UDP.name)
+ self.nat_t_header = nat_t_header
+
++ def build_aead(self, esp):
++ if self.esn_en:
++ return (struct.pack('!LLL', esp.spi, self.seq_num >> 32, esp.seq))
++ else:
++ return (struct.pack('!LL', esp.spi, esp.seq))
++
++ def build_seq_num(self, num):
++ # only lower order bits are transmitted
++ # higher order bits are used in the ICV
++ lower = num & 0xffffffff
++ upper = num >> 32
++
++ if self.esn_en:
++ return lower, struct.pack("!I", upper)
++ else:
++ return lower, None
++
+ def check_spi(self, pkt):
+ if pkt.spi != self.spi:
+ raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
+@@ -893,7 +919,8 @@ class SecurityAssociation(object):
+ if len(iv) != self.crypt_algo.iv_size:
+ raise TypeError('iv length must be %s' % self.crypt_algo.iv_size) # noqa: E501
+
+- esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv)
++ low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
++ esp = _ESPPlain(spi=self.spi, seq=low_seq_num, iv=iv)
+
+ if self.tunnel_header:
+ tunnel = self.tunnel_header.copy()
+@@ -917,7 +944,7 @@ class SecurityAssociation(object):
+ esn_en=esn_en or self.esn_en,
+ esn=esn or self.esn)
+
+- self.auth_algo.sign(esp, self.auth_key)
++ self.auth_algo.sign(esp, self.auth_key, high_seq_num)
+
+ if self.nat_t_header:
+ nat_t_header = self.nat_t_header.copy()
+@@ -944,7 +971,8 @@ class SecurityAssociation(object):
+
+ def _encrypt_ah(self, pkt, seq_num=None, esn_en=False, esn=0):
+
+- ah = AH(spi=self.spi, seq=seq_num or self.seq_num,
++ low_seq_num, high_seq_num = self.build_seq_num(seq_num or self.seq_num)
++ ah = AH(spi=self.spi, seq=low_seq_num,
+ icv=b"\x00" * self.auth_algo.icv_size)
+
+ if self.tunnel_header:
+@@ -985,7 +1013,7 @@ class SecurityAssociation(object):
+ ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
+
+ signed_pkt = self.auth_algo.sign(ip_header / ah / payload,
+- self.auth_key,
++ self.auth_key, high_seq_num,
+ esn_en=esn_en or self.esn_en,
+ esn=esn or self.esn)
+
+@@ -1025,11 +1053,12 @@ class SecurityAssociation(object):
+
+ def _decrypt_esp(self, pkt, verify=True, esn_en=None, esn=None):
+
++ low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
+ encrypted = pkt[ESP]
+
+ if verify:
+ self.check_spi(pkt)
+- self.auth_algo.verify(encrypted, self.auth_key)
++ self.auth_algo.verify(encrypted, self.auth_key, high_seq_num)
+
+ esp = self.crypt_algo.decrypt(self, encrypted, self.crypt_key,
+ self.crypt_algo.icv_size or
+@@ -1070,9 +1099,10 @@ class SecurityAssociation(object):
+
+ def _decrypt_ah(self, pkt, verify=True, esn_en=None, esn=None):
+
++ low_seq_num, high_seq_num = self.build_seq_num(self.seq_num)
+ if verify:
+ self.check_spi(pkt)
+- self.auth_algo.verify(pkt, self.auth_key,
++ self.auth_algo.verify(pkt, self.auth_key, high_seq_num,
+ esn_en=esn_en or self.esn_en,
+ esn=esn or self.esn)
+
diff --git a/test/patches/scapy-2.4.5/ppp.patch b/test/patches/scapy-2.4.5/ppp.patch
new file mode 100644
index 00000000000..a3680bfee08
--- /dev/null
+++ b/test/patches/scapy-2.4.5/ppp.patch
@@ -0,0 +1,45 @@
+# NOTE: This patch copied from https://github.com/secdev/scapy
+# commit 3e6900776698cd5472c5405294414d5b672a3f18
+#
+diff --git a/scapy/layers/ppp.py b/scapy/layers/ppp.py
+index b5cd42b4..e0f4c593 100644
+--- a/scapy/layers/ppp.py
++++ b/scapy/layers/ppp.py
+@@ -292,6 +292,14 @@ class _PPPProtoField(EnumField):
+
+ See RFC 1661 section 2
+ <https://tools.ietf.org/html/rfc1661#section-2>
++
++ The generated proto field is two bytes when not specified, or when specified
++ as an integer or a string:
++ PPP()
++ PPP(proto=0x21)
++ PPP(proto="Internet Protocol version 4")
++ To explicitly forge a one byte proto field, use the bytes representation:
++ PPP(proto=b'\x21')
+ """
+ def getfield(self, pkt, s):
+ if ord(s[:1]) & 0x01:
+@@ -304,12 +312,18 @@ class _PPPProtoField(EnumField):
+ return super(_PPPProtoField, self).getfield(pkt, s)
+
+ def addfield(self, pkt, s, val):
+- if val < 0x100:
+- self.fmt = "!B"
+- self.sz = 1
++ if isinstance(val, bytes):
++ if len(val) == 1:
++ fmt, sz = "!B", 1
++ elif len(val) == 2:
++ fmt, sz = "!H", 2
++ else:
++ raise TypeError('Invalid length for PPP proto')
++ val = struct.Struct(fmt).unpack(val)[0]
+ else:
+- self.fmt = "!H"
+- self.sz = 2
++ fmt, sz = "!H", 2
++ self.fmt = fmt
++ self.sz = sz
+ self.struct = struct.Struct(self.fmt)
+ return super(_PPPProtoField, self).addfield(pkt, s, val)
diff --git a/test/patches/scapy-2.4.5/scapy-python312.patch b/test/patches/scapy-2.4.5/scapy-python312.patch
new file mode 100644
index 00000000000..f0638ff4dd6
--- /dev/null
+++ b/test/patches/scapy-2.4.5/scapy-python312.patch
@@ -0,0 +1,590 @@
+diff --git a/scapy/arch/bpf/core.py b/scapy/arch/bpf/core.py
+index d49267cd..13b7cff7 100644
+--- a/scapy/arch/bpf/core.py
++++ b/scapy/arch/bpf/core.py
+@@ -27,7 +27,7 @@ from scapy.error import Scapy_Exception, warning
+ from scapy.interfaces import InterfaceProvider, IFACES, NetworkInterface, \
+ network_name
+ from scapy.pton_ntop import inet_ntop
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+
+ # ctypes definitions
+diff --git a/scapy/arch/linux.py b/scapy/arch/linux.py
+index 88f0de80..8870320f 100644
+--- a/scapy/arch/linux.py
++++ b/scapy/arch/linux.py
+@@ -49,8 +49,8 @@ from scapy.packet import Packet, Padding
+ from scapy.pton_ntop import inet_ntop
+ from scapy.supersocket import SuperSocket
+
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+ # Typing imports
+ from scapy.compat import (
+diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py
+index 3e640f48..8a01681c 100755
+--- a/scapy/arch/windows/__init__.py
++++ b/scapy/arch/windows/__init__.py
+@@ -36,8 +36,8 @@ from scapy.pton_ntop import inet_ntop, inet_pton
+ from scapy.utils import atol, itom, mac2str, str2mac
+ from scapy.utils6 import construct_source_candidate_set, in6_getscope
+ from scapy.data import ARPHDR_ETHER, load_manuf
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import input, winreg
++import six
++from six.moves import input, winreg
+ from scapy.compat import plain_str
+ from scapy.supersocket import SuperSocket
+
+diff --git a/scapy/asn1/asn1.py b/scapy/asn1/asn1.py
+index 45eea565..a694de0d 100644
+--- a/scapy/asn1/asn1.py
++++ b/scapy/asn1/asn1.py
+@@ -18,8 +18,8 @@ from scapy.error import Scapy_Exception, warning
+ from scapy.volatile import RandField, RandIP, GeneralizedTime
+ from scapy.utils import Enum_metaclass, EnumElement, binrepr
+ from scapy.compat import plain_str, chb, orb
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+
+ class RandASN1Object(RandField):
+diff --git a/scapy/asn1fields.py b/scapy/asn1fields.py
+index 87679b55..887dd42e 100644
+--- a/scapy/asn1fields.py
++++ b/scapy/asn1fields.py
+@@ -20,8 +20,8 @@ from scapy.base_classes import BasePacket
+ from scapy.utils import binrepr
+ from scapy import packet
+ from functools import reduce
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+
+ class ASN1F_badsequence(Exception):
+diff --git a/scapy/base_classes.py b/scapy/base_classes.py
+index ec532110..51897d05 100644
+--- a/scapy/base_classes.py
++++ b/scapy/base_classes.py
+@@ -27,9 +27,9 @@ import warnings
+ import scapy
+ from scapy.error import Scapy_Exception
+ from scapy.consts import WINDOWS
+-import scapy.modules.six as six
++import six
+
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+ from scapy.compat import (
+ Any,
+diff --git a/scapy/contrib/automotive/someip.py b/scapy/contrib/automotive/someip.py
+index a19e008d..136ab64c 100644
+--- a/scapy/contrib/automotive/someip.py
++++ b/scapy/contrib/automotive/someip.py
+@@ -36,7 +36,7 @@ from scapy.layers.inet import TCP, UDP
+ from scapy.layers.inet6 import IP6Field
+ from scapy.compat import raw, orb
+ from scapy.config import conf
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.packet import Packet, Raw, bind_top_down, bind_bottom_up
+ from scapy.fields import XShortField, BitEnumField, ConditionalField, \
+ BitField, XBitField, IntField, XByteField, ByteEnumField, \
+diff --git a/scapy/contrib/cansocket_python_can.py b/scapy/contrib/cansocket_python_can.py
+index 936d39cf..1a1b717d 100644
+--- a/scapy/contrib/cansocket_python_can.py
++++ b/scapy/contrib/cansocket_python_can.py
+@@ -21,7 +21,7 @@ from scapy.config import conf
+ from scapy.supersocket import SuperSocket
+ from scapy.layers.can import CAN
+ from scapy.error import warning
+-from scapy.modules.six.moves import queue
++from six.moves import queue
+ from scapy.compat import Any, List
+ from can import Message as can_Message
+ from can import CanError as can_CanError
+diff --git a/scapy/contrib/cdp.py b/scapy/contrib/cdp.py
+index fa116538..9700deba 100644
+--- a/scapy/contrib/cdp.py
++++ b/scapy/contrib/cdp.py
+@@ -43,7 +43,7 @@ from scapy.fields import (
+ from scapy.layers.inet import checksum
+ from scapy.layers.l2 import SNAP
+ from scapy.compat import orb, chb
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.config import conf
+
+
+diff --git a/scapy/contrib/diameter.py b/scapy/contrib/diameter.py
+index e99cb424..9fedca3d 100644
+--- a/scapy/contrib/diameter.py
++++ b/scapy/contrib/diameter.py
+@@ -32,8 +32,8 @@ from scapy.fields import ConditionalField, EnumField, Field, FieldLenField, \
+ XByteField, XIntField
+ from scapy.layers.inet import TCP
+ from scapy.layers.sctp import SCTPChunkData
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.compat import chb, orb, raw, bytes_hex, plain_str
+ from scapy.error import warning
+ from scapy.utils import inet_ntoa, inet_aton
+diff --git a/scapy/contrib/gtp.py b/scapy/contrib/gtp.py
+index bf369847..de3b8961 100644
+--- a/scapy/contrib/gtp.py
++++ b/scapy/contrib/gtp.py
+@@ -30,7 +30,7 @@ from scapy.fields import BitEnumField, BitField, ByteEnumField, ByteField, \
+ from scapy.layers.inet import IP, UDP
+ from scapy.layers.inet6 import IPv6, IP6Field
+ from scapy.layers.ppp import PPP
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.packet import bind_layers, bind_bottom_up, bind_top_down, \
+ Packet, Raw
+ from scapy.volatile import RandInt, RandIP, RandNum, RandString
+diff --git a/scapy/contrib/homeplugav.py b/scapy/contrib/homeplugav.py
+index 171eb7d0..92b22d16 100644
+--- a/scapy/contrib/homeplugav.py
++++ b/scapy/contrib/homeplugav.py
+@@ -44,7 +44,7 @@ from scapy.fields import (
+ XShortField,
+ )
+ from scapy.layers.l2 import Ether
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+ """
+ Copyright (C) HomePlugAV Layer for Scapy by FlUxIuS (Sebastien Dudek)
+diff --git a/scapy/contrib/isis.py b/scapy/contrib/isis.py
+index b7fc222e..f68bb37d 100644
+--- a/scapy/contrib/isis.py
++++ b/scapy/contrib/isis.py
+@@ -80,7 +80,7 @@ from scapy.layers.clns import network_layer_protocol_ids, register_cln_protocol
+ from scapy.layers.inet6 import IP6ListField, IP6Field
+ from scapy.utils import fletcher16_checkbytes
+ from scapy.volatile import RandString, RandByte
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.compat import orb, hex_bytes
+
+ EXT_VERSION = "v0.0.3"
+diff --git a/scapy/contrib/isotp.py b/scapy/contrib/isotp.py
+index 845d566d..225c6b86 100644
+--- a/scapy/contrib/isotp.py
++++ b/scapy/contrib/isotp.py
+@@ -29,9 +29,9 @@ from scapy.fields import BitField, FlagsField, StrLenField, \
+ BitEnumField, ByteField, XByteField, BitFieldLenField, StrField
+ from scapy.compat import chb, orb
+ from scapy.layers.can import CAN, CAN_MAX_IDENTIFIER, CAN_MTU, CAN_MAX_DLEN
+-import scapy.modules.six as six
++import six
+ import scapy.automaton as automaton
+-from scapy.modules.six.moves import queue
++from six.moves import queue
+ from scapy.error import Scapy_Exception, warning, log_loading, log_runtime
+ from scapy.supersocket import SuperSocket, SO_TIMESTAMPNS
+ from scapy.config import conf
+diff --git a/scapy/contrib/ldp.py b/scapy/contrib/ldp.py
+index 25152ab7..ea8a6b83 100644
+--- a/scapy/contrib/ldp.py
++++ b/scapy/contrib/ldp.py
+@@ -27,7 +27,7 @@ from scapy.fields import BitField, IPField, IntField, ShortField, StrField, \
+ XBitField
+ from scapy.layers.inet import UDP
+ from scapy.layers.inet import TCP
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.config import conf
+ from scapy.utils import inet_aton, inet_ntoa
+
+diff --git a/scapy/contrib/lldp.py b/scapy/contrib/lldp.py
+index 04d37192..91b64439 100644
+--- a/scapy/contrib/lldp.py
++++ b/scapy/contrib/lldp.py
+@@ -51,7 +51,7 @@ from scapy.fields import MACField, IPField, BitField, \
+ ShortField, XStrLenField, ByteField, ConditionalField, \
+ MultipleTypeField
+ from scapy.packet import Packet, bind_layers
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.data import ETHER_TYPES
+ from scapy.compat import orb
+
+diff --git a/scapy/contrib/nfs.py b/scapy/contrib/nfs.py
+index 79259e39..6d6f47a1 100644
+--- a/scapy/contrib/nfs.py
++++ b/scapy/contrib/nfs.py
+@@ -12,7 +12,7 @@ from scapy.packet import Packet, bind_layers
+ from scapy.fields import IntField, IntEnumField, FieldListField, LongField, \
+ XIntField, XLongField, ConditionalField, PacketListField, StrLenField, \
+ PacketField
+-from scapy.modules.six import integer_types
++from six import integer_types
+
+ nfsstat3 = {
+ 0: 'NFS3_OK',
+diff --git a/scapy/contrib/ppi_geotag.py b/scapy/contrib/ppi_geotag.py
+index a7cc6345..bf16ae2b 100644
+--- a/scapy/contrib/ppi_geotag.py
++++ b/scapy/contrib/ppi_geotag.py
+@@ -34,8 +34,8 @@ from scapy.fields import ByteField, ConditionalField, Field, FlagsField, \
+ UTCTimeField, XLEIntField, SignedByteField, XLEShortField
+ from scapy.layers.ppi import PPI_Hdr, PPI_Element
+ from scapy.error import warning
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+ CURR_GEOTAG_VER = 2 # Major revision of specification
+
+diff --git a/scapy/contrib/skinny.py b/scapy/contrib/skinny.py
+index c12cb94e..f8a8be06 100644
+--- a/scapy/contrib/skinny.py
++++ b/scapy/contrib/skinny.py
+@@ -29,7 +29,7 @@ from scapy.packet import Packet, bind_layers
+ from scapy.fields import FlagsField, IPField, LEIntEnumField, LEIntField, \
+ StrFixedLenField
+ from scapy.layers.inet import TCP
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.volatile import RandShort
+ from scapy.config import conf
+
+diff --git a/scapy/contrib/tacacs.py b/scapy/contrib/tacacs.py
+index ed933f10..7b31f4c0 100755
+--- a/scapy/contrib/tacacs.py
++++ b/scapy/contrib/tacacs.py
+@@ -29,7 +29,7 @@ from scapy.fields import FieldLenField, ConditionalField, StrLenField
+ from scapy.layers.inet import TCP
+ from scapy.compat import chb, orb
+ from scapy.config import conf
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+ SECRET = 'test'
+
+diff --git a/scapy/fields.py b/scapy/fields.py
+index 7448400c..5db02244 100644
+--- a/scapy/fields.py
++++ b/scapy/fields.py
+@@ -37,9 +37,9 @@ from scapy.utils6 import in6_6to4ExtractAddr, in6_isaddr6to4, \
+ in6_isaddrTeredo, in6_ptop, Net6, teredoAddrExtractInfo
+ from scapy.base_classes import Gen, Net, BasePacket, Field_metaclass
+ from scapy.error import warning
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
+-from scapy.modules.six import integer_types
++import six
++from six.moves import range
++from six import integer_types
+
+ # Typing imports
+ from scapy.compat import (
+diff --git a/scapy/interfaces.py b/scapy/interfaces.py
+index aae0c55a..75919bd2 100644
+--- a/scapy/interfaces.py
++++ b/scapy/interfaces.py
+@@ -17,8 +17,8 @@ from scapy.consts import WINDOWS
+ from scapy.utils import pretty_list
+ from scapy.utils6 import in6_isvalid
+
+-from scapy.modules.six.moves import UserDict
+-import scapy.modules.six as six
++from six.moves import UserDict
++import six
+
+ # Typing imports
+ import scapy
+diff --git a/scapy/layers/bluetooth4LE.py b/scapy/layers/bluetooth4LE.py
+index 40f8b0bb..d461b808 100644
+--- a/scapy/layers/bluetooth4LE.py
++++ b/scapy/layers/bluetooth4LE.py
+@@ -23,7 +23,7 @@ from scapy.contrib.ethercat import LEBitEnumField, LEBitField
+ from scapy.layers.bluetooth import EIR_Hdr, L2CAP_Hdr
+ from scapy.layers.ppi import PPI_Element, PPI_Hdr
+
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.utils import mac2str, str2mac
+
+ ####################
+diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py
+index 4164d88e..ccb42e93 100644
+--- a/scapy/layers/dhcp.py
++++ b/scapy/layers/dhcp.py
+@@ -31,8 +31,8 @@ from scapy.volatile import RandBin, RandField, RandNum, RandNumExpo
+ from scapy.arch import get_if_raw_hwaddr
+ from scapy.sendrecv import srp1, sendp
+ from scapy.error import warning
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.config import conf
+
+ dhcpmagic = b"c\x82Sc"
+diff --git a/scapy/layers/dns.py b/scapy/layers/dns.py
+index b1c9f456..5e87ef5e 100755
+--- a/scapy/layers/dns.py
++++ b/scapy/layers/dns.py
+@@ -24,8 +24,8 @@ from scapy.sendrecv import sr1
+ from scapy.layers.inet import IP, DestIPField, IPField, UDP, TCP
+ from scapy.layers.inet6 import DestIP6Field, IP6Field
+ from scapy.error import log_runtime, warning, Scapy_Exception
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+
+ def dns_get_str(s, pointer=0, pkt=None, _fullpacket=False):
+diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py
+index 5222df51..2c411b81 100644
+--- a/scapy/layers/inet.py
++++ b/scapy/layers/inet.py
+@@ -64,8 +64,8 @@ from scapy.pton_ntop import inet_pton
+
+ import scapy.as_resolvers
+
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+ ####################
+ # IP Tools class #
+diff --git a/scapy/layers/ipsec.py b/scapy/layers/ipsec.py
+index 8251dc14..852b3dfb 100644
+--- a/scapy/layers/ipsec.py
++++ b/scapy/layers/ipsec.py
+@@ -56,8 +56,8 @@ from scapy.fields import ByteEnumField, ByteField, IntField, PacketField, \
+ ShortField, StrField, XIntField, XStrField, XStrLenField
+ from scapy.packet import Packet, bind_layers, Raw
+ from scapy.layers.inet import IP, UDP
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
+ IPv6ExtHdrRouting
+
+diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py
+index b1224208..85377b37 100644
+--- a/scapy/layers/l2.py
++++ b/scapy/layers/l2.py
+@@ -51,7 +51,7 @@ from scapy.fields import (
+ XShortEnumField,
+ XShortField,
+ )
+-from scapy.modules.six import viewitems
++from six import viewitems
+ from scapy.packet import bind_layers, Packet
+ from scapy.plist import (
+ PacketList,
+diff --git a/scapy/layers/ntp.py b/scapy/layers/ntp.py
+index 21da95c8..c705c96a 100644
+--- a/scapy/layers/ntp.py
++++ b/scapy/layers/ntp.py
+@@ -25,8 +25,8 @@ from scapy.layers.inet import UDP
+ from scapy.utils import lhex
+ from scapy.compat import orb
+ from scapy.config import conf
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+
+
+ #############################################################################
+diff --git a/scapy/layers/tftp.py b/scapy/layers/tftp.py
+index 2e3077d9..11f1ed94 100644
+--- a/scapy/layers/tftp.py
++++ b/scapy/layers/tftp.py
+@@ -16,7 +16,7 @@ from scapy.fields import PacketListField, ShortEnumField, ShortField, \
+ StrNullField
+ from scapy.automaton import ATMT, Automaton
+ from scapy.layers.inet import UDP, IP
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.config import conf
+ from scapy.volatile import RandShort
+
+diff --git a/scapy/layers/tls/cert.py b/scapy/layers/tls/cert.py
+index b6eb0af2..293ef971 100644
+--- a/scapy/layers/tls/cert.py
++++ b/scapy/layers/tls/cert.py
+@@ -33,8 +33,8 @@ import os
+ import time
+
+ from scapy.config import conf, crypto_validator
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.error import warning
+ from scapy.utils import binrepr
+ from scapy.asn1.asn1 import ASN1_BIT_STRING
+diff --git a/scapy/layers/tls/crypto/prf.py b/scapy/layers/tls/crypto/prf.py
+index 210f9108..cb56f247 100644
+--- a/scapy/layers/tls/crypto/prf.py
++++ b/scapy/layers/tls/crypto/prf.py
+@@ -13,7 +13,7 @@ from scapy.utils import strxor
+
+ from scapy.layers.tls.crypto.hash import _tls_hash_algs
+ from scapy.layers.tls.crypto.h_mac import _tls_hmac_algs
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.compat import bytes_encode
+
+
+diff --git a/scapy/modules/krack/crypto.py b/scapy/modules/krack/crypto.py
+index a4803def..69cc678a 100644
+--- a/scapy/modules/krack/crypto.py
++++ b/scapy/modules/krack/crypto.py
+@@ -6,8 +6,8 @@ from zlib import crc32
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
+ from cryptography.hazmat.backends import default_backend
+
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.compat import orb, chb
+ from scapy.layers.dot11 import Dot11TKIP
+ from scapy.utils import mac2str
+diff --git a/scapy/modules/p0f.py b/scapy/modules/p0f.py
+index 74ee9f16..5bca0bec 100644
+--- a/scapy/modules/p0f.py
++++ b/scapy/modules/p0f.py
+@@ -24,7 +24,7 @@ from scapy.error import warning, Scapy_Exception, log_runtime
+ from scapy.volatile import RandInt, RandByte, RandNum, RandShort, RandString
+ from scapy.sendrecv import sniff
+ from scapy.modules import six
+-from scapy.modules.six.moves import map, range
++from six.moves import map, range
+ if conf.route is None:
+ # unused import, only to initialize conf.route
+ import scapy.route # noqa: F401
+diff --git a/scapy/modules/voip.py b/scapy/modules/voip.py
+index 420ed641..9aa3cceb 100644
+--- a/scapy/modules/voip.py
++++ b/scapy/modules/voip.py
+@@ -18,7 +18,7 @@ from scapy.layers.inet import IP, UDP
+ from scapy.layers.rtp import RTP
+ from scapy.consts import WINDOWS
+ from scapy.config import conf
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+
+ sox_base = (["sox", "-t", ".ul"], ["-", "-t", "ossdsp", "/dev/dsp"])
+diff --git a/scapy/plist.py b/scapy/plist.py
+index 6e959f9b..b9ba2d47 100644
+--- a/scapy/plist.py
++++ b/scapy/plist.py
+@@ -27,8 +27,8 @@ from scapy.utils import do_graph, hexdump, make_table, make_lined_table, \
+ from scapy.extlib import plt, Line2D, \
+ MATPLOTLIB_INLINED, MATPLOTLIB_DEFAULT_PLOT_KARGS
+ from functools import reduce
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range, zip
++import six
++from six.moves import range, zip
+
+ # typings
+ from scapy.compat import (
+diff --git a/scapy/pton_ntop.py b/scapy/pton_ntop.py
+index ba023a77..fd3e2522 100644
+--- a/scapy/pton_ntop.py
++++ b/scapy/pton_ntop.py
+@@ -14,7 +14,7 @@ from __future__ import absolute_import
+ import socket
+ import re
+ import binascii
+-from scapy.modules.six.moves import range
++from six.moves import range
+ from scapy.compat import plain_str, hex_bytes, bytes_encode, bytes_hex
+
+ from scapy.compat import (
+diff --git a/scapy/scapypipes.py b/scapy/scapypipes.py
+index 1cbd43cb..e8553493 100644
+--- a/scapy/scapypipes.py
++++ b/scapy/scapypipes.py
+@@ -7,7 +7,7 @@ from __future__ import print_function
+ import socket
+ import subprocess
+
+-from scapy.modules.six.moves.queue import Queue, Empty
++from six.moves.queue import Queue, Empty
+ from scapy.pipetool import Source, Drain, Sink
+ from scapy.config import conf
+ from scapy.compat import raw
+diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py
+index 503c6a3b..372668de 100644
+--- a/scapy/sendrecv.py
++++ b/scapy/sendrecv.py
+@@ -36,7 +36,7 @@ from scapy.plist import (
+ from scapy.error import log_runtime, log_interactive, Scapy_Exception
+ from scapy.base_classes import Gen, SetGen
+ from scapy.modules import six
+-from scapy.modules.six.moves import map
++from six.moves import map
+ from scapy.sessions import DefaultSession
+ from scapy.supersocket import SuperSocket, IterSocket
+
+diff --git a/scapy/tools/UTscapy.py b/scapy/tools/UTscapy.py
+index 18e01659..a045bd49 100644
+--- a/scapy/tools/UTscapy.py
++++ b/scapy/tools/UTscapy.py
+@@ -27,8 +27,8 @@ import warnings
+ import zlib
+
+ from scapy.consts import WINDOWS
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range
++import six
++from six.moves import range
+ from scapy.config import conf
+ from scapy.compat import base64_bytes, bytes_hex, plain_str
+ from scapy.themes import DefaultTheme, BlackAndWhite
+diff --git a/scapy/utils.py b/scapy/utils.py
+index 12747fa6..09002915 100644
+--- a/scapy/utils.py
++++ b/scapy/utils.py
+@@ -28,8 +28,8 @@ import time
+ import threading
+ import warnings
+
+-import scapy.modules.six as six
+-from scapy.modules.six.moves import range, input, zip_longest
++import six
++from six.moves import range, input, zip_longest
+
+ from scapy.config import conf
+ from scapy.consts import DARWIN, OPENBSD, WINDOWS
+diff --git a/scapy/volatile.py b/scapy/volatile.py
+index 5587c7ce..f7e1b326 100644
+--- a/scapy/volatile.py
++++ b/scapy/volatile.py
+@@ -21,7 +21,7 @@ import struct
+ from scapy.base_classes import Net
+ from scapy.compat import bytes_encode, chb, plain_str
+ from scapy.utils import corrupt_bits, corrupt_bytes
+-from scapy.modules.six.moves import range
++from six.moves import range
+
+ ####################
+ # Random numbers #
diff --git a/test/requirements-3.txt b/test/requirements-3.txt
index 101f9d880c7..2284a67e5a9 100644
--- a/test/requirements-3.txt
+++ b/test/requirements-3.txt
@@ -14,41 +14,41 @@ attrs==23.2.0 \
# via
# jsonschema
# referencing
-babel==2.14.0 \
- --hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
- --hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
+babel==2.15.0 \
+ --hash=sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb \
+ --hash=sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413
# via sphinx
-black==24.3.0 \
- --hash=sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f \
- --hash=sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93 \
- --hash=sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11 \
- --hash=sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0 \
- --hash=sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9 \
- --hash=sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5 \
- --hash=sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213 \
- --hash=sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d \
- --hash=sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7 \
- --hash=sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837 \
- --hash=sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f \
- --hash=sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395 \
- --hash=sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995 \
- --hash=sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f \
- --hash=sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597 \
- --hash=sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959 \
- --hash=sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5 \
- --hash=sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb \
- --hash=sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4 \
- --hash=sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7 \
- --hash=sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd \
- --hash=sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7
+black==24.4.2 \
+ --hash=sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474 \
+ --hash=sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1 \
+ --hash=sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0 \
+ --hash=sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8 \
+ --hash=sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96 \
+ --hash=sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1 \
+ --hash=sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04 \
+ --hash=sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021 \
+ --hash=sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94 \
+ --hash=sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d \
+ --hash=sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c \
+ --hash=sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7 \
+ --hash=sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c \
+ --hash=sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc \
+ --hash=sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7 \
+ --hash=sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d \
+ --hash=sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c \
+ --hash=sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741 \
+ --hash=sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce \
+ --hash=sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb \
+ --hash=sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063 \
+ --hash=sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e
# via -r requirements.txt
build==1.2.1 \
--hash=sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d \
--hash=sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4
# via pip-tools
-certifi==2024.2.2 \
- --hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
- --hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
+certifi==2024.7.4 \
+ --hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
+ --hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
# via requests
cffi==1.16.0 \
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
@@ -206,39 +206,34 @@ commonmark==0.9.1 \
--hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \
--hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9
# via recommonmark
-cryptography==42.0.5 \
- --hash=sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee \
- --hash=sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576 \
- --hash=sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d \
- --hash=sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30 \
- --hash=sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413 \
- --hash=sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb \
- --hash=sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da \
- --hash=sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4 \
- --hash=sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd \
- --hash=sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc \
- --hash=sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8 \
- --hash=sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1 \
- --hash=sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc \
- --hash=sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e \
- --hash=sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8 \
- --hash=sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940 \
- --hash=sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400 \
- --hash=sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7 \
- --hash=sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16 \
- --hash=sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278 \
- --hash=sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74 \
- --hash=sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec \
- --hash=sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1 \
- --hash=sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2 \
- --hash=sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c \
- --hash=sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922 \
- --hash=sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a \
- --hash=sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6 \
- --hash=sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1 \
- --hash=sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e \
- --hash=sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac \
- --hash=sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7
+cryptography==43.0.0 \
+ --hash=sha256:0663585d02f76929792470451a5ba64424acc3cd5227b03921dab0e2f27b1709 \
+ --hash=sha256:08a24a7070b2b6804c1940ff0f910ff728932a9d0e80e7814234269f9d46d069 \
+ --hash=sha256:232ce02943a579095a339ac4b390fbbe97f5b5d5d107f8a08260ea2768be8cc2 \
+ --hash=sha256:2905ccf93a8a2a416f3ec01b1a7911c3fe4073ef35640e7ee5296754e30b762b \
+ --hash=sha256:299d3da8e00b7e2b54bb02ef58d73cd5f55fb31f33ebbf33bd00d9aa6807df7e \
+ --hash=sha256:2c6d112bf61c5ef44042c253e4859b3cbbb50df2f78fa8fae6747a7814484a70 \
+ --hash=sha256:31e44a986ceccec3d0498e16f3d27b2ee5fdf69ce2ab89b52eaad1d2f33d8778 \
+ --hash=sha256:3d9a1eca329405219b605fac09ecfc09ac09e595d6def650a437523fcd08dd22 \
+ --hash=sha256:3dcdedae5c7710b9f97ac6bba7e1052b95c7083c9d0e9df96e02a1932e777895 \
+ --hash=sha256:47ca71115e545954e6c1d207dd13461ab81f4eccfcb1345eac874828b5e3eaaf \
+ --hash=sha256:4a997df8c1c2aae1e1e5ac49c2e4f610ad037fc5a3aadc7b64e39dea42249431 \
+ --hash=sha256:51956cf8730665e2bdf8ddb8da0056f699c1a5715648c1b0144670c1ba00b48f \
+ --hash=sha256:5bcb8a5620008a8034d39bce21dc3e23735dfdb6a33a06974739bfa04f853947 \
+ --hash=sha256:64c3f16e2a4fc51c0d06af28441881f98c5d91009b8caaff40cf3548089e9c74 \
+ --hash=sha256:6e2b11c55d260d03a8cf29ac9b5e0608d35f08077d8c087be96287f43af3ccdc \
+ --hash=sha256:7b3f5fe74a5ca32d4d0f302ffe6680fcc5c28f8ef0dc0ae8f40c0f3a1b4fca66 \
+ --hash=sha256:844b6d608374e7d08f4f6e6f9f7b951f9256db41421917dfb2d003dde4cd6b66 \
+ --hash=sha256:9a8d6802e0825767476f62aafed40532bd435e8a5f7d23bd8b4f5fd04cc80ecf \
+ --hash=sha256:aae4d918f6b180a8ab8bf6511a419473d107df4dbb4225c7b48c5c9602c38c7f \
+ --hash=sha256:ac1955ce000cb29ab40def14fd1bbfa7af2017cca696ee696925615cafd0dce5 \
+ --hash=sha256:b88075ada2d51aa9f18283532c9f60e72170041bba88d7f37e49cbb10275299e \
+ --hash=sha256:cb013933d4c127349b3948aa8aaf2f12c0353ad0eccd715ca789c8a0f671646f \
+ --hash=sha256:cc70b4b581f28d0a254d006f26949245e3657d40d8857066c2ae22a61222ef55 \
+ --hash=sha256:e9c5266c432a1e23738d178e51c2c7a5e2ddf790f248be939448c0ba2021f9d1 \
+ --hash=sha256:ea9e57f8ea880eeea38ab5abf9fbe39f923544d7884228ec67d666abd60f5a47 \
+ --hash=sha256:ee0c405832ade84d4de74b9029bedb7b31200600fa524d218fc29bfa371e97f5 \
+ --hash=sha256:fdcb265de28585de5b859ae13e3846a8e805268a823a12a4da2597f1f5afc9f0
# via
# -r requirements.txt
# noiseprotocol
@@ -253,17 +248,17 @@ docutils==0.20.1 \
# recommonmark
# sphinx
# sphinx-rtd-theme
-idna==3.6 \
- --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
- --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+idna==3.7 \
+ --hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
+ --hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
# via requests
imagesize==1.4.1 \
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
# via sphinx
-importlib-metadata==7.1.0 \
- --hash=sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570 \
- --hash=sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2
+importlib-metadata==8.2.0 \
+ --hash=sha256:11901fa0c2f97919b288679932bb64febaeacf289d18ac84dd68cb2e74213369 \
+ --hash=sha256:72e8d4399996132204f9a16dcc751af254a48f8d1b20b9ff0f98d4a8f901e73d
# via
# build
# sphinx
@@ -273,13 +268,13 @@ importlib-resources==6.4.0 \
# via
# jsonschema
# jsonschema-specifications
-jinja2==3.1.3 \
- --hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
- --hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
+jinja2==3.1.4 \
+ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
+ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
# via sphinx
-jsonschema==4.21.1 ; python_version >= "3.7" \
- --hash=sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f \
- --hash=sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5
+jsonschema==4.23.0 ; python_version >= "3.7" \
+ --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \
+ --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566
# via -r requirements.txt
jsonschema-specifications==2023.12.1 \
--hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \
@@ -362,9 +357,9 @@ objgraph==3.6.1 \
--hash=sha256:21c6bc62df0e7b77cc0a31d96feec04c965f09ec2e3d78b816b516a604f0defd \
--hash=sha256:fe96c74147bbcaae8665b396e5388bdcc3197deebba4e6381f05202ee5b453a7
# via -r requirements.txt
-packaging==24.0 \
- --hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
- --hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
+packaging==24.1 \
+ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
# via
# black
# build
@@ -382,35 +377,36 @@ pexpect==4.9.0 \
--hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
--hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
# via -r requirements.txt
-pip-tools==7.3.0 \
- --hash=sha256:8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e \
- --hash=sha256:8e9c99127fe024c025b46a0b2d15c7bd47f18f33226cf7330d35493663fc1d1d
+pip-tools==7.4.1 \
+ --hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \
+ --hash=sha256:864826f5073864450e24dbeeb85ce3920cdfb09848a3d69ebf537b521f14bcc9
# via -r requirements.txt
pkgutil-resolve-name==1.3.10 \
--hash=sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174 \
--hash=sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e
# via jsonschema
-platformdirs==4.2.0 \
- --hash=sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068 \
- --hash=sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768
+platformdirs==4.2.2 \
+ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \
+ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3
# via black
-psutil==5.9.8 \
- --hash=sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d \
- --hash=sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73 \
- --hash=sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8 \
- --hash=sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2 \
- --hash=sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e \
- --hash=sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36 \
- --hash=sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7 \
- --hash=sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c \
- --hash=sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee \
- --hash=sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421 \
- --hash=sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf \
- --hash=sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81 \
- --hash=sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0 \
- --hash=sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631 \
- --hash=sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4 \
- --hash=sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8
+psutil==6.0.0 \
+ --hash=sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35 \
+ --hash=sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0 \
+ --hash=sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c \
+ --hash=sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1 \
+ --hash=sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3 \
+ --hash=sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c \
+ --hash=sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd \
+ --hash=sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3 \
+ --hash=sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0 \
+ --hash=sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2 \
+ --hash=sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6 \
+ --hash=sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d \
+ --hash=sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c \
+ --hash=sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0 \
+ --hash=sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132 \
+ --hash=sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14 \
+ --hash=sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0
# via -r requirements.txt
ptyprocess==0.7.0 \
--hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
@@ -460,22 +456,24 @@ pyenchant==3.2.2 \
--hash=sha256:5facc821ece957208a81423af7d6ec7810dad29697cb0d77aae81e4e11c8e5a6 \
--hash=sha256:6153f521852e23a5add923dbacfbf4bebbb8d70c4e4bad609a8e0f9faeb915d1
# via sphinxcontrib-spelling
-pygments==2.17.2 \
- --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
- --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
+pygments==2.18.0 \
+ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
+ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
# via sphinx
-pympler==1.0.1 \
- --hash=sha256:993f1a3599ca3f4fcd7160c7545ad06310c9e12f70174ae7ae8d4e25f6c5d3fa \
- --hash=sha256:d260dda9ae781e1eab6ea15bacb84015849833ba5555f141d2d9b7b7473b307d
+pympler==1.1 \
+ --hash=sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424 \
+ --hash=sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506
# via -r requirements.txt
pyparsing==3.1.2 \
--hash=sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad \
--hash=sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742
# via -r requirements.txt
-pyproject-hooks==1.0.0 \
- --hash=sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8 \
- --hash=sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5
- # via build
+pyproject-hooks==1.1.0 \
+ --hash=sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965 \
+ --hash=sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2
+ # via
+ # build
+ # pip-tools
pytz==2024.1 \
--hash=sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812 \
--hash=sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319
@@ -537,125 +535,129 @@ recommonmark==0.7.1 \
--hash=sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f \
--hash=sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67
# via -r requirements.txt
-referencing==0.34.0 \
- --hash=sha256:5773bd84ef41799a5a8ca72dc34590c041eb01bf9aa02632b4a973fb0181a844 \
- --hash=sha256:d53ae300ceddd3169f1ffa9caf2cb7b769e92657e4fafb23d34b93679116dfd4
+referencing==0.35.1 \
+ --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \
+ --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de
# via
# jsonschema
# jsonschema-specifications
-requests==2.31.0 \
- --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
- --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+requests==2.32.3 \
+ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
+ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
# via sphinx
-rpds-py==0.18.0 \
- --hash=sha256:01e36a39af54a30f28b73096dd39b6802eddd04c90dbe161c1b8dbe22353189f \
- --hash=sha256:044a3e61a7c2dafacae99d1e722cc2d4c05280790ec5a05031b3876809d89a5c \
- --hash=sha256:08231ac30a842bd04daabc4d71fddd7e6d26189406d5a69535638e4dcb88fe76 \
- --hash=sha256:08f9ad53c3f31dfb4baa00da22f1e862900f45908383c062c27628754af2e88e \
- --hash=sha256:0ab39c1ba9023914297dd88ec3b3b3c3f33671baeb6acf82ad7ce883f6e8e157 \
- --hash=sha256:0af039631b6de0397ab2ba16eaf2872e9f8fca391b44d3d8cac317860a700a3f \
- --hash=sha256:0b8612cd233543a3781bc659c731b9d607de65890085098986dfd573fc2befe5 \
- --hash=sha256:11a8c85ef4a07a7638180bf04fe189d12757c696eb41f310d2426895356dcf05 \
- --hash=sha256:1374f4129f9bcca53a1bba0bb86bf78325a0374577cf7e9e4cd046b1e6f20e24 \
- --hash=sha256:1d4acf42190d449d5e89654d5c1ed3a4f17925eec71f05e2a41414689cda02d1 \
- --hash=sha256:1d9a5be316c15ffb2b3c405c4ff14448c36b4435be062a7f578ccd8b01f0c4d8 \
- --hash=sha256:1df3659d26f539ac74fb3b0c481cdf9d725386e3552c6fa2974f4d33d78e544b \
- --hash=sha256:22806714311a69fd0af9b35b7be97c18a0fc2826e6827dbb3a8c94eac6cf7eeb \
- --hash=sha256:2644e47de560eb7bd55c20fc59f6daa04682655c58d08185a9b95c1970fa1e07 \
- --hash=sha256:2e6d75ab12b0bbab7215e5d40f1e5b738aa539598db27ef83b2ec46747df90e1 \
- --hash=sha256:30f43887bbae0d49113cbaab729a112251a940e9b274536613097ab8b4899cf6 \
- --hash=sha256:34b18ba135c687f4dac449aa5157d36e2cbb7c03cbea4ddbd88604e076aa836e \
- --hash=sha256:36b3ee798c58ace201289024b52788161e1ea133e4ac93fba7d49da5fec0ef9e \
- --hash=sha256:39514da80f971362f9267c600b6d459bfbbc549cffc2cef8e47474fddc9b45b1 \
- --hash=sha256:39f5441553f1c2aed4de4377178ad8ff8f9d733723d6c66d983d75341de265ab \
- --hash=sha256:3a96e0c6a41dcdba3a0a581bbf6c44bb863f27c541547fb4b9711fd8cf0ffad4 \
- --hash=sha256:3f26b5bd1079acdb0c7a5645e350fe54d16b17bfc5e71f371c449383d3342e17 \
- --hash=sha256:41ef53e7c58aa4ef281da975f62c258950f54b76ec8e45941e93a3d1d8580594 \
- --hash=sha256:42821446ee7a76f5d9f71f9e33a4fb2ffd724bb3e7f93386150b61a43115788d \
- --hash=sha256:43fbac5f22e25bee1d482c97474f930a353542855f05c1161fd804c9dc74a09d \
- --hash=sha256:4457a94da0d5c53dc4b3e4de1158bdab077db23c53232f37a3cb7afdb053a4e3 \
- --hash=sha256:465a3eb5659338cf2a9243e50ad9b2296fa15061736d6e26240e713522b6235c \
- --hash=sha256:482103aed1dfe2f3b71a58eff35ba105289b8d862551ea576bd15479aba01f66 \
- --hash=sha256:4832d7d380477521a8c1644bbab6588dfedea5e30a7d967b5fb75977c45fd77f \
- --hash=sha256:4901165d170a5fde6f589acb90a6b33629ad1ec976d4529e769c6f3d885e3e80 \
- --hash=sha256:5307def11a35f5ae4581a0b658b0af8178c65c530e94893345bebf41cc139d33 \
- --hash=sha256:5417558f6887e9b6b65b4527232553c139b57ec42c64570569b155262ac0754f \
- --hash=sha256:56a737287efecafc16f6d067c2ea0117abadcd078d58721f967952db329a3e5c \
- --hash=sha256:586f8204935b9ec884500498ccc91aa869fc652c40c093bd9e1471fbcc25c022 \
- --hash=sha256:5b4e7d8d6c9b2e8ee2d55c90b59c707ca59bc30058269b3db7b1f8df5763557e \
- --hash=sha256:5ddcba87675b6d509139d1b521e0c8250e967e63b5909a7e8f8944d0f90ff36f \
- --hash=sha256:618a3d6cae6ef8ec88bb76dd80b83cfe415ad4f1d942ca2a903bf6b6ff97a2da \
- --hash=sha256:635dc434ff724b178cb192c70016cc0ad25a275228f749ee0daf0eddbc8183b1 \
- --hash=sha256:661d25cbffaf8cc42e971dd570d87cb29a665f49f4abe1f9e76be9a5182c4688 \
- --hash=sha256:66e6a3af5a75363d2c9a48b07cb27c4ea542938b1a2e93b15a503cdfa8490795 \
- --hash=sha256:67071a6171e92b6da534b8ae326505f7c18022c6f19072a81dcf40db2638767c \
- --hash=sha256:685537e07897f173abcf67258bee3c05c374fa6fff89d4c7e42fb391b0605e98 \
- --hash=sha256:69e64831e22a6b377772e7fb337533c365085b31619005802a79242fee620bc1 \
- --hash=sha256:6b0817e34942b2ca527b0e9298373e7cc75f429e8da2055607f4931fded23e20 \
- --hash=sha256:6c81e5f372cd0dc5dc4809553d34f832f60a46034a5f187756d9b90586c2c307 \
- --hash=sha256:6d7faa6f14017c0b1e69f5e2c357b998731ea75a442ab3841c0dbbbfe902d2c4 \
- --hash=sha256:6ef0befbb5d79cf32d0266f5cff01545602344eda89480e1dd88aca964260b18 \
- --hash=sha256:6ef687afab047554a2d366e112dd187b62d261d49eb79b77e386f94644363294 \
- --hash=sha256:7223a2a5fe0d217e60a60cdae28d6949140dde9c3bcc714063c5b463065e3d66 \
- --hash=sha256:77f195baa60a54ef9d2de16fbbfd3ff8b04edc0c0140a761b56c267ac11aa467 \
- --hash=sha256:793968759cd0d96cac1e367afd70c235867831983f876a53389ad869b043c948 \
- --hash=sha256:7bd339195d84439cbe5771546fe8a4e8a7a045417d8f9de9a368c434e42a721e \
- --hash=sha256:7cd863afe7336c62ec78d7d1349a2f34c007a3cc6c2369d667c65aeec412a5b1 \
- --hash=sha256:7f2facbd386dd60cbbf1a794181e6aa0bd429bd78bfdf775436020172e2a23f0 \
- --hash=sha256:84ffab12db93b5f6bad84c712c92060a2d321b35c3c9960b43d08d0f639d60d7 \
- --hash=sha256:8c8370641f1a7f0e0669ddccca22f1da893cef7628396431eb445d46d893e5cd \
- --hash=sha256:8db715ebe3bb7d86d77ac1826f7d67ec11a70dbd2376b7cc214199360517b641 \
- --hash=sha256:8e8916ae4c720529e18afa0b879473049e95949bf97042e938530e072fde061d \
- --hash=sha256:8f03bccbd8586e9dd37219bce4d4e0d3ab492e6b3b533e973fa08a112cb2ffc9 \
- --hash=sha256:8f2fc11e8fe034ee3c34d316d0ad8808f45bc3b9ce5857ff29d513f3ff2923a1 \
- --hash=sha256:923d39efa3cfb7279a0327e337a7958bff00cc447fd07a25cddb0a1cc9a6d2da \
- --hash=sha256:93df1de2f7f7239dc9cc5a4a12408ee1598725036bd2dedadc14d94525192fc3 \
- --hash=sha256:998e33ad22dc7ec7e030b3df701c43630b5bc0d8fbc2267653577e3fec279afa \
- --hash=sha256:99f70b740dc04d09e6b2699b675874367885217a2e9f782bdf5395632ac663b7 \
- --hash=sha256:9a00312dea9310d4cb7dbd7787e722d2e86a95c2db92fbd7d0155f97127bcb40 \
- --hash=sha256:9d54553c1136b50fd12cc17e5b11ad07374c316df307e4cfd6441bea5fb68496 \
- --hash=sha256:9dbbeb27f4e70bfd9eec1be5477517365afe05a9b2c441a0b21929ee61048124 \
- --hash=sha256:a1ce3ba137ed54f83e56fb983a5859a27d43a40188ba798993812fed73c70836 \
- --hash=sha256:a34d557a42aa28bd5c48a023c570219ba2593bcbbb8dc1b98d8cf5d529ab1434 \
- --hash=sha256:a5f446dd5055667aabaee78487f2b5ab72e244f9bc0b2ffebfeec79051679984 \
- --hash=sha256:ad36cfb355e24f1bd37cac88c112cd7730873f20fb0bdaf8ba59eedf8216079f \
- --hash=sha256:aec493917dd45e3c69d00a8874e7cbed844efd935595ef78a0f25f14312e33c6 \
- --hash=sha256:b316144e85316da2723f9d8dc75bada12fa58489a527091fa1d5a612643d1a0e \
- --hash=sha256:b34ae4636dfc4e76a438ab826a0d1eed2589ca7d9a1b2d5bb546978ac6485461 \
- --hash=sha256:b34b7aa8b261c1dbf7720b5d6f01f38243e9b9daf7e6b8bc1fd4657000062f2c \
- --hash=sha256:bc362ee4e314870a70f4ae88772d72d877246537d9f8cb8f7eacf10884862432 \
- --hash=sha256:bed88b9a458e354014d662d47e7a5baafd7ff81c780fd91584a10d6ec842cb73 \
- --hash=sha256:c0013fe6b46aa496a6749c77e00a3eb07952832ad6166bd481c74bda0dcb6d58 \
- --hash=sha256:c0b5dcf9193625afd8ecc92312d6ed78781c46ecbf39af9ad4681fc9f464af88 \
- --hash=sha256:c4325ff0442a12113a6379af66978c3fe562f846763287ef66bdc1d57925d337 \
- --hash=sha256:c463ed05f9dfb9baebef68048aed8dcdc94411e4bf3d33a39ba97e271624f8f7 \
- --hash=sha256:c8362467a0fdeccd47935f22c256bec5e6abe543bf0d66e3d3d57a8fb5731863 \
- --hash=sha256:cd5bf1af8efe569654bbef5a3e0a56eca45f87cfcffab31dd8dde70da5982475 \
- --hash=sha256:cf1ea2e34868f6fbf070e1af291c8180480310173de0b0c43fc38a02929fc0e3 \
- --hash=sha256:d62dec4976954a23d7f91f2f4530852b0c7608116c257833922a896101336c51 \
- --hash=sha256:d68c93e381010662ab873fea609bf6c0f428b6d0bb00f2c6939782e0818d37bf \
- --hash=sha256:d7c36232a90d4755b720fbd76739d8891732b18cf240a9c645d75f00639a9024 \
- --hash=sha256:dd18772815d5f008fa03d2b9a681ae38d5ae9f0e599f7dda233c439fcaa00d40 \
- --hash=sha256:ddc2f4dfd396c7bfa18e6ce371cba60e4cf9d2e5cdb71376aa2da264605b60b9 \
- --hash=sha256:e003b002ec72c8d5a3e3da2989c7d6065b47d9eaa70cd8808b5384fbb970f4ec \
- --hash=sha256:e32a92116d4f2a80b629778280103d2a510a5b3f6314ceccd6e38006b5e92dcb \
- --hash=sha256:e4461d0f003a0aa9be2bdd1b798a041f177189c1a0f7619fe8c95ad08d9a45d7 \
- --hash=sha256:e541ec6f2ec456934fd279a3120f856cd0aedd209fc3852eca563f81738f6861 \
- --hash=sha256:e546e768d08ad55b20b11dbb78a745151acbd938f8f00d0cfbabe8b0199b9880 \
- --hash=sha256:ea7d4a99f3b38c37eac212dbd6ec42b7a5ec51e2c74b5d3223e43c811609e65f \
- --hash=sha256:ed4eb745efbff0a8e9587d22a84be94a5eb7d2d99c02dacf7bd0911713ed14dd \
- --hash=sha256:f8a2f084546cc59ea99fda8e070be2fd140c3092dc11524a71aa8f0f3d5a55ca \
- --hash=sha256:fcb25daa9219b4cf3a0ab24b0eb9a5cc8949ed4dc72acb8fa16b7e1681aa3c58 \
- --hash=sha256:fdea4952db2793c4ad0bdccd27c1d8fdd1423a92f04598bc39425bcc2b8ee46e
+rpds-py==0.19.1 \
+ --hash=sha256:01227f8b3e6c8961490d869aa65c99653df80d2f0a7fde8c64ebddab2b9b02fd \
+ --hash=sha256:08ce9c95a0b093b7aec75676b356a27879901488abc27e9d029273d280438505 \
+ --hash=sha256:0b02dd77a2de6e49078c8937aadabe933ceac04b41c5dde5eca13a69f3cf144e \
+ --hash=sha256:0d4b52811dcbc1aba08fd88d475f75b4f6db0984ba12275d9bed1a04b2cae9b5 \
+ --hash=sha256:13e6d4840897d4e4e6b2aa1443e3a8eca92b0402182aafc5f4ca1f5e24f9270a \
+ --hash=sha256:1a129c02b42d46758c87faeea21a9f574e1c858b9f358b6dd0bbd71d17713175 \
+ --hash=sha256:1a8dfa125b60ec00c7c9baef945bb04abf8ac772d8ebefd79dae2a5f316d7850 \
+ --hash=sha256:1c32e41de995f39b6b315d66c27dea3ef7f7c937c06caab4c6a79a5e09e2c415 \
+ --hash=sha256:1d494887d40dc4dd0d5a71e9d07324e5c09c4383d93942d391727e7a40ff810b \
+ --hash=sha256:1d4af2eb520d759f48f1073ad3caef997d1bfd910dc34e41261a595d3f038a94 \
+ --hash=sha256:1fb93d3486f793d54a094e2bfd9cd97031f63fcb5bc18faeb3dd4b49a1c06523 \
+ --hash=sha256:24f8ae92c7fae7c28d0fae9b52829235df83f34847aa8160a47eb229d9666c7b \
+ --hash=sha256:24fc5a84777cb61692d17988989690d6f34f7f95968ac81398d67c0d0994a897 \
+ --hash=sha256:26ab43b6d65d25b1a333c8d1b1c2f8399385ff683a35ab5e274ba7b8bb7dc61c \
+ --hash=sha256:271accf41b02687cef26367c775ab220372ee0f4925591c6796e7c148c50cab5 \
+ --hash=sha256:2ddd50f18ebc05ec29a0d9271e9dbe93997536da3546677f8ca00b76d477680c \
+ --hash=sha256:31dd5794837f00b46f4096aa8ccaa5972f73a938982e32ed817bb520c465e520 \
+ --hash=sha256:31e450840f2f27699d014cfc8865cc747184286b26d945bcea6042bb6aa4d26e \
+ --hash=sha256:32e0db3d6e4f45601b58e4ac75c6f24afbf99818c647cc2066f3e4b192dabb1f \
+ --hash=sha256:346557f5b1d8fd9966059b7a748fd79ac59f5752cd0e9498d6a40e3ac1c1875f \
+ --hash=sha256:34bca66e2e3eabc8a19e9afe0d3e77789733c702c7c43cd008e953d5d1463fde \
+ --hash=sha256:3511f6baf8438326e351097cecd137eb45c5f019944fe0fd0ae2fea2fd26be39 \
+ --hash=sha256:35af5e4d5448fa179fd7fff0bba0fba51f876cd55212f96c8bbcecc5c684ae5c \
+ --hash=sha256:3837c63dd6918a24de6c526277910e3766d8c2b1627c500b155f3eecad8fad65 \
+ --hash=sha256:39d67896f7235b2c886fb1ee77b1491b77049dcef6fbf0f401e7b4cbed86bbd4 \
+ --hash=sha256:3b823be829407393d84ee56dc849dbe3b31b6a326f388e171555b262e8456cc1 \
+ --hash=sha256:3c73254c256081704dba0a333457e2fb815364018788f9b501efe7c5e0ada401 \
+ --hash=sha256:3ddab996807c6b4227967fe1587febade4e48ac47bb0e2d3e7858bc621b1cace \
+ --hash=sha256:3e1dc59a5e7bc7f44bd0c048681f5e05356e479c50be4f2c1a7089103f1621d5 \
+ --hash=sha256:4383beb4a29935b8fa28aca8fa84c956bf545cb0c46307b091b8d312a9150e6a \
+ --hash=sha256:4cc4bc73e53af8e7a42c8fd7923bbe35babacfa7394ae9240b3430b5dcf16b2a \
+ --hash=sha256:4dd02e29c8cbed21a1875330b07246b71121a1c08e29f0ee3db5b4cfe16980c4 \
+ --hash=sha256:4f580ae79d0b861dfd912494ab9d477bea535bfb4756a2269130b6607a21802e \
+ --hash=sha256:53dbc35808c6faa2ce3e48571f8f74ef70802218554884787b86a30947842a14 \
+ --hash=sha256:56313be667a837ff1ea3508cebb1ef6681d418fa2913a0635386cf29cff35165 \
+ --hash=sha256:57863d16187995c10fe9cf911b897ed443ac68189179541734502353af33e693 \
+ --hash=sha256:5953391af1405f968eb5701ebbb577ebc5ced8d0041406f9052638bafe52209d \
+ --hash=sha256:5beffdbe766cfe4fb04f30644d822a1080b5359df7db3a63d30fa928375b2720 \
+ --hash=sha256:5e360188b72f8080fefa3adfdcf3618604cc8173651c9754f189fece068d2a45 \
+ --hash=sha256:5e58b61dcbb483a442c6239c3836696b79f2cd8e7eec11e12155d3f6f2d886d1 \
+ --hash=sha256:69084fd29bfeff14816666c93a466e85414fe6b7d236cfc108a9c11afa6f7301 \
+ --hash=sha256:6d1d7539043b2b31307f2c6c72957a97c839a88b2629a348ebabe5aa8b626d6b \
+ --hash=sha256:6d8b735c4d162dc7d86a9cf3d717f14b6c73637a1f9cd57fe7e61002d9cb1972 \
+ --hash=sha256:6ea961a674172ed2235d990d7edf85d15d8dfa23ab8575e48306371c070cda67 \
+ --hash=sha256:71157f9db7f6bc6599a852852f3389343bea34315b4e6f109e5cbc97c1fb2963 \
+ --hash=sha256:720f3108fb1bfa32e51db58b832898372eb5891e8472a8093008010911e324c5 \
+ --hash=sha256:74129d5ffc4cde992d89d345f7f7d6758320e5d44a369d74d83493429dad2de5 \
+ --hash=sha256:747251e428406b05fc86fee3904ee19550c4d2d19258cef274e2151f31ae9d38 \
+ --hash=sha256:75130df05aae7a7ac171b3b5b24714cffeabd054ad2ebc18870b3aa4526eba23 \
+ --hash=sha256:7b3661e6d4ba63a094138032c1356d557de5b3ea6fd3cca62a195f623e381c76 \
+ --hash=sha256:7d5c7e32f3ee42f77d8ff1a10384b5cdcc2d37035e2e3320ded909aa192d32c3 \
+ --hash=sha256:8124101e92c56827bebef084ff106e8ea11c743256149a95b9fd860d3a4f331f \
+ --hash=sha256:81db2e7282cc0487f500d4db203edc57da81acde9e35f061d69ed983228ffe3b \
+ --hash=sha256:840e18c38098221ea6201f091fc5d4de6128961d2930fbbc96806fb43f69aec1 \
+ --hash=sha256:89cc8921a4a5028d6dd388c399fcd2eef232e7040345af3d5b16c04b91cf3c7e \
+ --hash=sha256:8b32cd4ab6db50c875001ba4f5a6b30c0f42151aa1fbf9c2e7e3674893fb1dc4 \
+ --hash=sha256:8df1c283e57c9cb4d271fdc1875f4a58a143a2d1698eb0d6b7c0d7d5f49c53a1 \
+ --hash=sha256:902cf4739458852fe917104365ec0efbea7d29a15e4276c96a8d33e6ed8ec137 \
+ --hash=sha256:97fbb77eaeb97591efdc654b8b5f3ccc066406ccfb3175b41382f221ecc216e8 \
+ --hash=sha256:9c7042488165f7251dc7894cd533a875d2875af6d3b0e09eda9c4b334627ad1c \
+ --hash=sha256:9e318e6786b1e750a62f90c6f7fa8b542102bdcf97c7c4de2a48b50b61bd36ec \
+ --hash=sha256:a9421b23c85f361a133aa7c5e8ec757668f70343f4ed8fdb5a4a14abd5437244 \
+ --hash=sha256:aaf71f95b21f9dc708123335df22e5a2fef6307e3e6f9ed773b2e0938cc4d491 \
+ --hash=sha256:afedc35fe4b9e30ab240b208bb9dc8938cb4afe9187589e8d8d085e1aacb8309 \
+ --hash=sha256:b5e28e56143750808c1c79c70a16519e9bc0a68b623197b96292b21b62d6055c \
+ --hash=sha256:b82c9514c6d74b89a370c4060bdb80d2299bc6857e462e4a215b4ef7aa7b090e \
+ --hash=sha256:b8f78398e67a7227aefa95f876481485403eb974b29e9dc38b307bb6eb2315ea \
+ --hash=sha256:bbda75f245caecff8faa7e32ee94dfaa8312a3367397975527f29654cd17a6ed \
+ --hash=sha256:bca34e913d27401bda2a6f390d0614049f5a95b3b11cd8eff80fe4ec340a1208 \
+ --hash=sha256:bd04d8cab16cab5b0a9ffc7d10f0779cf1120ab16c3925404428f74a0a43205a \
+ --hash=sha256:c149a652aeac4902ecff2dd93c3b2681c608bd5208c793c4a99404b3e1afc87c \
+ --hash=sha256:c2087dbb76a87ec2c619253e021e4fb20d1a72580feeaa6892b0b3d955175a71 \
+ --hash=sha256:c34f751bf67cab69638564eee34023909380ba3e0d8ee7f6fe473079bf93f09b \
+ --hash=sha256:c6d20c8896c00775e6f62d8373aba32956aa0b850d02b5ec493f486c88e12859 \
+ --hash=sha256:c7af6f7b80f687b33a4cdb0a785a5d4de1fb027a44c9a049d8eb67d5bfe8a687 \
+ --hash=sha256:c7b07959866a6afb019abb9564d8a55046feb7a84506c74a6f197cbcdf8a208e \
+ --hash=sha256:ca0dda0c5715efe2ab35bb83f813f681ebcd2840d8b1b92bfc6fe3ab382fae4a \
+ --hash=sha256:cdb7eb3cf3deb3dd9e7b8749323b5d970052711f9e1e9f36364163627f96da58 \
+ --hash=sha256:ce757c7c90d35719b38fa3d4ca55654a76a40716ee299b0865f2de21c146801c \
+ --hash=sha256:d1fa67ef839bad3815124f5f57e48cd50ff392f4911a9f3cf449d66fa3df62a5 \
+ --hash=sha256:d2dbd8f4990d4788cb122f63bf000357533f34860d269c1a8e90ae362090ff3a \
+ --hash=sha256:d4ec0046facab83012d821b33cead742a35b54575c4edfb7ed7445f63441835f \
+ --hash=sha256:dbceedcf4a9329cc665452db1aaf0845b85c666e4885b92ee0cddb1dbf7e052a \
+ --hash=sha256:dc733d35f861f8d78abfaf54035461e10423422999b360966bf1c443cbc42705 \
+ --hash=sha256:dd635c2c4043222d80d80ca1ac4530a633102a9f2ad12252183bcf338c1b9474 \
+ --hash=sha256:de1f7cd5b6b351e1afd7568bdab94934d656abe273d66cda0ceea43bbc02a0c2 \
+ --hash=sha256:df7c841813f6265e636fe548a49664c77af31ddfa0085515326342a751a6ba51 \
+ --hash=sha256:e0f9d268b19e8f61bf42a1da48276bcd05f7ab5560311f541d22557f8227b866 \
+ --hash=sha256:e2d66eb41ffca6cc3c91d8387509d27ba73ad28371ef90255c50cb51f8953301 \
+ --hash=sha256:e429fc517a1c5e2a70d576077231538a98d59a45dfc552d1ac45a132844e6dfb \
+ --hash=sha256:e4d2b88efe65544a7d5121b0c3b003ebba92bfede2ea3577ce548b69c5235185 \
+ --hash=sha256:e76c902d229a3aa9d5ceb813e1cbcc69bf5bda44c80d574ff1ac1fa3136dea71 \
+ --hash=sha256:ef07a0a1d254eeb16455d839cef6e8c2ed127f47f014bbda64a58b5482b6c836 \
+ --hash=sha256:f09529d2332264a902688031a83c19de8fda5eb5881e44233286b9c9ec91856d \
+ --hash=sha256:f0a6d4a93d2a05daec7cb885157c97bbb0be4da739d6f9dfb02e101eb40921cd \
+ --hash=sha256:f0cf2a0dbb5987da4bd92a7ca727eadb225581dd9681365beba9accbe5308f7d \
+ --hash=sha256:f2671cb47e50a97f419a02cd1e0c339b31de017b033186358db92f4d8e2e17d8 \
+ --hash=sha256:f35b34a5184d5e0cc360b61664c1c06e866aab077b5a7c538a3e20c8fcdbf90b \
+ --hash=sha256:f3d73022990ab0c8b172cce57c69fd9a89c24fd473a5e79cbce92df87e3d9c48 \
+ --hash=sha256:f5b8353ea1a4d7dfb59a7f45c04df66ecfd363bb5b35f33b11ea579111d4655f \
+ --hash=sha256:f809a17cc78bd331e137caa25262b507225854073fd319e987bd216bed911b7c \
+ --hash=sha256:f9bc4161bd3b970cd6a6fcda70583ad4afd10f2750609fb1f3ca9505050d4ef3 \
+ --hash=sha256:fdf4890cda3b59170009d012fca3294c00140e7f2abe1910e6a730809d0f3f9b
# via
# jsonschema
# referencing
-scapy==2.4.3 ; python_version >= "2.7" or python_version >= "3.4" \
- --hash=sha256:e2f8d11f6a941c14a789ae8b236b27bd634681f1b29b5e893861e284d234f6b0
+scapy==2.4.5 ; python_version >= "3.4" \
+ --hash=sha256:bc707e3604784496b6665a9e5b2a69c36cc9fb032af4864b29051531b24c8593
# via -r requirements.txt
-sh==2.0.6 \
- --hash=sha256:9b2998f313f201c777e2c0061f0b1367497097ef13388595be147e2a00bf7ba1 \
- --hash=sha256:ced8f2e081a858b66a46ace3703dec243779abbd5a1887ba7e3c34f34da70cd2
+sh==2.0.7 \
+ --hash=sha256:029d45198902bfb967391eccfd13a88d92f7cebd200411e93f99ebacc6afbb35 \
+ --hash=sha256:2f2f79a65abd00696cf2e9ad26508cf8abb6dba5745f40255f1c0ded2876926d
# via -r requirements.txt
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
@@ -721,22 +723,21 @@ tomli==2.0.1 \
# black
# build
# pip-tools
- # pyproject-hooks
-typing-extensions==4.10.0 \
- --hash=sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475 \
- --hash=sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb
+typing-extensions==4.12.2 \
+ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
+ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
# via black
-urllib3==2.2.1 \
- --hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
- --hash=sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19
+urllib3==2.2.2 \
+ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
+ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
# via requests
wheel==0.43.0 \
--hash=sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85 \
--hash=sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81
# via pip-tools
-zipp==3.18.1 \
- --hash=sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b \
- --hash=sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715
+zipp==3.19.2 \
+ --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \
+ --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c
# via
# importlib-metadata
# importlib-resources
diff --git a/test/requirements.txt b/test/requirements.txt
index c01d31161f7..d1ab9492ae8 100644
--- a/test/requirements.txt
+++ b/test/requirements.txt
@@ -1,4 +1,4 @@
-pip-tools==7.3.0 # BSD Keep this in sync with Makefile's PIP_TOOLS_VERSION
+pip-tools==7.4.1 # BSD Keep this in sync with Makefile's PIP_TOOLS_VERSION
cryptography!=2.0 # BSD/Apache-2.0
deprecation>=2.0.6 # Apache-2.0
faulthandler; python_version < '3.3' # # BSD License (2 clause)
@@ -6,7 +6,7 @@ ipaddress; python_version < '3.3' # PSF
parameterized>=0.6.1 # BSD
pexpect # ISC
psutil # BSD
-scapy==2.4.3; python_version >= '2.7' or python_version >= '3.4' # GPL2 https://github.com/secdev/scapy/blob/master/LICENSE
+scapy==2.4.5; python_version >= '3.4' # GPL2 https://github.com/secdev/scapy/blob/master/LICENSE
six # MIT
syslog_rfc5424_parser>=0.3.1 # ISC
objgraph # MIT
diff --git a/test/template_ipsec.py b/test/template_ipsec.py
index d5ef023cb1b..4e68d44013f 100644
--- a/test/template_ipsec.py
+++ b/test/template_ipsec.py
@@ -1,11 +1,13 @@
import unittest
import socket
import struct
+import re
+import os
from scapy.layers.inet import IP, ICMP, TCP, UDP
from scapy.layers.ipsec import SecurityAssociation, ESP
from scapy.layers.l2 import Ether
-from scapy.packet import raw, Raw
+from scapy.packet import raw, Raw, Padding
from scapy.layers.inet6 import (
IPv6,
ICMPv6EchoRequest,
@@ -22,8 +24,6 @@ from vpp_papi import VppEnum
from vpp_ipsec import VppIpsecSpd, VppIpsecSpdEntry, VppIpsecSpdItfBinding
from ipaddress import ip_address
-from re import search
-from os import popen
from config import config
@@ -1938,7 +1938,7 @@ class IpsecTra6(object):
Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac)
/ IPv6(src=src, dst=dst)
/ IPv6ExtHdrHopByHop()
- / IPv6ExtHdrFragment(id=2, offset=200)
+ / IPv6ExtHdrFragment(id=2, offset=0)
/ Raw(b"\xff" * 200)
for i in range(count)
]
@@ -1985,7 +1985,7 @@ class IpsecTra6(object):
tx = (
Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
/ IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
- / IPv6ExtHdrFragment(id=2, offset=200)
+ / IPv6ExtHdrFragment(id=2, offset=0)
/ Raw(b"\xff" * 200)
)
@@ -2004,7 +2004,7 @@ class IpsecTra6(object):
Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
/ IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
/ IPv6ExtHdrHopByHop()
- / IPv6ExtHdrFragment(id=2, offset=200)
+ / IPv6ExtHdrFragment(id=2, offset=0)
/ Raw(b"\xff" * 200)
)
@@ -2021,7 +2021,7 @@ class IpsecTra6(object):
Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
/ IPv6(src=self.tra_if.local_ip6, dst=self.tra_if.remote_ip6)
/ IPv6ExtHdrHopByHop()
- / IPv6ExtHdrFragment(id=2, offset=200)
+ / IPv6ExtHdrFragment(id=2, offset=0)
/ IPv6ExtHdrDestOpt()
/ Raw(b"\xff" * 200)
)
diff --git a/test/test_dhcp.py b/test/test_dhcp.py
index 64c4654b418..e668b7bd1c0 100644
--- a/test/test_dhcp.py
+++ b/test/test_dhcp.py
@@ -121,7 +121,7 @@ class TestDHCP(VppTestCase):
for i in dhcp.options:
if isinstance(i, tuple):
- if i[0] == "relay_agent_Information":
+ if i[0] == "relay_agent_information":
#
# There are two sb-options present - each of length 6.
#
@@ -532,7 +532,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", option_82),
+ ("relay_agent_information", option_82),
("end"),
]
)
@@ -543,7 +543,7 @@ class TestDHCP(VppTestCase):
self.pg_enable_capture(self.pg_interfaces)
self.pg_start()
- rx = self.pg3.get_capture(1)
+ rx = self.pg3.get_capture(1, timeout=5)
rx = rx[0]
self.verify_dhcp_offer(rx, self.pg3)
@@ -563,7 +563,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", bad_ip),
+ ("relay_agent_information", bad_ip),
("end"),
]
)
@@ -584,7 +584,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", bad_if_index),
+ ("relay_agent_information", bad_if_index),
("end"),
]
)
@@ -748,7 +748,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", option_82),
+ ("relay_agent_information", option_82),
("end"),
]
)
@@ -761,7 +761,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", option_82),
+ ("relay_agent_information", option_82),
("end"),
]
)
@@ -788,7 +788,7 @@ class TestDHCP(VppTestCase):
/ DHCP(
options=[
("message-type", "offer"),
- ("relay_agent_Information", option_82),
+ ("relay_agent_information", option_82),
("end"),
]
)
diff --git a/test/test_dhcp6.py b/test/test_dhcp6.py
index dbb550b1725..1328a62e1d3 100644
--- a/test/test_dhcp6.py
+++ b/test/test_dhcp6.py
@@ -307,7 +307,7 @@ class TestDHCPv6IANAControlPlane(VppTestCase):
return addresses.difference(self.initial_addresses)
def validate_duid_ll(self, duid):
- DUID_LL(duid)
+ DUID_LL(bytes(duid))
def validate_packet(self, packet, msg_type, is_resend=False):
try:
@@ -562,7 +562,7 @@ class TestDHCPv6PDControlPlane(VppTestCase):
return addresses.difference(self.initial_addresses)
def validate_duid_ll(self, duid):
- DUID_LL(duid)
+ DUID_LL(bytes(duid))
def validate_packet(self, packet, msg_type, is_resend=False):
try:
diff --git a/test/test_ikev2.py b/test/test_ikev2.py
index ea425e2e489..4bff829c51b 100644
--- a/test/test_ikev2.py
+++ b/test/test_ikev2.py
@@ -23,10 +23,7 @@ from scapy.utils import long_converter
from framework import VppTestCase
from asfframework import (
tag_fixme_vpp_workers,
- tag_fixme_ubuntu2204,
- tag_fixme_debian11,
- is_distro_ubuntu2204,
- is_distro_debian11,
+ tag_fixme_ubuntu2404,
VppTestRunner,
)
from vpp_ikev2 import Profile, IDType, AuthMethod
@@ -677,7 +674,7 @@ class IkePeer(VppTestCase):
self.assertIsNotNone(self.p.query_vpp_config())
if self.sa.is_initiator:
self.sa.generate_dh_data()
- self.vapi.cli("ikev2 set logging level 4")
+ self.vapi.cli("ikev2 set logging level 5")
self.vapi.cli("event-lo clear")
def assert_counter(self, count, name, version="ip4"):
@@ -1215,7 +1212,7 @@ class TemplateInitiator(IkePeer):
if self.no_idr_auth:
self.assertEqual(idi.next_payload, 39) # AUTH
else:
- idr = ikev2.IKEv2_payload_IDr(idi.payload)
+ idr = ikev2.IKEv2_payload_IDr(bytes(idi.payload))
self.assertEqual(idr.load, self.sa.r_id)
prop = idi[ikev2.IKEv2_payload_Proposal]
c = self.sa.child_sas[0]
@@ -2025,21 +2022,21 @@ class TestApi(VppTestCase):
self.assertEqual(ap.tun_itf, 0xFFFFFFFF)
-@tag_fixme_vpp_workers
class TestResponderBehindNAT(TemplateResponder, Ikev2Params):
"""test responder - responder behind NAT"""
IKE_NODE_SUFFIX = "ip4-natt"
+ vpp_worker_count = 2
def config_tc(self):
self.config_params({"r_natt": True})
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
"""test ikev2 initiator - NAT traversal (intitiator behind NAT)"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2068,11 +2065,11 @@ class TestInitiatorNATT(TemplateInitiator, Ikev2Params):
)
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
"""test ikev2 initiator - pre shared key auth"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2100,11 +2097,11 @@ class TestInitiatorPsk(TemplateInitiator, Ikev2Params):
)
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorRequestWindowSize(TestInitiatorPsk):
"""test initiator - request window size (1)"""
+ vpp_worker_count = 2
+
def rekey_respond(self, req, update_child_sa_data):
ih = self.get_ike_header(req)
plain = self.sa.hmac_and_decrypt(ih)
@@ -2150,11 +2147,11 @@ class TestInitiatorRequestWindowSize(TestInitiatorPsk):
self.verify_ipsec_sas(is_rekey=True)
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorRekey(TestInitiatorPsk):
"""test ikev2 initiator - rekey"""
+ vpp_worker_count = 2
+
def rekey_from_initiator(self):
ispi = int.from_bytes(self.sa.child_sas[0].ispi, "little")
self.pg0.enable_capture()
@@ -2196,11 +2193,11 @@ class TestInitiatorRekey(TestInitiatorPsk):
self.verify_ipsec_sas(is_rekey=True)
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
"""test ikev2 initiator - delete IKE SA from responder"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2230,30 +2227,32 @@ class TestInitiatorDelSAFromResponder(TemplateInitiator, Ikev2Params):
)
-@tag_fixme_vpp_workers
class TestResponderInitBehindNATT(TemplateResponder, Ikev2Params):
"""test ikev2 responder - initiator behind NAT"""
IKE_NODE_SUFFIX = "ip4-natt"
+ vpp_worker_count = 2
def config_tc(self):
self.config_params({"i_natt": True})
-@tag_fixme_vpp_workers
class TestResponderPsk(TemplateResponder, Ikev2Params):
"""test ikev2 responder - pre shared key auth"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params()
-@tag_fixme_vpp_workers
class TestResponderDpd(TestResponderPsk):
"""
Dead peer detection test
"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params({"dpd_disabled": False})
@@ -2281,11 +2280,11 @@ class TestResponderDpd(TestResponderPsk):
self.assertEqual(len(ipsec_sas), 0)
-@tag_fixme_vpp_workers
class TestResponderRekey(TestResponderPsk):
"""test ikev2 responder - rekey"""
WITH_KEX = False
+ vpp_worker_count = 2
def send_rekey_from_initiator(self):
if self.WITH_KEX:
@@ -2323,10 +2322,12 @@ class TestResponderRekey(TestResponderPsk):
self.assertEqual(r[0].sa.stats.n_rekey_req, 1)
-@tag_fixme_vpp_workers
+@tag_fixme_ubuntu2404
class TestResponderRekeyRepeat(TestResponderRekey):
"""test ikev2 responder - rekey repeat"""
+ vpp_worker_count = 2
+
def test_responder(self):
super(TestResponderRekeyRepeat, self).test_responder()
# rekey request is not accepted until old IPsec SA is expired
@@ -2349,24 +2350,26 @@ class TestResponderRekeyRepeat(TestResponderRekey):
self.verify_ipsec_sas(sa_count=3)
-@tag_fixme_vpp_workers
class TestResponderRekeyKEX(TestResponderRekey):
"""test ikev2 responder - rekey with key exchange"""
WITH_KEX = True
+ vpp_worker_count = 2
-@tag_fixme_vpp_workers
+@tag_fixme_ubuntu2404
class TestResponderRekeyRepeatKEX(TestResponderRekeyRepeat):
"""test ikev2 responder - rekey repeat with key exchange"""
WITH_KEX = True
+ vpp_worker_count = 2
-@tag_fixme_vpp_workers
class TestResponderRekeySA(TestResponderPsk):
"""test ikev2 responder - rekey IKE SA"""
+ vpp_worker_count = 2
+
def send_rekey_from_initiator(self, newsa):
packet = self.create_sa_rekey_request(
spi=newsa.ispi,
@@ -2407,8 +2410,6 @@ class TestResponderRekeySA(TestResponderPsk):
self.verify_ike_sas()
-@tag_fixme_ubuntu2204
-@tag_fixme_debian11
class TestResponderVrf(TestResponderPsk, Ikev2Params):
"""test ikev2 responder - non-default table id"""
@@ -2418,8 +2419,7 @@ class TestResponderVrf(TestResponderPsk, Ikev2Params):
globals()["ikev2"] = _ikev2
super(IkePeer, cls).setUpClass()
- if (is_distro_debian11 == True) and not hasattr(cls, "vpp"):
- return
+
cls.create_pg_interfaces(range(1))
cls.vapi.cli("ip table add 1")
cls.vapi.cli("set interface ip table pg0 1")
@@ -2434,7 +2434,7 @@ class TestResponderVrf(TestResponderPsk, Ikev2Params):
self.config_params({"dpd_disabled": False})
def test_responder(self):
- self.vapi.ikev2_profile_set_liveness(period=2, max_retries=1)
+ self.vapi.ikev2_profile_set_liveness(period=2, max_retries=3)
super(TestResponderVrf, self).test_responder()
self.pg0.enable_capture()
self.pg_start()
@@ -2445,10 +2445,11 @@ class TestResponderVrf(TestResponderPsk, Ikev2Params):
self.assertEqual(plain, b"")
-@tag_fixme_vpp_workers
class TestResponderRsaSign(TemplateResponder, Ikev2Params):
"""test ikev2 responder - cert based auth"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2462,7 +2463,6 @@ class TestResponderRsaSign(TemplateResponder, Ikev2Params):
)
-@tag_fixme_vpp_workers
class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
TemplateResponder, Ikev2Params
):
@@ -2470,6 +2470,8 @@ class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
IKE:AES_CBC_128_SHA256_128,DH=modp2048 ESP:AES_CBC_192_SHA_384_192
"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2484,7 +2486,6 @@ class Test_IKE_AES_CBC_128_SHA256_128_MODP2048_ESP_AES_CBC_192_SHA_384_192(
)
-@tag_fixme_vpp_workers
class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
TemplateResponder, Ikev2Params
):
@@ -2492,6 +2493,8 @@ class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
IKE:AES_CBC_128_SHA256_128,DH=modp3072 ESP:AES_GCM_16
"""
+ vpp_worker_count = 2
+
def config_tc(self):
self.config_params(
{
@@ -2504,13 +2507,13 @@ class TestAES_CBC_128_SHA256_128_MODP3072_ESP_AES_GCM_16(
)
-@tag_fixme_vpp_workers
class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
"""
IKE:AES_GCM_16_256
"""
IKE_NODE_SUFFIX = "ip6"
+ vpp_worker_count = 2
def config_tc(self):
self.config_params(
@@ -2527,13 +2530,13 @@ class Test_IKE_AES_GCM_16_256(TemplateResponder, Ikev2Params):
)
-@tag_fixme_vpp_workers
-@tag_fixme_ubuntu2204
class TestInitiatorKeepaliveMsg(TestInitiatorPsk):
"""
Test for keep alive messages
"""
+ vpp_worker_count = 2
+
def send_empty_req_from_responder(self):
packet = self.create_empty_request()
self.pg0.add_stream(packet)
diff --git a/test/test_ip4.py b/test/test_ip4.py
index f4b428df4d3..150ea629308 100644
--- a/test/test_ip4.py
+++ b/test/test_ip4.py
@@ -1456,7 +1456,7 @@ class TestIPLoadBalance(VppTestCase):
src_pkts.append(
(
Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
- / IP(dst="1.1.1.1", src="20.0.0.%d" % ii)
+ / IP(dst="1.1.1.1", src="20.0.0.%d" % (ii % 256))
/ UDP(sport=1234, dport=1234)
/ Raw(b"\xa5" * 100)
)
diff --git a/test/test_ip6_nd_mirror_proxy.py b/test/test_ip6_nd_mirror_proxy.py
index 10dc77e1a86..e94309e8b50 100644
--- a/test/test_ip6_nd_mirror_proxy.py
+++ b/test/test_ip6_nd_mirror_proxy.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import unittest
-from socket import inet_pton, inet_ntop
+from socket import inet_pton, inet_ntop, AF_INET6
from framework import VppTestCase
from asfframework import VppTestRunner
@@ -59,8 +59,8 @@ class TestNDPROXY(VppTestCase):
# will come from the VPP's own address.
#
addr = self.pg0.remote_ip6
- nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr))
- d = inet_ntop(socket.AF_INET6, nsma)
+ nsma = in6_getnsma(inet_pton(AF_INET6, addr))
+ d = inet_ntop(AF_INET6, nsma)
# Make pg1 un-numbered to pg0
#
diff --git a/test/test_ipip.py b/test/test_ipip.py
index 9574c2c299c..85b35fa7f24 100644
--- a/test/test_ipip.py
+++ b/test/test_ipip.py
@@ -88,7 +88,7 @@ class TestIPIP(VppTestCase):
self.table.remove_vpp_config()
def validate(self, rx, expected):
- self.assertEqual(rx, expected.__class__(expected))
+ self.assertTrue(bytes(rx), bytes(expected))
def generate_ip4_frags(self, payload_length, fragment_size):
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
@@ -764,7 +764,7 @@ class TestIPIP6(VppTestCase):
rv = self.vapi.ipip_del_tunnel(sw_if_index=self.tunnel_if_index)
def validate(self, rx, expected):
- self.assertEqual(rx, expected.__class__(expected))
+ self.assertTrue(bytes(rx), bytes(expected))
def generate_ip6_frags(self, payload_length, fragment_size):
p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
diff --git a/test/test_ipsec_tun_if_esp.py b/test/test_ipsec_tun_if_esp.py
index a17e432ac51..cda52dc64c2 100644
--- a/test/test_ipsec_tun_if_esp.py
+++ b/test/test_ipsec_tun_if_esp.py
@@ -4,7 +4,7 @@ import copy
from scapy.layers.ipsec import SecurityAssociation, ESP
from scapy.layers.l2 import Ether, GRE, Dot1Q
-from scapy.packet import Raw, bind_layers
+from scapy.packet import Raw, bind_layers, Padding
from scapy.layers.inet import IP, UDP, ICMP
from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
from scapy.contrib.mpls import MPLS
diff --git a/test/test_linux_cp.py b/test/test_linux_cp.py
index 84d5cb6cd88..ff6023cea26 100644
--- a/test/test_linux_cp.py
+++ b/test/test_linux_cp.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import unittest
+import socket
from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6, Raw
@@ -241,7 +242,7 @@ class TestLinuxCP(VppTestCase):
self.assertEqual(rx[Ether].dst, phy.remote_mac)
self.assertEqual(rx[IP].dst, phy.remote_ip4)
self.assertEqual(rx[IP].src, phy.local_ip4)
- inner = IP(rx[IP].payload)
+ inner = IP(bytes(rx[IP].payload))
self.assertEqual(inner.src, tun4.local_ip4)
self.assertEqual(inner.dst, "2.2.2.2")
@@ -254,7 +255,7 @@ class TestLinuxCP(VppTestCase):
for rx in rxs:
self.assertEqual(rx[IPv6].dst, phy.remote_ip6)
self.assertEqual(rx[IPv6].src, phy.local_ip6)
- inner = IPv6(rx[IPv6].payload)
+ inner = IPv6(bytes(rx[IPv6].payload))
self.assertEqual(inner.src, tun6.local_ip6)
self.assertEqual(inner.dst, "2::2")
@@ -269,7 +270,7 @@ class TestLinuxCP(VppTestCase):
rxs = self.send_and_expect(phy, p * N_PKTS, self.pg4)
for rx in rxs:
- rx = IP(rx)
+ rx = IP(bytes(rx))
self.assertEqual(rx[IP].dst, tun4.local_ip4)
self.assertEqual(rx[IP].src, tun4.remote_ip4)
@@ -284,7 +285,7 @@ class TestLinuxCP(VppTestCase):
rxs = self.send_and_expect(phy, p * N_PKTS, self.pg5)
for rx in rxs:
- rx = IPv6(rx)
+ rx = IPv6(bytes(rx))
self.assertEqual(rx[IPv6].dst, tun6.local_ip6)
self.assertEqual(rx[IPv6].src, tun6.remote_ip6)
@@ -353,7 +354,7 @@ class TestLinuxCPIpsec(TemplateIpsec, TemplateIpsecItf4, IpsecTun4):
def verify_decrypted(self, p, rxs):
for rx in rxs:
- rx = IP(rx)
+ rx = IP(bytes(rx))
self.assert_equal(rx[IP].src, p.tun_if.remote_ip4)
self.assert_equal(rx[IP].dst, p.tun_if.local_ip4)
self.assert_packet_checksums_valid(rx)
diff --git a/test/test_mtu.py b/test/test_mtu.py
index 6735cc602a8..c5fb4278dfc 100644
--- a/test/test_mtu.py
+++ b/test/test_mtu.py
@@ -55,7 +55,7 @@ class TestMTU(VppTestCase):
i.admin_down()
def validate(self, rx, expected):
- self.assertEqual(rx, expected.__class__(expected))
+ self.assertTrue(bytes(rx), bytes(expected))
def validate_bytes(self, rx, expected):
self.assertEqual(rx, expected)
@@ -104,13 +104,10 @@ class TestMTU(VppTestCase):
/ p_ip4
/ p_payload
)
- n = icmp4_reply.__class__(icmp4_reply)
s = bytes(icmp4_reply)
icmp4_reply = s[0:576]
rx = self.send_and_expect_some(self.pg0, p4 * 11, self.pg0)
for p in rx:
- # p.show2()
- # n.show2()
self.validate_bytes(bytes(p[1]), icmp4_reply)
self.assert_error_counter_equal("/err/ip4-input/mtu_exceeded", 11)
@@ -185,7 +182,6 @@ class TestMTU(VppTestCase):
/ p_payload
)
icmp6_reply[2].hlim -= 1
- n = icmp6_reply.__class__(icmp6_reply)
s = bytes(icmp6_reply)
icmp6_reply_str = s[0:1280]
diff --git a/test/test_nat44_ed_output.py b/test/test_nat44_ed_output.py
index eea610df70e..55c43196295 100644
--- a/test/test_nat44_ed_output.py
+++ b/test/test_nat44_ed_output.py
@@ -3,6 +3,8 @@
import random
import unittest
+import struct
+import socket
from scapy.layers.inet import Ether, IP, TCP
from scapy.packet import Raw
from scapy.data import IP_PROTOS
diff --git a/test/test_pg.py b/test/test_pg.py
index d2e656df58b..da3b2254968 100644
--- a/test/test_pg.py
+++ b/test/test_pg.py
@@ -83,7 +83,7 @@ class TestPgTun(VppTestCase):
rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg1)
for rx in rxs:
- rx = IP(rx)
+ rx = IP(bytes(rx))
self.assertFalse(rx.haslayer(Ether))
self.assertEqual(rx[IP].dst, self.pg1.remote_ip4)
@@ -97,7 +97,7 @@ class TestPgTun(VppTestCase):
rxs = self.send_and_expect(self.pg0, p * N_PKTS, self.pg2)
for rx in rxs:
- rx = IPv6(rx)
+ rx = IPv6(bytes(rx))
self.assertFalse(rx.haslayer(Ether))
self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6)
diff --git a/test/test_pnat.py b/test/test_pnat.py
index 45e20240760..ef5b3a107dc 100644
--- a/test/test_pnat.py
+++ b/test/test_pnat.py
@@ -40,7 +40,7 @@ class TestPNAT(VppTestCase):
i.admin_down()
def validate(self, rx, expected):
- self.assertEqual(rx, expected.__class__(expected))
+ self.assertTrue(bytes(rx), bytes(expected))
def validate_bytes(self, rx, expected):
self.assertEqual(rx, expected)
diff --git a/test/test_pppoe.py b/test/test_pppoe.py
index 4a6a0251b9f..b0ea5cfe4f4 100644
--- a/test/test_pppoe.py
+++ b/test/test_pppoe.py
@@ -224,7 +224,6 @@ class TestPPPoE(VppTestCase):
)
pppoe_if.add_vpp_config()
pppoe_if.set_unnumbered(self.pg0.sw_if_index)
-
#
# Send tunneled packets that match the created tunnel and
# are decapped and forwarded
diff --git a/test/test_span.py b/test/test_span.py
index 31dff682f92..b151ef4f7a1 100644
--- a/test/test_span.py
+++ b/test/test_span.py
@@ -3,7 +3,8 @@
import unittest
from scapy.packet import Raw
-from scapy.layers.l2 import Ether, GRE, ERSPAN
+from scapy.layers.l2 import Ether, GRE
+from scapy.contrib.erspan import ERSPAN
from scapy.layers.inet import IP, UDP
from scapy.layers.vxlan import VXLAN
diff --git a/test/test_udp.py b/test/test_udp.py
index 2c0710ba2e2..6315f0efd5e 100644
--- a/test/test_udp.py
+++ b/test/test_udp.py
@@ -633,9 +633,9 @@ class TestUdpEncap(VppTestCase):
)
rx = self.send_and_expect(self.pg0, p_4 * NUM_PKTS, self.pg0)
- p_4 = IP(p_4["UDP"].payload)
+ p_4 = IP(bytes(p_4["UDP"].payload))
for p in rx:
- p = IP(p["Ether"].payload)
+ p = IP(bytes(p["Ether"].payload))
self.validate_inner4(p, p_4, ttl=63)
#
@@ -651,10 +651,10 @@ class TestUdpEncap(VppTestCase):
)
rx = self.send_and_expect(self.pg1, p_6 * NUM_PKTS, self.pg1)
- p_6 = IPv6(p_6["UDP"].payload)
- p = IPv6(rx[0]["Ether"].payload)
+ p_6 = IPv6(bytes(p_6["UDP"].payload))
+ p = IPv6(bytes(rx[0]["Ether"].payload))
for p in rx:
- p = IPv6(p["Ether"].payload)
+ p = IPv6(bytes(p["Ether"].payload))
self.validate_inner6(p, p_6, hlim=63)
#
@@ -673,9 +673,9 @@ class TestUdpEncap(VppTestCase):
self.pg2.enable_mpls()
rx = self.send_and_expect(self.pg2, p_mo4 * NUM_PKTS, self.pg2)
self.pg2.disable_mpls()
- p_mo4 = IP(MPLS(p_mo4["UDP"].payload).payload)
+ p_mo4 = IP(bytes(MPLS(bytes(p_mo4["UDP"].payload)).payload))
for p in rx:
- p = IP(p["Ether"].payload)
+ p = IP(bytes(p["Ether"].payload))
self.validate_inner4(p, p_mo4, ttl=63)
diff --git a/test/test_vlib.py b/test/test_vlib.py
index 60c354bccfc..48e32b6e669 100644
--- a/test/test_vlib.py
+++ b/test/test_vlib.py
@@ -274,7 +274,7 @@ class TestVlibFrameLeak(VppTestCase):
rx = self.pg0.get_capture(1)
- self.assertEquals(len(rx), 1)
+ self.assertEqual(len(rx), 1)
rx = rx[0]
ether = rx[Ether]
ipv4 = rx[IP]
@@ -305,7 +305,7 @@ class TestVlibFrameLeak(VppTestCase):
rx = self.pg0.get_capture(1)
- self.assertEquals(len(rx), 1)
+ self.assertEqual(len(rx), 1)
rx = rx[0]
ether = rx[Ether]
ipv4 = rx[IP]
diff --git a/test/test_vxlan6.py b/test/test_vxlan6.py
index 36e2f26e62f..09a99604311 100644
--- a/test/test_vxlan6.py
+++ b/test/test_vxlan6.py
@@ -258,7 +258,7 @@ class TestVxlan6(BridgeDomain, VppTestCase):
reassembled = util.reassemble4(payload)
- self.assertEqual(Ether(raw(frame))[IP], reassembled[IP])
+ self.assertEqual(Ether(bytes(frame))[IP], reassembled[IP])
"""
Tests with default port (4789)
diff --git a/test/test_wireguard.py b/test/test_wireguard.py
index e809daec163..481aa558312 100644
--- a/test/test_wireguard.py
+++ b/test/test_wireguard.py
@@ -261,7 +261,7 @@ class VppWgPeer(VppObject):
def mk_cookie(self, p, tx_itf, is_resp=False, is_ip6=False):
self.verify_header(p, is_ip6)
- wg_pkt = Wireguard(p[Raw])
+ wg_pkt = Wireguard(bytes(p[Raw]))
if is_resp:
self._test.assertEqual(wg_pkt[Wireguard].message_type, 2)
@@ -310,7 +310,7 @@ class VppWgPeer(VppObject):
def consume_cookie(self, p, is_ip6=False):
self.verify_header(p, is_ip6)
- cookie_reply = Wireguard(p[Raw])
+ cookie_reply = Wireguard(bytes(p[Raw]))
self._test.assertEqual(cookie_reply[Wireguard].message_type, 3)
self._test.assertEqual(cookie_reply[Wireguard].reserved_zero, 0)
@@ -390,7 +390,7 @@ class VppWgPeer(VppObject):
self.noise_init(self.itf.public_key)
self.verify_header(p, is_ip6)
- init = Wireguard(p[Raw])
+ init = Wireguard(bytes(p[Raw]))
self._test.assertEqual(init[Wireguard].message_type, 1)
self._test.assertEqual(init[Wireguard].reserved_zero, 0)
@@ -438,9 +438,7 @@ class VppWgPeer(VppObject):
def consume_response(self, p, is_ip6=False):
self.verify_header(p, is_ip6)
-
- resp = Wireguard(p[Raw])
-
+ resp = Wireguard(bytes(p[Raw]))
self._test.assertEqual(resp[Wireguard].message_type, 2)
self._test.assertEqual(resp[Wireguard].reserved_zero, 0)
self._test.assertEqual(
@@ -456,7 +454,7 @@ class VppWgPeer(VppObject):
def decrypt_transport(self, p, is_ip6=False):
self.verify_header(p, is_ip6)
- p = Wireguard(p[Raw])
+ p = Wireguard(bytes(p[Raw]))
self._test.assertEqual(p[Wireguard].message_type, 4)
self._test.assertEqual(p[Wireguard].reserved_zero, 0)
self._test.assertEqual(
@@ -501,7 +499,7 @@ class VppWgPeer(VppObject):
def is_handshake_init(p):
- wg_p = Wireguard(p[Raw])
+ wg_p = Wireguard(bytes(p[Raw]))
return wg_p[Wireguard].message_type == 1
diff --git a/test/vpp_pg_interface.py b/test/vpp_pg_interface.py
index cdb91ed1e41..1e02801cda9 100644
--- a/test/vpp_pg_interface.py
+++ b/test/vpp_pg_interface.py
@@ -187,7 +187,7 @@ class VppPGInterface(VppInterface):
self.test.logger.debug(
f"Generating testcase pg streams decode file: {pg_decode}"
)
- ts_opts = "-Vr"
+ ts_opts = "-Vxr"
for p in sorted(Path(pcap_dir).glob(f"{filename_prefix}*.pcap")):
self.test.logger.debug(f"Decoding {p}")
with open(f"{pg_decode}", "a", buffering=1) as f: