aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-15 18:04:25 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-15 18:04:25 -0400
commit9a76aba02a37718242d7cdc294f0a3901928aa57 (patch)
tree2040d038f85d2120f21af83b0793efd5af1864e3 /tools
parent0a957467c5fd46142bc9c52758ffc552d4c5e2f7 (diff)
parent26a1ccc6c117be8e33e0410fce8c5298b0015b99 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Highlights: - Gustavo A. R. Silva keeps working on the implicit switch fallthru changes. - Support 802.11ax High-Efficiency wireless in cfg80211 et al, From Luca Coelho. - Re-enable ASPM in r8169, from Kai-Heng Feng. - Add virtual XFRM interfaces, which avoids all of the limitations of existing IPSEC tunnels. From Steffen Klassert. - Convert GRO over to use a hash table, so that when we have many flows active we don't traverse a long list during accumluation. - Many new self tests for routing, TC, tunnels, etc. Too many contributors to mention them all, but I'm really happy to keep seeing this stuff. - Hardware timestamping support for dpaa_eth/fsl-fman from Yangbo Lu. - Lots of cleanups and fixes in L2TP code from Guillaume Nault. - Add IPSEC offload support to netdevsim, from Shannon Nelson. - Add support for slotting with non-uniform distribution to netem packet scheduler, from Yousuk Seung. - Add UDP GSO support to mlx5e, from Boris Pismenny. - Support offloading of Team LAG in NFP, from John Hurley. - Allow to configure TX queue selection based upon RX queue, from Amritha Nambiar. - Support ethtool ring size configuration in aquantia, from Anton Mikaev. - Support DSCP and flowlabel per-transport in SCTP, from Xin Long. - Support list based batching and stack traversal of SKBs, this is very exciting work. From Edward Cree. - Busyloop optimizations in vhost_net, from Toshiaki Makita. - Introduce the ETF qdisc, which allows time based transmissions. IGB can offload this in hardware. From Vinicius Costa Gomes. - Add parameter support to devlink, from Moshe Shemesh. - Several multiplication and division optimizations for BPF JIT in nfp driver, from Jiong Wang. - Lots of prepatory work to make more of the packet scheduler layer lockless, when possible, from Vlad Buslov. - Add ACK filter and NAT awareness to sch_cake packet scheduler, from Toke Høiland-Jørgensen. - Support regions and region snapshots in devlink, from Alex Vesker. - Allow to attach XDP programs to both HW and SW at the same time on a given device, with initial support in nfp. From Jakub Kicinski. - Add TLS RX offload and support in mlx5, from Ilya Lesokhin. - Use PHYLIB in r8169 driver, from Heiner Kallweit. - All sorts of changes to support Spectrum 2 in mlxsw driver, from Ido Schimmel. - PTP support in mv88e6xxx DSA driver, from Andrew Lunn. - Make TCP_USER_TIMEOUT socket option more accurate, from Jon Maxwell. - Support for templates in packet scheduler classifier, from Jiri Pirko. - IPV6 support in RDS, from Ka-Cheong Poon. - Native tproxy support in nf_tables, from Máté Eckl. - Maintain IP fragment queue in an rbtree, but optimize properly for in-order frags. From Peter Oskolkov. - Improvde handling of ACKs on hole repairs, from Yuchung Cheng" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1996 commits) bpf: test: fix spelling mistake "REUSEEPORT" -> "REUSEPORT" hv/netvsc: Fix NULL dereference at single queue mode fallback net: filter: mark expected switch fall-through xen-netfront: fix warn message as irq device name has '/' cxgb4: Add new T5 PCI device ids 0x50af and 0x50b0 net: dsa: mv88e6xxx: missing unlock on error path rds: fix building with IPV6=m inet/connection_sock: prefer _THIS_IP_ to current_text_addr net: dsa: mv88e6xxx: bitwise vs logical bug net: sock_diag: Fix spectre v1 gadget in __sock_diag_cmd() ieee802154: hwsim: using right kind of iteration net: hns3: Add vlan filter setting by ethtool command -K net: hns3: Set tx ring' tc info when netdev is up net: hns3: Remove tx ring BD len register in hns3_enet net: hns3: Fix desc num set to default when setting channel net: hns3: Fix for phy link issue when using marvell phy driver net: hns3: Fix for information of phydev lost problem when down/up net: hns3: Fix for command format parsing error in hclge_is_all_function_id_zero net: hns3: Add support for serdes loopback selftest bnxt_en: take coredump_record structure off stack ...
Diffstat (limited to 'tools')
-rw-r--r--tools/bpf/.gitignore5
-rw-r--r--tools/bpf/Makefile.helpers59
-rw-r--r--tools/bpf/bpftool/.gitignore2
-rw-r--r--tools/bpf/bpftool/Documentation/Makefile13
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-cgroup.rst12
-rw-r--r--tools/bpf/bpftool/Documentation/bpftool-prog.rst33
-rw-r--r--tools/bpf/bpftool/Makefile10
-rw-r--r--tools/bpf/bpftool/bash-completion/bpftool134
-rw-r--r--tools/bpf/bpftool/btf_dumper.c251
-rw-r--r--tools/bpf/bpftool/cgroup.c170
-rw-r--r--tools/bpf/bpftool/common.c2
-rw-r--r--tools/bpf/bpftool/main.c4
-rw-r--r--tools/bpf/bpftool/main.h36
-rw-r--r--tools/bpf/bpftool/map.c224
-rw-r--r--tools/bpf/bpftool/prog.c249
-rw-r--r--tools/bpf/bpftool/xlated_dumper.c6
-rw-r--r--tools/build/Makefile.feature1
-rw-r--r--tools/build/feature/Makefile4
-rw-r--r--tools/build/feature/test-reallocarray.c8
-rw-r--r--tools/include/linux/compiler-gcc.h4
-rw-r--r--tools/include/linux/overflow.h278
-rw-r--r--tools/include/tools/libc_compat.h20
-rw-r--r--tools/include/uapi/linux/bpf.h104
-rw-r--r--tools/lib/bpf/Build2
-rw-r--r--tools/lib/bpf/Makefile6
-rw-r--r--tools/lib/bpf/bpf.c1
-rw-r--r--tools/lib/bpf/bpf.h1
-rw-r--r--tools/lib/bpf/btf.c43
-rw-r--r--tools/lib/bpf/btf.h2
-rw-r--r--tools/lib/bpf/libbpf.c295
-rw-r--r--tools/lib/bpf/libbpf.h16
-rw-r--r--tools/lib/bpf/libbpf_errno.c74
-rw-r--r--tools/testing/selftests/bpf/Makefile15
-rw-r--r--tools/testing/selftests/bpf/bpf_helpers.h12
-rw-r--r--tools/testing/selftests/bpf/bpf_util.h4
-rw-r--r--tools/testing/selftests/bpf/cgroup_helpers.c6
-rw-r--r--tools/testing/selftests/bpf/cgroup_helpers.h6
-rw-r--r--tools/testing/selftests/bpf/socket_cookie_prog.c60
-rwxr-xr-xtools/testing/selftests/bpf/tcp_client.py12
-rwxr-xr-xtools/testing/selftests/bpf/tcp_server.py16
-rw-r--r--tools/testing/selftests/bpf/test_align.c5
-rw-r--r--tools/testing/selftests/bpf/test_btf.c92
-rw-r--r--tools/testing/selftests/bpf/test_cgroup_storage.c130
-rw-r--r--tools/testing/selftests/bpf/test_maps.c262
-rwxr-xr-xtools/testing/selftests/bpf/test_offload.py232
-rw-r--r--tools/testing/selftests/bpf/test_select_reuseport.c688
-rw-r--r--tools/testing/selftests/bpf/test_select_reuseport_common.h36
-rw-r--r--tools/testing/selftests/bpf/test_select_reuseport_kern.c180
-rwxr-xr-xtools/testing/selftests/bpf/test_skb_cgroup_id.sh62
-rw-r--r--tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c47
-rw-r--r--tools/testing/selftests/bpf/test_skb_cgroup_id_user.c187
-rw-r--r--tools/testing/selftests/bpf/test_sock.c5
-rw-r--r--tools/testing/selftests/bpf/test_sock_addr.c42
-rw-r--r--tools/testing/selftests/bpf/test_socket_cookie.c225
-rw-r--r--tools/testing/selftests/bpf/test_tcpbpf.h1
-rw-r--r--tools/testing/selftests/bpf/test_tcpbpf_kern.c17
-rw-r--r--tools/testing/selftests/bpf/test_tcpbpf_user.c119
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c177
-rw-r--r--tools/testing/selftests/bpf/trace_helpers.c48
-rw-r--r--tools/testing/selftests/bpf/trace_helpers.h4
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh217
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh197
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh189
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh233
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/router_scale.sh167
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh366
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh119
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh117
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh13
-rwxr-xr-xtools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh55
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh18
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh19
-rw-r--r--tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh134
-rw-r--r--tools/testing/selftests/net/.gitignore1
-rw-r--r--tools/testing/selftests/net/Makefile2
-rw-r--r--tools/testing/selftests/net/forwarding/README2
-rwxr-xr-xtools/testing/selftests/net/forwarding/bridge_port_isolation.sh151
-rw-r--r--tools/testing/selftests/net/forwarding/devlink_lib.sh108
-rwxr-xr-xtools/testing/selftests/net/forwarding/gre_multipath.sh253
-rw-r--r--tools/testing/selftests/net/forwarding/lib.sh291
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh132
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh6
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh126
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh283
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_changes.sh11
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh285
-rw-r--r--tools/testing/selftests/net/forwarding/mirror_gre_lib.sh4
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_nh.sh4
-rw-r--r--tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh2
-rwxr-xr-xtools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh21
-rw-r--r--tools/testing/selftests/net/forwarding/mirror_lib.sh2
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_bridge.sh113
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_bridge_vlan.sh132
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_broadcast.sh233
-rwxr-xr-xtools/testing/selftests/net/forwarding/router_multipath.sh39
-rwxr-xr-xtools/testing/selftests/net/forwarding/tc_chains.sh86
-rwxr-xr-xtools/testing/selftests/net/forwarding/tc_shblocks.sh2
-rwxr-xr-xtools/testing/selftests/net/ip6_gre_headroom.sh65
-rwxr-xr-xtools/testing/selftests/net/rtnetlink.sh128
-rw-r--r--tools/testing/selftests/net/tls.c692
-rw-r--r--tools/testing/selftests/tc-testing/README16
-rw-r--r--tools/testing/selftests/tc-testing/config48
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json24
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/csum.json24
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json3
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/nat.json593
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json26
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json917
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/fw.json1049
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/filters/tests.json4
110 files changed, 11995 insertions, 486 deletions
diff --git a/tools/bpf/.gitignore b/tools/bpf/.gitignore
new file mode 100644
index 000000000000..dfe2bd5a4b95
--- /dev/null
+++ b/tools/bpf/.gitignore
@@ -0,0 +1,5 @@
1FEATURE-DUMP.bpf
2bpf_asm
3bpf_dbg
4bpf_exp.yacc.*
5bpf_jit_disasm
diff --git a/tools/bpf/Makefile.helpers b/tools/bpf/Makefile.helpers
new file mode 100644
index 000000000000..c34fea77f39f
--- /dev/null
+++ b/tools/bpf/Makefile.helpers
@@ -0,0 +1,59 @@
1ifndef allow-override
2 include ../scripts/Makefile.include
3 include ../scripts/utilities.mak
4else
5 # Assume Makefile.helpers is being run from bpftool/Documentation
6 # subdirectory. Go up two more directories to fetch bpf.h header and
7 # associated script.
8 UP2DIR := ../../
9endif
10
11INSTALL ?= install
12RM ?= rm -f
13RMDIR ?= rmdir --ignore-fail-on-non-empty
14
15ifeq ($(V),1)
16 Q =
17else
18 Q = @
19endif
20
21prefix ?= /usr/local
22mandir ?= $(prefix)/man
23man7dir = $(mandir)/man7
24
25HELPERS_RST = bpf-helpers.rst
26MAN7_RST = $(HELPERS_RST)
27
28_DOC_MAN7 = $(patsubst %.rst,%.7,$(MAN7_RST))
29DOC_MAN7 = $(addprefix $(OUTPUT),$(_DOC_MAN7))
30
31helpers: man7
32man7: $(DOC_MAN7)
33
34RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null)
35
36$(OUTPUT)$(HELPERS_RST): $(UP2DIR)../../include/uapi/linux/bpf.h
37 $(QUIET_GEN)$(UP2DIR)../../scripts/bpf_helpers_doc.py --filename $< > $@
38
39$(OUTPUT)%.7: $(OUTPUT)%.rst
40ifndef RST2MAN_DEP
41 $(error "rst2man not found, but required to generate man pages")
42endif
43 $(QUIET_GEN)rst2man $< > $@
44
45helpers-clean:
46 $(call QUIET_CLEAN, eBPF_helpers-manpage)
47 $(Q)$(RM) $(DOC_MAN7) $(OUTPUT)$(HELPERS_RST)
48
49helpers-install: helpers
50 $(call QUIET_INSTALL, eBPF_helpers-manpage)
51 $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
52 $(Q)$(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
53
54helpers-uninstall:
55 $(call QUIET_UNINST, eBPF_helpers-manpage)
56 $(Q)$(RM) $(addprefix $(DESTDIR)$(man7dir)/,$(_DOC_MAN7))
57 $(Q)$(RMDIR) $(DESTDIR)$(man7dir)
58
59.PHONY: helpers helpers-clean helpers-install helpers-uninstall
diff --git a/tools/bpf/bpftool/.gitignore b/tools/bpf/bpftool/.gitignore
index d7e678c2d396..67167e44b726 100644
--- a/tools/bpf/bpftool/.gitignore
+++ b/tools/bpf/bpftool/.gitignore
@@ -1,3 +1,5 @@
1*.d 1*.d
2bpftool 2bpftool
3bpftool*.8
4bpf-helpers.*
3FEATURE-DUMP.bpftool 5FEATURE-DUMP.bpftool
diff --git a/tools/bpf/bpftool/Documentation/Makefile b/tools/bpf/bpftool/Documentation/Makefile
index a9d47c1558bb..f7663a3e60c9 100644
--- a/tools/bpf/bpftool/Documentation/Makefile
+++ b/tools/bpf/bpftool/Documentation/Makefile
@@ -15,12 +15,15 @@ prefix ?= /usr/local
15mandir ?= $(prefix)/man 15mandir ?= $(prefix)/man
16man8dir = $(mandir)/man8 16man8dir = $(mandir)/man8
17 17
18MAN8_RST = $(wildcard *.rst) 18# Load targets for building eBPF helpers man page.
19include ../../Makefile.helpers
20
21MAN8_RST = $(filter-out $(HELPERS_RST),$(wildcard *.rst))
19 22
20_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST)) 23_DOC_MAN8 = $(patsubst %.rst,%.8,$(MAN8_RST))
21DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) 24DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8))
22 25
23man: man8 26man: man8 helpers
24man8: $(DOC_MAN8) 27man8: $(DOC_MAN8)
25 28
26RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) 29RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null)
@@ -31,16 +34,16 @@ ifndef RST2MAN_DEP
31endif 34endif
32 $(QUIET_GEN)rst2man $< > $@ 35 $(QUIET_GEN)rst2man $< > $@
33 36
34clean: 37clean: helpers-clean
35 $(call QUIET_CLEAN, Documentation) 38 $(call QUIET_CLEAN, Documentation)
36 $(Q)$(RM) $(DOC_MAN8) 39 $(Q)$(RM) $(DOC_MAN8)
37 40
38install: man 41install: man helpers-install
39 $(call QUIET_INSTALL, Documentation-man) 42 $(call QUIET_INSTALL, Documentation-man)
40 $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir) 43 $(Q)$(INSTALL) -d -m 755 $(DESTDIR)$(man8dir)
41 $(Q)$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir) 44 $(Q)$(INSTALL) -m 644 $(DOC_MAN8) $(DESTDIR)$(man8dir)
42 45
43uninstall: 46uninstall: helpers-uninstall
44 $(call QUIET_UNINST, Documentation-man) 47 $(call QUIET_UNINST, Documentation-man)
45 $(Q)$(RM) $(addprefix $(DESTDIR)$(man8dir)/,$(_DOC_MAN8)) 48 $(Q)$(RM) $(addprefix $(DESTDIR)$(man8dir)/,$(_DOC_MAN8))
46 $(Q)$(RMDIR) $(DESTDIR)$(man8dir) 49 $(Q)$(RMDIR) $(DESTDIR)$(man8dir)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
index 7b0e6d453e92..edbe81534c6d 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
@@ -15,12 +15,13 @@ SYNOPSIS
15 *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } } 15 *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
16 16
17 *COMMANDS* := 17 *COMMANDS* :=
18 { **show** | **list** | **attach** | **detach** | **help** } 18 { **show** | **list** | **tree** | **attach** | **detach** | **help** }
19 19
20MAP COMMANDS 20MAP COMMANDS
21============= 21=============
22 22
23| **bpftool** **cgroup { show | list }** *CGROUP* 23| **bpftool** **cgroup { show | list }** *CGROUP*
24| **bpftool** **cgroup tree** [*CGROUP_ROOT*]
24| **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] 25| **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
25| **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG* 26| **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG*
26| **bpftool** **cgroup help** 27| **bpftool** **cgroup help**
@@ -39,6 +40,15 @@ DESCRIPTION
39 Output will start with program ID followed by attach type, 40 Output will start with program ID followed by attach type,
40 attach flags and program name. 41 attach flags and program name.
41 42
43 **bpftool cgroup tree** [*CGROUP_ROOT*]
44 Iterate over all cgroups in *CGROUP_ROOT* and list all
45 attached programs. If *CGROUP_ROOT* is not specified,
46 bpftool uses cgroup v2 mountpoint.
47
48 The output is similar to the output of cgroup show/list
49 commands: it starts with absolute cgroup path, followed by
50 program ID, attach type, attach flags and program name.
51
42 **bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*] 52 **bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
43 Attach program *PROG* to the cgroup *CGROUP* with attach type 53 Attach program *PROG* to the cgroup *CGROUP* with attach type
44 *ATTACH_TYPE* and optional *ATTACH_FLAGS*. 54 *ATTACH_TYPE* and optional *ATTACH_FLAGS*.
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index 43d34a5c3ec5..64156a16d530 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -24,10 +24,20 @@ MAP COMMANDS
24| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] 24| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
25| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] 25| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
26| **bpftool** **prog pin** *PROG* *FILE* 26| **bpftool** **prog pin** *PROG* *FILE*
27| **bpftool** **prog load** *OBJ* *FILE* 27| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
28| **bpftool** **prog help** 28| **bpftool** **prog help**
29| 29|
30| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
30| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } 31| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
32| *TYPE* := {
33| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
34| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** |
35| **cgroup/sock** | **cgroup/dev** | **lwt_in** | **lwt_out** | **lwt_xmit** |
36| **lwt_seg6local** | **sockops** | **sk_skb** | **sk_msg** | **lirc_mode2** |
37| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
38| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
39| }
40
31 41
32DESCRIPTION 42DESCRIPTION
33=========== 43===========
@@ -64,8 +74,19 @@ DESCRIPTION
64 74
65 Note: *FILE* must be located in *bpffs* mount. 75 Note: *FILE* must be located in *bpffs* mount.
66 76
67 **bpftool prog load** *OBJ* *FILE* 77 **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
68 Load bpf program from binary *OBJ* and pin as *FILE*. 78 Load bpf program from binary *OBJ* and pin as *FILE*.
79 **type** is optional, if not specified program type will be
80 inferred from section names.
81 By default bpftool will create new maps as declared in the ELF
82 object being loaded. **map** parameter allows for the reuse
83 of existing maps. It can be specified multiple times, each
84 time for a different map. *IDX* refers to index of the map
85 to be replaced in the ELF file counting from 0, while *NAME*
86 allows to replace a map by name. *MAP* specifies the map to
87 use, referring to it by **id** or through a **pinned** file.
88 If **dev** *NAME* is specified program will be loaded onto
89 given networking device (offload).
69 90
70 Note: *FILE* must be located in *bpffs* mount. 91 Note: *FILE* must be located in *bpffs* mount.
71 92
@@ -159,6 +180,14 @@ EXAMPLES
159 mov %rbx,0x0(%rbp) 180 mov %rbx,0x0(%rbp)
160 48 89 5d 00 181 48 89 5d 00
161 182
183|
184| **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7**
185| **# bpftool prog show pinned /sys/fs/bpf/xdp1**
186| 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl
187| loaded_at 2018-06-25T16:17:31-0700 uid 0
188| xlated 488B jited 336B memlock 4096B map_ids 7
189| **# rm /sys/fs/bpf/xdp1**
190|
162 191
163SEE ALSO 192SEE ALSO
164======== 193========
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
index 892dbf095bff..74288a2197ab 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -23,10 +23,10 @@ endif
23 23
24LIBBPF = $(BPF_PATH)libbpf.a 24LIBBPF = $(BPF_PATH)libbpf.a
25 25
26BPFTOOL_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) 26BPFTOOL_VERSION := $(shell make --no-print-directory -sC ../../.. kernelversion)
27 27
28$(LIBBPF): FORCE 28$(LIBBPF): FORCE
29 $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT) 29 $(Q)$(MAKE) -C $(BPF_DIR) OUTPUT=$(OUTPUT) $(OUTPUT)libbpf.a
30 30
31$(LIBBPF)-clean: 31$(LIBBPF)-clean:
32 $(call QUIET_CLEAN, libbpf) 32 $(call QUIET_CLEAN, libbpf)
@@ -52,7 +52,7 @@ INSTALL ?= install
52RM ?= rm -f 52RM ?= rm -f
53 53
54FEATURE_USER = .bpftool 54FEATURE_USER = .bpftool
55FEATURE_TESTS = libbfd disassembler-four-args 55FEATURE_TESTS = libbfd disassembler-four-args reallocarray
56FEATURE_DISPLAY = libbfd disassembler-four-args 56FEATURE_DISPLAY = libbfd disassembler-four-args
57 57
58check_feat := 1 58check_feat := 1
@@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1)
75CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE 75CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
76endif 76endif
77 77
78ifeq ($(feature-reallocarray), 0)
79CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
80endif
81
78include $(wildcard $(OUTPUT)*.d) 82include $(wildcard $(OUTPUT)*.d)
79 83
80all: $(OUTPUT)bpftool 84all: $(OUTPUT)bpftool
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 1e1083321643..598066c40191 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -99,6 +99,35 @@ _bpftool_get_prog_tags()
99 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) ) 99 command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
100} 100}
101 101
102_bpftool_get_obj_map_names()
103{
104 local obj
105
106 obj=$1
107
108 maps=$(objdump -j maps -t $obj 2>/dev/null | \
109 command awk '/g . maps/ {print $NF}')
110
111 COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
112}
113
114_bpftool_get_obj_map_idxs()
115{
116 local obj
117
118 obj=$1
119
120 nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
121
122 COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
123}
124
125_sysfs_get_netdevs()
126{
127 COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
128 "$cur" ) )
129}
130
102# For bpftool map update: retrieve type of the map to update. 131# For bpftool map update: retrieve type of the map to update.
103_bpftool_map_update_map_type() 132_bpftool_map_update_map_type()
104{ 133{
@@ -153,6 +182,13 @@ _bpftool()
153 local cur prev words objword 182 local cur prev words objword
154 _init_completion || return 183 _init_completion || return
155 184
185 # Deal with options
186 if [[ ${words[cword]} == -* ]]; then
187 local c='--version --json --pretty --bpffs'
188 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
189 return 0
190 fi
191
156 # Deal with simplest keywords 192 # Deal with simplest keywords
157 case $prev in 193 case $prev in
158 help|hex|opcodes|visual) 194 help|hex|opcodes|visual)
@@ -172,20 +208,23 @@ _bpftool()
172 ;; 208 ;;
173 esac 209 esac
174 210
175 # Search for object and command 211 # Remove all options so completions don't have to deal with them.
176 local object command cmdword 212 local i
177 for (( cmdword=1; cmdword < ${#words[@]}-1; cmdword++ )); do 213 for (( i=1; i < ${#words[@]}; )); do
178 [[ -n $object ]] && command=${words[cmdword]} && break 214 if [[ ${words[i]::1} == - ]]; then
179 [[ ${words[cmdword]} != -* ]] && object=${words[cmdword]} 215 words=( "${words[@]:0:i}" "${words[@]:i+1}" )
216 [[ $i -le $cword ]] && cword=$(( cword - 1 ))
217 else
218 i=$(( ++i ))
219 fi
180 done 220 done
221 cur=${words[cword]}
222 prev=${words[cword - 1]}
223
224 local object=${words[1]} command=${words[2]}
181 225
182 if [[ -z $object ]]; then 226 if [[ -z $object || $cword -eq 1 ]]; then
183 case $cur in 227 case $cur in
184 -*)
185 local c='--version --json --pretty'
186 COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
187 return 0
188 ;;
189 *) 228 *)
190 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \ 229 COMPREPLY=( $( compgen -W "$( bpftool help 2>&1 | \
191 command sed \ 230 command sed \
@@ -204,12 +243,14 @@ _bpftool()
204 # Completion depends on object and command in use 243 # Completion depends on object and command in use
205 case $object in 244 case $object in
206 prog) 245 prog)
207 case $prev in 246 if [[ $command != "load" ]]; then
208 id) 247 case $prev in
209 _bpftool_get_prog_ids 248 id)
210 return 0 249 _bpftool_get_prog_ids
211 ;; 250 return 0
212 esac 251 ;;
252 esac
253 fi
213 254
214 local PROG_TYPE='id pinned tag' 255 local PROG_TYPE='id pinned tag'
215 case $command in 256 case $command in
@@ -252,8 +293,57 @@ _bpftool()
252 return 0 293 return 0
253 ;; 294 ;;
254 load) 295 load)
255 _filedir 296 local obj
256 return 0 297
298 if [[ ${#words[@]} -lt 6 ]]; then
299 _filedir
300 return 0
301 fi
302
303 obj=${words[3]}
304
305 if [[ ${words[-4]} == "map" ]]; then
306 COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
307 return 0
308 fi
309 if [[ ${words[-3]} == "map" ]]; then
310 if [[ ${words[-2]} == "idx" ]]; then
311 _bpftool_get_obj_map_idxs $obj
312 elif [[ ${words[-2]} == "name" ]]; then
313 _bpftool_get_obj_map_names $obj
314 fi
315 return 0
316 fi
317 if [[ ${words[-2]} == "map" ]]; then
318 COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
319 return 0
320 fi
321
322 case $prev in
323 type)
324 COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \
325 "$cur" ) )
326 return 0
327 ;;
328 id)
329 _bpftool_get_map_ids
330 return 0
331 ;;
332 pinned)
333 _filedir
334 return 0
335 ;;
336 dev)
337 _sysfs_get_netdevs
338 return 0
339 ;;
340 *)
341 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
342 _bpftool_once_attr 'type'
343 _bpftool_once_attr 'dev'
344 return 0
345 ;;
346 esac
257 ;; 347 ;;
258 *) 348 *)
259 [[ $prev == $object ]] && \ 349 [[ $prev == $object ]] && \
@@ -404,6 +494,10 @@ _bpftool()
404 _filedir 494 _filedir
405 return 0 495 return 0
406 ;; 496 ;;
497 tree)
498 _filedir
499 return 0
500 ;;
407 attach|detach) 501 attach|detach)
408 local ATTACH_TYPES='ingress egress sock_create sock_ops \ 502 local ATTACH_TYPES='ingress egress sock_create sock_ops \
409 device bind4 bind6 post_bind4 post_bind6 connect4 \ 503 device bind4 bind6 post_bind4 post_bind6 connect4 \
@@ -445,7 +539,7 @@ _bpftool()
445 *) 539 *)
446 [[ $prev == $object ]] && \ 540 [[ $prev == $object ]] && \
447 COMPREPLY=( $( compgen -W 'help attach detach \ 541 COMPREPLY=( $( compgen -W 'help attach detach \
448 show list' -- "$cur" ) ) 542 show list tree' -- "$cur" ) )
449 ;; 543 ;;
450 esac 544 esac
451 ;; 545 ;;
diff --git a/tools/bpf/bpftool/btf_dumper.c b/tools/bpf/bpftool/btf_dumper.c
new file mode 100644
index 000000000000..55bc512a1831
--- /dev/null
+++ b/tools/bpf/bpftool/btf_dumper.c
@@ -0,0 +1,251 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018 Facebook */
3
4#include <ctype.h>
5#include <stdio.h> /* for (FILE *) used by json_writer */
6#include <string.h>
7#include <asm/byteorder.h>
8#include <linux/bitops.h>
9#include <linux/btf.h>
10#include <linux/err.h>
11
12#include "btf.h"
13#include "json_writer.h"
14#include "main.h"
15
16#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
17#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
18#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
19#define BITS_ROUNDUP_BYTES(bits) \
20 (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
21
22static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
23 __u8 bit_offset, const void *data);
24
25static void btf_dumper_ptr(const void *data, json_writer_t *jw,
26 bool is_plain_text)
27{
28 if (is_plain_text)
29 jsonw_printf(jw, "%p", *(unsigned long *)data);
30 else
31 jsonw_printf(jw, "%u", *(unsigned long *)data);
32}
33
34static int btf_dumper_modifier(const struct btf_dumper *d, __u32 type_id,
35 const void *data)
36{
37 int actual_type_id;
38
39 actual_type_id = btf__resolve_type(d->btf, type_id);
40 if (actual_type_id < 0)
41 return actual_type_id;
42
43 return btf_dumper_do_type(d, actual_type_id, 0, data);
44}
45
46static void btf_dumper_enum(const void *data, json_writer_t *jw)
47{
48 jsonw_printf(jw, "%d", *(int *)data);
49}
50
51static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
52 const void *data)
53{
54 const struct btf_type *t = btf__type_by_id(d->btf, type_id);
55 struct btf_array *arr = (struct btf_array *)(t + 1);
56 long long elem_size;
57 int ret = 0;
58 __u32 i;
59
60 elem_size = btf__resolve_size(d->btf, arr->type);
61 if (elem_size < 0)
62 return elem_size;
63
64 jsonw_start_array(d->jw);
65 for (i = 0; i < arr->nelems; i++) {
66 ret = btf_dumper_do_type(d, arr->type, 0,
67 data + i * elem_size);
68 if (ret)
69 break;
70 }
71
72 jsonw_end_array(d->jw);
73 return ret;
74}
75
76static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
77 const void *data, json_writer_t *jw,
78 bool is_plain_text)
79{
80 int left_shift_bits, right_shift_bits;
81 int nr_bits = BTF_INT_BITS(int_type);
82 int total_bits_offset;
83 int bytes_to_copy;
84 int bits_to_copy;
85 __u64 print_num;
86
87 total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
88 data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
89 bit_offset = BITS_PER_BYTE_MASKED(total_bits_offset);
90 bits_to_copy = bit_offset + nr_bits;
91 bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
92
93 print_num = 0;
94 memcpy(&print_num, data, bytes_to_copy);
95#if defined(__BIG_ENDIAN_BITFIELD)
96 left_shift_bits = bit_offset;
97#elif defined(__LITTLE_ENDIAN_BITFIELD)
98 left_shift_bits = 64 - bits_to_copy;
99#else
100#error neither big nor little endian
101#endif
102 right_shift_bits = 64 - nr_bits;
103
104 print_num <<= left_shift_bits;
105 print_num >>= right_shift_bits;
106 if (is_plain_text)
107 jsonw_printf(jw, "0x%llx", print_num);
108 else
109 jsonw_printf(jw, "%llu", print_num);
110}
111
112static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
113 const void *data, json_writer_t *jw,
114 bool is_plain_text)
115{
116 __u32 *int_type;
117 __u32 nr_bits;
118
119 int_type = (__u32 *)(t + 1);
120 nr_bits = BTF_INT_BITS(*int_type);
121 /* if this is bit field */
122 if (bit_offset || BTF_INT_OFFSET(*int_type) ||
123 BITS_PER_BYTE_MASKED(nr_bits)) {
124 btf_dumper_int_bits(*int_type, bit_offset, data, jw,
125 is_plain_text);
126 return 0;
127 }
128
129 switch (BTF_INT_ENCODING(*int_type)) {
130 case 0:
131 if (BTF_INT_BITS(*int_type) == 64)
132 jsonw_printf(jw, "%lu", *(__u64 *)data);
133 else if (BTF_INT_BITS(*int_type) == 32)
134 jsonw_printf(jw, "%u", *(__u32 *)data);
135 else if (BTF_INT_BITS(*int_type) == 16)
136 jsonw_printf(jw, "%hu", *(__u16 *)data);
137 else if (BTF_INT_BITS(*int_type) == 8)
138 jsonw_printf(jw, "%hhu", *(__u8 *)data);
139 else
140 btf_dumper_int_bits(*int_type, bit_offset, data, jw,
141 is_plain_text);
142 break;
143 case BTF_INT_SIGNED:
144 if (BTF_INT_BITS(*int_type) == 64)
145 jsonw_printf(jw, "%ld", *(long long *)data);
146 else if (BTF_INT_BITS(*int_type) == 32)
147 jsonw_printf(jw, "%d", *(int *)data);
148 else if (BTF_INT_BITS(*int_type) == 16)
149 jsonw_printf(jw, "%hd", *(short *)data);
150 else if (BTF_INT_BITS(*int_type) == 8)
151 jsonw_printf(jw, "%hhd", *(char *)data);
152 else
153 btf_dumper_int_bits(*int_type, bit_offset, data, jw,
154 is_plain_text);
155 break;
156 case BTF_INT_CHAR:
157 if (isprint(*(char *)data))
158 jsonw_printf(jw, "\"%c\"", *(char *)data);
159 else
160 if (is_plain_text)
161 jsonw_printf(jw, "0x%hhx", *(char *)data);
162 else
163 jsonw_printf(jw, "\"\\u00%02hhx\"",
164 *(char *)data);
165 break;
166 case BTF_INT_BOOL:
167 jsonw_bool(jw, *(int *)data);
168 break;
169 default:
170 /* shouldn't happen */
171 return -EINVAL;
172 }
173
174 return 0;
175}
176
177static int btf_dumper_struct(const struct btf_dumper *d, __u32 type_id,
178 const void *data)
179{
180 const struct btf_type *t;
181 struct btf_member *m;
182 const void *data_off;
183 int ret = 0;
184 int i, vlen;
185
186 t = btf__type_by_id(d->btf, type_id);
187 if (!t)
188 return -EINVAL;
189
190 vlen = BTF_INFO_VLEN(t->info);
191 jsonw_start_object(d->jw);
192 m = (struct btf_member *)(t + 1);
193
194 for (i = 0; i < vlen; i++) {
195 data_off = data + BITS_ROUNDDOWN_BYTES(m[i].offset);
196 jsonw_name(d->jw, btf__name_by_offset(d->btf, m[i].name_off));
197 ret = btf_dumper_do_type(d, m[i].type,
198 BITS_PER_BYTE_MASKED(m[i].offset),
199 data_off);
200 if (ret)
201 break;
202 }
203
204 jsonw_end_object(d->jw);
205
206 return ret;
207}
208
209static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id,
210 __u8 bit_offset, const void *data)
211{
212 const struct btf_type *t = btf__type_by_id(d->btf, type_id);
213
214 switch (BTF_INFO_KIND(t->info)) {
215 case BTF_KIND_INT:
216 return btf_dumper_int(t, bit_offset, data, d->jw,
217 d->is_plain_text);
218 case BTF_KIND_STRUCT:
219 case BTF_KIND_UNION:
220 return btf_dumper_struct(d, type_id, data);
221 case BTF_KIND_ARRAY:
222 return btf_dumper_array(d, type_id, data);
223 case BTF_KIND_ENUM:
224 btf_dumper_enum(data, d->jw);
225 return 0;
226 case BTF_KIND_PTR:
227 btf_dumper_ptr(data, d->jw, d->is_plain_text);
228 return 0;
229 case BTF_KIND_UNKN:
230 jsonw_printf(d->jw, "(unknown)");
231 return 0;
232 case BTF_KIND_FWD:
233 /* map key or value can't be forward */
234 jsonw_printf(d->jw, "(fwd-kind-invalid)");
235 return -EINVAL;
236 case BTF_KIND_TYPEDEF:
237 case BTF_KIND_VOLATILE:
238 case BTF_KIND_CONST:
239 case BTF_KIND_RESTRICT:
240 return btf_dumper_modifier(d, type_id, data);
241 default:
242 jsonw_printf(d->jw, "(unsupported-kind");
243 return -EINVAL;
244 }
245}
246
247int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
248 const void *data)
249{
250 return btf_dumper_do_type(d, type_id, 0, data);
251}
diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index 16bee011e16c..ee7a9765c6b3 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -2,7 +2,12 @@
2// Copyright (C) 2017 Facebook 2// Copyright (C) 2017 Facebook
3// Author: Roman Gushchin <guro@fb.com> 3// Author: Roman Gushchin <guro@fb.com>
4 4
5#define _XOPEN_SOURCE 500
6#include <errno.h>
5#include <fcntl.h> 7#include <fcntl.h>
8#include <ftw.h>
9#include <mntent.h>
10#include <stdio.h>
6#include <stdlib.h> 11#include <stdlib.h>
7#include <string.h> 12#include <string.h>
8#include <sys/stat.h> 13#include <sys/stat.h>
@@ -53,7 +58,8 @@ static enum bpf_attach_type parse_attach_type(const char *str)
53} 58}
54 59
55static int show_bpf_prog(int id, const char *attach_type_str, 60static int show_bpf_prog(int id, const char *attach_type_str,
56 const char *attach_flags_str) 61 const char *attach_flags_str,
62 int level)
57{ 63{
58 struct bpf_prog_info info = {}; 64 struct bpf_prog_info info = {};
59 __u32 info_len = sizeof(info); 65 __u32 info_len = sizeof(info);
@@ -78,7 +84,8 @@ static int show_bpf_prog(int id, const char *attach_type_str,
78 jsonw_string_field(json_wtr, "name", info.name); 84 jsonw_string_field(json_wtr, "name", info.name);
79 jsonw_end_object(json_wtr); 85 jsonw_end_object(json_wtr);
80 } else { 86 } else {
81 printf("%-8u %-15s %-15s %-15s\n", info.id, 87 printf("%s%-8u %-15s %-15s %-15s\n", level ? " " : "",
88 info.id,
82 attach_type_str, 89 attach_type_str,
83 attach_flags_str, 90 attach_flags_str,
84 info.name); 91 info.name);
@@ -88,7 +95,20 @@ static int show_bpf_prog(int id, const char *attach_type_str,
88 return 0; 95 return 0;
89} 96}
90 97
91static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) 98static int count_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
99{
100 __u32 prog_cnt = 0;
101 int ret;
102
103 ret = bpf_prog_query(cgroup_fd, type, 0, NULL, NULL, &prog_cnt);
104 if (ret)
105 return -1;
106
107 return prog_cnt;
108}
109
110static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type,
111 int level)
92{ 112{
93 __u32 prog_ids[1024] = {0}; 113 __u32 prog_ids[1024] = {0};
94 char *attach_flags_str; 114 char *attach_flags_str;
@@ -123,7 +143,7 @@ static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
123 143
124 for (iter = 0; iter < prog_cnt; iter++) 144 for (iter = 0; iter < prog_cnt; iter++)
125 show_bpf_prog(prog_ids[iter], attach_type_strings[type], 145 show_bpf_prog(prog_ids[iter], attach_type_strings[type],
126 attach_flags_str); 146 attach_flags_str, level);
127 147
128 return 0; 148 return 0;
129} 149}
@@ -161,7 +181,7 @@ static int do_show(int argc, char **argv)
161 * If we were able to get the show for at least one 181 * If we were able to get the show for at least one
162 * attach type, let's return 0. 182 * attach type, let's return 0.
163 */ 183 */
164 if (show_attached_bpf_progs(cgroup_fd, type) == 0) 184 if (show_attached_bpf_progs(cgroup_fd, type, 0) == 0)
165 ret = 0; 185 ret = 0;
166 } 186 }
167 187
@@ -173,6 +193,143 @@ exit:
173 return ret; 193 return ret;
174} 194}
175 195
196/*
197 * To distinguish nftw() errors and do_show_tree_fn() errors
198 * and avoid duplicating error messages, let's return -2
199 * from do_show_tree_fn() in case of error.
200 */
201#define NFTW_ERR -1
202#define SHOW_TREE_FN_ERR -2
203static int do_show_tree_fn(const char *fpath, const struct stat *sb,
204 int typeflag, struct FTW *ftw)
205{
206 enum bpf_attach_type type;
207 bool skip = true;
208 int cgroup_fd;
209
210 if (typeflag != FTW_D)
211 return 0;
212
213 cgroup_fd = open(fpath, O_RDONLY);
214 if (cgroup_fd < 0) {
215 p_err("can't open cgroup %s: %s", fpath, strerror(errno));
216 return SHOW_TREE_FN_ERR;
217 }
218
219 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
220 int count = count_attached_bpf_progs(cgroup_fd, type);
221
222 if (count < 0 && errno != EINVAL) {
223 p_err("can't query bpf programs attached to %s: %s",
224 fpath, strerror(errno));
225 close(cgroup_fd);
226 return SHOW_TREE_FN_ERR;
227 }
228 if (count > 0) {
229 skip = false;
230 break;
231 }
232 }
233
234 if (skip) {
235 close(cgroup_fd);
236 return 0;
237 }
238
239 if (json_output) {
240 jsonw_start_object(json_wtr);
241 jsonw_string_field(json_wtr, "cgroup", fpath);
242 jsonw_name(json_wtr, "programs");
243 jsonw_start_array(json_wtr);
244 } else {
245 printf("%s\n", fpath);
246 }
247
248 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++)
249 show_attached_bpf_progs(cgroup_fd, type, ftw->level);
250
251 if (json_output) {
252 jsonw_end_array(json_wtr);
253 jsonw_end_object(json_wtr);
254 }
255
256 close(cgroup_fd);
257
258 return 0;
259}
260
261static char *find_cgroup_root(void)
262{
263 struct mntent *mnt;
264 FILE *f;
265
266 f = fopen("/proc/mounts", "r");
267 if (f == NULL)
268 return NULL;
269
270 while ((mnt = getmntent(f))) {
271 if (strcmp(mnt->mnt_type, "cgroup2") == 0) {
272 fclose(f);
273 return strdup(mnt->mnt_dir);
274 }
275 }
276
277 fclose(f);
278 return NULL;
279}
280
281static int do_show_tree(int argc, char **argv)
282{
283 char *cgroup_root;
284 int ret;
285
286 switch (argc) {
287 case 0:
288 cgroup_root = find_cgroup_root();
289 if (!cgroup_root) {
290 p_err("cgroup v2 isn't mounted");
291 return -1;
292 }
293 break;
294 case 1:
295 cgroup_root = argv[0];
296 break;
297 default:
298 p_err("too many parameters for cgroup tree");
299 return -1;
300 }
301
302
303 if (json_output)
304 jsonw_start_array(json_wtr);
305 else
306 printf("%s\n"
307 "%-8s %-15s %-15s %-15s\n",
308 "CgroupPath",
309 "ID", "AttachType", "AttachFlags", "Name");
310
311 switch (nftw(cgroup_root, do_show_tree_fn, 1024, FTW_MOUNT)) {
312 case NFTW_ERR:
313 p_err("can't iterate over %s: %s", cgroup_root,
314 strerror(errno));
315 ret = -1;
316 break;
317 case SHOW_TREE_FN_ERR:
318 ret = -1;
319 break;
320 default:
321 ret = 0;
322 }
323
324 if (json_output)
325 jsonw_end_array(json_wtr);
326
327 if (argc == 0)
328 free(cgroup_root);
329
330 return ret;
331}
332
176static int do_attach(int argc, char **argv) 333static int do_attach(int argc, char **argv)
177{ 334{
178 enum bpf_attach_type attach_type; 335 enum bpf_attach_type attach_type;
@@ -289,6 +446,7 @@ static int do_help(int argc, char **argv)
289 446
290 fprintf(stderr, 447 fprintf(stderr,
291 "Usage: %s %s { show | list } CGROUP\n" 448 "Usage: %s %s { show | list } CGROUP\n"
449 " %s %s tree [CGROUP_ROOT]\n"
292 " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n" 450 " %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
293 " %s %s detach CGROUP ATTACH_TYPE PROG\n" 451 " %s %s detach CGROUP ATTACH_TYPE PROG\n"
294 " %s %s help\n" 452 " %s %s help\n"
@@ -298,6 +456,7 @@ static int do_help(int argc, char **argv)
298 " " HELP_SPEC_PROGRAM "\n" 456 " " HELP_SPEC_PROGRAM "\n"
299 " " HELP_SPEC_OPTIONS "\n" 457 " " HELP_SPEC_OPTIONS "\n"
300 "", 458 "",
459 bin_name, argv[-2],
301 bin_name, argv[-2], bin_name, argv[-2], 460 bin_name, argv[-2], bin_name, argv[-2],
302 bin_name, argv[-2], bin_name, argv[-2]); 461 bin_name, argv[-2], bin_name, argv[-2]);
303 462
@@ -307,6 +466,7 @@ static int do_help(int argc, char **argv)
307static const struct cmd cmds[] = { 466static const struct cmd cmds[] = {
308 { "show", do_show }, 467 { "show", do_show },
309 { "list", do_show }, 468 { "list", do_show },
469 { "tree", do_show_tree },
310 { "attach", do_attach }, 470 { "attach", do_attach },
311 { "detach", do_detach }, 471 { "detach", do_detach },
312 { "help", do_help }, 472 { "help", do_help },
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index 3f140eff039f..b3a0709ea7ed 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -31,8 +31,6 @@
31 * SOFTWARE. 31 * SOFTWARE.
32 */ 32 */
33 33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#include <ctype.h> 34#include <ctype.h>
37#include <errno.h> 35#include <errno.h>
38#include <fcntl.h> 36#include <fcntl.h>
diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
index eea7f14355f3..d15a62be6cf0 100644
--- a/tools/bpf/bpftool/main.c
+++ b/tools/bpf/bpftool/main.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -31,8 +31,6 @@
31 * SOFTWARE. 31 * SOFTWARE.
32 */ 32 */
33 33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#include <bfd.h> 34#include <bfd.h>
37#include <ctype.h> 35#include <ctype.h>
38#include <errno.h> 36#include <errno.h>
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 63fdb310b9a4..238e734d75b3 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -31,8 +31,6 @@
31 * SOFTWARE. 31 * SOFTWARE.
32 */ 32 */
33 33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#ifndef __BPF_TOOL_H 34#ifndef __BPF_TOOL_H
37#define __BPF_TOOL_H 35#define __BPF_TOOL_H
38 36
@@ -44,6 +42,7 @@
44#include <linux/compiler.h> 42#include <linux/compiler.h>
45#include <linux/kernel.h> 43#include <linux/kernel.h>
46#include <linux/hashtable.h> 44#include <linux/hashtable.h>
45#include <tools/libc_compat.h>
47 46
48#include "json_writer.h" 47#include "json_writer.h"
49 48
@@ -52,6 +51,21 @@
52#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) 51#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
53#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) 52#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
54#define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; }) 53#define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; })
54#define GET_ARG() ({ argc--; *argv++; })
55#define REQ_ARGS(cnt) \
56 ({ \
57 int _cnt = (cnt); \
58 bool _res; \
59 \
60 if (argc < _cnt) { \
61 p_err("'%s' needs at least %d arguments, %d found", \
62 argv[-1], _cnt, argc); \
63 _res = false; \
64 } else { \
65 _res = true; \
66 } \
67 _res; \
68 })
55 69
56#define ERR_MAX_LEN 1024 70#define ERR_MAX_LEN 1024
57 71
@@ -61,6 +75,8 @@
61 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" 75 "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
62#define HELP_SPEC_OPTIONS \ 76#define HELP_SPEC_OPTIONS \
63 "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }" 77 "OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }"
78#define HELP_SPEC_MAP \
79 "MAP := { id MAP_ID | pinned FILE }"
64 80
65enum bpf_obj_type { 81enum bpf_obj_type {
66 BPF_OBJ_UNKNOWN, 82 BPF_OBJ_UNKNOWN,
@@ -122,6 +138,7 @@ int do_cgroup(int argc, char **arg);
122int do_perf(int argc, char **arg); 138int do_perf(int argc, char **arg);
123 139
124int prog_parse_fd(int *argc, char ***argv); 140int prog_parse_fd(int *argc, char ***argv);
141int map_parse_fd(int *argc, char ***argv);
125int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); 142int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
126 143
127void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 144void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
@@ -133,4 +150,19 @@ unsigned int get_page_size(void);
133unsigned int get_possible_cpus(void); 150unsigned int get_possible_cpus(void);
134const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino); 151const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino);
135 152
153struct btf_dumper {
154 const struct btf *btf;
155 json_writer_t *jw;
156 bool is_plain_text;
157};
158
159/* btf_dumper_type - print data along with type information
160 * @d: an instance containing context for dumping types
161 * @type_id: index in btf->types array. this points to the type to be dumped
162 * @data: pointer the actual data, i.e. the values to be printed
163 *
164 * Returns zero on success and negative error code otherwise
165 */
166int btf_dumper_type(const struct btf_dumper *d, __u32 type_id,
167 const void *data);
136#endif 168#endif
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index f74a8bcbda87..b2ec20e562bd 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -31,11 +31,10 @@
31 * SOFTWARE. 31 * SOFTWARE.
32 */ 32 */
33 33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#include <assert.h> 34#include <assert.h>
37#include <errno.h> 35#include <errno.h>
38#include <fcntl.h> 36#include <fcntl.h>
37#include <linux/err.h>
39#include <linux/kernel.h> 38#include <linux/kernel.h>
40#include <stdbool.h> 39#include <stdbool.h>
41#include <stdio.h> 40#include <stdio.h>
@@ -47,6 +46,8 @@
47 46
48#include <bpf.h> 47#include <bpf.h>
49 48
49#include "btf.h"
50#include "json_writer.h"
50#include "main.h" 51#include "main.h"
51 52
52static const char * const map_type_name[] = { 53static const char * const map_type_name[] = {
@@ -68,6 +69,7 @@ static const char * const map_type_name[] = {
68 [BPF_MAP_TYPE_SOCKMAP] = "sockmap", 69 [BPF_MAP_TYPE_SOCKMAP] = "sockmap",
69 [BPF_MAP_TYPE_CPUMAP] = "cpumap", 70 [BPF_MAP_TYPE_CPUMAP] = "cpumap",
70 [BPF_MAP_TYPE_SOCKHASH] = "sockhash", 71 [BPF_MAP_TYPE_SOCKHASH] = "sockhash",
72 [BPF_MAP_TYPE_CGROUP_STORAGE] = "cgroup_storage",
71}; 73};
72 74
73static bool map_is_per_cpu(__u32 type) 75static bool map_is_per_cpu(__u32 type)
@@ -97,7 +99,7 @@ static void *alloc_value(struct bpf_map_info *info)
97 return malloc(info->value_size); 99 return malloc(info->value_size);
98} 100}
99 101
100static int map_parse_fd(int *argc, char ***argv) 102int map_parse_fd(int *argc, char ***argv)
101{ 103{
102 int fd; 104 int fd;
103 105
@@ -152,8 +154,109 @@ int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len)
152 return fd; 154 return fd;
153} 155}
154 156
157static int do_dump_btf(const struct btf_dumper *d,
158 struct bpf_map_info *map_info, void *key,
159 void *value)
160{
161 int ret;
162
163 /* start of key-value pair */
164 jsonw_start_object(d->jw);
165
166 jsonw_name(d->jw, "key");
167
168 ret = btf_dumper_type(d, map_info->btf_key_type_id, key);
169 if (ret)
170 goto err_end_obj;
171
172 jsonw_name(d->jw, "value");
173
174 ret = btf_dumper_type(d, map_info->btf_value_type_id, value);
175
176err_end_obj:
177 /* end of key-value pair */
178 jsonw_end_object(d->jw);
179
180 return ret;
181}
182
183static int get_btf(struct bpf_map_info *map_info, struct btf **btf)
184{
185 struct bpf_btf_info btf_info = { 0 };
186 __u32 len = sizeof(btf_info);
187 __u32 last_size;
188 int btf_fd;
189 void *ptr;
190 int err;
191
192 err = 0;
193 *btf = NULL;
194 btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id);
195 if (btf_fd < 0)
196 return 0;
197
198 /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
199 * let's start with a sane default - 4KiB here - and resize it only if
200 * bpf_obj_get_info_by_fd() needs a bigger buffer.
201 */
202 btf_info.btf_size = 4096;
203 last_size = btf_info.btf_size;
204 ptr = malloc(last_size);
205 if (!ptr) {
206 err = -ENOMEM;
207 goto exit_free;
208 }
209
210 bzero(ptr, last_size);
211 btf_info.btf = ptr_to_u64(ptr);
212 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
213
214 if (!err && btf_info.btf_size > last_size) {
215 void *temp_ptr;
216
217 last_size = btf_info.btf_size;
218 temp_ptr = realloc(ptr, last_size);
219 if (!temp_ptr) {
220 err = -ENOMEM;
221 goto exit_free;
222 }
223 ptr = temp_ptr;
224 bzero(ptr, last_size);
225 btf_info.btf = ptr_to_u64(ptr);
226 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
227 }
228
229 if (err || btf_info.btf_size > last_size) {
230 err = errno;
231 goto exit_free;
232 }
233
234 *btf = btf__new((__u8 *)btf_info.btf, btf_info.btf_size, NULL);
235 if (IS_ERR(*btf)) {
236 err = PTR_ERR(*btf);
237 *btf = NULL;
238 }
239
240exit_free:
241 close(btf_fd);
242 free(ptr);
243
244 return err;
245}
246
247static json_writer_t *get_btf_writer(void)
248{
249 json_writer_t *jw = jsonw_new(stdout);
250
251 if (!jw)
252 return NULL;
253 jsonw_pretty(jw, true);
254
255 return jw;
256}
257
155static void print_entry_json(struct bpf_map_info *info, unsigned char *key, 258static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
156 unsigned char *value) 259 unsigned char *value, struct btf *btf)
157{ 260{
158 jsonw_start_object(json_wtr); 261 jsonw_start_object(json_wtr);
159 262
@@ -162,6 +265,16 @@ static void print_entry_json(struct bpf_map_info *info, unsigned char *key,
162 print_hex_data_json(key, info->key_size); 265 print_hex_data_json(key, info->key_size);
163 jsonw_name(json_wtr, "value"); 266 jsonw_name(json_wtr, "value");
164 print_hex_data_json(value, info->value_size); 267 print_hex_data_json(value, info->value_size);
268 if (btf) {
269 struct btf_dumper d = {
270 .btf = btf,
271 .jw = json_wtr,
272 .is_plain_text = false,
273 };
274
275 jsonw_name(json_wtr, "formatted");
276 do_dump_btf(&d, info, key, value);
277 }
165 } else { 278 } else {
166 unsigned int i, n, step; 279 unsigned int i, n, step;
167 280
@@ -514,10 +627,12 @@ static int do_show(int argc, char **argv)
514 627
515static int do_dump(int argc, char **argv) 628static int do_dump(int argc, char **argv)
516{ 629{
630 struct bpf_map_info info = {};
517 void *key, *value, *prev_key; 631 void *key, *value, *prev_key;
518 unsigned int num_elems = 0; 632 unsigned int num_elems = 0;
519 struct bpf_map_info info = {};
520 __u32 len = sizeof(info); 633 __u32 len = sizeof(info);
634 json_writer_t *btf_wtr;
635 struct btf *btf = NULL;
521 int err; 636 int err;
522 int fd; 637 int fd;
523 638
@@ -543,8 +658,27 @@ static int do_dump(int argc, char **argv)
543 } 658 }
544 659
545 prev_key = NULL; 660 prev_key = NULL;
661
662 err = get_btf(&info, &btf);
663 if (err) {
664 p_err("failed to get btf");
665 goto exit_free;
666 }
667
546 if (json_output) 668 if (json_output)
547 jsonw_start_array(json_wtr); 669 jsonw_start_array(json_wtr);
670 else
671 if (btf) {
672 btf_wtr = get_btf_writer();
673 if (!btf_wtr) {
674 p_info("failed to create json writer for btf. falling back to plain output");
675 btf__free(btf);
676 btf = NULL;
677 } else {
678 jsonw_start_array(btf_wtr);
679 }
680 }
681
548 while (true) { 682 while (true) {
549 err = bpf_map_get_next_key(fd, prev_key, key); 683 err = bpf_map_get_next_key(fd, prev_key, key);
550 if (err) { 684 if (err) {
@@ -555,9 +689,19 @@ static int do_dump(int argc, char **argv)
555 689
556 if (!bpf_map_lookup_elem(fd, key, value)) { 690 if (!bpf_map_lookup_elem(fd, key, value)) {
557 if (json_output) 691 if (json_output)
558 print_entry_json(&info, key, value); 692 print_entry_json(&info, key, value, btf);
559 else 693 else
560 print_entry_plain(&info, key, value); 694 if (btf) {
695 struct btf_dumper d = {
696 .btf = btf,
697 .jw = btf_wtr,
698 .is_plain_text = true,
699 };
700
701 do_dump_btf(&d, &info, key, value);
702 } else {
703 print_entry_plain(&info, key, value);
704 }
561 } else { 705 } else {
562 if (json_output) { 706 if (json_output) {
563 jsonw_name(json_wtr, "key"); 707 jsonw_name(json_wtr, "key");
@@ -580,14 +724,19 @@ static int do_dump(int argc, char **argv)
580 724
581 if (json_output) 725 if (json_output)
582 jsonw_end_array(json_wtr); 726 jsonw_end_array(json_wtr);
583 else 727 else if (btf) {
728 jsonw_end_array(btf_wtr);
729 jsonw_destroy(&btf_wtr);
730 } else {
584 printf("Found %u element%s\n", num_elems, 731 printf("Found %u element%s\n", num_elems,
585 num_elems != 1 ? "s" : ""); 732 num_elems != 1 ? "s" : "");
733 }
586 734
587exit_free: 735exit_free:
588 free(key); 736 free(key);
589 free(value); 737 free(value);
590 close(fd); 738 close(fd);
739 btf__free(btf);
591 740
592 return err; 741 return err;
593} 742}
@@ -643,6 +792,8 @@ static int do_lookup(int argc, char **argv)
643{ 792{
644 struct bpf_map_info info = {}; 793 struct bpf_map_info info = {};
645 __u32 len = sizeof(info); 794 __u32 len = sizeof(info);
795 json_writer_t *btf_wtr;
796 struct btf *btf = NULL;
646 void *key, *value; 797 void *key, *value;
647 int err; 798 int err;
648 int fd; 799 int fd;
@@ -667,27 +818,60 @@ static int do_lookup(int argc, char **argv)
667 goto exit_free; 818 goto exit_free;
668 819
669 err = bpf_map_lookup_elem(fd, key, value); 820 err = bpf_map_lookup_elem(fd, key, value);
670 if (!err) { 821 if (err) {
671 if (json_output) 822 if (errno == ENOENT) {
672 print_entry_json(&info, key, value); 823 if (json_output) {
673 else 824 jsonw_null(json_wtr);
825 } else {
826 printf("key:\n");
827 fprint_hex(stdout, key, info.key_size, " ");
828 printf("\n\nNot found\n");
829 }
830 } else {
831 p_err("lookup failed: %s", strerror(errno));
832 }
833
834 goto exit_free;
835 }
836
837 /* here means bpf_map_lookup_elem() succeeded */
838 err = get_btf(&info, &btf);
839 if (err) {
840 p_err("failed to get btf");
841 goto exit_free;
842 }
843
844 if (json_output) {
845 print_entry_json(&info, key, value, btf);
846 } else if (btf) {
847 /* if here json_wtr wouldn't have been initialised,
848 * so let's create separate writer for btf
849 */
850 btf_wtr = get_btf_writer();
851 if (!btf_wtr) {
852 p_info("failed to create json writer for btf. falling back to plain output");
853 btf__free(btf);
854 btf = NULL;
674 print_entry_plain(&info, key, value); 855 print_entry_plain(&info, key, value);
675 } else if (errno == ENOENT) {
676 if (json_output) {
677 jsonw_null(json_wtr);
678 } else { 856 } else {
679 printf("key:\n"); 857 struct btf_dumper d = {
680 fprint_hex(stdout, key, info.key_size, " "); 858 .btf = btf,
681 printf("\n\nNot found\n"); 859 .jw = btf_wtr,
860 .is_plain_text = true,
861 };
862
863 do_dump_btf(&d, &info, key, value);
864 jsonw_destroy(&btf_wtr);
682 } 865 }
683 } else { 866 } else {
684 p_err("lookup failed: %s", strerror(errno)); 867 print_entry_plain(&info, key, value);
685 } 868 }
686 869
687exit_free: 870exit_free:
688 free(key); 871 free(key);
689 free(value); 872 free(value);
690 close(fd); 873 close(fd);
874 btf__free(btf);
691 875
692 return err; 876 return err;
693} 877}
@@ -830,7 +1014,7 @@ static int do_help(int argc, char **argv)
830 " %s %s event_pipe MAP [cpu N index M]\n" 1014 " %s %s event_pipe MAP [cpu N index M]\n"
831 " %s %s help\n" 1015 " %s %s help\n"
832 "\n" 1016 "\n"
833 " MAP := { id MAP_ID | pinned FILE }\n" 1017 " " HELP_SPEC_MAP "\n"
834 " DATA := { [hex] BYTES }\n" 1018 " DATA := { [hex] BYTES }\n"
835 " " HELP_SPEC_PROGRAM "\n" 1019 " " HELP_SPEC_PROGRAM "\n"
836 " VALUE := { DATA | MAP | PROG }\n" 1020 " VALUE := { DATA | MAP | PROG }\n"
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 959aa53ab678..dce960d22106 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -31,8 +31,7 @@
31 * SOFTWARE. 31 * SOFTWARE.
32 */ 32 */
33 33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */ 34#define _GNU_SOURCE
35
36#include <errno.h> 35#include <errno.h>
37#include <fcntl.h> 36#include <fcntl.h>
38#include <stdarg.h> 37#include <stdarg.h>
@@ -41,9 +40,12 @@
41#include <string.h> 40#include <string.h>
42#include <time.h> 41#include <time.h>
43#include <unistd.h> 42#include <unistd.h>
43#include <net/if.h>
44#include <sys/types.h> 44#include <sys/types.h>
45#include <sys/stat.h> 45#include <sys/stat.h>
46 46
47#include <linux/err.h>
48
47#include <bpf.h> 49#include <bpf.h>
48#include <libbpf.h> 50#include <libbpf.h>
49 51
@@ -681,31 +683,247 @@ static int do_pin(int argc, char **argv)
681 return err; 683 return err;
682} 684}
683 685
686struct map_replace {
687 int idx;
688 int fd;
689 char *name;
690};
691
692int map_replace_compar(const void *p1, const void *p2)
693{
694 const struct map_replace *a = p1, *b = p2;
695
696 return a->idx - b->idx;
697}
698
684static int do_load(int argc, char **argv) 699static int do_load(int argc, char **argv)
685{ 700{
701 enum bpf_attach_type expected_attach_type;
702 struct bpf_object_open_attr attr = {
703 .prog_type = BPF_PROG_TYPE_UNSPEC,
704 };
705 struct map_replace *map_replace = NULL;
706 unsigned int old_map_fds = 0;
707 struct bpf_program *prog;
686 struct bpf_object *obj; 708 struct bpf_object *obj;
687 int prog_fd; 709 struct bpf_map *map;
688 710 const char *pinfile;
689 if (argc != 2) 711 unsigned int i, j;
690 usage(); 712 __u32 ifindex = 0;
713 int idx, err;
691 714
692 if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) { 715 if (!REQ_ARGS(2))
693 p_err("failed to load program");
694 return -1; 716 return -1;
717 attr.file = GET_ARG();
718 pinfile = GET_ARG();
719
720 while (argc) {
721 if (is_prefix(*argv, "type")) {
722 char *type;
723
724 NEXT_ARG();
725
726 if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) {
727 p_err("program type already specified");
728 goto err_free_reuse_maps;
729 }
730 if (!REQ_ARGS(1))
731 goto err_free_reuse_maps;
732
733 /* Put a '/' at the end of type to appease libbpf */
734 type = malloc(strlen(*argv) + 2);
735 if (!type) {
736 p_err("mem alloc failed");
737 goto err_free_reuse_maps;
738 }
739 *type = 0;
740 strcat(type, *argv);
741 strcat(type, "/");
742
743 err = libbpf_prog_type_by_name(type, &attr.prog_type,
744 &expected_attach_type);
745 free(type);
746 if (err < 0) {
747 p_err("unknown program type '%s'", *argv);
748 goto err_free_reuse_maps;
749 }
750 NEXT_ARG();
751 } else if (is_prefix(*argv, "map")) {
752 char *endptr, *name;
753 int fd;
754
755 NEXT_ARG();
756
757 if (!REQ_ARGS(4))
758 goto err_free_reuse_maps;
759
760 if (is_prefix(*argv, "idx")) {
761 NEXT_ARG();
762
763 idx = strtoul(*argv, &endptr, 0);
764 if (*endptr) {
765 p_err("can't parse %s as IDX", *argv);
766 goto err_free_reuse_maps;
767 }
768 name = NULL;
769 } else if (is_prefix(*argv, "name")) {
770 NEXT_ARG();
771
772 name = *argv;
773 idx = -1;
774 } else {
775 p_err("expected 'idx' or 'name', got: '%s'?",
776 *argv);
777 goto err_free_reuse_maps;
778 }
779 NEXT_ARG();
780
781 fd = map_parse_fd(&argc, &argv);
782 if (fd < 0)
783 goto err_free_reuse_maps;
784
785 map_replace = reallocarray(map_replace, old_map_fds + 1,
786 sizeof(*map_replace));
787 if (!map_replace) {
788 p_err("mem alloc failed");
789 goto err_free_reuse_maps;
790 }
791 map_replace[old_map_fds].idx = idx;
792 map_replace[old_map_fds].name = name;
793 map_replace[old_map_fds].fd = fd;
794 old_map_fds++;
795 } else if (is_prefix(*argv, "dev")) {
796 NEXT_ARG();
797
798 if (ifindex) {
799 p_err("offload device already specified");
800 goto err_free_reuse_maps;
801 }
802 if (!REQ_ARGS(1))
803 goto err_free_reuse_maps;
804
805 ifindex = if_nametoindex(*argv);
806 if (!ifindex) {
807 p_err("unrecognized netdevice '%s': %s",
808 *argv, strerror(errno));
809 goto err_free_reuse_maps;
810 }
811 NEXT_ARG();
812 } else {
813 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
814 *argv);
815 goto err_free_reuse_maps;
816 }
817 }
818
819 obj = bpf_object__open_xattr(&attr);
820 if (IS_ERR_OR_NULL(obj)) {
821 p_err("failed to open object file");
822 goto err_free_reuse_maps;
823 }
824
825 prog = bpf_program__next(NULL, obj);
826 if (!prog) {
827 p_err("object file doesn't contain any bpf program");
828 goto err_close_obj;
829 }
830
831 bpf_program__set_ifindex(prog, ifindex);
832 if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
833 const char *sec_name = bpf_program__title(prog, false);
834
835 err = libbpf_prog_type_by_name(sec_name, &attr.prog_type,
836 &expected_attach_type);
837 if (err < 0) {
838 p_err("failed to guess program type based on section name %s\n",
839 sec_name);
840 goto err_close_obj;
841 }
842 }
843 bpf_program__set_type(prog, attr.prog_type);
844 bpf_program__set_expected_attach_type(prog, expected_attach_type);
845
846 qsort(map_replace, old_map_fds, sizeof(*map_replace),
847 map_replace_compar);
848
849 /* After the sort maps by name will be first on the list, because they
850 * have idx == -1. Resolve them.
851 */
852 j = 0;
853 while (j < old_map_fds && map_replace[j].name) {
854 i = 0;
855 bpf_map__for_each(map, obj) {
856 if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
857 map_replace[j].idx = i;
858 break;
859 }
860 i++;
861 }
862 if (map_replace[j].idx == -1) {
863 p_err("unable to find map '%s'", map_replace[j].name);
864 goto err_close_obj;
865 }
866 j++;
867 }
868 /* Resort if any names were resolved */
869 if (j)
870 qsort(map_replace, old_map_fds, sizeof(*map_replace),
871 map_replace_compar);
872
873 /* Set ifindex and name reuse */
874 j = 0;
875 idx = 0;
876 bpf_map__for_each(map, obj) {
877 if (!bpf_map__is_offload_neutral(map))
878 bpf_map__set_ifindex(map, ifindex);
879
880 if (j < old_map_fds && idx == map_replace[j].idx) {
881 err = bpf_map__reuse_fd(map, map_replace[j++].fd);
882 if (err) {
883 p_err("unable to set up map reuse: %d", err);
884 goto err_close_obj;
885 }
886
887 /* Next reuse wants to apply to the same map */
888 if (j < old_map_fds && map_replace[j].idx == idx) {
889 p_err("replacement for map idx %d specified more than once",
890 idx);
891 goto err_close_obj;
892 }
893 }
894
895 idx++;
896 }
897 if (j < old_map_fds) {
898 p_err("map idx '%d' not used", map_replace[j].idx);
899 goto err_close_obj;
900 }
901
902 err = bpf_object__load(obj);
903 if (err) {
904 p_err("failed to load object file");
905 goto err_close_obj;
695 } 906 }
696 907
697 if (do_pin_fd(prog_fd, argv[1])) 908 if (do_pin_fd(bpf_program__fd(prog), pinfile))
698 goto err_close_obj; 909 goto err_close_obj;
699 910
700 if (json_output) 911 if (json_output)
701 jsonw_null(json_wtr); 912 jsonw_null(json_wtr);
702 913
703 bpf_object__close(obj); 914 bpf_object__close(obj);
915 for (i = 0; i < old_map_fds; i++)
916 close(map_replace[i].fd);
917 free(map_replace);
704 918
705 return 0; 919 return 0;
706 920
707err_close_obj: 921err_close_obj:
708 bpf_object__close(obj); 922 bpf_object__close(obj);
923err_free_reuse_maps:
924 for (i = 0; i < old_map_fds; i++)
925 close(map_replace[i].fd);
926 free(map_replace);
709 return -1; 927 return -1;
710} 928}
711 929
@@ -721,10 +939,19 @@ static int do_help(int argc, char **argv)
721 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 939 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
722 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 940 " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
723 " %s %s pin PROG FILE\n" 941 " %s %s pin PROG FILE\n"
724 " %s %s load OBJ FILE\n" 942 " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n"
943 " [map { idx IDX | name NAME } MAP]\n"
725 " %s %s help\n" 944 " %s %s help\n"
726 "\n" 945 "\n"
946 " " HELP_SPEC_MAP "\n"
727 " " HELP_SPEC_PROGRAM "\n" 947 " " HELP_SPEC_PROGRAM "\n"
948 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
949 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
950 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
951 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
952 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
953 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
954 " cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
728 " " HELP_SPEC_OPTIONS "\n" 955 " " HELP_SPEC_OPTIONS "\n"
729 "", 956 "",
730 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 957 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
index b97f1da60dd1..3284759df98a 100644
--- a/tools/bpf/bpftool/xlated_dumper.c
+++ b/tools/bpf/bpftool/xlated_dumper.c
@@ -35,6 +35,7 @@
35 * POSSIBILITY OF SUCH DAMAGE. 35 * POSSIBILITY OF SUCH DAMAGE.
36 */ 36 */
37 37
38#define _GNU_SOURCE
38#include <stdarg.h> 39#include <stdarg.h>
39#include <stdio.h> 40#include <stdio.h>
40#include <stdlib.h> 41#include <stdlib.h>
@@ -66,9 +67,8 @@ void kernel_syms_load(struct dump_data *dd)
66 while (!feof(fp)) { 67 while (!feof(fp)) {
67 if (!fgets(buff, sizeof(buff), fp)) 68 if (!fgets(buff, sizeof(buff), fp))
68 break; 69 break;
69 tmp = realloc(dd->sym_mapping, 70 tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1,
70 (dd->sym_count + 1) * 71 sizeof(*dd->sym_mapping));
71 sizeof(*dd->sym_mapping));
72 if (!tmp) { 72 if (!tmp) {
73out: 73out:
74 free(dd->sym_mapping); 74 free(dd->sym_mapping);
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 5b6dda3b1ca8..f216b2f5c3d7 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -57,6 +57,7 @@ FEATURE_TESTS_BASIC := \
57 libunwind-aarch64 \ 57 libunwind-aarch64 \
58 pthread-attr-setaffinity-np \ 58 pthread-attr-setaffinity-np \
59 pthread-barrier \ 59 pthread-barrier \
60 reallocarray \
60 stackprotector-all \ 61 stackprotector-all \
61 timerfd \ 62 timerfd \
62 libdw-dwarf-unwind \ 63 libdw-dwarf-unwind \
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index dac9563b5470..0516259be70f 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -14,6 +14,7 @@ FILES= \
14 test-libaudit.bin \ 14 test-libaudit.bin \
15 test-libbfd.bin \ 15 test-libbfd.bin \
16 test-disassembler-four-args.bin \ 16 test-disassembler-four-args.bin \
17 test-reallocarray.bin \
17 test-liberty.bin \ 18 test-liberty.bin \
18 test-liberty-z.bin \ 19 test-liberty-z.bin \
19 test-cplus-demangle.bin \ 20 test-cplus-demangle.bin \
@@ -204,6 +205,9 @@ $(OUTPUT)test-libbfd.bin:
204$(OUTPUT)test-disassembler-four-args.bin: 205$(OUTPUT)test-disassembler-four-args.bin:
205 $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes 206 $(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
206 207
208$(OUTPUT)test-reallocarray.bin:
209 $(BUILD)
210
207$(OUTPUT)test-liberty.bin: 211$(OUTPUT)test-liberty.bin:
208 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty 212 $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
209 213
diff --git a/tools/build/feature/test-reallocarray.c b/tools/build/feature/test-reallocarray.c
new file mode 100644
index 000000000000..8170de35150d
--- /dev/null
+++ b/tools/build/feature/test-reallocarray.c
@@ -0,0 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
2#define _GNU_SOURCE
3#include <stdlib.h>
4
5int main(void)
6{
7 return !!reallocarray(NULL, 1, 1);
8}
diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h
index 70fe61295733..0d35f18006a1 100644
--- a/tools/include/linux/compiler-gcc.h
+++ b/tools/include/linux/compiler-gcc.h
@@ -36,3 +36,7 @@
36#endif 36#endif
37#define __printf(a, b) __attribute__((format(printf, a, b))) 37#define __printf(a, b) __attribute__((format(printf, a, b)))
38#define __scanf(a, b) __attribute__((format(scanf, a, b))) 38#define __scanf(a, b) __attribute__((format(scanf, a, b)))
39
40#if GCC_VERSION >= 50100
41#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
42#endif
diff --git a/tools/include/linux/overflow.h b/tools/include/linux/overflow.h
new file mode 100644
index 000000000000..8712ff70995f
--- /dev/null
+++ b/tools/include/linux/overflow.h
@@ -0,0 +1,278 @@
1/* SPDX-License-Identifier: GPL-2.0 OR MIT */
2#ifndef __LINUX_OVERFLOW_H
3#define __LINUX_OVERFLOW_H
4
5#include <linux/compiler.h>
6
7/*
8 * In the fallback code below, we need to compute the minimum and
9 * maximum values representable in a given type. These macros may also
10 * be useful elsewhere, so we provide them outside the
11 * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block.
12 *
13 * It would seem more obvious to do something like
14 *
15 * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
16 * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
17 *
18 * Unfortunately, the middle expressions, strictly speaking, have
19 * undefined behaviour, and at least some versions of gcc warn about
20 * the type_max expression (but not if -fsanitize=undefined is in
21 * effect; in that case, the warning is deferred to runtime...).
22 *
23 * The slightly excessive casting in type_min is to make sure the
24 * macros also produce sensible values for the exotic type _Bool. [The
25 * overflow checkers only almost work for _Bool, but that's
26 * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
27 * _Bools. Besides, the gcc builtins don't allow _Bool* as third
28 * argument.]
29 *
30 * Idea stolen from
31 * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
32 * credit to Christian Biere.
33 */
34#define is_signed_type(type) (((type)(-1)) < (type)1)
35#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
36#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
37#define type_min(T) ((T)((T)-type_max(T)-(T)1))
38
39
40#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
41/*
42 * For simplicity and code hygiene, the fallback code below insists on
43 * a, b and *d having the same type (similar to the min() and max()
44 * macros), whereas gcc's type-generic overflow checkers accept
45 * different types. Hence we don't just make check_add_overflow an
46 * alias for __builtin_add_overflow, but add type checks similar to
47 * below.
48 */
49#define check_add_overflow(a, b, d) ({ \
50 typeof(a) __a = (a); \
51 typeof(b) __b = (b); \
52 typeof(d) __d = (d); \
53 (void) (&__a == &__b); \
54 (void) (&__a == __d); \
55 __builtin_add_overflow(__a, __b, __d); \
56})
57
58#define check_sub_overflow(a, b, d) ({ \
59 typeof(a) __a = (a); \
60 typeof(b) __b = (b); \
61 typeof(d) __d = (d); \
62 (void) (&__a == &__b); \
63 (void) (&__a == __d); \
64 __builtin_sub_overflow(__a, __b, __d); \
65})
66
67#define check_mul_overflow(a, b, d) ({ \
68 typeof(a) __a = (a); \
69 typeof(b) __b = (b); \
70 typeof(d) __d = (d); \
71 (void) (&__a == &__b); \
72 (void) (&__a == __d); \
73 __builtin_mul_overflow(__a, __b, __d); \
74})
75
76#else
77
78
79/* Checking for unsigned overflow is relatively easy without causing UB. */
80#define __unsigned_add_overflow(a, b, d) ({ \
81 typeof(a) __a = (a); \
82 typeof(b) __b = (b); \
83 typeof(d) __d = (d); \
84 (void) (&__a == &__b); \
85 (void) (&__a == __d); \
86 *__d = __a + __b; \
87 *__d < __a; \
88})
89#define __unsigned_sub_overflow(a, b, d) ({ \
90 typeof(a) __a = (a); \
91 typeof(b) __b = (b); \
92 typeof(d) __d = (d); \
93 (void) (&__a == &__b); \
94 (void) (&__a == __d); \
95 *__d = __a - __b; \
96 __a < __b; \
97})
98/*
99 * If one of a or b is a compile-time constant, this avoids a division.
100 */
101#define __unsigned_mul_overflow(a, b, d) ({ \
102 typeof(a) __a = (a); \
103 typeof(b) __b = (b); \
104 typeof(d) __d = (d); \
105 (void) (&__a == &__b); \
106 (void) (&__a == __d); \
107 *__d = __a * __b; \
108 __builtin_constant_p(__b) ? \
109 __b > 0 && __a > type_max(typeof(__a)) / __b : \
110 __a > 0 && __b > type_max(typeof(__b)) / __a; \
111})
112
113/*
114 * For signed types, detecting overflow is much harder, especially if
115 * we want to avoid UB. But the interface of these macros is such that
116 * we must provide a result in *d, and in fact we must produce the
117 * result promised by gcc's builtins, which is simply the possibly
118 * wrapped-around value. Fortunately, we can just formally do the
119 * operations in the widest relevant unsigned type (u64) and then
120 * truncate the result - gcc is smart enough to generate the same code
121 * with and without the (u64) casts.
122 */
123
124/*
125 * Adding two signed integers can overflow only if they have the same
126 * sign, and overflow has happened iff the result has the opposite
127 * sign.
128 */
129#define __signed_add_overflow(a, b, d) ({ \
130 typeof(a) __a = (a); \
131 typeof(b) __b = (b); \
132 typeof(d) __d = (d); \
133 (void) (&__a == &__b); \
134 (void) (&__a == __d); \
135 *__d = (u64)__a + (u64)__b; \
136 (((~(__a ^ __b)) & (*__d ^ __a)) \
137 & type_min(typeof(__a))) != 0; \
138})
139
140/*
141 * Subtraction is similar, except that overflow can now happen only
142 * when the signs are opposite. In this case, overflow has happened if
143 * the result has the opposite sign of a.
144 */
145#define __signed_sub_overflow(a, b, d) ({ \
146 typeof(a) __a = (a); \
147 typeof(b) __b = (b); \
148 typeof(d) __d = (d); \
149 (void) (&__a == &__b); \
150 (void) (&__a == __d); \
151 *__d = (u64)__a - (u64)__b; \
152 ((((__a ^ __b)) & (*__d ^ __a)) \
153 & type_min(typeof(__a))) != 0; \
154})
155
156/*
157 * Signed multiplication is rather hard. gcc always follows C99, so
158 * division is truncated towards 0. This means that we can write the
159 * overflow check like this:
160 *
161 * (a > 0 && (b > MAX/a || b < MIN/a)) ||
162 * (a < -1 && (b > MIN/a || b < MAX/a) ||
163 * (a == -1 && b == MIN)
164 *
165 * The redundant casts of -1 are to silence an annoying -Wtype-limits
166 * (included in -Wextra) warning: When the type is u8 or u16, the
167 * __b_c_e in check_mul_overflow obviously selects
168 * __unsigned_mul_overflow, but unfortunately gcc still parses this
169 * code and warns about the limited range of __b.
170 */
171
172#define __signed_mul_overflow(a, b, d) ({ \
173 typeof(a) __a = (a); \
174 typeof(b) __b = (b); \
175 typeof(d) __d = (d); \
176 typeof(a) __tmax = type_max(typeof(a)); \
177 typeof(a) __tmin = type_min(typeof(a)); \
178 (void) (&__a == &__b); \
179 (void) (&__a == __d); \
180 *__d = (u64)__a * (u64)__b; \
181 (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \
182 (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \
183 (__b == (typeof(__b))-1 && __a == __tmin); \
184})
185
186
187#define check_add_overflow(a, b, d) \
188 __builtin_choose_expr(is_signed_type(typeof(a)), \
189 __signed_add_overflow(a, b, d), \
190 __unsigned_add_overflow(a, b, d))
191
192#define check_sub_overflow(a, b, d) \
193 __builtin_choose_expr(is_signed_type(typeof(a)), \
194 __signed_sub_overflow(a, b, d), \
195 __unsigned_sub_overflow(a, b, d))
196
197#define check_mul_overflow(a, b, d) \
198 __builtin_choose_expr(is_signed_type(typeof(a)), \
199 __signed_mul_overflow(a, b, d), \
200 __unsigned_mul_overflow(a, b, d))
201
202
203#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
204
205/**
206 * array_size() - Calculate size of 2-dimensional array.
207 *
208 * @a: dimension one
209 * @b: dimension two
210 *
211 * Calculates size of 2-dimensional array: @a * @b.
212 *
213 * Returns: number of bytes needed to represent the array or SIZE_MAX on
214 * overflow.
215 */
216static inline __must_check size_t array_size(size_t a, size_t b)
217{
218 size_t bytes;
219
220 if (check_mul_overflow(a, b, &bytes))
221 return SIZE_MAX;
222
223 return bytes;
224}
225
226/**
227 * array3_size() - Calculate size of 3-dimensional array.
228 *
229 * @a: dimension one
230 * @b: dimension two
231 * @c: dimension three
232 *
233 * Calculates size of 3-dimensional array: @a * @b * @c.
234 *
235 * Returns: number of bytes needed to represent the array or SIZE_MAX on
236 * overflow.
237 */
238static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
239{
240 size_t bytes;
241
242 if (check_mul_overflow(a, b, &bytes))
243 return SIZE_MAX;
244 if (check_mul_overflow(bytes, c, &bytes))
245 return SIZE_MAX;
246
247 return bytes;
248}
249
250static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
251{
252 size_t bytes;
253
254 if (check_mul_overflow(n, size, &bytes))
255 return SIZE_MAX;
256 if (check_add_overflow(bytes, c, &bytes))
257 return SIZE_MAX;
258
259 return bytes;
260}
261
262/**
263 * struct_size() - Calculate size of structure with trailing array.
264 * @p: Pointer to the structure.
265 * @member: Name of the array member.
266 * @n: Number of elements in the array.
267 *
268 * Calculates size of memory needed for structure @p followed by an
269 * array of @n @member elements.
270 *
271 * Return: number of bytes needed or SIZE_MAX on overflow.
272 */
273#define struct_size(p, member, n) \
274 __ab_c_size(n, \
275 sizeof(*(p)->member) + __must_be_array((p)->member),\
276 sizeof(*(p)))
277
278#endif /* __LINUX_OVERFLOW_H */
diff --git a/tools/include/tools/libc_compat.h b/tools/include/tools/libc_compat.h
new file mode 100644
index 000000000000..664ced8cb1b0
--- /dev/null
+++ b/tools/include/tools/libc_compat.h
@@ -0,0 +1,20 @@
1// SPDX-License-Identifier: GPL-2.0+
2/* Copyright (C) 2018 Netronome Systems, Inc. */
3
4#ifndef __TOOLS_LIBC_COMPAT_H
5#define __TOOLS_LIBC_COMPAT_H
6
7#include <stdlib.h>
8#include <linux/overflow.h>
9
10#ifdef COMPAT_NEED_REALLOCARRAY
11static inline void *reallocarray(void *ptr, size_t nmemb, size_t size)
12{
13 size_t bytes;
14
15 if (unlikely(check_mul_overflow(nmemb, size, &bytes)))
16 return NULL;
17 return realloc(ptr, bytes);
18}
19#endif
20#endif
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index b7db3261c62d..66917a4eba27 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -75,6 +75,11 @@ struct bpf_lpm_trie_key {
75 __u8 data[0]; /* Arbitrary size */ 75 __u8 data[0]; /* Arbitrary size */
76}; 76};
77 77
78struct bpf_cgroup_storage_key {
79 __u64 cgroup_inode_id; /* cgroup inode id */
80 __u32 attach_type; /* program attach type */
81};
82
78/* BPF syscall commands, see bpf(2) man-page for details. */ 83/* BPF syscall commands, see bpf(2) man-page for details. */
79enum bpf_cmd { 84enum bpf_cmd {
80 BPF_MAP_CREATE, 85 BPF_MAP_CREATE,
@@ -120,6 +125,8 @@ enum bpf_map_type {
120 BPF_MAP_TYPE_CPUMAP, 125 BPF_MAP_TYPE_CPUMAP,
121 BPF_MAP_TYPE_XSKMAP, 126 BPF_MAP_TYPE_XSKMAP,
122 BPF_MAP_TYPE_SOCKHASH, 127 BPF_MAP_TYPE_SOCKHASH,
128 BPF_MAP_TYPE_CGROUP_STORAGE,
129 BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
123}; 130};
124 131
125enum bpf_prog_type { 132enum bpf_prog_type {
@@ -144,6 +151,7 @@ enum bpf_prog_type {
144 BPF_PROG_TYPE_CGROUP_SOCK_ADDR, 151 BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
145 BPF_PROG_TYPE_LWT_SEG6LOCAL, 152 BPF_PROG_TYPE_LWT_SEG6LOCAL,
146 BPF_PROG_TYPE_LIRC_MODE2, 153 BPF_PROG_TYPE_LIRC_MODE2,
154 BPF_PROG_TYPE_SK_REUSEPORT,
147}; 155};
148 156
149enum bpf_attach_type { 157enum bpf_attach_type {
@@ -1371,6 +1379,20 @@ union bpf_attr {
1371 * A 8-byte long non-decreasing number on success, or 0 if the 1379 * A 8-byte long non-decreasing number on success, or 0 if the
1372 * socket field is missing inside *skb*. 1380 * socket field is missing inside *skb*.
1373 * 1381 *
1382 * u64 bpf_get_socket_cookie(struct bpf_sock_addr *ctx)
1383 * Description
1384 * Equivalent to bpf_get_socket_cookie() helper that accepts
1385 * *skb*, but gets socket from **struct bpf_sock_addr** contex.
1386 * Return
1387 * A 8-byte long non-decreasing number.
1388 *
1389 * u64 bpf_get_socket_cookie(struct bpf_sock_ops *ctx)
1390 * Description
1391 * Equivalent to bpf_get_socket_cookie() helper that accepts
1392 * *skb*, but gets socket from **struct bpf_sock_ops** contex.
1393 * Return
1394 * A 8-byte long non-decreasing number.
1395 *
1374 * u32 bpf_get_socket_uid(struct sk_buff *skb) 1396 * u32 bpf_get_socket_uid(struct sk_buff *skb)
1375 * Return 1397 * Return
1376 * The owner UID of the socket associated to *skb*. If the socket 1398 * The owner UID of the socket associated to *skb*. If the socket
@@ -1826,7 +1848,7 @@ union bpf_attr {
1826 * A non-negative value equal to or less than *size* on success, 1848 * A non-negative value equal to or less than *size* on success,
1827 * or a negative error in case of failure. 1849 * or a negative error in case of failure.
1828 * 1850 *
1829 * int skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) 1851 * int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header)
1830 * Description 1852 * Description
1831 * This helper is similar to **bpf_skb_load_bytes**\ () in that 1853 * This helper is similar to **bpf_skb_load_bytes**\ () in that
1832 * it provides an easy way to load *len* bytes from *offset* 1854 * it provides an easy way to load *len* bytes from *offset*
@@ -1877,7 +1899,7 @@ union bpf_attr {
1877 * * < 0 if any input argument is invalid 1899 * * < 0 if any input argument is invalid
1878 * * 0 on success (packet is forwarded, nexthop neighbor exists) 1900 * * 0 on success (packet is forwarded, nexthop neighbor exists)
1879 * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the 1901 * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the
1880 * * packet is not forwarded or needs assist from full stack 1902 * packet is not forwarded or needs assist from full stack
1881 * 1903 *
1882 * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags) 1904 * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags)
1883 * Description 1905 * Description
@@ -2033,7 +2055,6 @@ union bpf_attr {
2033 * This helper is only available is the kernel was compiled with 2055 * This helper is only available is the kernel was compiled with
2034 * the **CONFIG_BPF_LIRC_MODE2** configuration option set to 2056 * the **CONFIG_BPF_LIRC_MODE2** configuration option set to
2035 * "**y**". 2057 * "**y**".
2036 *
2037 * Return 2058 * Return
2038 * 0 2059 * 0
2039 * 2060 *
@@ -2053,7 +2074,6 @@ union bpf_attr {
2053 * This helper is only available is the kernel was compiled with 2074 * This helper is only available is the kernel was compiled with
2054 * the **CONFIG_BPF_LIRC_MODE2** configuration option set to 2075 * the **CONFIG_BPF_LIRC_MODE2** configuration option set to
2055 * "**y**". 2076 * "**y**".
2056 *
2057 * Return 2077 * Return
2058 * 0 2078 * 0
2059 * 2079 *
@@ -2073,10 +2093,54 @@ union bpf_attr {
2073 * Return 2093 * Return
2074 * The id is returned or 0 in case the id could not be retrieved. 2094 * The id is returned or 0 in case the id could not be retrieved.
2075 * 2095 *
2096 * u64 bpf_skb_ancestor_cgroup_id(struct sk_buff *skb, int ancestor_level)
2097 * Description
2098 * Return id of cgroup v2 that is ancestor of cgroup associated
2099 * with the *skb* at the *ancestor_level*. The root cgroup is at
2100 * *ancestor_level* zero and each step down the hierarchy
2101 * increments the level. If *ancestor_level* == level of cgroup
2102 * associated with *skb*, then return value will be same as that
2103 * of **bpf_skb_cgroup_id**\ ().
2104 *
2105 * The helper is useful to implement policies based on cgroups
2106 * that are upper in hierarchy than immediate cgroup associated
2107 * with *skb*.
2108 *
2109 * The format of returned id and helper limitations are same as in
2110 * **bpf_skb_cgroup_id**\ ().
2111 * Return
2112 * The id is returned or 0 in case the id could not be retrieved.
2113 *
2076 * u64 bpf_get_current_cgroup_id(void) 2114 * u64 bpf_get_current_cgroup_id(void)
2077 * Return 2115 * Return
2078 * A 64-bit integer containing the current cgroup id based 2116 * A 64-bit integer containing the current cgroup id based
2079 * on the cgroup within which the current task is running. 2117 * on the cgroup within which the current task is running.
2118 *
2119 * void* get_local_storage(void *map, u64 flags)
2120 * Description
2121 * Get the pointer to the local storage area.
2122 * The type and the size of the local storage is defined
2123 * by the *map* argument.
2124 * The *flags* meaning is specific for each map type,
2125 * and has to be 0 for cgroup local storage.
2126 *
2127 * Depending on the bpf program type, a local storage area
2128 * can be shared between multiple instances of the bpf program,
2129 * running simultaneously.
2130 *
2131 * A user should care about the synchronization by himself.
2132 * For example, by using the BPF_STX_XADD instruction to alter
2133 * the shared data.
2134 * Return
2135 * Pointer to the local storage area.
2136 *
2137 * int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags)
2138 * Description
2139 * Select a SO_REUSEPORT sk from a BPF_MAP_TYPE_REUSEPORT_ARRAY map
2140 * It checks the selected sk is matching the incoming
2141 * request in the skb.
2142 * Return
2143 * 0 on success, or a negative error in case of failure.
2080 */ 2144 */
2081#define __BPF_FUNC_MAPPER(FN) \ 2145#define __BPF_FUNC_MAPPER(FN) \
2082 FN(unspec), \ 2146 FN(unspec), \
@@ -2159,7 +2223,10 @@ union bpf_attr {
2159 FN(rc_repeat), \ 2223 FN(rc_repeat), \
2160 FN(rc_keydown), \ 2224 FN(rc_keydown), \
2161 FN(skb_cgroup_id), \ 2225 FN(skb_cgroup_id), \
2162 FN(get_current_cgroup_id), 2226 FN(get_current_cgroup_id), \
2227 FN(get_local_storage), \
2228 FN(sk_select_reuseport), \
2229 FN(skb_ancestor_cgroup_id),
2163 2230
2164/* integer value in 'imm' field of BPF_CALL instruction selects which helper 2231/* integer value in 'imm' field of BPF_CALL instruction selects which helper
2165 * function eBPF program intends to call 2232 * function eBPF program intends to call
@@ -2376,6 +2443,30 @@ struct sk_msg_md {
2376 __u32 local_port; /* stored in host byte order */ 2443 __u32 local_port; /* stored in host byte order */
2377}; 2444};
2378 2445
2446struct sk_reuseport_md {
2447 /*
2448 * Start of directly accessible data. It begins from
2449 * the tcp/udp header.
2450 */
2451 void *data;
2452 void *data_end; /* End of directly accessible data */
2453 /*
2454 * Total length of packet (starting from the tcp/udp header).
2455 * Note that the directly accessible bytes (data_end - data)
2456 * could be less than this "len". Those bytes could be
2457 * indirectly read by a helper "bpf_skb_load_bytes()".
2458 */
2459 __u32 len;
2460 /*
2461 * Eth protocol in the mac header (network byte order). e.g.
2462 * ETH_P_IP(0x0800) and ETH_P_IPV6(0x86DD)
2463 */
2464 __u32 eth_protocol;
2465 __u32 ip_protocol; /* IP protocol. e.g. IPPROTO_TCP, IPPROTO_UDP */
2466 __u32 bind_inany; /* Is sock bound to an INANY address? */
2467 __u32 hash; /* A hash of the packet 4 tuples */
2468};
2469
2379#define BPF_TAG_SIZE 8 2470#define BPF_TAG_SIZE 8
2380 2471
2381struct bpf_prog_info { 2472struct bpf_prog_info {
@@ -2557,6 +2648,9 @@ enum {
2557 * Arg1: old_state 2648 * Arg1: old_state
2558 * Arg2: new_state 2649 * Arg2: new_state
2559 */ 2650 */
2651 BPF_SOCK_OPS_TCP_LISTEN_CB, /* Called on listen(2), right after
2652 * socket transition to LISTEN state.
2653 */
2560}; 2654};
2561 2655
2562/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect 2656/* List of TCP states. There is a build check in net/ipv4/tcp.c to detect
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 6070e655042d..13a861135127 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index 5390e7725e43..d49902e818b5 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -66,7 +66,7 @@ ifndef VERBOSE
66endif 66endif
67 67
68FEATURE_USER = .libbpf 68FEATURE_USER = .libbpf
69FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf 69FEATURE_TESTS = libelf libelf-mmap bpf reallocarray
70FEATURE_DISPLAY = libelf bpf 70FEATURE_DISPLAY = libelf bpf
71 71
72INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf 72INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf
@@ -116,8 +116,8 @@ ifeq ($(feature-libelf-mmap), 1)
116 override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT 116 override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
117endif 117endif
118 118
119ifeq ($(feature-libelf-getphdrnum), 1) 119ifeq ($(feature-reallocarray), 0)
120 override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT 120 override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
121endif 121endif
122 122
123# Append required CFLAGS 123# Append required CFLAGS
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 9ddc89dae962..60aa4ca8b2c5 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -92,6 +92,7 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr)
92 attr.btf_key_type_id = create_attr->btf_key_type_id; 92 attr.btf_key_type_id = create_attr->btf_key_type_id;
93 attr.btf_value_type_id = create_attr->btf_value_type_id; 93 attr.btf_value_type_id = create_attr->btf_value_type_id;
94 attr.map_ifindex = create_attr->map_ifindex; 94 attr.map_ifindex = create_attr->map_ifindex;
95 attr.inner_map_fd = create_attr->inner_map_fd;
95 96
96 return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); 97 return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
97} 98}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 0639a30a457d..6f38164b2618 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -39,6 +39,7 @@ struct bpf_create_map_attr {
39 __u32 btf_key_type_id; 39 __u32 btf_key_type_id;
40 __u32 btf_value_type_id; 40 __u32 btf_value_type_id;
41 __u32 map_ifindex; 41 __u32 map_ifindex;
42 __u32 inner_map_fd;
42}; 43};
43 44
44int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); 45int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr);
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index c36a3a76986a..cf94b0770522 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -16,6 +16,11 @@
16 16
17#define BTF_MAX_NR_TYPES 65535 17#define BTF_MAX_NR_TYPES 65535
18 18
19#define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \
20 ((k) == BTF_KIND_VOLATILE) || \
21 ((k) == BTF_KIND_CONST) || \
22 ((k) == BTF_KIND_RESTRICT))
23
19static struct btf_type btf_void; 24static struct btf_type btf_void;
20 25
21struct btf { 26struct btf {
@@ -32,14 +37,6 @@ struct btf {
32 int fd; 37 int fd;
33}; 38};
34 39
35static const char *btf_name_by_offset(const struct btf *btf, __u32 offset)
36{
37 if (offset < btf->hdr->str_len)
38 return &btf->strings[offset];
39 else
40 return NULL;
41}
42
43static int btf_add_type(struct btf *btf, struct btf_type *t) 40static int btf_add_type(struct btf *btf, struct btf_type *t)
44{ 41{
45 if (btf->types_size - btf->nr_types < 2) { 42 if (btf->types_size - btf->nr_types < 2) {
@@ -269,6 +266,26 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
269 return nelems * size; 266 return nelems * size;
270} 267}
271 268
269int btf__resolve_type(const struct btf *btf, __u32 type_id)
270{
271 const struct btf_type *t;
272 int depth = 0;
273
274 t = btf__type_by_id(btf, type_id);
275 while (depth < MAX_RESOLVE_DEPTH &&
276 !btf_type_is_void_or_null(t) &&
277 IS_MODIFIER(BTF_INFO_KIND(t->info))) {
278 type_id = t->type;
279 t = btf__type_by_id(btf, type_id);
280 depth++;
281 }
282
283 if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
284 return -EINVAL;
285
286 return type_id;
287}
288
272__s32 btf__find_by_name(const struct btf *btf, const char *type_name) 289__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
273{ 290{
274 __u32 i; 291 __u32 i;
@@ -278,7 +295,7 @@ __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
278 295
279 for (i = 1; i <= btf->nr_types; i++) { 296 for (i = 1; i <= btf->nr_types; i++) {
280 const struct btf_type *t = btf->types[i]; 297 const struct btf_type *t = btf->types[i];
281 const char *name = btf_name_by_offset(btf, t->name_off); 298 const char *name = btf__name_by_offset(btf, t->name_off);
282 299
283 if (name && !strcmp(type_name, name)) 300 if (name && !strcmp(type_name, name))
284 return i; 301 return i;
@@ -368,3 +385,11 @@ int btf__fd(const struct btf *btf)
368{ 385{
369 return btf->fd; 386 return btf->fd;
370} 387}
388
389const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
390{
391 if (offset < btf->hdr->str_len)
392 return &btf->strings[offset];
393 else
394 return NULL;
395}
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index caac3a404dc5..4897e0724d4e 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -19,6 +19,8 @@ struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
19__s32 btf__find_by_name(const struct btf *btf, const char *type_name); 19__s32 btf__find_by_name(const struct btf *btf, const char *type_name);
20const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); 20const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id);
21__s64 btf__resolve_size(const struct btf *btf, __u32 type_id); 21__s64 btf__resolve_size(const struct btf *btf, __u32 type_id);
22int btf__resolve_type(const struct btf *btf, __u32 type_id);
22int btf__fd(const struct btf *btf); 23int btf__fd(const struct btf *btf);
24const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
23 25
24#endif 26#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 1aafdbe827fe..2abd0f112627 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -22,6 +22,7 @@
22 * License along with this program; if not, see <http://www.gnu.org/licenses> 22 * License along with this program; if not, see <http://www.gnu.org/licenses>
23 */ 23 */
24 24
25#define _GNU_SOURCE
25#include <stdlib.h> 26#include <stdlib.h>
26#include <stdio.h> 27#include <stdio.h>
27#include <stdarg.h> 28#include <stdarg.h>
@@ -42,6 +43,7 @@
42#include <sys/stat.h> 43#include <sys/stat.h>
43#include <sys/types.h> 44#include <sys/types.h>
44#include <sys/vfs.h> 45#include <sys/vfs.h>
46#include <tools/libc_compat.h>
45#include <libelf.h> 47#include <libelf.h>
46#include <gelf.h> 48#include <gelf.h>
47 49
@@ -96,54 +98,6 @@ void libbpf_set_print(libbpf_print_fn_t warn,
96 98
97#define STRERR_BUFSIZE 128 99#define STRERR_BUFSIZE 128
98 100
99#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
100#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
101#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
102
103static const char *libbpf_strerror_table[NR_ERRNO] = {
104 [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
105 [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
106 [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
107 [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
108 [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
109 [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
110 [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
111 [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
112 [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
113 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
114 [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
115 [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
116};
117
118int libbpf_strerror(int err, char *buf, size_t size)
119{
120 if (!buf || !size)
121 return -1;
122
123 err = err > 0 ? err : -err;
124
125 if (err < __LIBBPF_ERRNO__START) {
126 int ret;
127
128 ret = strerror_r(err, buf, size);
129 buf[size - 1] = '\0';
130 return ret;
131 }
132
133 if (err < __LIBBPF_ERRNO__END) {
134 const char *msg;
135
136 msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
137 snprintf(buf, size, "%s", msg);
138 buf[size - 1] = '\0';
139 return 0;
140 }
141
142 snprintf(buf, size, "Unknown libbpf error %d", err);
143 buf[size - 1] = '\0';
144 return -1;
145}
146
147#define CHECK_ERR(action, err, out) do { \ 101#define CHECK_ERR(action, err, out) do { \
148 err = action; \ 102 err = action; \
149 if (err) \ 103 if (err) \
@@ -235,6 +189,7 @@ struct bpf_object {
235 size_t nr_maps; 189 size_t nr_maps;
236 190
237 bool loaded; 191 bool loaded;
192 bool has_pseudo_calls;
238 193
239 /* 194 /*
240 * Information when doing elf related work. Only valid if fd 195 * Information when doing elf related work. Only valid if fd
@@ -369,7 +324,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
369 progs = obj->programs; 324 progs = obj->programs;
370 nr_progs = obj->nr_programs; 325 nr_progs = obj->nr_programs;
371 326
372 progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1)); 327 progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0]));
373 if (!progs) { 328 if (!progs) {
374 /* 329 /*
375 * In this case the original obj->programs 330 * In this case the original obj->programs
@@ -401,10 +356,6 @@ bpf_object__init_prog_names(struct bpf_object *obj)
401 const char *name = NULL; 356 const char *name = NULL;
402 357
403 prog = &obj->programs[pi]; 358 prog = &obj->programs[pi];
404 if (prog->idx == obj->efile.text_shndx) {
405 name = ".text";
406 goto skip_search;
407 }
408 359
409 for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name; 360 for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name;
410 si++) { 361 si++) {
@@ -427,12 +378,15 @@ bpf_object__init_prog_names(struct bpf_object *obj)
427 } 378 }
428 } 379 }
429 380
381 if (!name && prog->idx == obj->efile.text_shndx)
382 name = ".text";
383
430 if (!name) { 384 if (!name) {
431 pr_warning("failed to find sym for prog %s\n", 385 pr_warning("failed to find sym for prog %s\n",
432 prog->section_name); 386 prog->section_name);
433 return -EINVAL; 387 return -EINVAL;
434 } 388 }
435skip_search: 389
436 prog->name = strdup(name); 390 prog->name = strdup(name);
437 if (!prog->name) { 391 if (!prog->name) {
438 pr_warning("failed to allocate memory for prog sym %s\n", 392 pr_warning("failed to allocate memory for prog sym %s\n",
@@ -514,8 +468,10 @@ static int bpf_object__elf_init(struct bpf_object *obj)
514 } else { 468 } else {
515 obj->efile.fd = open(obj->path, O_RDONLY); 469 obj->efile.fd = open(obj->path, O_RDONLY);
516 if (obj->efile.fd < 0) { 470 if (obj->efile.fd < 0) {
517 pr_warning("failed to open %s: %s\n", obj->path, 471 char errmsg[STRERR_BUFSIZE];
518 strerror(errno)); 472 char *cp = strerror_r(errno, errmsg, sizeof(errmsg));
473
474 pr_warning("failed to open %s: %s\n", obj->path, cp);
519 return -errno; 475 return -errno;
520 } 476 }
521 477
@@ -854,10 +810,11 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
854 data->d_size, name, idx); 810 data->d_size, name, idx);
855 if (err) { 811 if (err) {
856 char errmsg[STRERR_BUFSIZE]; 812 char errmsg[STRERR_BUFSIZE];
813 char *cp = strerror_r(-err, errmsg,
814 sizeof(errmsg));
857 815
858 strerror_r(-err, errmsg, sizeof(errmsg));
859 pr_warning("failed to alloc program %s (%s): %s", 816 pr_warning("failed to alloc program %s (%s): %s",
860 name, obj->path, errmsg); 817 name, obj->path, cp);
861 } 818 }
862 } else if (sh.sh_type == SHT_REL) { 819 } else if (sh.sh_type == SHT_REL) {
863 void *reloc = obj->efile.reloc; 820 void *reloc = obj->efile.reloc;
@@ -871,8 +828,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
871 continue; 828 continue;
872 } 829 }
873 830
874 reloc = realloc(reloc, 831 reloc = reallocarray(reloc, nr_reloc,
875 sizeof(*obj->efile.reloc) * nr_reloc); 832 sizeof(*obj->efile.reloc));
876 if (!reloc) { 833 if (!reloc) {
877 pr_warning("realloc failed\n"); 834 pr_warning("realloc failed\n");
878 err = -ENOMEM; 835 err = -ENOMEM;
@@ -920,6 +877,18 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
920 return NULL; 877 return NULL;
921} 878}
922 879
880struct bpf_program *
881bpf_object__find_program_by_title(struct bpf_object *obj, const char *title)
882{
883 struct bpf_program *pos;
884
885 bpf_object__for_each_program(pos, obj) {
886 if (pos->section_name && !strcmp(pos->section_name, title))
887 return pos;
888 }
889 return NULL;
890}
891
923static int 892static int
924bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, 893bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
925 Elf_Data *data, struct bpf_object *obj) 894 Elf_Data *data, struct bpf_object *obj)
@@ -982,6 +951,7 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
982 prog->reloc_desc[i].type = RELO_CALL; 951 prog->reloc_desc[i].type = RELO_CALL;
983 prog->reloc_desc[i].insn_idx = insn_idx; 952 prog->reloc_desc[i].insn_idx = insn_idx;
984 prog->reloc_desc[i].text_off = sym.st_value; 953 prog->reloc_desc[i].text_off = sym.st_value;
954 obj->has_pseudo_calls = true;
985 continue; 955 continue;
986 } 956 }
987 957
@@ -1085,6 +1055,53 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf)
1085 return 0; 1055 return 0;
1086} 1056}
1087 1057
1058int bpf_map__reuse_fd(struct bpf_map *map, int fd)
1059{
1060 struct bpf_map_info info = {};
1061 __u32 len = sizeof(info);
1062 int new_fd, err;
1063 char *new_name;
1064
1065 err = bpf_obj_get_info_by_fd(fd, &info, &len);
1066 if (err)
1067 return err;
1068
1069 new_name = strdup(info.name);
1070 if (!new_name)
1071 return -errno;
1072
1073 new_fd = open("/", O_RDONLY | O_CLOEXEC);
1074 if (new_fd < 0)
1075 goto err_free_new_name;
1076
1077 new_fd = dup3(fd, new_fd, O_CLOEXEC);
1078 if (new_fd < 0)
1079 goto err_close_new_fd;
1080
1081 err = zclose(map->fd);
1082 if (err)
1083 goto err_close_new_fd;
1084 free(map->name);
1085
1086 map->fd = new_fd;
1087 map->name = new_name;
1088 map->def.type = info.type;
1089 map->def.key_size = info.key_size;
1090 map->def.value_size = info.value_size;
1091 map->def.max_entries = info.max_entries;
1092 map->def.map_flags = info.map_flags;
1093 map->btf_key_type_id = info.btf_key_type_id;
1094 map->btf_value_type_id = info.btf_value_type_id;
1095
1096 return 0;
1097
1098err_close_new_fd:
1099 close(new_fd);
1100err_free_new_name:
1101 free(new_name);
1102 return -errno;
1103}
1104
1088static int 1105static int
1089bpf_object__create_maps(struct bpf_object *obj) 1106bpf_object__create_maps(struct bpf_object *obj)
1090{ 1107{
@@ -1095,8 +1112,15 @@ bpf_object__create_maps(struct bpf_object *obj)
1095 for (i = 0; i < obj->nr_maps; i++) { 1112 for (i = 0; i < obj->nr_maps; i++) {
1096 struct bpf_map *map = &obj->maps[i]; 1113 struct bpf_map *map = &obj->maps[i];
1097 struct bpf_map_def *def = &map->def; 1114 struct bpf_map_def *def = &map->def;
1115 char *cp, errmsg[STRERR_BUFSIZE];
1098 int *pfd = &map->fd; 1116 int *pfd = &map->fd;
1099 1117
1118 if (map->fd >= 0) {
1119 pr_debug("skip map create (preset) %s: fd=%d\n",
1120 map->name, map->fd);
1121 continue;
1122 }
1123
1100 create_attr.name = map->name; 1124 create_attr.name = map->name;
1101 create_attr.map_ifindex = map->map_ifindex; 1125 create_attr.map_ifindex = map->map_ifindex;
1102 create_attr.map_type = def->type; 1126 create_attr.map_type = def->type;
@@ -1116,8 +1140,9 @@ bpf_object__create_maps(struct bpf_object *obj)
1116 1140
1117 *pfd = bpf_create_map_xattr(&create_attr); 1141 *pfd = bpf_create_map_xattr(&create_attr);
1118 if (*pfd < 0 && create_attr.btf_key_type_id) { 1142 if (*pfd < 0 && create_attr.btf_key_type_id) {
1143 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1119 pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n", 1144 pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",
1120 map->name, strerror(errno), errno); 1145 map->name, cp, errno);
1121 create_attr.btf_fd = 0; 1146 create_attr.btf_fd = 0;
1122 create_attr.btf_key_type_id = 0; 1147 create_attr.btf_key_type_id = 0;
1123 create_attr.btf_value_type_id = 0; 1148 create_attr.btf_value_type_id = 0;
@@ -1130,9 +1155,9 @@ bpf_object__create_maps(struct bpf_object *obj)
1130 size_t j; 1155 size_t j;
1131 1156
1132 err = *pfd; 1157 err = *pfd;
1158 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1133 pr_warning("failed to create map (name: '%s'): %s\n", 1159 pr_warning("failed to create map (name: '%s'): %s\n",
1134 map->name, 1160 map->name, cp);
1135 strerror(errno));
1136 for (j = 0; j < i; j++) 1161 for (j = 0; j < i; j++)
1137 zclose(obj->maps[j].fd); 1162 zclose(obj->maps[j].fd);
1138 return err; 1163 return err;
@@ -1167,7 +1192,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
1167 return -LIBBPF_ERRNO__RELOC; 1192 return -LIBBPF_ERRNO__RELOC;
1168 } 1193 }
1169 new_cnt = prog->insns_cnt + text->insns_cnt; 1194 new_cnt = prog->insns_cnt + text->insns_cnt;
1170 new_insn = realloc(prog->insns, new_cnt * sizeof(*insn)); 1195 new_insn = reallocarray(prog->insns, new_cnt, sizeof(*insn));
1171 if (!new_insn) { 1196 if (!new_insn) {
1172 pr_warning("oom in prog realloc\n"); 1197 pr_warning("oom in prog realloc\n");
1173 return -ENOMEM; 1198 return -ENOMEM;
@@ -1284,6 +1309,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
1284 char *license, u32 kern_version, int *pfd, int prog_ifindex) 1309 char *license, u32 kern_version, int *pfd, int prog_ifindex)
1285{ 1310{
1286 struct bpf_load_program_attr load_attr; 1311 struct bpf_load_program_attr load_attr;
1312 char *cp, errmsg[STRERR_BUFSIZE];
1287 char *log_buf; 1313 char *log_buf;
1288 int ret; 1314 int ret;
1289 1315
@@ -1313,7 +1339,8 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
1313 } 1339 }
1314 1340
1315 ret = -LIBBPF_ERRNO__LOAD; 1341 ret = -LIBBPF_ERRNO__LOAD;
1316 pr_warning("load bpf program failed: %s\n", strerror(errno)); 1342 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1343 pr_warning("load bpf program failed: %s\n", cp);
1317 1344
1318 if (log_buf && log_buf[0] != '\0') { 1345 if (log_buf && log_buf[0] != '\0') {
1319 ret = -LIBBPF_ERRNO__VERIFY; 1346 ret = -LIBBPF_ERRNO__VERIFY;
@@ -1431,6 +1458,12 @@ out:
1431 return err; 1458 return err;
1432} 1459}
1433 1460
1461static bool bpf_program__is_function_storage(struct bpf_program *prog,
1462 struct bpf_object *obj)
1463{
1464 return prog->idx == obj->efile.text_shndx && obj->has_pseudo_calls;
1465}
1466
1434static int 1467static int
1435bpf_object__load_progs(struct bpf_object *obj) 1468bpf_object__load_progs(struct bpf_object *obj)
1436{ 1469{
@@ -1438,7 +1471,7 @@ bpf_object__load_progs(struct bpf_object *obj)
1438 int err; 1471 int err;
1439 1472
1440 for (i = 0; i < obj->nr_programs; i++) { 1473 for (i = 0; i < obj->nr_programs; i++) {
1441 if (obj->programs[i].idx == obj->efile.text_shndx) 1474 if (bpf_program__is_function_storage(&obj->programs[i], obj))
1442 continue; 1475 continue;
1443 err = bpf_program__load(&obj->programs[i], 1476 err = bpf_program__load(&obj->programs[i],
1444 obj->license, 1477 obj->license,
@@ -1468,6 +1501,7 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)
1468 case BPF_PROG_TYPE_SK_MSG: 1501 case BPF_PROG_TYPE_SK_MSG:
1469 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: 1502 case BPF_PROG_TYPE_CGROUP_SOCK_ADDR:
1470 case BPF_PROG_TYPE_LIRC_MODE2: 1503 case BPF_PROG_TYPE_LIRC_MODE2:
1504 case BPF_PROG_TYPE_SK_REUSEPORT:
1471 return false; 1505 return false;
1472 case BPF_PROG_TYPE_UNSPEC: 1506 case BPF_PROG_TYPE_UNSPEC:
1473 case BPF_PROG_TYPE_KPROBE: 1507 case BPF_PROG_TYPE_KPROBE:
@@ -1518,15 +1552,26 @@ out:
1518 return ERR_PTR(err); 1552 return ERR_PTR(err);
1519} 1553}
1520 1554
1521struct bpf_object *bpf_object__open(const char *path) 1555struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
1522{ 1556{
1523 /* param validation */ 1557 /* param validation */
1524 if (!path) 1558 if (!attr->file)
1525 return NULL; 1559 return NULL;
1526 1560
1527 pr_debug("loading %s\n", path); 1561 pr_debug("loading %s\n", attr->file);
1528 1562
1529 return __bpf_object__open(path, NULL, 0, true); 1563 return __bpf_object__open(attr->file, NULL, 0,
1564 bpf_prog_type__needs_kver(attr->prog_type));
1565}
1566
1567struct bpf_object *bpf_object__open(const char *path)
1568{
1569 struct bpf_object_open_attr attr = {
1570 .file = path,
1571 .prog_type = BPF_PROG_TYPE_UNSPEC,
1572 };
1573
1574 return bpf_object__open_xattr(&attr);
1530} 1575}
1531 1576
1532struct bpf_object *bpf_object__open_buffer(void *obj_buf, 1577struct bpf_object *bpf_object__open_buffer(void *obj_buf,
@@ -1595,6 +1640,7 @@ out:
1595 1640
1596static int check_path(const char *path) 1641static int check_path(const char *path)
1597{ 1642{
1643 char *cp, errmsg[STRERR_BUFSIZE];
1598 struct statfs st_fs; 1644 struct statfs st_fs;
1599 char *dname, *dir; 1645 char *dname, *dir;
1600 int err = 0; 1646 int err = 0;
@@ -1608,7 +1654,8 @@ static int check_path(const char *path)
1608 1654
1609 dir = dirname(dname); 1655 dir = dirname(dname);
1610 if (statfs(dir, &st_fs)) { 1656 if (statfs(dir, &st_fs)) {
1611 pr_warning("failed to statfs %s: %s\n", dir, strerror(errno)); 1657 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1658 pr_warning("failed to statfs %s: %s\n", dir, cp);
1612 err = -errno; 1659 err = -errno;
1613 } 1660 }
1614 free(dname); 1661 free(dname);
@@ -1624,6 +1671,7 @@ static int check_path(const char *path)
1624int bpf_program__pin_instance(struct bpf_program *prog, const char *path, 1671int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
1625 int instance) 1672 int instance)
1626{ 1673{
1674 char *cp, errmsg[STRERR_BUFSIZE];
1627 int err; 1675 int err;
1628 1676
1629 err = check_path(path); 1677 err = check_path(path);
@@ -1642,7 +1690,8 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
1642 } 1690 }
1643 1691
1644 if (bpf_obj_pin(prog->instances.fds[instance], path)) { 1692 if (bpf_obj_pin(prog->instances.fds[instance], path)) {
1645 pr_warning("failed to pin program: %s\n", strerror(errno)); 1693 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1694 pr_warning("failed to pin program: %s\n", cp);
1646 return -errno; 1695 return -errno;
1647 } 1696 }
1648 pr_debug("pinned program '%s'\n", path); 1697 pr_debug("pinned program '%s'\n", path);
@@ -1652,13 +1701,16 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
1652 1701
1653static int make_dir(const char *path) 1702static int make_dir(const char *path)
1654{ 1703{
1704 char *cp, errmsg[STRERR_BUFSIZE];
1655 int err = 0; 1705 int err = 0;
1656 1706
1657 if (mkdir(path, 0700) && errno != EEXIST) 1707 if (mkdir(path, 0700) && errno != EEXIST)
1658 err = -errno; 1708 err = -errno;
1659 1709
1660 if (err) 1710 if (err) {
1661 pr_warning("failed to mkdir %s: %s\n", path, strerror(-err)); 1711 cp = strerror_r(-err, errmsg, sizeof(errmsg));
1712 pr_warning("failed to mkdir %s: %s\n", path, cp);
1713 }
1662 return err; 1714 return err;
1663} 1715}
1664 1716
@@ -1705,6 +1757,7 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
1705 1757
1706int bpf_map__pin(struct bpf_map *map, const char *path) 1758int bpf_map__pin(struct bpf_map *map, const char *path)
1707{ 1759{
1760 char *cp, errmsg[STRERR_BUFSIZE];
1708 int err; 1761 int err;
1709 1762
1710 err = check_path(path); 1763 err = check_path(path);
@@ -1717,7 +1770,8 @@ int bpf_map__pin(struct bpf_map *map, const char *path)
1717 } 1770 }
1718 1771
1719 if (bpf_obj_pin(map->fd, path)) { 1772 if (bpf_obj_pin(map->fd, path)) {
1720 pr_warning("failed to pin map: %s\n", strerror(errno)); 1773 cp = strerror_r(errno, errmsg, sizeof(errmsg));
1774 pr_warning("failed to pin map: %s\n", cp);
1721 return -errno; 1775 return -errno;
1722 } 1776 }
1723 1777
@@ -1863,8 +1917,8 @@ void *bpf_object__priv(struct bpf_object *obj)
1863 return obj ? obj->priv : ERR_PTR(-EINVAL); 1917 return obj ? obj->priv : ERR_PTR(-EINVAL);
1864} 1918}
1865 1919
1866struct bpf_program * 1920static struct bpf_program *
1867bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) 1921__bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
1868{ 1922{
1869 size_t idx; 1923 size_t idx;
1870 1924
@@ -1885,6 +1939,18 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
1885 return &obj->programs[idx]; 1939 return &obj->programs[idx];
1886} 1940}
1887 1941
1942struct bpf_program *
1943bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
1944{
1945 struct bpf_program *prog = prev;
1946
1947 do {
1948 prog = __bpf_program__next(prog, obj);
1949 } while (prog && bpf_program__is_function_storage(prog, obj));
1950
1951 return prog;
1952}
1953
1888int bpf_program__set_priv(struct bpf_program *prog, void *priv, 1954int bpf_program__set_priv(struct bpf_program *prog, void *priv,
1889 bpf_program_clear_priv_t clear_priv) 1955 bpf_program_clear_priv_t clear_priv)
1890{ 1956{
@@ -1901,6 +1967,11 @@ void *bpf_program__priv(struct bpf_program *prog)
1901 return prog ? prog->priv : ERR_PTR(-EINVAL); 1967 return prog ? prog->priv : ERR_PTR(-EINVAL);
1902} 1968}
1903 1969
1970void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex)
1971{
1972 prog->prog_ifindex = ifindex;
1973}
1974
1904const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) 1975const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
1905{ 1976{
1906 const char *title; 1977 const char *title;
@@ -1954,6 +2025,9 @@ int bpf_program__nth_fd(struct bpf_program *prog, int n)
1954{ 2025{
1955 int fd; 2026 int fd;
1956 2027
2028 if (!prog)
2029 return -EINVAL;
2030
1957 if (n >= prog->instances.nr || n < 0) { 2031 if (n >= prog->instances.nr || n < 0) {
1958 pr_warning("Can't get the %dth fd from program %s: only %d instances\n", 2032 pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
1959 n, prog->section_name, prog->instances.nr); 2033 n, prog->section_name, prog->instances.nr);
@@ -2042,9 +2116,11 @@ static const struct {
2042 BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN), 2116 BPF_PROG_SEC("lwt_in", BPF_PROG_TYPE_LWT_IN),
2043 BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT), 2117 BPF_PROG_SEC("lwt_out", BPF_PROG_TYPE_LWT_OUT),
2044 BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), 2118 BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT),
2119 BPF_PROG_SEC("lwt_seg6local", BPF_PROG_TYPE_LWT_SEG6LOCAL),
2045 BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), 2120 BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS),
2046 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), 2121 BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
2047 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), 2122 BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG),
2123 BPF_PROG_SEC("lirc_mode2", BPF_PROG_TYPE_LIRC_MODE2),
2048 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), 2124 BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND),
2049 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), 2125 BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND),
2050 BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), 2126 BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT),
@@ -2060,23 +2136,31 @@ static const struct {
2060#undef BPF_S_PROG_SEC 2136#undef BPF_S_PROG_SEC
2061#undef BPF_SA_PROG_SEC 2137#undef BPF_SA_PROG_SEC
2062 2138
2063static int bpf_program__identify_section(struct bpf_program *prog) 2139int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
2140 enum bpf_attach_type *expected_attach_type)
2064{ 2141{
2065 int i; 2142 int i;
2066 2143
2067 if (!prog->section_name) 2144 if (!name)
2068 goto err; 2145 return -EINVAL;
2069
2070 for (i = 0; i < ARRAY_SIZE(section_names); i++)
2071 if (strncmp(prog->section_name, section_names[i].sec,
2072 section_names[i].len) == 0)
2073 return i;
2074 2146
2075err: 2147 for (i = 0; i < ARRAY_SIZE(section_names); i++) {
2076 pr_warning("failed to guess program type based on section name %s\n", 2148 if (strncmp(name, section_names[i].sec, section_names[i].len))
2077 prog->section_name); 2149 continue;
2150 *prog_type = section_names[i].prog_type;
2151 *expected_attach_type = section_names[i].expected_attach_type;
2152 return 0;
2153 }
2154 return -EINVAL;
2155}
2078 2156
2079 return -1; 2157static int
2158bpf_program__identify_section(struct bpf_program *prog,
2159 enum bpf_prog_type *prog_type,
2160 enum bpf_attach_type *expected_attach_type)
2161{
2162 return libbpf_prog_type_by_name(prog->section_name, prog_type,
2163 expected_attach_type);
2080} 2164}
2081 2165
2082int bpf_map__fd(struct bpf_map *map) 2166int bpf_map__fd(struct bpf_map *map)
@@ -2125,6 +2209,16 @@ void *bpf_map__priv(struct bpf_map *map)
2125 return map ? map->priv : ERR_PTR(-EINVAL); 2209 return map ? map->priv : ERR_PTR(-EINVAL);
2126} 2210}
2127 2211
2212bool bpf_map__is_offload_neutral(struct bpf_map *map)
2213{
2214 return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
2215}
2216
2217void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
2218{
2219 map->map_ifindex = ifindex;
2220}
2221
2128struct bpf_map * 2222struct bpf_map *
2129bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) 2223bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
2130{ 2224{
@@ -2199,12 +2293,15 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
2199int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, 2293int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2200 struct bpf_object **pobj, int *prog_fd) 2294 struct bpf_object **pobj, int *prog_fd)
2201{ 2295{
2296 struct bpf_object_open_attr open_attr = {
2297 .file = attr->file,
2298 .prog_type = attr->prog_type,
2299 };
2202 struct bpf_program *prog, *first_prog = NULL; 2300 struct bpf_program *prog, *first_prog = NULL;
2203 enum bpf_attach_type expected_attach_type; 2301 enum bpf_attach_type expected_attach_type;
2204 enum bpf_prog_type prog_type; 2302 enum bpf_prog_type prog_type;
2205 struct bpf_object *obj; 2303 struct bpf_object *obj;
2206 struct bpf_map *map; 2304 struct bpf_map *map;
2207 int section_idx;
2208 int err; 2305 int err;
2209 2306
2210 if (!attr) 2307 if (!attr)
@@ -2212,8 +2309,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2212 if (!attr->file) 2309 if (!attr->file)
2213 return -EINVAL; 2310 return -EINVAL;
2214 2311
2215 obj = __bpf_object__open(attr->file, NULL, 0, 2312 obj = bpf_object__open_xattr(&open_attr);
2216 bpf_prog_type__needs_kver(attr->prog_type));
2217 if (IS_ERR_OR_NULL(obj)) 2313 if (IS_ERR_OR_NULL(obj))
2218 return -ENOENT; 2314 return -ENOENT;
2219 2315
@@ -2226,26 +2322,27 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
2226 prog->prog_ifindex = attr->ifindex; 2322 prog->prog_ifindex = attr->ifindex;
2227 expected_attach_type = attr->expected_attach_type; 2323 expected_attach_type = attr->expected_attach_type;
2228 if (prog_type == BPF_PROG_TYPE_UNSPEC) { 2324 if (prog_type == BPF_PROG_TYPE_UNSPEC) {
2229 section_idx = bpf_program__identify_section(prog); 2325 err = bpf_program__identify_section(prog, &prog_type,
2230 if (section_idx < 0) { 2326 &expected_attach_type);
2327 if (err < 0) {
2328 pr_warning("failed to guess program type based on section name %s\n",
2329 prog->section_name);
2231 bpf_object__close(obj); 2330 bpf_object__close(obj);
2232 return -EINVAL; 2331 return -EINVAL;
2233 } 2332 }
2234 prog_type = section_names[section_idx].prog_type;
2235 expected_attach_type =
2236 section_names[section_idx].expected_attach_type;
2237 } 2333 }
2238 2334
2239 bpf_program__set_type(prog, prog_type); 2335 bpf_program__set_type(prog, prog_type);
2240 bpf_program__set_expected_attach_type(prog, 2336 bpf_program__set_expected_attach_type(prog,
2241 expected_attach_type); 2337 expected_attach_type);
2242 2338
2243 if (prog->idx != obj->efile.text_shndx && !first_prog) 2339 if (!bpf_program__is_function_storage(prog, obj) && !first_prog)
2244 first_prog = prog; 2340 first_prog = prog;
2245 } 2341 }
2246 2342
2247 bpf_map__for_each(map, obj) { 2343 bpf_map__for_each(map, obj) {
2248 map->map_ifindex = attr->ifindex; 2344 if (!bpf_map__is_offload_neutral(map))
2345 map->map_ifindex = attr->ifindex;
2249 } 2346 }
2250 2347
2251 if (!first_prog) { 2348 if (!first_prog) {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b33ae02f7d0e..96c55fac54c3 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -66,7 +66,13 @@ void libbpf_set_print(libbpf_print_fn_t warn,
66/* Hide internal to user */ 66/* Hide internal to user */
67struct bpf_object; 67struct bpf_object;
68 68
69struct bpf_object_open_attr {
70 const char *file;
71 enum bpf_prog_type prog_type;
72};
73
69struct bpf_object *bpf_object__open(const char *path); 74struct bpf_object *bpf_object__open(const char *path);
75struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr);
70struct bpf_object *bpf_object__open_buffer(void *obj_buf, 76struct bpf_object *bpf_object__open_buffer(void *obj_buf,
71 size_t obj_buf_sz, 77 size_t obj_buf_sz,
72 const char *name); 78 const char *name);
@@ -80,6 +86,9 @@ const char *bpf_object__name(struct bpf_object *obj);
80unsigned int bpf_object__kversion(struct bpf_object *obj); 86unsigned int bpf_object__kversion(struct bpf_object *obj);
81int bpf_object__btf_fd(const struct bpf_object *obj); 87int bpf_object__btf_fd(const struct bpf_object *obj);
82 88
89struct bpf_program *
90bpf_object__find_program_by_title(struct bpf_object *obj, const char *title);
91
83struct bpf_object *bpf_object__next(struct bpf_object *prev); 92struct bpf_object *bpf_object__next(struct bpf_object *prev);
84#define bpf_object__for_each_safe(pos, tmp) \ 93#define bpf_object__for_each_safe(pos, tmp) \
85 for ((pos) = bpf_object__next(NULL), \ 94 for ((pos) = bpf_object__next(NULL), \
@@ -92,6 +101,9 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv,
92 bpf_object_clear_priv_t clear_priv); 101 bpf_object_clear_priv_t clear_priv);
93void *bpf_object__priv(struct bpf_object *prog); 102void *bpf_object__priv(struct bpf_object *prog);
94 103
104int libbpf_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
105 enum bpf_attach_type *expected_attach_type);
106
95/* Accessors of bpf_program */ 107/* Accessors of bpf_program */
96struct bpf_program; 108struct bpf_program;
97struct bpf_program *bpf_program__next(struct bpf_program *prog, 109struct bpf_program *bpf_program__next(struct bpf_program *prog,
@@ -109,6 +121,7 @@ int bpf_program__set_priv(struct bpf_program *prog, void *priv,
109 bpf_program_clear_priv_t clear_priv); 121 bpf_program_clear_priv_t clear_priv);
110 122
111void *bpf_program__priv(struct bpf_program *prog); 123void *bpf_program__priv(struct bpf_program *prog);
124void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex);
112 125
113const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); 126const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
114 127
@@ -251,6 +264,9 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
251int bpf_map__set_priv(struct bpf_map *map, void *priv, 264int bpf_map__set_priv(struct bpf_map *map, void *priv,
252 bpf_map_clear_priv_t clear_priv); 265 bpf_map_clear_priv_t clear_priv);
253void *bpf_map__priv(struct bpf_map *map); 266void *bpf_map__priv(struct bpf_map *map);
267int bpf_map__reuse_fd(struct bpf_map *map, int fd);
268bool bpf_map__is_offload_neutral(struct bpf_map *map);
269void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
254int bpf_map__pin(struct bpf_map *map, const char *path); 270int bpf_map__pin(struct bpf_map *map, const char *path);
255 271
256long libbpf_get_error(const void *ptr); 272long libbpf_get_error(const void *ptr);
diff --git a/tools/lib/bpf/libbpf_errno.c b/tools/lib/bpf/libbpf_errno.c
new file mode 100644
index 000000000000..d9ba851bd7f9
--- /dev/null
+++ b/tools/lib/bpf/libbpf_errno.c
@@ -0,0 +1,74 @@
1// SPDX-License-Identifier: LGPL-2.1
2
3/*
4 * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
5 * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
6 * Copyright (C) 2015 Huawei Inc.
7 * Copyright (C) 2017 Nicira, Inc.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation;
12 * version 2.1 of the License (not later!)
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, see <http://www.gnu.org/licenses>
21 */
22
23#include <stdio.h>
24#include <string.h>
25
26#include "libbpf.h"
27
28#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
29#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
30#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
31
32static const char *libbpf_strerror_table[NR_ERRNO] = {
33 [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
34 [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
35 [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
36 [ERRCODE_OFFSET(ENDIAN)] = "Endian mismatch",
37 [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
38 [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
39 [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
40 [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
41 [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
42 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
43 [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
44 [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
45};
46
47int libbpf_strerror(int err, char *buf, size_t size)
48{
49 if (!buf || !size)
50 return -1;
51
52 err = err > 0 ? err : -err;
53
54 if (err < __LIBBPF_ERRNO__START) {
55 int ret;
56
57 ret = strerror_r(err, buf, size);
58 buf[size - 1] = '\0';
59 return ret;
60 }
61
62 if (err < __LIBBPF_ERRNO__END) {
63 const char *msg;
64
65 msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
66 snprintf(buf, size, "%s", msg);
67 buf[size - 1] = '\0';
68 return 0;
69 }
70
71 snprintf(buf, size, "Unknown libbpf error %d", err);
72 buf[size - 1] = '\0';
73 return -1;
74}
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index a362e3d7abc6..fff7fb1285fc 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -22,7 +22,8 @@ $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c
22# Order correspond to 'make run_tests' order 22# Order correspond to 'make run_tests' order
23TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 23TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
24 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ 24 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \
25 test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user 25 test_sock test_btf test_sockmap test_lirc_mode2_user get_cgroup_id_user \
26 test_socket_cookie test_cgroup_storage test_select_reuseport
26 27
27TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 28TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
28 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 29 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
@@ -33,7 +34,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
33 test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \ 34 test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \
34 test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ 35 test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \
35 test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ 36 test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \
36 get_cgroup_id_kern.o 37 get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \
38 test_skb_cgroup_id_kern.o
37 39
38# Order correspond to 'make run_tests' order 40# Order correspond to 'make run_tests' order
39TEST_PROGS := test_kmod.sh \ 41TEST_PROGS := test_kmod.sh \
@@ -44,10 +46,11 @@ TEST_PROGS := test_kmod.sh \
44 test_sock_addr.sh \ 46 test_sock_addr.sh \
45 test_tunnel.sh \ 47 test_tunnel.sh \
46 test_lwt_seg6local.sh \ 48 test_lwt_seg6local.sh \
47 test_lirc_mode2.sh 49 test_lirc_mode2.sh \
50 test_skb_cgroup_id.sh
48 51
49# Compile but not part of 'make run_tests' 52# Compile but not part of 'make run_tests'
50TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr 53TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user
51 54
52include ../lib.mk 55include ../lib.mk
53 56
@@ -58,11 +61,15 @@ $(TEST_GEN_PROGS): $(BPFOBJ)
58$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a 61$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
59 62
60$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c 63$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c
64$(OUTPUT)/test_skb_cgroup_id_user: cgroup_helpers.c
61$(OUTPUT)/test_sock: cgroup_helpers.c 65$(OUTPUT)/test_sock: cgroup_helpers.c
62$(OUTPUT)/test_sock_addr: cgroup_helpers.c 66$(OUTPUT)/test_sock_addr: cgroup_helpers.c
67$(OUTPUT)/test_socket_cookie: cgroup_helpers.c
63$(OUTPUT)/test_sockmap: cgroup_helpers.c 68$(OUTPUT)/test_sockmap: cgroup_helpers.c
69$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c
64$(OUTPUT)/test_progs: trace_helpers.c 70$(OUTPUT)/test_progs: trace_helpers.c
65$(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c 71$(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c
72$(OUTPUT)/test_cgroup_storage: cgroup_helpers.c
66 73
67.PHONY: force 74.PHONY: force
68 75
diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h
index 810de20e8e26..e4be7730222d 100644
--- a/tools/testing/selftests/bpf/bpf_helpers.h
+++ b/tools/testing/selftests/bpf/bpf_helpers.h
@@ -65,6 +65,8 @@ static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
65 (void *) BPF_FUNC_xdp_adjust_head; 65 (void *) BPF_FUNC_xdp_adjust_head;
66static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = 66static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
67 (void *) BPF_FUNC_xdp_adjust_meta; 67 (void *) BPF_FUNC_xdp_adjust_meta;
68static int (*bpf_get_socket_cookie)(void *ctx) =
69 (void *) BPF_FUNC_get_socket_cookie;
68static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, 70static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
69 int optlen) = 71 int optlen) =
70 (void *) BPF_FUNC_setsockopt; 72 (void *) BPF_FUNC_setsockopt;
@@ -109,6 +111,8 @@ static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) =
109static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, 111static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state,
110 int size, int flags) = 112 int size, int flags) =
111 (void *) BPF_FUNC_skb_get_xfrm_state; 113 (void *) BPF_FUNC_skb_get_xfrm_state;
114static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) =
115 (void *) BPF_FUNC_sk_select_reuseport;
112static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = 116static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) =
113 (void *) BPF_FUNC_get_stack; 117 (void *) BPF_FUNC_get_stack;
114static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, 118static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params,
@@ -133,6 +137,12 @@ static int (*bpf_rc_keydown)(void *ctx, unsigned int protocol,
133 (void *) BPF_FUNC_rc_keydown; 137 (void *) BPF_FUNC_rc_keydown;
134static unsigned long long (*bpf_get_current_cgroup_id)(void) = 138static unsigned long long (*bpf_get_current_cgroup_id)(void) =
135 (void *) BPF_FUNC_get_current_cgroup_id; 139 (void *) BPF_FUNC_get_current_cgroup_id;
140static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) =
141 (void *) BPF_FUNC_get_local_storage;
142static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) =
143 (void *) BPF_FUNC_skb_cgroup_id;
144static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) =
145 (void *) BPF_FUNC_skb_ancestor_cgroup_id;
136 146
137/* llvm builtin functions that eBPF C program may use to 147/* llvm builtin functions that eBPF C program may use to
138 * emit BPF_LD_ABS and BPF_LD_IND instructions 148 * emit BPF_LD_ABS and BPF_LD_IND instructions
@@ -169,6 +179,8 @@ struct bpf_map_def {
169 179
170static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = 180static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
171 (void *) BPF_FUNC_skb_load_bytes; 181 (void *) BPF_FUNC_skb_load_bytes;
182static int (*bpf_skb_load_bytes_relative)(void *ctx, int off, void *to, int len, __u32 start_header) =
183 (void *) BPF_FUNC_skb_load_bytes_relative;
172static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = 184static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
173 (void *) BPF_FUNC_skb_store_bytes; 185 (void *) BPF_FUNC_skb_store_bytes;
174static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = 186static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h
index d0811b3d6a6f..315a44fa32af 100644
--- a/tools/testing/selftests/bpf/bpf_util.h
+++ b/tools/testing/selftests/bpf/bpf_util.h
@@ -44,4 +44,8 @@ static inline unsigned int bpf_num_possible_cpus(void)
44 name[bpf_num_possible_cpus()] 44 name[bpf_num_possible_cpus()]
45#define bpf_percpu(name, cpu) name[(cpu)].v 45#define bpf_percpu(name, cpu) name[(cpu)].v
46 46
47#ifndef ARRAY_SIZE
48# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
49#endif
50
47#endif /* __BPF_UTIL__ */ 51#endif /* __BPF_UTIL__ */
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c
index c87b4e052ce9..cf16948aad4a 100644
--- a/tools/testing/selftests/bpf/cgroup_helpers.c
+++ b/tools/testing/selftests/bpf/cgroup_helpers.c
@@ -118,7 +118,7 @@ static int join_cgroup_from_top(char *cgroup_path)
118 * 118 *
119 * On success, it returns 0, otherwise on failure it returns 1. 119 * On success, it returns 0, otherwise on failure it returns 1.
120 */ 120 */
121int join_cgroup(char *path) 121int join_cgroup(const char *path)
122{ 122{
123 char cgroup_path[PATH_MAX + 1]; 123 char cgroup_path[PATH_MAX + 1];
124 124
@@ -158,7 +158,7 @@ void cleanup_cgroup_environment(void)
158 * On success, it returns the file descriptor. On failure it returns 0. 158 * On success, it returns the file descriptor. On failure it returns 0.
159 * If there is a failure, it prints the error to stderr. 159 * If there is a failure, it prints the error to stderr.
160 */ 160 */
161int create_and_get_cgroup(char *path) 161int create_and_get_cgroup(const char *path)
162{ 162{
163 char cgroup_path[PATH_MAX + 1]; 163 char cgroup_path[PATH_MAX + 1];
164 int fd; 164 int fd;
@@ -186,7 +186,7 @@ int create_and_get_cgroup(char *path)
186 * which is an invalid cgroup id. 186 * which is an invalid cgroup id.
187 * If there is a failure, it prints the error to stderr. 187 * If there is a failure, it prints the error to stderr.
188 */ 188 */
189unsigned long long get_cgroup_id(char *path) 189unsigned long long get_cgroup_id(const char *path)
190{ 190{
191 int dirfd, err, flags, mount_id, fhsize; 191 int dirfd, err, flags, mount_id, fhsize;
192 union { 192 union {
diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/selftests/bpf/cgroup_helpers.h
index 20a4a5dcd469..d64bb8957090 100644
--- a/tools/testing/selftests/bpf/cgroup_helpers.h
+++ b/tools/testing/selftests/bpf/cgroup_helpers.h
@@ -9,10 +9,10 @@
9 __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__) 9 __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
10 10
11 11
12int create_and_get_cgroup(char *path); 12int create_and_get_cgroup(const char *path);
13int join_cgroup(char *path); 13int join_cgroup(const char *path);
14int setup_cgroup_environment(void); 14int setup_cgroup_environment(void);
15void cleanup_cgroup_environment(void); 15void cleanup_cgroup_environment(void);
16unsigned long long get_cgroup_id(char *path); 16unsigned long long get_cgroup_id(const char *path);
17 17
18#endif 18#endif
diff --git a/tools/testing/selftests/bpf/socket_cookie_prog.c b/tools/testing/selftests/bpf/socket_cookie_prog.c
new file mode 100644
index 000000000000..9ff8ac4b0bf6
--- /dev/null
+++ b/tools/testing/selftests/bpf/socket_cookie_prog.c
@@ -0,0 +1,60 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <linux/bpf.h>
5#include <sys/socket.h>
6
7#include "bpf_helpers.h"
8#include "bpf_endian.h"
9
10struct bpf_map_def SEC("maps") socket_cookies = {
11 .type = BPF_MAP_TYPE_HASH,
12 .key_size = sizeof(__u64),
13 .value_size = sizeof(__u32),
14 .max_entries = 1 << 8,
15};
16
17SEC("cgroup/connect6")
18int set_cookie(struct bpf_sock_addr *ctx)
19{
20 __u32 cookie_value = 0xFF;
21 __u64 cookie_key;
22
23 if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6)
24 return 1;
25
26 cookie_key = bpf_get_socket_cookie(ctx);
27 if (bpf_map_update_elem(&socket_cookies, &cookie_key, &cookie_value, 0))
28 return 0;
29
30 return 1;
31}
32
33SEC("sockops")
34int update_cookie(struct bpf_sock_ops *ctx)
35{
36 __u32 new_cookie_value;
37 __u32 *cookie_value;
38 __u64 cookie_key;
39
40 if (ctx->family != AF_INET6)
41 return 1;
42
43 if (ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB)
44 return 1;
45
46 cookie_key = bpf_get_socket_cookie(ctx);
47
48 cookie_value = bpf_map_lookup_elem(&socket_cookies, &cookie_key);
49 if (!cookie_value)
50 return 1;
51
52 new_cookie_value = (ctx->local_port << 8) | *cookie_value;
53 bpf_map_update_elem(&socket_cookies, &cookie_key, &new_cookie_value, 0);
54
55 return 1;
56}
57
58int _version SEC("version") = 1;
59
60char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/tcp_client.py b/tools/testing/selftests/bpf/tcp_client.py
index 481dccdf140c..7f8200a8702b 100755
--- a/tools/testing/selftests/bpf/tcp_client.py
+++ b/tools/testing/selftests/bpf/tcp_client.py
@@ -1,4 +1,4 @@
1#!/usr/bin/env python2 1#!/usr/bin/env python3
2# 2#
3# SPDX-License-Identifier: GPL-2.0 3# SPDX-License-Identifier: GPL-2.0
4# 4#
@@ -9,11 +9,11 @@ import subprocess
9import select 9import select
10 10
11def read(sock, n): 11def read(sock, n):
12 buf = '' 12 buf = b''
13 while len(buf) < n: 13 while len(buf) < n:
14 rem = n - len(buf) 14 rem = n - len(buf)
15 try: s = sock.recv(rem) 15 try: s = sock.recv(rem)
16 except (socket.error), e: return '' 16 except (socket.error) as e: return b''
17 buf += s 17 buf += s
18 return buf 18 return buf
19 19
@@ -22,7 +22,7 @@ def send(sock, s):
22 count = 0 22 count = 0
23 while count < total: 23 while count < total:
24 try: n = sock.send(s) 24 try: n = sock.send(s)
25 except (socket.error), e: n = 0 25 except (socket.error) as e: n = 0
26 if n == 0: 26 if n == 0:
27 return count; 27 return count;
28 count += n 28 count += n
@@ -39,10 +39,10 @@ try:
39except socket.error as e: 39except socket.error as e:
40 sys.exit(1) 40 sys.exit(1)
41 41
42buf = '' 42buf = b''
43n = 0 43n = 0
44while n < 1000: 44while n < 1000:
45 buf += '+' 45 buf += b'+'
46 n += 1 46 n += 1
47 47
48sock.settimeout(1); 48sock.settimeout(1);
diff --git a/tools/testing/selftests/bpf/tcp_server.py b/tools/testing/selftests/bpf/tcp_server.py
index bc454d7d0be2..b39903fca4c8 100755
--- a/tools/testing/selftests/bpf/tcp_server.py
+++ b/tools/testing/selftests/bpf/tcp_server.py
@@ -1,4 +1,4 @@
1#!/usr/bin/env python2 1#!/usr/bin/env python3
2# 2#
3# SPDX-License-Identifier: GPL-2.0 3# SPDX-License-Identifier: GPL-2.0
4# 4#
@@ -9,11 +9,11 @@ import subprocess
9import select 9import select
10 10
11def read(sock, n): 11def read(sock, n):
12 buf = '' 12 buf = b''
13 while len(buf) < n: 13 while len(buf) < n:
14 rem = n - len(buf) 14 rem = n - len(buf)
15 try: s = sock.recv(rem) 15 try: s = sock.recv(rem)
16 except (socket.error), e: return '' 16 except (socket.error) as e: return b''
17 buf += s 17 buf += s
18 return buf 18 return buf
19 19
@@ -22,7 +22,7 @@ def send(sock, s):
22 count = 0 22 count = 0
23 while count < total: 23 while count < total:
24 try: n = sock.send(s) 24 try: n = sock.send(s)
25 except (socket.error), e: n = 0 25 except (socket.error) as e: n = 0
26 if n == 0: 26 if n == 0:
27 return count; 27 return count;
28 count += n 28 count += n
@@ -43,7 +43,7 @@ host = socket.gethostname()
43 43
44try: serverSocket.bind((host, 0)) 44try: serverSocket.bind((host, 0))
45except socket.error as msg: 45except socket.error as msg:
46 print 'bind fails: ', msg 46 print('bind fails: ' + str(msg))
47 47
48sn = serverSocket.getsockname() 48sn = serverSocket.getsockname()
49serverPort = sn[1] 49serverPort = sn[1]
@@ -51,10 +51,10 @@ serverPort = sn[1]
51cmdStr = ("./tcp_client.py %d &") % (serverPort) 51cmdStr = ("./tcp_client.py %d &") % (serverPort)
52os.system(cmdStr) 52os.system(cmdStr)
53 53
54buf = '' 54buf = b''
55n = 0 55n = 0
56while n < 500: 56while n < 500:
57 buf += '.' 57 buf += b'.'
58 n += 1 58 n += 1
59 59
60serverSocket.listen(MAX_PORTS) 60serverSocket.listen(MAX_PORTS)
@@ -79,5 +79,5 @@ while True:
79 serverSocket.close() 79 serverSocket.close()
80 sys.exit(0) 80 sys.exit(0)
81 else: 81 else:
82 print 'Select timeout!' 82 print('Select timeout!')
83 sys.exit(1) 83 sys.exit(1)
diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c
index 6b1b302310fe..5f377ec53f2f 100644
--- a/tools/testing/selftests/bpf/test_align.c
+++ b/tools/testing/selftests/bpf/test_align.c
@@ -18,10 +18,7 @@
18 18
19#include "../../../include/linux/filter.h" 19#include "../../../include/linux/filter.h"
20#include "bpf_rlimit.h" 20#include "bpf_rlimit.h"
21 21#include "bpf_util.h"
22#ifndef ARRAY_SIZE
23# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
24#endif
25 22
26#define MAX_INSNS 512 23#define MAX_INSNS 512
27#define MAX_MATCHES 16 24#define MAX_MATCHES 16
diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c
index ffdd27737c9e..6b5cfeb7a9cc 100644
--- a/tools/testing/selftests/bpf/test_btf.c
+++ b/tools/testing/selftests/bpf/test_btf.c
@@ -19,6 +19,7 @@
19#include <bpf/btf.h> 19#include <bpf/btf.h>
20 20
21#include "bpf_rlimit.h" 21#include "bpf_rlimit.h"
22#include "bpf_util.h"
22 23
23static uint32_t pass_cnt; 24static uint32_t pass_cnt;
24static uint32_t error_cnt; 25static uint32_t error_cnt;
@@ -93,10 +94,6 @@ static int __base_pr(const char *format, ...)
93#define MAX_NR_RAW_TYPES 1024 94#define MAX_NR_RAW_TYPES 1024
94#define BTF_LOG_BUF_SIZE 65535 95#define BTF_LOG_BUF_SIZE 65535
95 96
96#ifndef ARRAY_SIZE
97# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
98#endif
99
100static struct args { 97static struct args {
101 unsigned int raw_test_num; 98 unsigned int raw_test_num;
102 unsigned int file_test_num; 99 unsigned int file_test_num;
@@ -131,6 +128,8 @@ struct btf_raw_test {
131 __u32 max_entries; 128 __u32 max_entries;
132 bool btf_load_err; 129 bool btf_load_err;
133 bool map_create_err; 130 bool map_create_err;
131 bool ordered_map;
132 bool lossless_map;
134 int hdr_len_delta; 133 int hdr_len_delta;
135 int type_off_delta; 134 int type_off_delta;
136 int str_off_delta; 135 int str_off_delta;
@@ -2093,8 +2092,7 @@ struct pprint_mapv {
2093 } aenum; 2092 } aenum;
2094}; 2093};
2095 2094
2096static struct btf_raw_test pprint_test = { 2095static struct btf_raw_test pprint_test_template = {
2097 .descr = "BTF pretty print test #1",
2098 .raw_types = { 2096 .raw_types = {
2099 /* unsighed char */ /* [1] */ 2097 /* unsighed char */ /* [1] */
2100 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1), 2098 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
@@ -2146,8 +2144,6 @@ static struct btf_raw_test pprint_test = {
2146 }, 2144 },
2147 .str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum", 2145 .str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum",
2148 .str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"), 2146 .str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
2149 .map_type = BPF_MAP_TYPE_ARRAY,
2150 .map_name = "pprint_test",
2151 .key_size = sizeof(unsigned int), 2147 .key_size = sizeof(unsigned int),
2152 .value_size = sizeof(struct pprint_mapv), 2148 .value_size = sizeof(struct pprint_mapv),
2153 .key_type_id = 3, /* unsigned int */ 2149 .key_type_id = 3, /* unsigned int */
@@ -2155,6 +2151,40 @@ static struct btf_raw_test pprint_test = {
2155 .max_entries = 128 * 1024, 2151 .max_entries = 128 * 1024,
2156}; 2152};
2157 2153
2154static struct btf_pprint_test_meta {
2155 const char *descr;
2156 enum bpf_map_type map_type;
2157 const char *map_name;
2158 bool ordered_map;
2159 bool lossless_map;
2160} pprint_tests_meta[] = {
2161{
2162 .descr = "BTF pretty print array",
2163 .map_type = BPF_MAP_TYPE_ARRAY,
2164 .map_name = "pprint_test_array",
2165 .ordered_map = true,
2166 .lossless_map = true,
2167},
2168
2169{
2170 .descr = "BTF pretty print hash",
2171 .map_type = BPF_MAP_TYPE_HASH,
2172 .map_name = "pprint_test_hash",
2173 .ordered_map = false,
2174 .lossless_map = true,
2175},
2176
2177{
2178 .descr = "BTF pretty print lru hash",
2179 .map_type = BPF_MAP_TYPE_LRU_HASH,
2180 .map_name = "pprint_test_lru_hash",
2181 .ordered_map = false,
2182 .lossless_map = false,
2183},
2184
2185};
2186
2187
2158static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) 2188static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
2159{ 2189{
2160 v->ui32 = i; 2190 v->ui32 = i;
@@ -2166,10 +2196,12 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
2166 v->aenum = i & 0x03; 2196 v->aenum = i & 0x03;
2167} 2197}
2168 2198
2169static int test_pprint(void) 2199static int do_test_pprint(void)
2170{ 2200{
2171 const struct btf_raw_test *test = &pprint_test; 2201 const struct btf_raw_test *test = &pprint_test_template;
2172 struct bpf_create_map_attr create_attr = {}; 2202 struct bpf_create_map_attr create_attr = {};
2203 unsigned int key, nr_read_elems;
2204 bool ordered_map, lossless_map;
2173 int map_fd = -1, btf_fd = -1; 2205 int map_fd = -1, btf_fd = -1;
2174 struct pprint_mapv mapv = {}; 2206 struct pprint_mapv mapv = {};
2175 unsigned int raw_btf_size; 2207 unsigned int raw_btf_size;
@@ -2178,7 +2210,6 @@ static int test_pprint(void)
2178 char pin_path[255]; 2210 char pin_path[255];
2179 size_t line_len = 0; 2211 size_t line_len = 0;
2180 char *line = NULL; 2212 char *line = NULL;
2181 unsigned int key;
2182 uint8_t *raw_btf; 2213 uint8_t *raw_btf;
2183 ssize_t nread; 2214 ssize_t nread;
2184 int err, ret; 2215 int err, ret;
@@ -2251,14 +2282,18 @@ static int test_pprint(void)
2251 goto done; 2282 goto done;
2252 } 2283 }
2253 2284
2254 key = 0; 2285 nr_read_elems = 0;
2286 ordered_map = test->ordered_map;
2287 lossless_map = test->lossless_map;
2255 do { 2288 do {
2256 ssize_t nexpected_line; 2289 ssize_t nexpected_line;
2290 unsigned int next_key;
2257 2291
2258 set_pprint_mapv(&mapv, key); 2292 next_key = ordered_map ? nr_read_elems : atoi(line);
2293 set_pprint_mapv(&mapv, next_key);
2259 nexpected_line = snprintf(expected_line, sizeof(expected_line), 2294 nexpected_line = snprintf(expected_line, sizeof(expected_line),
2260 "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n", 2295 "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
2261 key, 2296 next_key,
2262 mapv.ui32, mapv.si32, 2297 mapv.ui32, mapv.si32,
2263 mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b, 2298 mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b,
2264 mapv.ui64, 2299 mapv.ui64,
@@ -2281,11 +2316,12 @@ static int test_pprint(void)
2281 } 2316 }
2282 2317
2283 nread = getline(&line, &line_len, pin_file); 2318 nread = getline(&line, &line_len, pin_file);
2284 } while (++key < test->max_entries && nread > 0); 2319 } while (++nr_read_elems < test->max_entries && nread > 0);
2285 2320
2286 if (CHECK(key < test->max_entries, 2321 if (lossless_map &&
2287 "Unexpected EOF. key:%u test->max_entries:%u", 2322 CHECK(nr_read_elems < test->max_entries,
2288 key, test->max_entries)) { 2323 "Unexpected EOF. nr_read_elems:%u test->max_entries:%u",
2324 nr_read_elems, test->max_entries)) {
2289 err = -1; 2325 err = -1;
2290 goto done; 2326 goto done;
2291 } 2327 }
@@ -2314,6 +2350,24 @@ done:
2314 return err; 2350 return err;
2315} 2351}
2316 2352
2353static int test_pprint(void)
2354{
2355 unsigned int i;
2356 int err = 0;
2357
2358 for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
2359 pprint_test_template.descr = pprint_tests_meta[i].descr;
2360 pprint_test_template.map_type = pprint_tests_meta[i].map_type;
2361 pprint_test_template.map_name = pprint_tests_meta[i].map_name;
2362 pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
2363 pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
2364
2365 err |= count_result(do_test_pprint());
2366 }
2367
2368 return err;
2369}
2370
2317static void usage(const char *cmd) 2371static void usage(const char *cmd)
2318{ 2372{
2319 fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n", 2373 fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n",
@@ -2409,7 +2463,7 @@ int main(int argc, char **argv)
2409 err |= test_file(); 2463 err |= test_file();
2410 2464
2411 if (args.pprint_test) 2465 if (args.pprint_test)
2412 err |= count_result(test_pprint()); 2466 err |= test_pprint();
2413 2467
2414 if (args.raw_test || args.get_info_test || args.file_test || 2468 if (args.raw_test || args.get_info_test || args.file_test ||
2415 args.pprint_test) 2469 args.pprint_test)
diff --git a/tools/testing/selftests/bpf/test_cgroup_storage.c b/tools/testing/selftests/bpf/test_cgroup_storage.c
new file mode 100644
index 000000000000..dc83fb2d3f27
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_cgroup_storage.c
@@ -0,0 +1,130 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <assert.h>
3#include <bpf/bpf.h>
4#include <linux/filter.h>
5#include <stdio.h>
6#include <stdlib.h>
7
8#include "cgroup_helpers.h"
9
10char bpf_log_buf[BPF_LOG_BUF_SIZE];
11
12#define TEST_CGROUP "/test-bpf-cgroup-storage-buf/"
13
14int main(int argc, char **argv)
15{
16 struct bpf_insn prog[] = {
17 BPF_LD_MAP_FD(BPF_REG_1, 0), /* map fd */
18 BPF_MOV64_IMM(BPF_REG_2, 0), /* flags, not used */
19 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
20 BPF_FUNC_get_local_storage),
21 BPF_MOV64_IMM(BPF_REG_1, 1),
22 BPF_STX_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0),
23 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
24 BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x1),
25 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
26 BPF_EXIT_INSN(),
27 };
28 size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
29 int error = EXIT_FAILURE;
30 int map_fd, prog_fd, cgroup_fd;
31 struct bpf_cgroup_storage_key key;
32 unsigned long long value;
33
34 map_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE, sizeof(key),
35 sizeof(value), 0, 0);
36 if (map_fd < 0) {
37 printf("Failed to create map: %s\n", strerror(errno));
38 goto out;
39 }
40
41 prog[0].imm = map_fd;
42 prog_fd = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
43 prog, insns_cnt, "GPL", 0,
44 bpf_log_buf, BPF_LOG_BUF_SIZE);
45 if (prog_fd < 0) {
46 printf("Failed to load bpf program: %s\n", bpf_log_buf);
47 goto out;
48 }
49
50 if (setup_cgroup_environment()) {
51 printf("Failed to setup cgroup environment\n");
52 goto err;
53 }
54
55 /* Create a cgroup, get fd, and join it */
56 cgroup_fd = create_and_get_cgroup(TEST_CGROUP);
57 if (!cgroup_fd) {
58 printf("Failed to create test cgroup\n");
59 goto err;
60 }
61
62 if (join_cgroup(TEST_CGROUP)) {
63 printf("Failed to join cgroup\n");
64 goto err;
65 }
66
67 /* Attach the bpf program */
68 if (bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS, 0)) {
69 printf("Failed to attach bpf program\n");
70 goto err;
71 }
72
73 if (bpf_map_get_next_key(map_fd, NULL, &key)) {
74 printf("Failed to get the first key in cgroup storage\n");
75 goto err;
76 }
77
78 if (bpf_map_lookup_elem(map_fd, &key, &value)) {
79 printf("Failed to lookup cgroup storage\n");
80 goto err;
81 }
82
83 /* Every second packet should be dropped */
84 assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
85 assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
86 assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
87
88 /* Check the counter in the cgroup local storage */
89 if (bpf_map_lookup_elem(map_fd, &key, &value)) {
90 printf("Failed to lookup cgroup storage\n");
91 goto err;
92 }
93
94 if (value != 3) {
95 printf("Unexpected data in the cgroup storage: %llu\n", value);
96 goto err;
97 }
98
99 /* Bump the counter in the cgroup local storage */
100 value++;
101 if (bpf_map_update_elem(map_fd, &key, &value, 0)) {
102 printf("Failed to update the data in the cgroup storage\n");
103 goto err;
104 }
105
106 /* Every second packet should be dropped */
107 assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
108 assert(system("ping localhost -c 1 -W 1 -q > /dev/null"));
109 assert(system("ping localhost -c 1 -W 1 -q > /dev/null") == 0);
110
111 /* Check the final value of the counter in the cgroup local storage */
112 if (bpf_map_lookup_elem(map_fd, &key, &value)) {
113 printf("Failed to lookup the cgroup storage\n");
114 goto err;
115 }
116
117 if (value != 7) {
118 printf("Unexpected data in the cgroup storage: %llu\n", value);
119 goto err;
120 }
121
122 error = 0;
123 printf("test_cgroup_storage:PASS\n");
124
125err:
126 cleanup_cgroup_environment();
127
128out:
129 return error;
130}
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c
index 6c253343a6f9..6f54f84144a0 100644
--- a/tools/testing/selftests/bpf/test_maps.c
+++ b/tools/testing/selftests/bpf/test_maps.c
@@ -17,7 +17,8 @@
17#include <stdlib.h> 17#include <stdlib.h>
18 18
19#include <sys/wait.h> 19#include <sys/wait.h>
20 20#include <sys/socket.h>
21#include <netinet/in.h>
21#include <linux/bpf.h> 22#include <linux/bpf.h>
22 23
23#include <bpf/bpf.h> 24#include <bpf/bpf.h>
@@ -26,8 +27,21 @@
26#include "bpf_util.h" 27#include "bpf_util.h"
27#include "bpf_rlimit.h" 28#include "bpf_rlimit.h"
28 29
30#ifndef ENOTSUPP
31#define ENOTSUPP 524
32#endif
33
29static int map_flags; 34static int map_flags;
30 35
36#define CHECK(condition, tag, format...) ({ \
37 int __ret = !!(condition); \
38 if (__ret) { \
39 printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \
40 printf(format); \
41 exit(-1); \
42 } \
43})
44
31static void test_hashmap(int task, void *data) 45static void test_hashmap(int task, void *data)
32{ 46{
33 long long key, next_key, first_key, value; 47 long long key, next_key, first_key, value;
@@ -1150,6 +1164,250 @@ static void test_map_wronly(void)
1150 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM); 1164 assert(bpf_map_get_next_key(fd, &key, &value) == -1 && errno == EPERM);
1151} 1165}
1152 1166
1167static void prepare_reuseport_grp(int type, int map_fd,
1168 __s64 *fds64, __u64 *sk_cookies,
1169 unsigned int n)
1170{
1171 socklen_t optlen, addrlen;
1172 struct sockaddr_in6 s6;
1173 const __u32 index0 = 0;
1174 const int optval = 1;
1175 unsigned int i;
1176 u64 sk_cookie;
1177 __s64 fd64;
1178 int err;
1179
1180 s6.sin6_family = AF_INET6;
1181 s6.sin6_addr = in6addr_any;
1182 s6.sin6_port = 0;
1183 addrlen = sizeof(s6);
1184 optlen = sizeof(sk_cookie);
1185
1186 for (i = 0; i < n; i++) {
1187 fd64 = socket(AF_INET6, type, 0);
1188 CHECK(fd64 == -1, "socket()",
1189 "sock_type:%d fd64:%lld errno:%d\n",
1190 type, fd64, errno);
1191
1192 err = setsockopt(fd64, SOL_SOCKET, SO_REUSEPORT,
1193 &optval, sizeof(optval));
1194 CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
1195 "err:%d errno:%d\n", err, errno);
1196
1197 /* reuseport_array does not allow unbound sk */
1198 err = bpf_map_update_elem(map_fd, &index0, &fd64,
1199 BPF_ANY);
1200 CHECK(err != -1 || errno != EINVAL,
1201 "reuseport array update unbound sk",
1202 "sock_type:%d err:%d errno:%d\n",
1203 type, err, errno);
1204
1205 err = bind(fd64, (struct sockaddr *)&s6, sizeof(s6));
1206 CHECK(err == -1, "bind()",
1207 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1208
1209 if (i == 0) {
1210 err = getsockname(fd64, (struct sockaddr *)&s6,
1211 &addrlen);
1212 CHECK(err == -1, "getsockname()",
1213 "sock_type:%d err:%d errno:%d\n",
1214 type, err, errno);
1215 }
1216
1217 err = getsockopt(fd64, SOL_SOCKET, SO_COOKIE, &sk_cookie,
1218 &optlen);
1219 CHECK(err == -1, "getsockopt(SO_COOKIE)",
1220 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1221
1222 if (type == SOCK_STREAM) {
1223 /*
1224 * reuseport_array does not allow
1225 * non-listening tcp sk.
1226 */
1227 err = bpf_map_update_elem(map_fd, &index0, &fd64,
1228 BPF_ANY);
1229 CHECK(err != -1 || errno != EINVAL,
1230 "reuseport array update non-listening sk",
1231 "sock_type:%d err:%d errno:%d\n",
1232 type, err, errno);
1233 err = listen(fd64, 0);
1234 CHECK(err == -1, "listen()",
1235 "sock_type:%d, err:%d errno:%d\n",
1236 type, err, errno);
1237 }
1238
1239 fds64[i] = fd64;
1240 sk_cookies[i] = sk_cookie;
1241 }
1242}
1243
1244static void test_reuseport_array(void)
1245{
1246#define REUSEPORT_FD_IDX(err, last) ({ (err) ? last : !last; })
1247
1248 const __u32 array_size = 4, index0 = 0, index3 = 3;
1249 int types[2] = { SOCK_STREAM, SOCK_DGRAM }, type;
1250 __u64 grpa_cookies[2], sk_cookie, map_cookie;
1251 __s64 grpa_fds64[2] = { -1, -1 }, fd64 = -1;
1252 const __u32 bad_index = array_size;
1253 int map_fd, err, t, f;
1254 __u32 fds_idx = 0;
1255 int fd;
1256
1257 map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
1258 sizeof(__u32), sizeof(__u64), array_size, 0);
1259 CHECK(map_fd == -1, "reuseport array create",
1260 "map_fd:%d, errno:%d\n", map_fd, errno);
1261
1262 /* Test lookup/update/delete with invalid index */
1263 err = bpf_map_delete_elem(map_fd, &bad_index);
1264 CHECK(err != -1 || errno != E2BIG, "reuseport array del >=max_entries",
1265 "err:%d errno:%d\n", err, errno);
1266
1267 err = bpf_map_update_elem(map_fd, &bad_index, &fd64, BPF_ANY);
1268 CHECK(err != -1 || errno != E2BIG,
1269 "reuseport array update >=max_entries",
1270 "err:%d errno:%d\n", err, errno);
1271
1272 err = bpf_map_lookup_elem(map_fd, &bad_index, &map_cookie);
1273 CHECK(err != -1 || errno != ENOENT,
1274 "reuseport array update >=max_entries",
1275 "err:%d errno:%d\n", err, errno);
1276
1277 /* Test lookup/delete non existence elem */
1278 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1279 CHECK(err != -1 || errno != ENOENT,
1280 "reuseport array lookup not-exist elem",
1281 "err:%d errno:%d\n", err, errno);
1282 err = bpf_map_delete_elem(map_fd, &index3);
1283 CHECK(err != -1 || errno != ENOENT,
1284 "reuseport array del not-exist elem",
1285 "err:%d errno:%d\n", err, errno);
1286
1287 for (t = 0; t < ARRAY_SIZE(types); t++) {
1288 type = types[t];
1289
1290 prepare_reuseport_grp(type, map_fd, grpa_fds64,
1291 grpa_cookies, ARRAY_SIZE(grpa_fds64));
1292
1293 /* Test BPF_* update flags */
1294 /* BPF_EXIST failure case */
1295 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1296 BPF_EXIST);
1297 CHECK(err != -1 || errno != ENOENT,
1298 "reuseport array update empty elem BPF_EXIST",
1299 "sock_type:%d err:%d errno:%d\n",
1300 type, err, errno);
1301 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1302
1303 /* BPF_NOEXIST success case */
1304 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1305 BPF_NOEXIST);
1306 CHECK(err == -1,
1307 "reuseport array update empty elem BPF_NOEXIST",
1308 "sock_type:%d err:%d errno:%d\n",
1309 type, err, errno);
1310 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1311
1312 /* BPF_EXIST success case. */
1313 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1314 BPF_EXIST);
1315 CHECK(err == -1,
1316 "reuseport array update same elem BPF_EXIST",
1317 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1318 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1319
1320 /* BPF_NOEXIST failure case */
1321 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1322 BPF_NOEXIST);
1323 CHECK(err != -1 || errno != EEXIST,
1324 "reuseport array update non-empty elem BPF_NOEXIST",
1325 "sock_type:%d err:%d errno:%d\n",
1326 type, err, errno);
1327 fds_idx = REUSEPORT_FD_IDX(err, fds_idx);
1328
1329 /* BPF_ANY case (always succeed) */
1330 err = bpf_map_update_elem(map_fd, &index3, &grpa_fds64[fds_idx],
1331 BPF_ANY);
1332 CHECK(err == -1,
1333 "reuseport array update same sk with BPF_ANY",
1334 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1335
1336 fd64 = grpa_fds64[fds_idx];
1337 sk_cookie = grpa_cookies[fds_idx];
1338
1339 /* The same sk cannot be added to reuseport_array twice */
1340 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_ANY);
1341 CHECK(err != -1 || errno != EBUSY,
1342 "reuseport array update same sk with same index",
1343 "sock_type:%d err:%d errno:%d\n",
1344 type, err, errno);
1345
1346 err = bpf_map_update_elem(map_fd, &index0, &fd64, BPF_ANY);
1347 CHECK(err != -1 || errno != EBUSY,
1348 "reuseport array update same sk with different index",
1349 "sock_type:%d err:%d errno:%d\n",
1350 type, err, errno);
1351
1352 /* Test delete elem */
1353 err = bpf_map_delete_elem(map_fd, &index3);
1354 CHECK(err == -1, "reuseport array delete sk",
1355 "sock_type:%d err:%d errno:%d\n",
1356 type, err, errno);
1357
1358 /* Add it back with BPF_NOEXIST */
1359 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1360 CHECK(err == -1,
1361 "reuseport array re-add with BPF_NOEXIST after del",
1362 "sock_type:%d err:%d errno:%d\n", type, err, errno);
1363
1364 /* Test cookie */
1365 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1366 CHECK(err == -1 || sk_cookie != map_cookie,
1367 "reuseport array lookup re-added sk",
1368 "sock_type:%d err:%d errno:%d sk_cookie:0x%llx map_cookie:0x%llxn",
1369 type, err, errno, sk_cookie, map_cookie);
1370
1371 /* Test elem removed by close() */
1372 for (f = 0; f < ARRAY_SIZE(grpa_fds64); f++)
1373 close(grpa_fds64[f]);
1374 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1375 CHECK(err != -1 || errno != ENOENT,
1376 "reuseport array lookup after close()",
1377 "sock_type:%d err:%d errno:%d\n",
1378 type, err, errno);
1379 }
1380
1381 /* Test SOCK_RAW */
1382 fd64 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
1383 CHECK(fd64 == -1, "socket(SOCK_RAW)", "err:%d errno:%d\n",
1384 err, errno);
1385 err = bpf_map_update_elem(map_fd, &index3, &fd64, BPF_NOEXIST);
1386 CHECK(err != -1 || errno != ENOTSUPP, "reuseport array update SOCK_RAW",
1387 "err:%d errno:%d\n", err, errno);
1388 close(fd64);
1389
1390 /* Close the 64 bit value map */
1391 close(map_fd);
1392
1393 /* Test 32 bit fd */
1394 map_fd = bpf_create_map(BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
1395 sizeof(__u32), sizeof(__u32), array_size, 0);
1396 CHECK(map_fd == -1, "reuseport array create",
1397 "map_fd:%d, errno:%d\n", map_fd, errno);
1398 prepare_reuseport_grp(SOCK_STREAM, map_fd, &fd64, &sk_cookie, 1);
1399 fd = fd64;
1400 err = bpf_map_update_elem(map_fd, &index3, &fd, BPF_NOEXIST);
1401 CHECK(err == -1, "reuseport array update 32 bit fd",
1402 "err:%d errno:%d\n", err, errno);
1403 err = bpf_map_lookup_elem(map_fd, &index3, &map_cookie);
1404 CHECK(err != -1 || errno != ENOSPC,
1405 "reuseport array lookup 32 bit fd",
1406 "err:%d errno:%d\n", err, errno);
1407 close(fd);
1408 close(map_fd);
1409}
1410
1153static void run_all_tests(void) 1411static void run_all_tests(void)
1154{ 1412{
1155 test_hashmap(0, NULL); 1413 test_hashmap(0, NULL);
@@ -1170,6 +1428,8 @@ static void run_all_tests(void)
1170 1428
1171 test_map_rdonly(); 1429 test_map_rdonly();
1172 test_map_wronly(); 1430 test_map_wronly();
1431
1432 test_reuseport_array();
1173} 1433}
1174 1434
1175int main(void) 1435int main(void)
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index be800d0e7a84..d59642e70f56 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -158,8 +158,9 @@ def tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False):
158 else: 158 else:
159 return ret, out 159 return ret, out
160 160
161def bpftool(args, JSON=True, ns="", fail=True): 161def bpftool(args, JSON=True, ns="", fail=True, include_stderr=False):
162 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail) 162 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns,
163 fail=fail, include_stderr=include_stderr)
163 164
164def bpftool_prog_list(expected=None, ns=""): 165def bpftool_prog_list(expected=None, ns=""):
165 _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) 166 _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
@@ -201,6 +202,21 @@ def bpftool_map_list_wait(expected=0, n_retry=20):
201 time.sleep(0.05) 202 time.sleep(0.05)
202 raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps)) 203 raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
203 204
205def bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None,
206 fail=True, include_stderr=False):
207 args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name)
208 if prog_type is not None:
209 args += " type " + prog_type
210 if dev is not None:
211 args += " dev " + dev
212 if len(maps):
213 args += " map " + " map ".join(maps)
214
215 res = bpftool(args, fail=fail, include_stderr=include_stderr)
216 if res[0] == 0:
217 files.append(file_name)
218 return res
219
204def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): 220def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False):
205 if force: 221 if force:
206 args = "-force " + args 222 args = "-force " + args
@@ -307,21 +323,25 @@ class NetdevSim:
307 Class for netdevsim netdevice and its attributes. 323 Class for netdevsim netdevice and its attributes.
308 """ 324 """
309 325
310 def __init__(self): 326 def __init__(self, link=None):
327 self.link = link
328
311 self.dev = self._netdevsim_create() 329 self.dev = self._netdevsim_create()
312 devs.append(self) 330 devs.append(self)
313 331
314 self.ns = "" 332 self.ns = ""
315 333
316 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) 334 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
335 self.sdev_dir = self.dfs_dir + '/sdev/'
317 self.dfs_refresh() 336 self.dfs_refresh()
318 337
319 def __getitem__(self, key): 338 def __getitem__(self, key):
320 return self.dev[key] 339 return self.dev[key]
321 340
322 def _netdevsim_create(self): 341 def _netdevsim_create(self):
342 link = "" if self.link is None else "link " + self.link.dev['ifname']
323 _, old = ip("link show") 343 _, old = ip("link show")
324 ip("link add sim%d type netdevsim") 344 ip("link add sim%d {link} type netdevsim".format(link=link))
325 _, new = ip("link show") 345 _, new = ip("link show")
326 346
327 for dev in new: 347 for dev in new:
@@ -339,13 +359,18 @@ class NetdevSim:
339 self.dfs = DebugfsDir(self.dfs_dir) 359 self.dfs = DebugfsDir(self.dfs_dir)
340 return self.dfs 360 return self.dfs
341 361
362 def dfs_read(self, f):
363 path = os.path.join(self.dfs_dir, f)
364 _, data = cmd('cat %s' % (path))
365 return data.strip()
366
342 def dfs_num_bound_progs(self): 367 def dfs_num_bound_progs(self):
343 path = os.path.join(self.dfs_dir, "bpf_bound_progs") 368 path = os.path.join(self.sdev_dir, "bpf_bound_progs")
344 _, progs = cmd('ls %s' % (path)) 369 _, progs = cmd('ls %s' % (path))
345 return len(progs.split()) 370 return len(progs.split())
346 371
347 def dfs_get_bound_progs(self, expected): 372 def dfs_get_bound_progs(self, expected):
348 progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) 373 progs = DebugfsDir(os.path.join(self.sdev_dir, "bpf_bound_progs"))
349 if expected is not None: 374 if expected is not None:
350 if len(progs) != expected: 375 if len(progs) != expected:
351 fail(True, "%d BPF programs bound, expected %d" % 376 fail(True, "%d BPF programs bound, expected %d" %
@@ -547,11 +572,11 @@ def check_extack(output, reference, args):
547 if skip_extack: 572 if skip_extack:
548 return 573 return
549 lines = output.split("\n") 574 lines = output.split("\n")
550 comp = len(lines) >= 2 and lines[1] == reference 575 comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
551 fail(not comp, "Missing or incorrect netlink extack message") 576 fail(not comp, "Missing or incorrect netlink extack message")
552 577
553def check_extack_nsim(output, reference, args): 578def check_extack_nsim(output, reference, args):
554 check_extack(output, "Error: netdevsim: " + reference, args) 579 check_extack(output, "netdevsim: " + reference, args)
555 580
556def check_no_extack(res, needle): 581def check_no_extack(res, needle):
557 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"), 582 fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
@@ -654,7 +679,7 @@ try:
654 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True, 679 ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
655 fail=False, include_stderr=True) 680 fail=False, include_stderr=True)
656 fail(ret == 0, "TC filter loaded without enabling TC offloads") 681 fail(ret == 0, "TC filter loaded without enabling TC offloads")
657 check_extack(err, "Error: TC offload is disabled on net device.", args) 682 check_extack(err, "TC offload is disabled on net device.", args)
658 sim.wait_for_flush() 683 sim.wait_for_flush()
659 684
660 sim.set_ethtool_tc_offloads(True) 685 sim.set_ethtool_tc_offloads(True)
@@ -694,7 +719,7 @@ try:
694 skip_sw=True, 719 skip_sw=True,
695 fail=False, include_stderr=True) 720 fail=False, include_stderr=True)
696 fail(ret == 0, "Offloaded a filter to chain other than 0") 721 fail(ret == 0, "Offloaded a filter to chain other than 0")
697 check_extack(err, "Error: Driver supports only offload of chain 0.", args) 722 check_extack(err, "Driver supports only offload of chain 0.", args)
698 sim.tc_flush_filters() 723 sim.tc_flush_filters()
699 724
700 start_test("Test TC replace...") 725 start_test("Test TC replace...")
@@ -814,24 +839,20 @@ try:
814 "Device parameters reported for non-offloaded program") 839 "Device parameters reported for non-offloaded program")
815 840
816 start_test("Test XDP prog replace with bad flags...") 841 start_test("Test XDP prog replace with bad flags...")
817 ret, _, err = sim.set_xdp(obj, "offload", force=True, 842 ret, _, err = sim.set_xdp(obj, "generic", force=True,
818 fail=False, include_stderr=True) 843 fail=False, include_stderr=True)
819 fail(ret == 0, "Replaced XDP program with a program in different mode") 844 fail(ret == 0, "Replaced XDP program with a program in different mode")
820 check_extack_nsim(err, "program loaded with different flags.", args) 845 fail(err.count("File exists") != 1, "Replaced driver XDP with generic")
821 ret, _, err = sim.set_xdp(obj, "", force=True, 846 ret, _, err = sim.set_xdp(obj, "", force=True,
822 fail=False, include_stderr=True) 847 fail=False, include_stderr=True)
823 fail(ret == 0, "Replaced XDP program with a program in different mode") 848 fail(ret == 0, "Replaced XDP program with a program in different mode")
824 check_extack_nsim(err, "program loaded with different flags.", args) 849 check_extack(err, "program loaded with different flags.", args)
825 850
826 start_test("Test XDP prog remove with bad flags...") 851 start_test("Test XDP prog remove with bad flags...")
827 ret, _, err = sim.unset_xdp("offload", force=True,
828 fail=False, include_stderr=True)
829 fail(ret == 0, "Removed program with a bad mode mode")
830 check_extack_nsim(err, "program loaded with different flags.", args)
831 ret, _, err = sim.unset_xdp("", force=True, 852 ret, _, err = sim.unset_xdp("", force=True,
832 fail=False, include_stderr=True) 853 fail=False, include_stderr=True)
833 fail(ret == 0, "Removed program with a bad mode mode") 854 fail(ret == 0, "Removed program with a bad mode")
834 check_extack_nsim(err, "program loaded with different flags.", args) 855 check_extack(err, "program loaded with different flags.", args)
835 856
836 start_test("Test MTU restrictions...") 857 start_test("Test MTU restrictions...")
837 ret, _ = sim.set_mtu(9000, fail=False) 858 ret, _ = sim.set_mtu(9000, fail=False)
@@ -846,6 +867,25 @@ try:
846 sim.set_mtu(1500) 867 sim.set_mtu(1500)
847 868
848 sim.wait_for_flush() 869 sim.wait_for_flush()
870 start_test("Test non-offload XDP attaching to HW...")
871 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload")
872 nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
873 ret, _, err = sim.set_xdp(nooffload, "offload",
874 fail=False, include_stderr=True)
875 fail(ret == 0, "attached non-offloaded XDP program to HW")
876 check_extack_nsim(err, "xdpoffload of non-bound program.", args)
877 rm("/sys/fs/bpf/nooffload")
878
879 start_test("Test offload XDP attaching to drv...")
880 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",
881 dev=sim['ifname'])
882 offload = bpf_pinned("/sys/fs/bpf/offload")
883 ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
884 fail(ret == 0, "attached offloaded XDP program to drv")
885 check_extack(err, "using device-bound program without HW_MODE flag is not supported.", args)
886 rm("/sys/fs/bpf/offload")
887 sim.wait_for_flush()
888
849 start_test("Test XDP offload...") 889 start_test("Test XDP offload...")
850 _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True) 890 _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True)
851 ipl = sim.ip_link_show(xdp=True) 891 ipl = sim.ip_link_show(xdp=True)
@@ -891,6 +931,60 @@ try:
891 rm(pin_file) 931 rm(pin_file)
892 bpftool_prog_list_wait(expected=0) 932 bpftool_prog_list_wait(expected=0)
893 933
934 start_test("Test multi-attachment XDP - attach...")
935 sim.set_xdp(obj, "offload")
936 xdp = sim.ip_link_show(xdp=True)["xdp"]
937 offloaded = sim.dfs_read("bpf_offloaded_id")
938 fail("prog" not in xdp, "Base program not reported in single program mode")
939 fail(len(ipl["xdp"]["attached"]) != 1,
940 "Wrong attached program count with one program")
941
942 sim.set_xdp(obj, "")
943 two_xdps = sim.ip_link_show(xdp=True)["xdp"]
944 offloaded2 = sim.dfs_read("bpf_offloaded_id")
945
946 fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs")
947 fail("prog" in two_xdps, "Base program reported in multi program mode")
948 fail(xdp["attached"][0] not in two_xdps["attached"],
949 "Offload program not reported after driver activated")
950 fail(len(two_xdps["attached"]) != 2,
951 "Wrong attached program count with two programs")
952 fail(two_xdps["attached"][0]["prog"]["id"] ==
953 two_xdps["attached"][1]["prog"]["id"],
954 "offloaded and drv programs have the same id")
955 fail(offloaded != offloaded2,
956 "offload ID changed after loading driver program")
957
958 start_test("Test multi-attachment XDP - replace...")
959 ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
960 fail(err.count("busy") != 1, "Replaced one of programs without -force")
961
962 start_test("Test multi-attachment XDP - detach...")
963 ret, _, err = sim.unset_xdp("drv", force=True,
964 fail=False, include_stderr=True)
965 fail(ret == 0, "Removed program with a bad mode")
966 check_extack(err, "program loaded with different flags.", args)
967
968 sim.unset_xdp("offload")
969 xdp = sim.ip_link_show(xdp=True)["xdp"]
970 offloaded = sim.dfs_read("bpf_offloaded_id")
971
972 fail(xdp["mode"] != 1, "Bad mode reported after multiple programs")
973 fail("prog" not in xdp,
974 "Base program not reported after multi program mode")
975 fail(xdp["attached"][0] not in two_xdps["attached"],
976 "Offload program not reported after driver activated")
977 fail(len(ipl["xdp"]["attached"]) != 1,
978 "Wrong attached program count with remaining programs")
979 fail(offloaded != "0", "offload ID reported with only driver program left")
980
981 start_test("Test multi-attachment XDP - device remove...")
982 sim.set_xdp(obj, "offload")
983 sim.remove()
984
985 sim = NetdevSim()
986 sim.set_ethtool_tc_offloads(True)
987
894 start_test("Test mixing of TC and XDP...") 988 start_test("Test mixing of TC and XDP...")
895 sim.tc_add_ingress() 989 sim.tc_add_ingress()
896 sim.set_xdp(obj, "offload") 990 sim.set_xdp(obj, "offload")
@@ -1085,6 +1179,106 @@ try:
1085 fail(ret == 0, 1179 fail(ret == 0,
1086 "netdevsim didn't refuse to create a map with offload disabled") 1180 "netdevsim didn't refuse to create a map with offload disabled")
1087 1181
1182 sim.remove()
1183
1184 start_test("Test multi-dev ASIC program reuse...")
1185 simA = NetdevSim()
1186 simB1 = NetdevSim()
1187 simB2 = NetdevSim(link=simB1)
1188 simB3 = NetdevSim(link=simB1)
1189 sims = (simA, simB1, simB2, simB3)
1190 simB = (simB1, simB2, simB3)
1191
1192 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA",
1193 dev=simA['ifname'])
1194 progA = bpf_pinned("/sys/fs/bpf/nsimA")
1195 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB",
1196 dev=simB1['ifname'])
1197 progB = bpf_pinned("/sys/fs/bpf/nsimB")
1198
1199 simA.set_xdp(progA, "offload", JSON=False)
1200 for d in simB:
1201 d.set_xdp(progB, "offload", JSON=False)
1202
1203 start_test("Test multi-dev ASIC cross-dev replace...")
1204 ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False)
1205 fail(ret == 0, "cross-ASIC program allowed")
1206 for d in simB:
1207 ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False)
1208 fail(ret == 0, "cross-ASIC program allowed")
1209
1210 start_test("Test multi-dev ASIC cross-dev install...")
1211 for d in sims:
1212 d.unset_xdp("offload")
1213
1214 ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False,
1215 fail=False, include_stderr=True)
1216 fail(ret == 0, "cross-ASIC program allowed")
1217 check_extack_nsim(err, "program bound to different dev.", args)
1218 for d in simB:
1219 ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False,
1220 fail=False, include_stderr=True)
1221 fail(ret == 0, "cross-ASIC program allowed")
1222 check_extack_nsim(err, "program bound to different dev.", args)
1223
1224 start_test("Test multi-dev ASIC cross-dev map reuse...")
1225
1226 mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
1227 mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
1228
1229 ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
1230 dev=simB3['ifname'],
1231 maps=["idx 0 id %d" % (mapB)],
1232 fail=False)
1233 fail(ret != 0, "couldn't reuse a map on the same ASIC")
1234 rm("/sys/fs/bpf/nsimB_")
1235
1236 ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_",
1237 dev=simA['ifname'],
1238 maps=["idx 0 id %d" % (mapB)],
1239 fail=False, include_stderr=True)
1240 fail(ret == 0, "could reuse a map on a different ASIC")
1241 fail(err.count("offload device mismatch between prog and map") == 0,
1242 "error message missing for cross-ASIC map")
1243
1244 ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
1245 dev=simB1['ifname'],
1246 maps=["idx 0 id %d" % (mapA)],
1247 fail=False, include_stderr=True)
1248 fail(ret == 0, "could reuse a map on a different ASIC")
1249 fail(err.count("offload device mismatch between prog and map") == 0,
1250 "error message missing for cross-ASIC map")
1251
1252 start_test("Test multi-dev ASIC cross-dev destruction...")
1253 bpftool_prog_list_wait(expected=2)
1254
1255 simA.remove()
1256 bpftool_prog_list_wait(expected=1)
1257
1258 ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
1259 fail(ifnameB != simB1['ifname'], "program not bound to originial device")
1260 simB1.remove()
1261 bpftool_prog_list_wait(expected=1)
1262
1263 start_test("Test multi-dev ASIC cross-dev destruction - move...")
1264 ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
1265 fail(ifnameB not in (simB2['ifname'], simB3['ifname']),
1266 "program not bound to remaining devices")
1267
1268 simB2.remove()
1269 ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
1270 fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
1271
1272 simB3.remove()
1273 bpftool_prog_list_wait(expected=0)
1274
1275 start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
1276 ret, out = bpftool("prog show %s" % (progB), fail=False)
1277 fail(ret == 0, "got information about orphaned program")
1278 fail("error" not in out, "no error reported for get info on orphaned")
1279 fail(out["error"] != "can't get prog info: No such device",
1280 "wrong error for get info on orphaned")
1281
1088 print("%s: OK" % (os.path.basename(__file__))) 1282 print("%s: OK" % (os.path.basename(__file__)))
1089 1283
1090finally: 1284finally:
diff --git a/tools/testing/selftests/bpf/test_select_reuseport.c b/tools/testing/selftests/bpf/test_select_reuseport.c
new file mode 100644
index 000000000000..75646d9b34aa
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_select_reuseport.c
@@ -0,0 +1,688 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018 Facebook */
3
4#include <stdlib.h>
5#include <unistd.h>
6#include <stdbool.h>
7#include <string.h>
8#include <errno.h>
9#include <assert.h>
10#include <fcntl.h>
11#include <linux/bpf.h>
12#include <linux/err.h>
13#include <linux/types.h>
14#include <linux/if_ether.h>
15#include <sys/types.h>
16#include <sys/epoll.h>
17#include <sys/socket.h>
18#include <netinet/in.h>
19#include <bpf/bpf.h>
20#include <bpf/libbpf.h>
21#include "bpf_rlimit.h"
22#include "bpf_util.h"
23#include "test_select_reuseport_common.h"
24
25#define MIN_TCPHDR_LEN 20
26#define UDPHDR_LEN 8
27
28#define TCP_SYNCOOKIE_SYSCTL "/proc/sys/net/ipv4/tcp_syncookies"
29#define TCP_FO_SYSCTL "/proc/sys/net/ipv4/tcp_fastopen"
30#define REUSEPORT_ARRAY_SIZE 32
31
32static int result_map, tmp_index_ovr_map, linum_map, data_check_map;
33static enum result expected_results[NR_RESULTS];
34static int sk_fds[REUSEPORT_ARRAY_SIZE];
35static int reuseport_array, outer_map;
36static int select_by_skb_data_prog;
37static int saved_tcp_syncookie;
38static struct bpf_object *obj;
39static int saved_tcp_fo;
40static __u32 index_zero;
41static int epfd;
42
43static union sa46 {
44 struct sockaddr_in6 v6;
45 struct sockaddr_in v4;
46 sa_family_t family;
47} srv_sa;
48
49#define CHECK(condition, tag, format...) ({ \
50 int __ret = !!(condition); \
51 if (__ret) { \
52 printf("%s(%d):FAIL:%s ", __func__, __LINE__, tag); \
53 printf(format); \
54 exit(-1); \
55 } \
56})
57
58static void create_maps(void)
59{
60 struct bpf_create_map_attr attr = {};
61
62 /* Creating reuseport_array */
63 attr.name = "reuseport_array";
64 attr.map_type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY;
65 attr.key_size = sizeof(__u32);
66 attr.value_size = sizeof(__u32);
67 attr.max_entries = REUSEPORT_ARRAY_SIZE;
68
69 reuseport_array = bpf_create_map_xattr(&attr);
70 CHECK(reuseport_array == -1, "creating reuseport_array",
71 "reuseport_array:%d errno:%d\n", reuseport_array, errno);
72
73 /* Creating outer_map */
74 attr.name = "outer_map";
75 attr.map_type = BPF_MAP_TYPE_ARRAY_OF_MAPS;
76 attr.key_size = sizeof(__u32);
77 attr.value_size = sizeof(__u32);
78 attr.max_entries = 1;
79 attr.inner_map_fd = reuseport_array;
80 outer_map = bpf_create_map_xattr(&attr);
81 CHECK(outer_map == -1, "creating outer_map",
82 "outer_map:%d errno:%d\n", outer_map, errno);
83}
84
85static void prepare_bpf_obj(void)
86{
87 struct bpf_program *prog;
88 struct bpf_map *map;
89 int err;
90 struct bpf_object_open_attr attr = {
91 .file = "test_select_reuseport_kern.o",
92 .prog_type = BPF_PROG_TYPE_SK_REUSEPORT,
93 };
94
95 obj = bpf_object__open_xattr(&attr);
96 CHECK(IS_ERR_OR_NULL(obj), "open test_select_reuseport_kern.o",
97 "obj:%p PTR_ERR(obj):%ld\n", obj, PTR_ERR(obj));
98
99 prog = bpf_program__next(NULL, obj);
100 CHECK(!prog, "get first bpf_program", "!prog\n");
101 bpf_program__set_type(prog, attr.prog_type);
102
103 map = bpf_object__find_map_by_name(obj, "outer_map");
104 CHECK(!map, "find outer_map", "!map\n");
105 err = bpf_map__reuse_fd(map, outer_map);
106 CHECK(err, "reuse outer_map", "err:%d\n", err);
107
108 err = bpf_object__load(obj);
109 CHECK(err, "load bpf_object", "err:%d\n", err);
110
111 select_by_skb_data_prog = bpf_program__fd(prog);
112 CHECK(select_by_skb_data_prog == -1, "get prog fd",
113 "select_by_skb_data_prog:%d\n", select_by_skb_data_prog);
114
115 map = bpf_object__find_map_by_name(obj, "result_map");
116 CHECK(!map, "find result_map", "!map\n");
117 result_map = bpf_map__fd(map);
118 CHECK(result_map == -1, "get result_map fd",
119 "result_map:%d\n", result_map);
120
121 map = bpf_object__find_map_by_name(obj, "tmp_index_ovr_map");
122 CHECK(!map, "find tmp_index_ovr_map", "!map\n");
123 tmp_index_ovr_map = bpf_map__fd(map);
124 CHECK(tmp_index_ovr_map == -1, "get tmp_index_ovr_map fd",
125 "tmp_index_ovr_map:%d\n", tmp_index_ovr_map);
126
127 map = bpf_object__find_map_by_name(obj, "linum_map");
128 CHECK(!map, "find linum_map", "!map\n");
129 linum_map = bpf_map__fd(map);
130 CHECK(linum_map == -1, "get linum_map fd",
131 "linum_map:%d\n", linum_map);
132
133 map = bpf_object__find_map_by_name(obj, "data_check_map");
134 CHECK(!map, "find data_check_map", "!map\n");
135 data_check_map = bpf_map__fd(map);
136 CHECK(data_check_map == -1, "get data_check_map fd",
137 "data_check_map:%d\n", data_check_map);
138}
139
140static void sa46_init_loopback(union sa46 *sa, sa_family_t family)
141{
142 memset(sa, 0, sizeof(*sa));
143 sa->family = family;
144 if (sa->family == AF_INET6)
145 sa->v6.sin6_addr = in6addr_loopback;
146 else
147 sa->v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
148}
149
150static void sa46_init_inany(union sa46 *sa, sa_family_t family)
151{
152 memset(sa, 0, sizeof(*sa));
153 sa->family = family;
154 if (sa->family == AF_INET6)
155 sa->v6.sin6_addr = in6addr_any;
156 else
157 sa->v4.sin_addr.s_addr = INADDR_ANY;
158}
159
160static int read_int_sysctl(const char *sysctl)
161{
162 char buf[16];
163 int fd, ret;
164
165 fd = open(sysctl, 0);
166 CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
167 sysctl, fd, errno);
168
169 ret = read(fd, buf, sizeof(buf));
170 CHECK(ret <= 0, "read(sysctl)", "sysctl:%s ret:%d errno:%d\n",
171 sysctl, ret, errno);
172 close(fd);
173
174 return atoi(buf);
175}
176
177static void write_int_sysctl(const char *sysctl, int v)
178{
179 int fd, ret, size;
180 char buf[16];
181
182 fd = open(sysctl, O_RDWR);
183 CHECK(fd == -1, "open(sysctl)", "sysctl:%s fd:%d errno:%d\n",
184 sysctl, fd, errno);
185
186 size = snprintf(buf, sizeof(buf), "%d", v);
187 ret = write(fd, buf, size);
188 CHECK(ret != size, "write(sysctl)",
189 "sysctl:%s ret:%d size:%d errno:%d\n", sysctl, ret, size, errno);
190 close(fd);
191}
192
193static void restore_sysctls(void)
194{
195 write_int_sysctl(TCP_FO_SYSCTL, saved_tcp_fo);
196 write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, saved_tcp_syncookie);
197}
198
199static void enable_fastopen(void)
200{
201 int fo;
202
203 fo = read_int_sysctl(TCP_FO_SYSCTL);
204 write_int_sysctl(TCP_FO_SYSCTL, fo | 7);
205}
206
207static void enable_syncookie(void)
208{
209 write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 2);
210}
211
212static void disable_syncookie(void)
213{
214 write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 0);
215}
216
217static __u32 get_linum(void)
218{
219 __u32 linum;
220 int err;
221
222 err = bpf_map_lookup_elem(linum_map, &index_zero, &linum);
223 CHECK(err == -1, "lookup_elem(linum_map)", "err:%d errno:%d\n",
224 err, errno);
225
226 return linum;
227}
228
229static void check_data(int type, sa_family_t family, const struct cmd *cmd,
230 int cli_fd)
231{
232 struct data_check expected = {}, result;
233 union sa46 cli_sa;
234 socklen_t addrlen;
235 int err;
236
237 addrlen = sizeof(cli_sa);
238 err = getsockname(cli_fd, (struct sockaddr *)&cli_sa,
239 &addrlen);
240 CHECK(err == -1, "getsockname(cli_fd)", "err:%d errno:%d\n",
241 err, errno);
242
243 err = bpf_map_lookup_elem(data_check_map, &index_zero, &result);
244 CHECK(err == -1, "lookup_elem(data_check_map)", "err:%d errno:%d\n",
245 err, errno);
246
247 if (type == SOCK_STREAM) {
248 expected.len = MIN_TCPHDR_LEN;
249 expected.ip_protocol = IPPROTO_TCP;
250 } else {
251 expected.len = UDPHDR_LEN;
252 expected.ip_protocol = IPPROTO_UDP;
253 }
254
255 if (family == AF_INET6) {
256 expected.eth_protocol = htons(ETH_P_IPV6);
257 expected.bind_inany = !srv_sa.v6.sin6_addr.s6_addr32[3] &&
258 !srv_sa.v6.sin6_addr.s6_addr32[2] &&
259 !srv_sa.v6.sin6_addr.s6_addr32[1] &&
260 !srv_sa.v6.sin6_addr.s6_addr32[0];
261
262 memcpy(&expected.skb_addrs[0], cli_sa.v6.sin6_addr.s6_addr32,
263 sizeof(cli_sa.v6.sin6_addr));
264 memcpy(&expected.skb_addrs[4], &in6addr_loopback,
265 sizeof(in6addr_loopback));
266 expected.skb_ports[0] = cli_sa.v6.sin6_port;
267 expected.skb_ports[1] = srv_sa.v6.sin6_port;
268 } else {
269 expected.eth_protocol = htons(ETH_P_IP);
270 expected.bind_inany = !srv_sa.v4.sin_addr.s_addr;
271
272 expected.skb_addrs[0] = cli_sa.v4.sin_addr.s_addr;
273 expected.skb_addrs[1] = htonl(INADDR_LOOPBACK);
274 expected.skb_ports[0] = cli_sa.v4.sin_port;
275 expected.skb_ports[1] = srv_sa.v4.sin_port;
276 }
277
278 if (memcmp(&result, &expected, offsetof(struct data_check,
279 equal_check_end))) {
280 printf("unexpected data_check\n");
281 printf(" result: (0x%x, %u, %u)\n",
282 result.eth_protocol, result.ip_protocol,
283 result.bind_inany);
284 printf("expected: (0x%x, %u, %u)\n",
285 expected.eth_protocol, expected.ip_protocol,
286 expected.bind_inany);
287 CHECK(1, "data_check result != expected",
288 "bpf_prog_linum:%u\n", get_linum());
289 }
290
291 CHECK(!result.hash, "data_check result.hash empty",
292 "result.hash:%u", result.hash);
293
294 expected.len += cmd ? sizeof(*cmd) : 0;
295 if (type == SOCK_STREAM)
296 CHECK(expected.len > result.len, "expected.len > result.len",
297 "expected.len:%u result.len:%u bpf_prog_linum:%u\n",
298 expected.len, result.len, get_linum());
299 else
300 CHECK(expected.len != result.len, "expected.len != result.len",
301 "expected.len:%u result.len:%u bpf_prog_linum:%u\n",
302 expected.len, result.len, get_linum());
303}
304
305static void check_results(void)
306{
307 __u32 results[NR_RESULTS];
308 __u32 i, broken = 0;
309 int err;
310
311 for (i = 0; i < NR_RESULTS; i++) {
312 err = bpf_map_lookup_elem(result_map, &i, &results[i]);
313 CHECK(err == -1, "lookup_elem(result_map)",
314 "i:%u err:%d errno:%d\n", i, err, errno);
315 }
316
317 for (i = 0; i < NR_RESULTS; i++) {
318 if (results[i] != expected_results[i]) {
319 broken = i;
320 break;
321 }
322 }
323
324 if (i == NR_RESULTS)
325 return;
326
327 printf("unexpected result\n");
328 printf(" result: [");
329 printf("%u", results[0]);
330 for (i = 1; i < NR_RESULTS; i++)
331 printf(", %u", results[i]);
332 printf("]\n");
333
334 printf("expected: [");
335 printf("%u", expected_results[0]);
336 for (i = 1; i < NR_RESULTS; i++)
337 printf(", %u", expected_results[i]);
338 printf("]\n");
339
340 CHECK(expected_results[broken] != results[broken],
341 "unexpected result",
342 "expected_results[%u] != results[%u] bpf_prog_linum:%u\n",
343 broken, broken, get_linum());
344}
345
346static int send_data(int type, sa_family_t family, void *data, size_t len,
347 enum result expected)
348{
349 union sa46 cli_sa;
350 int fd, err;
351
352 fd = socket(family, type, 0);
353 CHECK(fd == -1, "socket()", "fd:%d errno:%d\n", fd, errno);
354
355 sa46_init_loopback(&cli_sa, family);
356 err = bind(fd, (struct sockaddr *)&cli_sa, sizeof(cli_sa));
357 CHECK(fd == -1, "bind(cli_sa)", "err:%d errno:%d\n", err, errno);
358
359 err = sendto(fd, data, len, MSG_FASTOPEN, (struct sockaddr *)&srv_sa,
360 sizeof(srv_sa));
361 CHECK(err != len && expected >= PASS,
362 "sendto()", "family:%u err:%d errno:%d expected:%d\n",
363 family, err, errno, expected);
364
365 return fd;
366}
367
368static void do_test(int type, sa_family_t family, struct cmd *cmd,
369 enum result expected)
370{
371 int nev, srv_fd, cli_fd;
372 struct epoll_event ev;
373 struct cmd rcv_cmd;
374 ssize_t nread;
375
376 cli_fd = send_data(type, family, cmd, cmd ? sizeof(*cmd) : 0,
377 expected);
378 nev = epoll_wait(epfd, &ev, 1, expected >= PASS ? 5 : 0);
379 CHECK((nev <= 0 && expected >= PASS) ||
380 (nev > 0 && expected < PASS),
381 "nev <> expected",
382 "nev:%d expected:%d type:%d family:%d data:(%d, %d)\n",
383 nev, expected, type, family,
384 cmd ? cmd->reuseport_index : -1,
385 cmd ? cmd->pass_on_failure : -1);
386 check_results();
387 check_data(type, family, cmd, cli_fd);
388
389 if (expected < PASS)
390 return;
391
392 CHECK(expected != PASS_ERR_SK_SELECT_REUSEPORT &&
393 cmd->reuseport_index != ev.data.u32,
394 "check cmd->reuseport_index",
395 "cmd:(%u, %u) ev.data.u32:%u\n",
396 cmd->pass_on_failure, cmd->reuseport_index, ev.data.u32);
397
398 srv_fd = sk_fds[ev.data.u32];
399 if (type == SOCK_STREAM) {
400 int new_fd = accept(srv_fd, NULL, 0);
401
402 CHECK(new_fd == -1, "accept(srv_fd)",
403 "ev.data.u32:%u new_fd:%d errno:%d\n",
404 ev.data.u32, new_fd, errno);
405
406 nread = recv(new_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
407 CHECK(nread != sizeof(rcv_cmd),
408 "recv(new_fd)",
409 "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
410 ev.data.u32, nread, sizeof(rcv_cmd), errno);
411
412 close(new_fd);
413 } else {
414 nread = recv(srv_fd, &rcv_cmd, sizeof(rcv_cmd), MSG_DONTWAIT);
415 CHECK(nread != sizeof(rcv_cmd),
416 "recv(sk_fds)",
417 "ev.data.u32:%u nread:%zd sizeof(rcv_cmd):%zu errno:%d\n",
418 ev.data.u32, nread, sizeof(rcv_cmd), errno);
419 }
420
421 close(cli_fd);
422}
423
424static void test_err_inner_map(int type, sa_family_t family)
425{
426 struct cmd cmd = {
427 .reuseport_index = 0,
428 .pass_on_failure = 0,
429 };
430
431 printf("%s: ", __func__);
432 expected_results[DROP_ERR_INNER_MAP]++;
433 do_test(type, family, &cmd, DROP_ERR_INNER_MAP);
434 printf("OK\n");
435}
436
437static void test_err_skb_data(int type, sa_family_t family)
438{
439 printf("%s: ", __func__);
440 expected_results[DROP_ERR_SKB_DATA]++;
441 do_test(type, family, NULL, DROP_ERR_SKB_DATA);
442 printf("OK\n");
443}
444
445static void test_err_sk_select_port(int type, sa_family_t family)
446{
447 struct cmd cmd = {
448 .reuseport_index = REUSEPORT_ARRAY_SIZE,
449 .pass_on_failure = 0,
450 };
451
452 printf("%s: ", __func__);
453 expected_results[DROP_ERR_SK_SELECT_REUSEPORT]++;
454 do_test(type, family, &cmd, DROP_ERR_SK_SELECT_REUSEPORT);
455 printf("OK\n");
456}
457
458static void test_pass(int type, sa_family_t family)
459{
460 struct cmd cmd;
461 int i;
462
463 printf("%s: ", __func__);
464 cmd.pass_on_failure = 0;
465 for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
466 expected_results[PASS]++;
467 cmd.reuseport_index = i;
468 do_test(type, family, &cmd, PASS);
469 }
470 printf("OK\n");
471}
472
473static void test_syncookie(int type, sa_family_t family)
474{
475 int err, tmp_index = 1;
476 struct cmd cmd = {
477 .reuseport_index = 0,
478 .pass_on_failure = 0,
479 };
480
481 if (type != SOCK_STREAM)
482 return;
483
484 printf("%s: ", __func__);
485 /*
486 * +1 for TCP-SYN and
487 * +1 for the TCP-ACK (ack the syncookie)
488 */
489 expected_results[PASS] += 2;
490 enable_syncookie();
491 /*
492 * Simulate TCP-SYN and TCP-ACK are handled by two different sk:
493 * TCP-SYN: select sk_fds[tmp_index = 1] tmp_index is from the
494 * tmp_index_ovr_map
495 * TCP-ACK: select sk_fds[reuseport_index = 0] reuseport_index
496 * is from the cmd.reuseport_index
497 */
498 err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero,
499 &tmp_index, BPF_ANY);
500 CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, 1)",
501 "err:%d errno:%d\n", err, errno);
502 do_test(type, family, &cmd, PASS);
503 err = bpf_map_lookup_elem(tmp_index_ovr_map, &index_zero,
504 &tmp_index);
505 CHECK(err == -1 || tmp_index != -1,
506 "lookup_elem(tmp_index_ovr_map)",
507 "err:%d errno:%d tmp_index:%d\n",
508 err, errno, tmp_index);
509 disable_syncookie();
510 printf("OK\n");
511}
512
513static void test_pass_on_err(int type, sa_family_t family)
514{
515 struct cmd cmd = {
516 .reuseport_index = REUSEPORT_ARRAY_SIZE,
517 .pass_on_failure = 1,
518 };
519
520 printf("%s: ", __func__);
521 expected_results[PASS_ERR_SK_SELECT_REUSEPORT] += 1;
522 do_test(type, family, &cmd, PASS_ERR_SK_SELECT_REUSEPORT);
523 printf("OK\n");
524}
525
526static void prepare_sk_fds(int type, sa_family_t family, bool inany)
527{
528 const int first = REUSEPORT_ARRAY_SIZE - 1;
529 int i, err, optval = 1;
530 struct epoll_event ev;
531 socklen_t addrlen;
532
533 if (inany)
534 sa46_init_inany(&srv_sa, family);
535 else
536 sa46_init_loopback(&srv_sa, family);
537 addrlen = sizeof(srv_sa);
538
539 /*
540 * The sk_fds[] is filled from the back such that the order
541 * is exactly opposite to the (struct sock_reuseport *)reuse->socks[].
542 */
543 for (i = first; i >= 0; i--) {
544 sk_fds[i] = socket(family, type, 0);
545 CHECK(sk_fds[i] == -1, "socket()", "sk_fds[%d]:%d errno:%d\n",
546 i, sk_fds[i], errno);
547 err = setsockopt(sk_fds[i], SOL_SOCKET, SO_REUSEPORT,
548 &optval, sizeof(optval));
549 CHECK(err == -1, "setsockopt(SO_REUSEPORT)",
550 "sk_fds[%d] err:%d errno:%d\n",
551 i, err, errno);
552
553 if (i == first) {
554 err = setsockopt(sk_fds[i], SOL_SOCKET,
555 SO_ATTACH_REUSEPORT_EBPF,
556 &select_by_skb_data_prog,
557 sizeof(select_by_skb_data_prog));
558 CHECK(err == -1, "setsockopt(SO_ATTACH_REUEPORT_EBPF)",
559 "err:%d errno:%d\n", err, errno);
560 }
561
562 err = bind(sk_fds[i], (struct sockaddr *)&srv_sa, addrlen);
563 CHECK(err == -1, "bind()", "sk_fds[%d] err:%d errno:%d\n",
564 i, err, errno);
565
566 if (type == SOCK_STREAM) {
567 err = listen(sk_fds[i], 10);
568 CHECK(err == -1, "listen()",
569 "sk_fds[%d] err:%d errno:%d\n",
570 i, err, errno);
571 }
572
573 err = bpf_map_update_elem(reuseport_array, &i, &sk_fds[i],
574 BPF_NOEXIST);
575 CHECK(err == -1, "update_elem(reuseport_array)",
576 "sk_fds[%d] err:%d errno:%d\n", i, err, errno);
577
578 if (i == first) {
579 socklen_t addrlen = sizeof(srv_sa);
580
581 err = getsockname(sk_fds[i], (struct sockaddr *)&srv_sa,
582 &addrlen);
583 CHECK(err == -1, "getsockname()",
584 "sk_fds[%d] err:%d errno:%d\n", i, err, errno);
585 }
586 }
587
588 epfd = epoll_create(1);
589 CHECK(epfd == -1, "epoll_create(1)",
590 "epfd:%d errno:%d\n", epfd, errno);
591
592 ev.events = EPOLLIN;
593 for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++) {
594 ev.data.u32 = i;
595 err = epoll_ctl(epfd, EPOLL_CTL_ADD, sk_fds[i], &ev);
596 CHECK(err, "epoll_ctl(EPOLL_CTL_ADD)", "sk_fds[%d]\n", i);
597 }
598}
599
600static void setup_per_test(int type, unsigned short family, bool inany)
601{
602 int ovr = -1, err;
603
604 prepare_sk_fds(type, family, inany);
605 err = bpf_map_update_elem(tmp_index_ovr_map, &index_zero, &ovr,
606 BPF_ANY);
607 CHECK(err == -1, "update_elem(tmp_index_ovr_map, 0, -1)",
608 "err:%d errno:%d\n", err, errno);
609}
610
611static void cleanup_per_test(void)
612{
613 int i, err;
614
615 for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++)
616 close(sk_fds[i]);
617 close(epfd);
618
619 err = bpf_map_delete_elem(outer_map, &index_zero);
620 CHECK(err == -1, "delete_elem(outer_map)",
621 "err:%d errno:%d\n", err, errno);
622}
623
624static void cleanup(void)
625{
626 close(outer_map);
627 close(reuseport_array);
628 bpf_object__close(obj);
629}
630
631static void test_all(void)
632{
633 /* Extra SOCK_STREAM to test bind_inany==true */
634 const int types[] = { SOCK_STREAM, SOCK_DGRAM, SOCK_STREAM };
635 const char * const type_strings[] = { "TCP", "UDP", "TCP" };
636 const char * const family_strings[] = { "IPv6", "IPv4" };
637 const unsigned short families[] = { AF_INET6, AF_INET };
638 const bool bind_inany[] = { false, false, true };
639 int t, f, err;
640
641 for (f = 0; f < ARRAY_SIZE(families); f++) {
642 unsigned short family = families[f];
643
644 for (t = 0; t < ARRAY_SIZE(types); t++) {
645 bool inany = bind_inany[t];
646 int type = types[t];
647
648 printf("######## %s/%s %s ########\n",
649 family_strings[f], type_strings[t],
650 inany ? " INANY " : "LOOPBACK");
651
652 setup_per_test(type, family, inany);
653
654 test_err_inner_map(type, family);
655
656 /* Install reuseport_array to the outer_map */
657 err = bpf_map_update_elem(outer_map, &index_zero,
658 &reuseport_array, BPF_ANY);
659 CHECK(err == -1, "update_elem(outer_map)",
660 "err:%d errno:%d\n", err, errno);
661
662 test_err_skb_data(type, family);
663 test_err_sk_select_port(type, family);
664 test_pass(type, family);
665 test_syncookie(type, family);
666 test_pass_on_err(type, family);
667
668 cleanup_per_test();
669 printf("\n");
670 }
671 }
672}
673
674int main(int argc, const char **argv)
675{
676 create_maps();
677 prepare_bpf_obj();
678 saved_tcp_fo = read_int_sysctl(TCP_FO_SYSCTL);
679 saved_tcp_syncookie = read_int_sysctl(TCP_SYNCOOKIE_SYSCTL);
680 enable_fastopen();
681 disable_syncookie();
682 atexit(restore_sysctls);
683
684 test_all();
685
686 cleanup();
687 return 0;
688}
diff --git a/tools/testing/selftests/bpf/test_select_reuseport_common.h b/tools/testing/selftests/bpf/test_select_reuseport_common.h
new file mode 100644
index 000000000000..08eb2a9f145f
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_select_reuseport_common.h
@@ -0,0 +1,36 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (c) 2018 Facebook */
3
4#ifndef __TEST_SELECT_REUSEPORT_COMMON_H
5#define __TEST_SELECT_REUSEPORT_COMMON_H
6
7#include <linux/types.h>
8
9enum result {
10 DROP_ERR_INNER_MAP,
11 DROP_ERR_SKB_DATA,
12 DROP_ERR_SK_SELECT_REUSEPORT,
13 DROP_MISC,
14 PASS,
15 PASS_ERR_SK_SELECT_REUSEPORT,
16 NR_RESULTS,
17};
18
19struct cmd {
20 __u32 reuseport_index;
21 __u32 pass_on_failure;
22};
23
24struct data_check {
25 __u32 ip_protocol;
26 __u32 skb_addrs[8];
27 __u16 skb_ports[2];
28 __u16 eth_protocol;
29 __u8 bind_inany;
30 __u8 equal_check_end[0];
31
32 __u32 len;
33 __u32 hash;
34};
35
36#endif
diff --git a/tools/testing/selftests/bpf/test_select_reuseport_kern.c b/tools/testing/selftests/bpf/test_select_reuseport_kern.c
new file mode 100644
index 000000000000..5b54ec637ada
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_select_reuseport_kern.c
@@ -0,0 +1,180 @@
1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2018 Facebook */
3
4#include <stdlib.h>
5#include <linux/in.h>
6#include <linux/ip.h>
7#include <linux/ipv6.h>
8#include <linux/tcp.h>
9#include <linux/udp.h>
10#include <linux/bpf.h>
11#include <linux/types.h>
12#include <linux/if_ether.h>
13
14#include "bpf_endian.h"
15#include "bpf_helpers.h"
16#include "test_select_reuseport_common.h"
17
18int _version SEC("version") = 1;
19
20#ifndef offsetof
21#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
22#endif
23
24struct bpf_map_def SEC("maps") outer_map = {
25 .type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
26 .key_size = sizeof(__u32),
27 .value_size = sizeof(__u32),
28 .max_entries = 1,
29};
30
31struct bpf_map_def SEC("maps") result_map = {
32 .type = BPF_MAP_TYPE_ARRAY,
33 .key_size = sizeof(__u32),
34 .value_size = sizeof(__u32),
35 .max_entries = NR_RESULTS,
36};
37
38struct bpf_map_def SEC("maps") tmp_index_ovr_map = {
39 .type = BPF_MAP_TYPE_ARRAY,
40 .key_size = sizeof(__u32),
41 .value_size = sizeof(int),
42 .max_entries = 1,
43};
44
45struct bpf_map_def SEC("maps") linum_map = {
46 .type = BPF_MAP_TYPE_ARRAY,
47 .key_size = sizeof(__u32),
48 .value_size = sizeof(__u32),
49 .max_entries = 1,
50};
51
52struct bpf_map_def SEC("maps") data_check_map = {
53 .type = BPF_MAP_TYPE_ARRAY,
54 .key_size = sizeof(__u32),
55 .value_size = sizeof(struct data_check),
56 .max_entries = 1,
57};
58
59#define GOTO_DONE(_result) ({ \
60 result = (_result); \
61 linum = __LINE__; \
62 goto done; \
63})
64
65SEC("select_by_skb_data")
66int _select_by_skb_data(struct sk_reuseport_md *reuse_md)
67{
68 __u32 linum, index = 0, flags = 0, index_zero = 0;
69 __u32 *result_cnt, *linum_value;
70 struct data_check data_check = {};
71 struct cmd *cmd, cmd_copy;
72 void *data, *data_end;
73 void *reuseport_array;
74 enum result result;
75 int *index_ovr;
76 int err;
77
78 data = reuse_md->data;
79 data_end = reuse_md->data_end;
80 data_check.len = reuse_md->len;
81 data_check.eth_protocol = reuse_md->eth_protocol;
82 data_check.ip_protocol = reuse_md->ip_protocol;
83 data_check.hash = reuse_md->hash;
84 data_check.bind_inany = reuse_md->bind_inany;
85 if (data_check.eth_protocol == bpf_htons(ETH_P_IP)) {
86 if (bpf_skb_load_bytes_relative(reuse_md,
87 offsetof(struct iphdr, saddr),
88 data_check.skb_addrs, 8,
89 BPF_HDR_START_NET))
90 GOTO_DONE(DROP_MISC);
91 } else {
92 if (bpf_skb_load_bytes_relative(reuse_md,
93 offsetof(struct ipv6hdr, saddr),
94 data_check.skb_addrs, 32,
95 BPF_HDR_START_NET))
96 GOTO_DONE(DROP_MISC);
97 }
98
99 /*
100 * The ip_protocol could be a compile time decision
101 * if the bpf_prog.o is dedicated to either TCP or
102 * UDP.
103 *
104 * Otherwise, reuse_md->ip_protocol or
105 * the protocol field in the iphdr can be used.
106 */
107 if (data_check.ip_protocol == IPPROTO_TCP) {
108 struct tcphdr *th = data;
109
110 if (th + 1 > data_end)
111 GOTO_DONE(DROP_MISC);
112
113 data_check.skb_ports[0] = th->source;
114 data_check.skb_ports[1] = th->dest;
115
116 if ((th->doff << 2) + sizeof(*cmd) > data_check.len)
117 GOTO_DONE(DROP_ERR_SKB_DATA);
118 if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,
119 sizeof(cmd_copy)))
120 GOTO_DONE(DROP_MISC);
121 cmd = &cmd_copy;
122 } else if (data_check.ip_protocol == IPPROTO_UDP) {
123 struct udphdr *uh = data;
124
125 if (uh + 1 > data_end)
126 GOTO_DONE(DROP_MISC);
127
128 data_check.skb_ports[0] = uh->source;
129 data_check.skb_ports[1] = uh->dest;
130
131 if (sizeof(struct udphdr) + sizeof(*cmd) > data_check.len)
132 GOTO_DONE(DROP_ERR_SKB_DATA);
133 if (data + sizeof(struct udphdr) + sizeof(*cmd) > data_end) {
134 if (bpf_skb_load_bytes(reuse_md, sizeof(struct udphdr),
135 &cmd_copy, sizeof(cmd_copy)))
136 GOTO_DONE(DROP_MISC);
137 cmd = &cmd_copy;
138 } else {
139 cmd = data + sizeof(struct udphdr);
140 }
141 } else {
142 GOTO_DONE(DROP_MISC);
143 }
144
145 reuseport_array = bpf_map_lookup_elem(&outer_map, &index_zero);
146 if (!reuseport_array)
147 GOTO_DONE(DROP_ERR_INNER_MAP);
148
149 index = cmd->reuseport_index;
150 index_ovr = bpf_map_lookup_elem(&tmp_index_ovr_map, &index_zero);
151 if (!index_ovr)
152 GOTO_DONE(DROP_MISC);
153
154 if (*index_ovr != -1) {
155 index = *index_ovr;
156 *index_ovr = -1;
157 }
158 err = bpf_sk_select_reuseport(reuse_md, reuseport_array, &index,
159 flags);
160 if (!err)
161 GOTO_DONE(PASS);
162
163 if (cmd->pass_on_failure)
164 GOTO_DONE(PASS_ERR_SK_SELECT_REUSEPORT);
165 else
166 GOTO_DONE(DROP_ERR_SK_SELECT_REUSEPORT);
167
168done:
169 result_cnt = bpf_map_lookup_elem(&result_map, &result);
170 if (!result_cnt)
171 return SK_DROP;
172
173 bpf_map_update_elem(&linum_map, &index_zero, &linum, BPF_ANY);
174 bpf_map_update_elem(&data_check_map, &index_zero, &data_check, BPF_ANY);
175
176 (*result_cnt)++;
177 return result < PASS ? SK_DROP : SK_PASS;
178}
179
180char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id.sh b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh
new file mode 100755
index 000000000000..42544a969abc
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_skb_cgroup_id.sh
@@ -0,0 +1,62 @@
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (c) 2018 Facebook
4
5set -eu
6
7wait_for_ip()
8{
9 local _i
10 echo -n "Wait for testing link-local IP to become available "
11 for _i in $(seq ${MAX_PING_TRIES}); do
12 echo -n "."
13 if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
14 echo " OK"
15 return
16 fi
17 sleep 1
18 done
19 echo 1>&2 "ERROR: Timeout waiting for test IP to become available."
20 exit 1
21}
22
23setup()
24{
25 # Create testing interfaces not to interfere with current environment.
26 ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER}
27 ip link set ${TEST_IF} up
28 ip link set ${TEST_IF_PEER} up
29
30 wait_for_ip
31
32 tc qdisc add dev ${TEST_IF} clsact
33 tc filter add dev ${TEST_IF} egress bpf obj ${BPF_PROG_OBJ} \
34 sec ${BPF_PROG_SECTION} da
35
36 BPF_PROG_ID=$(tc filter show dev ${TEST_IF} egress | \
37 awk '/ id / {sub(/.* id /, "", $0); print($1)}')
38}
39
40cleanup()
41{
42 ip link del ${TEST_IF} 2>/dev/null || :
43 ip link del ${TEST_IF_PEER} 2>/dev/null || :
44}
45
46main()
47{
48 trap cleanup EXIT 2 3 6 15
49 setup
50 ${PROG} ${TEST_IF} ${BPF_PROG_ID}
51}
52
53DIR=$(dirname $0)
54TEST_IF="test_cgid_1"
55TEST_IF_PEER="test_cgid_2"
56MAX_PING_TRIES=5
57BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"
58BPF_PROG_SECTION="cgroup_id_logger"
59BPF_PROG_ID=0
60PROG="${DIR}/test_skb_cgroup_id_user"
61
62main
diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
new file mode 100644
index 000000000000..68cf9829f5a7
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_kern.c
@@ -0,0 +1,47 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <linux/bpf.h>
5#include <linux/pkt_cls.h>
6
7#include <string.h>
8
9#include "bpf_helpers.h"
10
11#define NUM_CGROUP_LEVELS 4
12
13struct bpf_map_def SEC("maps") cgroup_ids = {
14 .type = BPF_MAP_TYPE_ARRAY,
15 .key_size = sizeof(__u32),
16 .value_size = sizeof(__u64),
17 .max_entries = NUM_CGROUP_LEVELS,
18};
19
20static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level)
21{
22 __u64 id;
23
24 /* [1] &level passed to external function that may change it, it's
25 * incompatible with loop unroll.
26 */
27 id = bpf_skb_ancestor_cgroup_id(skb, level);
28 bpf_map_update_elem(&cgroup_ids, &level, &id, 0);
29}
30
31SEC("cgroup_id_logger")
32int log_cgroup_id(struct __sk_buff *skb)
33{
34 /* Loop unroll can't be used here due to [1]. Unrolling manually.
35 * Number of calls should be in sync with NUM_CGROUP_LEVELS.
36 */
37 log_nth_level(skb, 0);
38 log_nth_level(skb, 1);
39 log_nth_level(skb, 2);
40 log_nth_level(skb, 3);
41
42 return TC_ACT_OK;
43}
44
45int _version SEC("version") = 1;
46
47char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
new file mode 100644
index 000000000000..c121cc59f314
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_skb_cgroup_id_user.c
@@ -0,0 +1,187 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7
8#include <arpa/inet.h>
9#include <net/if.h>
10#include <netinet/in.h>
11#include <sys/socket.h>
12#include <sys/types.h>
13
14
15#include <bpf/bpf.h>
16#include <bpf/libbpf.h>
17
18#include "bpf_rlimit.h"
19#include "cgroup_helpers.h"
20
21#define CGROUP_PATH "/skb_cgroup_test"
22#define NUM_CGROUP_LEVELS 4
23
24/* RFC 4291, Section 2.7.1 */
25#define LINKLOCAL_MULTICAST "ff02::1"
26
27static int mk_dst_addr(const char *ip, const char *iface,
28 struct sockaddr_in6 *dst)
29{
30 memset(dst, 0, sizeof(*dst));
31
32 dst->sin6_family = AF_INET6;
33 dst->sin6_port = htons(1025);
34
35 if (inet_pton(AF_INET6, ip, &dst->sin6_addr) != 1) {
36 log_err("Invalid IPv6: %s", ip);
37 return -1;
38 }
39
40 dst->sin6_scope_id = if_nametoindex(iface);
41 if (!dst->sin6_scope_id) {
42 log_err("Failed to get index of iface: %s", iface);
43 return -1;
44 }
45
46 return 0;
47}
48
49static int send_packet(const char *iface)
50{
51 struct sockaddr_in6 dst;
52 char msg[] = "msg";
53 int err = 0;
54 int fd = -1;
55
56 if (mk_dst_addr(LINKLOCAL_MULTICAST, iface, &dst))
57 goto err;
58
59 fd = socket(AF_INET6, SOCK_DGRAM, 0);
60 if (fd == -1) {
61 log_err("Failed to create UDP socket");
62 goto err;
63 }
64
65 if (sendto(fd, &msg, sizeof(msg), 0, (const struct sockaddr *)&dst,
66 sizeof(dst)) == -1) {
67 log_err("Failed to send datagram");
68 goto err;
69 }
70
71 goto out;
72err:
73 err = -1;
74out:
75 if (fd >= 0)
76 close(fd);
77 return err;
78}
79
80int get_map_fd_by_prog_id(int prog_id)
81{
82 struct bpf_prog_info info = {};
83 __u32 info_len = sizeof(info);
84 __u32 map_ids[1];
85 int prog_fd = -1;
86 int map_fd = -1;
87
88 prog_fd = bpf_prog_get_fd_by_id(prog_id);
89 if (prog_fd < 0) {
90 log_err("Failed to get fd by prog id %d", prog_id);
91 goto err;
92 }
93
94 info.nr_map_ids = 1;
95 info.map_ids = (__u64) (unsigned long) map_ids;
96
97 if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
98 log_err("Failed to get info by prog fd %d", prog_fd);
99 goto err;
100 }
101
102 if (!info.nr_map_ids) {
103 log_err("No maps found for prog fd %d", prog_fd);
104 goto err;
105 }
106
107 map_fd = bpf_map_get_fd_by_id(map_ids[0]);
108 if (map_fd < 0)
109 log_err("Failed to get fd by map id %d", map_ids[0]);
110err:
111 if (prog_fd >= 0)
112 close(prog_fd);
113 return map_fd;
114}
115
116int check_ancestor_cgroup_ids(int prog_id)
117{
118 __u64 actual_ids[NUM_CGROUP_LEVELS], expected_ids[NUM_CGROUP_LEVELS];
119 __u32 level;
120 int err = 0;
121 int map_fd;
122
123 expected_ids[0] = 0x100000001; /* root cgroup */
124 expected_ids[1] = get_cgroup_id("");
125 expected_ids[2] = get_cgroup_id(CGROUP_PATH);
126 expected_ids[3] = 0; /* non-existent cgroup */
127
128 map_fd = get_map_fd_by_prog_id(prog_id);
129 if (map_fd < 0)
130 goto err;
131
132 for (level = 0; level < NUM_CGROUP_LEVELS; ++level) {
133 if (bpf_map_lookup_elem(map_fd, &level, &actual_ids[level])) {
134 log_err("Failed to lookup key %d", level);
135 goto err;
136 }
137 if (actual_ids[level] != expected_ids[level]) {
138 log_err("%llx (actual) != %llx (expected), level: %u\n",
139 actual_ids[level], expected_ids[level], level);
140 goto err;
141 }
142 }
143
144 goto out;
145err:
146 err = -1;
147out:
148 if (map_fd >= 0)
149 close(map_fd);
150 return err;
151}
152
153int main(int argc, char **argv)
154{
155 int cgfd = -1;
156 int err = 0;
157
158 if (argc < 3) {
159 fprintf(stderr, "Usage: %s iface prog_id\n", argv[0]);
160 exit(EXIT_FAILURE);
161 }
162
163 if (setup_cgroup_environment())
164 goto err;
165
166 cgfd = create_and_get_cgroup(CGROUP_PATH);
167 if (!cgfd)
168 goto err;
169
170 if (join_cgroup(CGROUP_PATH))
171 goto err;
172
173 if (send_packet(argv[1]))
174 goto err;
175
176 if (check_ancestor_cgroup_ids(atoi(argv[2])))
177 goto err;
178
179 goto out;
180err:
181 err = -1;
182out:
183 close(cgfd);
184 cleanup_cgroup_environment();
185 printf("[%s]\n", err ? "FAIL" : "PASS");
186 return err;
187}
diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c
index f4d99fabc56d..b8ebe2f58074 100644
--- a/tools/testing/selftests/bpf/test_sock.c
+++ b/tools/testing/selftests/bpf/test_sock.c
@@ -14,10 +14,7 @@
14 14
15#include "cgroup_helpers.h" 15#include "cgroup_helpers.h"
16#include "bpf_rlimit.h" 16#include "bpf_rlimit.h"
17 17#include "bpf_util.h"
18#ifndef ARRAY_SIZE
19# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
20#endif
21 18
22#define CG_PATH "/foo" 19#define CG_PATH "/foo"
23#define MAX_INSNS 512 20#define MAX_INSNS 512
diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c
index a5e76b9219b9..aeeb76a54d63 100644
--- a/tools/testing/selftests/bpf/test_sock_addr.c
+++ b/tools/testing/selftests/bpf/test_sock_addr.c
@@ -20,15 +20,12 @@
20 20
21#include "cgroup_helpers.h" 21#include "cgroup_helpers.h"
22#include "bpf_rlimit.h" 22#include "bpf_rlimit.h"
23#include "bpf_util.h"
23 24
24#ifndef ENOTSUPP 25#ifndef ENOTSUPP
25# define ENOTSUPP 524 26# define ENOTSUPP 524
26#endif 27#endif
27 28
28#ifndef ARRAY_SIZE
29# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
30#endif
31
32#define CG_PATH "/foo" 29#define CG_PATH "/foo"
33#define CONNECT4_PROG_PATH "./connect4_prog.o" 30#define CONNECT4_PROG_PATH "./connect4_prog.o"
34#define CONNECT6_PROG_PATH "./connect6_prog.o" 31#define CONNECT6_PROG_PATH "./connect6_prog.o"
@@ -998,8 +995,9 @@ int init_pktinfo(int domain, struct cmsghdr *cmsg)
998 return 0; 995 return 0;
999} 996}
1000 997
1001static int sendmsg_to_server(const struct sockaddr_storage *addr, 998static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
1002 socklen_t addr_len, int set_cmsg, int *syscall_err) 999 socklen_t addr_len, int set_cmsg, int flags,
1000 int *syscall_err)
1003{ 1001{
1004 union { 1002 union {
1005 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 1003 char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
@@ -1022,7 +1020,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
1022 goto err; 1020 goto err;
1023 } 1021 }
1024 1022
1025 fd = socket(domain, SOCK_DGRAM, 0); 1023 fd = socket(domain, type, 0);
1026 if (fd == -1) { 1024 if (fd == -1) {
1027 log_err("Failed to create client socket"); 1025 log_err("Failed to create client socket");
1028 goto err; 1026 goto err;
@@ -1052,7 +1050,7 @@ static int sendmsg_to_server(const struct sockaddr_storage *addr,
1052 } 1050 }
1053 } 1051 }
1054 1052
1055 if (sendmsg(fd, &hdr, 0) != sizeof(data)) { 1053 if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
1056 log_err("Fail to send message to server"); 1054 log_err("Fail to send message to server");
1057 *syscall_err = errno; 1055 *syscall_err = errno;
1058 goto err; 1056 goto err;
@@ -1066,6 +1064,15 @@ out:
1066 return fd; 1064 return fd;
1067} 1065}
1068 1066
1067static int fastconnect_to_server(const struct sockaddr_storage *addr,
1068 socklen_t addr_len)
1069{
1070 int sendmsg_err;
1071
1072 return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
1073 MSG_FASTOPEN, &sendmsg_err);
1074}
1075
1069static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) 1076static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
1070{ 1077{
1071 struct timeval tv; 1078 struct timeval tv;
@@ -1185,6 +1192,20 @@ static int run_connect_test_case(const struct sock_addr_test *test)
1185 if (cmp_local_ip(clientfd, &expected_src_addr)) 1192 if (cmp_local_ip(clientfd, &expected_src_addr))
1186 goto err; 1193 goto err;
1187 1194
1195 if (test->type == SOCK_STREAM) {
1196 /* Test TCP Fast Open scenario */
1197 clientfd = fastconnect_to_server(&requested_addr, addr_len);
1198 if (clientfd == -1)
1199 goto err;
1200
1201 /* Make sure src and dst addrs were overridden properly */
1202 if (cmp_peer_addr(clientfd, &expected_addr))
1203 goto err;
1204
1205 if (cmp_local_ip(clientfd, &expected_src_addr))
1206 goto err;
1207 }
1208
1188 goto out; 1209 goto out;
1189err: 1210err:
1190 err = -1; 1211 err = -1;
@@ -1222,8 +1243,9 @@ static int run_sendmsg_test_case(const struct sock_addr_test *test)
1222 if (clientfd >= 0) 1243 if (clientfd >= 0)
1223 close(clientfd); 1244 close(clientfd);
1224 1245
1225 clientfd = sendmsg_to_server(&requested_addr, addr_len, 1246 clientfd = sendmsg_to_server(test->type, &requested_addr,
1226 set_cmsg, &err); 1247 addr_len, set_cmsg, /*flags*/0,
1248 &err);
1227 if (err) 1249 if (err)
1228 goto out; 1250 goto out;
1229 else if (clientfd == -1) 1251 else if (clientfd == -1)
diff --git a/tools/testing/selftests/bpf/test_socket_cookie.c b/tools/testing/selftests/bpf/test_socket_cookie.c
new file mode 100644
index 000000000000..68e108e4687a
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_socket_cookie.c
@@ -0,0 +1,225 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#include <string.h>
5#include <unistd.h>
6
7#include <arpa/inet.h>
8#include <netinet/in.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11
12#include <bpf/bpf.h>
13#include <bpf/libbpf.h>
14
15#include "bpf_rlimit.h"
16#include "cgroup_helpers.h"
17
18#define CG_PATH "/foo"
19#define SOCKET_COOKIE_PROG "./socket_cookie_prog.o"
20
21static int start_server(void)
22{
23 struct sockaddr_in6 addr;
24 int fd;
25
26 fd = socket(AF_INET6, SOCK_STREAM, 0);
27 if (fd == -1) {
28 log_err("Failed to create server socket");
29 goto out;
30 }
31
32 memset(&addr, 0, sizeof(addr));
33 addr.sin6_family = AF_INET6;
34 addr.sin6_addr = in6addr_loopback;
35 addr.sin6_port = 0;
36
37 if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
38 log_err("Failed to bind server socket");
39 goto close_out;
40 }
41
42 if (listen(fd, 128) == -1) {
43 log_err("Failed to listen on server socket");
44 goto close_out;
45 }
46
47 goto out;
48
49close_out:
50 close(fd);
51 fd = -1;
52out:
53 return fd;
54}
55
56static int connect_to_server(int server_fd)
57{
58 struct sockaddr_storage addr;
59 socklen_t len = sizeof(addr);
60 int fd;
61
62 fd = socket(AF_INET6, SOCK_STREAM, 0);
63 if (fd == -1) {
64 log_err("Failed to create client socket");
65 goto out;
66 }
67
68 if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
69 log_err("Failed to get server addr");
70 goto close_out;
71 }
72
73 if (connect(fd, (const struct sockaddr *)&addr, len) == -1) {
74 log_err("Fail to connect to server");
75 goto close_out;
76 }
77
78 goto out;
79
80close_out:
81 close(fd);
82 fd = -1;
83out:
84 return fd;
85}
86
87static int validate_map(struct bpf_map *map, int client_fd)
88{
89 __u32 cookie_expected_value;
90 struct sockaddr_in6 addr;
91 socklen_t len = sizeof(addr);
92 __u32 cookie_value;
93 __u64 cookie_key;
94 int err = 0;
95 int map_fd;
96
97 if (!map) {
98 log_err("Map not found in BPF object");
99 goto err;
100 }
101
102 map_fd = bpf_map__fd(map);
103
104 err = bpf_map_get_next_key(map_fd, NULL, &cookie_key);
105 if (err) {
106 log_err("Can't get cookie key from map");
107 goto out;
108 }
109
110 err = bpf_map_lookup_elem(map_fd, &cookie_key, &cookie_value);
111 if (err) {
112 log_err("Can't get cookie value from map");
113 goto out;
114 }
115
116 err = getsockname(client_fd, (struct sockaddr *)&addr, &len);
117 if (err) {
118 log_err("Can't get client local addr");
119 goto out;
120 }
121
122 cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF;
123 if (cookie_value != cookie_expected_value) {
124 log_err("Unexpected value in map: %x != %x", cookie_value,
125 cookie_expected_value);
126 goto err;
127 }
128
129 goto out;
130err:
131 err = -1;
132out:
133 return err;
134}
135
136static int run_test(int cgfd)
137{
138 enum bpf_attach_type attach_type;
139 struct bpf_prog_load_attr attr;
140 struct bpf_program *prog;
141 struct bpf_object *pobj;
142 const char *prog_name;
143 int server_fd = -1;
144 int client_fd = -1;
145 int prog_fd = -1;
146 int err = 0;
147
148 memset(&attr, 0, sizeof(attr));
149 attr.file = SOCKET_COOKIE_PROG;
150 attr.prog_type = BPF_PROG_TYPE_UNSPEC;
151
152 err = bpf_prog_load_xattr(&attr, &pobj, &prog_fd);
153 if (err) {
154 log_err("Failed to load %s", attr.file);
155 goto out;
156 }
157
158 bpf_object__for_each_program(prog, pobj) {
159 prog_name = bpf_program__title(prog, /*needs_copy*/ false);
160
161 if (strcmp(prog_name, "cgroup/connect6") == 0) {
162 attach_type = BPF_CGROUP_INET6_CONNECT;
163 } else if (strcmp(prog_name, "sockops") == 0) {
164 attach_type = BPF_CGROUP_SOCK_OPS;
165 } else {
166 log_err("Unexpected prog: %s", prog_name);
167 goto err;
168 }
169
170 err = bpf_prog_attach(bpf_program__fd(prog), cgfd, attach_type,
171 BPF_F_ALLOW_OVERRIDE);
172 if (err) {
173 log_err("Failed to attach prog %s", prog_name);
174 goto out;
175 }
176 }
177
178 server_fd = start_server();
179 if (server_fd == -1)
180 goto err;
181
182 client_fd = connect_to_server(server_fd);
183 if (client_fd == -1)
184 goto err;
185
186 if (validate_map(bpf_map__next(NULL, pobj), client_fd))
187 goto err;
188
189 goto out;
190err:
191 err = -1;
192out:
193 close(client_fd);
194 close(server_fd);
195 bpf_object__close(pobj);
196 printf("%s\n", err ? "FAILED" : "PASSED");
197 return err;
198}
199
200int main(int argc, char **argv)
201{
202 int cgfd = -1;
203 int err = 0;
204
205 if (setup_cgroup_environment())
206 goto err;
207
208 cgfd = create_and_get_cgroup(CG_PATH);
209 if (!cgfd)
210 goto err;
211
212 if (join_cgroup(CG_PATH))
213 goto err;
214
215 if (run_test(cgfd))
216 goto err;
217
218 goto out;
219err:
220 err = -1;
221out:
222 close(cgfd);
223 cleanup_cgroup_environment();
224 return err;
225}
diff --git a/tools/testing/selftests/bpf/test_tcpbpf.h b/tools/testing/selftests/bpf/test_tcpbpf.h
index 2fe43289943c..7bcfa6207005 100644
--- a/tools/testing/selftests/bpf/test_tcpbpf.h
+++ b/tools/testing/selftests/bpf/test_tcpbpf.h
@@ -12,5 +12,6 @@ struct tcpbpf_globals {
12 __u32 good_cb_test_rv; 12 __u32 good_cb_test_rv;
13 __u64 bytes_received; 13 __u64 bytes_received;
14 __u64 bytes_acked; 14 __u64 bytes_acked;
15 __u32 num_listen;
15}; 16};
16#endif 17#endif
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_kern.c b/tools/testing/selftests/bpf/test_tcpbpf_kern.c
index 3e645ee41ed5..4b7fd540cea9 100644
--- a/tools/testing/selftests/bpf/test_tcpbpf_kern.c
+++ b/tools/testing/selftests/bpf/test_tcpbpf_kern.c
@@ -96,15 +96,22 @@ int bpf_testcb(struct bpf_sock_ops *skops)
96 if (!gp) 96 if (!gp)
97 break; 97 break;
98 g = *gp; 98 g = *gp;
99 g.total_retrans = skops->total_retrans; 99 if (skops->args[0] == BPF_TCP_LISTEN) {
100 g.data_segs_in = skops->data_segs_in; 100 g.num_listen++;
101 g.data_segs_out = skops->data_segs_out; 101 } else {
102 g.bytes_received = skops->bytes_received; 102 g.total_retrans = skops->total_retrans;
103 g.bytes_acked = skops->bytes_acked; 103 g.data_segs_in = skops->data_segs_in;
104 g.data_segs_out = skops->data_segs_out;
105 g.bytes_received = skops->bytes_received;
106 g.bytes_acked = skops->bytes_acked;
107 }
104 bpf_map_update_elem(&global_map, &key, &g, 108 bpf_map_update_elem(&global_map, &key, &g,
105 BPF_ANY); 109 BPF_ANY);
106 } 110 }
107 break; 111 break;
112 case BPF_SOCK_OPS_TCP_LISTEN_CB:
113 bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_STATE_CB_FLAG);
114 break;
108 default: 115 default:
109 rv = -1; 116 rv = -1;
110 } 117 }
diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c
index 84ab5163c828..a275c2971376 100644
--- a/tools/testing/selftests/bpf/test_tcpbpf_user.c
+++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c
@@ -1,27 +1,59 @@
1// SPDX-License-Identifier: GPL-2.0 1// SPDX-License-Identifier: GPL-2.0
2#include <inttypes.h>
2#include <stdio.h> 3#include <stdio.h>
3#include <stdlib.h> 4#include <stdlib.h>
4#include <stdio.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <errno.h> 6#include <errno.h>
7#include <signal.h>
8#include <string.h> 7#include <string.h>
9#include <assert.h>
10#include <linux/perf_event.h>
11#include <linux/ptrace.h>
12#include <linux/bpf.h> 8#include <linux/bpf.h>
13#include <sys/ioctl.h>
14#include <sys/time.h>
15#include <sys/types.h> 9#include <sys/types.h>
16#include <sys/stat.h>
17#include <fcntl.h>
18#include <bpf/bpf.h> 10#include <bpf/bpf.h>
19#include <bpf/libbpf.h> 11#include <bpf/libbpf.h>
20#include "bpf_util.h" 12
21#include "bpf_rlimit.h" 13#include "bpf_rlimit.h"
22#include <linux/perf_event.h> 14#include "bpf_util.h"
15#include "cgroup_helpers.h"
16
23#include "test_tcpbpf.h" 17#include "test_tcpbpf.h"
24 18
19#define EXPECT_EQ(expected, actual, fmt) \
20 do { \
21 if ((expected) != (actual)) { \
22 printf(" Value of: " #actual "\n" \
23 " Actual: %" fmt "\n" \
24 " Expected: %" fmt "\n", \
25 (actual), (expected)); \
26 goto err; \
27 } \
28 } while (0)
29
30int verify_result(const struct tcpbpf_globals *result)
31{
32 __u32 expected_events;
33
34 expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) |
35 (1 << BPF_SOCK_OPS_RWND_INIT) |
36 (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) |
37 (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) |
38 (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) |
39 (1 << BPF_SOCK_OPS_NEEDS_ECN) |
40 (1 << BPF_SOCK_OPS_STATE_CB) |
41 (1 << BPF_SOCK_OPS_TCP_LISTEN_CB));
42
43 EXPECT_EQ(expected_events, result->event_map, "#" PRIx32);
44 EXPECT_EQ(501ULL, result->bytes_received, "llu");
45 EXPECT_EQ(1002ULL, result->bytes_acked, "llu");
46 EXPECT_EQ(1, result->data_segs_in, PRIu32);
47 EXPECT_EQ(1, result->data_segs_out, PRIu32);
48 EXPECT_EQ(0x80, result->bad_cb_test_rv, PRIu32);
49 EXPECT_EQ(0, result->good_cb_test_rv, PRIu32);
50 EXPECT_EQ(1, result->num_listen, PRIu32);
51
52 return 0;
53err:
54 return -1;
55}
56
25static int bpf_find_map(const char *test, struct bpf_object *obj, 57static int bpf_find_map(const char *test, struct bpf_object *obj,
26 const char *name) 58 const char *name)
27{ 59{
@@ -35,42 +67,28 @@ static int bpf_find_map(const char *test, struct bpf_object *obj,
35 return bpf_map__fd(map); 67 return bpf_map__fd(map);
36} 68}
37 69
38#define SYSTEM(CMD) \
39 do { \
40 if (system(CMD)) { \
41 printf("system(%s) FAILS!\n", CMD); \
42 } \
43 } while (0)
44
45int main(int argc, char **argv) 70int main(int argc, char **argv)
46{ 71{
47 const char *file = "test_tcpbpf_kern.o"; 72 const char *file = "test_tcpbpf_kern.o";
48 struct tcpbpf_globals g = {0}; 73 struct tcpbpf_globals g = {0};
49 int cg_fd, prog_fd, map_fd; 74 const char *cg_path = "/foo";
50 bool debug_flag = false;
51 int error = EXIT_FAILURE; 75 int error = EXIT_FAILURE;
52 struct bpf_object *obj; 76 struct bpf_object *obj;
53 char cmd[100], *dir; 77 int prog_fd, map_fd;
54 struct stat buffer; 78 int cg_fd = -1;
55 __u32 key = 0; 79 __u32 key = 0;
56 int pid;
57 int rv; 80 int rv;
58 81
59 if (argc > 1 && strcmp(argv[1], "-d") == 0) 82 if (setup_cgroup_environment())
60 debug_flag = true; 83 goto err;
61 84
62 dir = "/tmp/cgroupv2/foo"; 85 cg_fd = create_and_get_cgroup(cg_path);
86 if (!cg_fd)
87 goto err;
63 88
64 if (stat(dir, &buffer) != 0) { 89 if (join_cgroup(cg_path))
65 SYSTEM("mkdir -p /tmp/cgroupv2"); 90 goto err;
66 SYSTEM("mount -t cgroup2 none /tmp/cgroupv2");
67 SYSTEM("mkdir -p /tmp/cgroupv2/foo");
68 }
69 pid = (int) getpid();
70 sprintf(cmd, "echo %d >> /tmp/cgroupv2/foo/cgroup.procs", pid);
71 SYSTEM(cmd);
72 91
73 cg_fd = open(dir, O_DIRECTORY, O_RDONLY);
74 if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) { 92 if (bpf_prog_load(file, BPF_PROG_TYPE_SOCK_OPS, &obj, &prog_fd)) {
75 printf("FAILED: load_bpf_file failed for: %s\n", file); 93 printf("FAILED: load_bpf_file failed for: %s\n", file);
76 goto err; 94 goto err;
@@ -83,7 +101,10 @@ int main(int argc, char **argv)
83 goto err; 101 goto err;
84 } 102 }
85 103
86 SYSTEM("./tcp_server.py"); 104 if (system("./tcp_server.py")) {
105 printf("FAILED: TCP server\n");
106 goto err;
107 }
87 108
88 map_fd = bpf_find_map(__func__, obj, "global_map"); 109 map_fd = bpf_find_map(__func__, obj, "global_map");
89 if (map_fd < 0) 110 if (map_fd < 0)
@@ -95,34 +116,16 @@ int main(int argc, char **argv)
95 goto err; 116 goto err;
96 } 117 }
97 118
98 if (g.bytes_received != 501 || g.bytes_acked != 1002 || 119 if (verify_result(&g)) {
99 g.data_segs_in != 1 || g.data_segs_out != 1 ||
100 (g.event_map ^ 0x47e) != 0 || g.bad_cb_test_rv != 0x80 ||
101 g.good_cb_test_rv != 0) {
102 printf("FAILED: Wrong stats\n"); 120 printf("FAILED: Wrong stats\n");
103 if (debug_flag) {
104 printf("\n");
105 printf("bytes_received: %d (expecting 501)\n",
106 (int)g.bytes_received);
107 printf("bytes_acked: %d (expecting 1002)\n",
108 (int)g.bytes_acked);
109 printf("data_segs_in: %d (expecting 1)\n",
110 g.data_segs_in);
111 printf("data_segs_out: %d (expecting 1)\n",
112 g.data_segs_out);
113 printf("event_map: 0x%x (at least 0x47e)\n",
114 g.event_map);
115 printf("bad_cb_test_rv: 0x%x (expecting 0x80)\n",
116 g.bad_cb_test_rv);
117 printf("good_cb_test_rv:0x%x (expecting 0)\n",
118 g.good_cb_test_rv);
119 }
120 goto err; 121 goto err;
121 } 122 }
123
122 printf("PASSED!\n"); 124 printf("PASSED!\n");
123 error = 0; 125 error = 0;
124err: 126err:
125 bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS); 127 bpf_prog_detach(cg_fd, BPF_CGROUP_SOCK_OPS);
128 close(cg_fd);
129 cleanup_cgroup_environment();
126 return error; 130 return error;
127
128} 131}
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 41106d9d5cc7..67c412d19c09 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -42,15 +42,12 @@
42#endif 42#endif
43#include "bpf_rlimit.h" 43#include "bpf_rlimit.h"
44#include "bpf_rand.h" 44#include "bpf_rand.h"
45#include "bpf_util.h"
45#include "../../../include/linux/filter.h" 46#include "../../../include/linux/filter.h"
46 47
47#ifndef ARRAY_SIZE
48# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
49#endif
50
51#define MAX_INSNS BPF_MAXINSNS 48#define MAX_INSNS BPF_MAXINSNS
52#define MAX_FIXUPS 8 49#define MAX_FIXUPS 8
53#define MAX_NR_MAPS 7 50#define MAX_NR_MAPS 8
54#define POINTER_VALUE 0xcafe4all 51#define POINTER_VALUE 0xcafe4all
55#define TEST_DATA_LEN 64 52#define TEST_DATA_LEN 64
56 53
@@ -70,6 +67,7 @@ struct bpf_test {
70 int fixup_prog1[MAX_FIXUPS]; 67 int fixup_prog1[MAX_FIXUPS];
71 int fixup_prog2[MAX_FIXUPS]; 68 int fixup_prog2[MAX_FIXUPS];
72 int fixup_map_in_map[MAX_FIXUPS]; 69 int fixup_map_in_map[MAX_FIXUPS];
70 int fixup_cgroup_storage[MAX_FIXUPS];
73 const char *errstr; 71 const char *errstr;
74 const char *errstr_unpriv; 72 const char *errstr_unpriv;
75 uint32_t retval; 73 uint32_t retval;
@@ -4631,6 +4629,121 @@ static struct bpf_test tests[] = {
4631 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS, 4629 .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
4632 }, 4630 },
4633 { 4631 {
4632 "valid cgroup storage access",
4633 .insns = {
4634 BPF_MOV64_IMM(BPF_REG_2, 0),
4635 BPF_LD_MAP_FD(BPF_REG_1, 0),
4636 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4637 BPF_FUNC_get_local_storage),
4638 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
4639 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
4640 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
4641 BPF_EXIT_INSN(),
4642 },
4643 .fixup_cgroup_storage = { 1 },
4644 .result = ACCEPT,
4645 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4646 },
4647 {
4648 "invalid cgroup storage access 1",
4649 .insns = {
4650 BPF_MOV64_IMM(BPF_REG_2, 0),
4651 BPF_LD_MAP_FD(BPF_REG_1, 0),
4652 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4653 BPF_FUNC_get_local_storage),
4654 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
4655 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
4656 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
4657 BPF_EXIT_INSN(),
4658 },
4659 .fixup_map1 = { 1 },
4660 .result = REJECT,
4661 .errstr = "cannot pass map_type 1 into func bpf_get_local_storage",
4662 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4663 },
4664 {
4665 "invalid cgroup storage access 2",
4666 .insns = {
4667 BPF_MOV64_IMM(BPF_REG_2, 0),
4668 BPF_LD_MAP_FD(BPF_REG_1, 1),
4669 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4670 BPF_FUNC_get_local_storage),
4671 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
4672 BPF_EXIT_INSN(),
4673 },
4674 .result = REJECT,
4675 .errstr = "fd 1 is not pointing to valid bpf_map",
4676 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4677 },
4678 {
4679 "invalid per-cgroup storage access 3",
4680 .insns = {
4681 BPF_MOV64_IMM(BPF_REG_2, 0),
4682 BPF_LD_MAP_FD(BPF_REG_1, 0),
4683 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4684 BPF_FUNC_get_local_storage),
4685 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 256),
4686 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1),
4687 BPF_MOV64_IMM(BPF_REG_0, 0),
4688 BPF_EXIT_INSN(),
4689 },
4690 .fixup_cgroup_storage = { 1 },
4691 .result = REJECT,
4692 .errstr = "invalid access to map value, value_size=64 off=256 size=4",
4693 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4694 },
4695 {
4696 "invalid cgroup storage access 4",
4697 .insns = {
4698 BPF_MOV64_IMM(BPF_REG_2, 0),
4699 BPF_LD_MAP_FD(BPF_REG_1, 0),
4700 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4701 BPF_FUNC_get_local_storage),
4702 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, -2),
4703 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
4704 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1),
4705 BPF_EXIT_INSN(),
4706 },
4707 .fixup_cgroup_storage = { 1 },
4708 .result = REJECT,
4709 .errstr = "invalid access to map value, value_size=64 off=-2 size=4",
4710 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4711 },
4712 {
4713 "invalid cgroup storage access 5",
4714 .insns = {
4715 BPF_MOV64_IMM(BPF_REG_2, 7),
4716 BPF_LD_MAP_FD(BPF_REG_1, 0),
4717 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4718 BPF_FUNC_get_local_storage),
4719 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
4720 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
4721 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
4722 BPF_EXIT_INSN(),
4723 },
4724 .fixup_cgroup_storage = { 1 },
4725 .result = REJECT,
4726 .errstr = "get_local_storage() doesn't support non-zero flags",
4727 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4728 },
4729 {
4730 "invalid cgroup storage access 6",
4731 .insns = {
4732 BPF_MOV64_REG(BPF_REG_2, BPF_REG_1),
4733 BPF_LD_MAP_FD(BPF_REG_1, 0),
4734 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
4735 BPF_FUNC_get_local_storage),
4736 BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0),
4737 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
4738 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
4739 BPF_EXIT_INSN(),
4740 },
4741 .fixup_cgroup_storage = { 1 },
4742 .result = REJECT,
4743 .errstr = "get_local_storage() doesn't support non-zero flags",
4744 .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
4745 },
4746 {
4634 "multiple registers share map_lookup_elem result", 4747 "multiple registers share map_lookup_elem result",
4635 .insns = { 4748 .insns = {
4636 BPF_MOV64_IMM(BPF_REG_1, 10), 4749 BPF_MOV64_IMM(BPF_REG_1, 10),
@@ -6997,7 +7110,7 @@ static struct bpf_test tests[] = {
6997 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 7110 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
6998 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 7111 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
6999 BPF_FUNC_map_lookup_elem), 7112 BPF_FUNC_map_lookup_elem),
7000 BPF_MOV64_REG(BPF_REG_0, 0), 7113 BPF_MOV64_IMM(BPF_REG_0, 0),
7001 BPF_EXIT_INSN(), 7114 BPF_EXIT_INSN(),
7002 }, 7115 },
7003 .fixup_map_in_map = { 3 }, 7116 .fixup_map_in_map = { 3 },
@@ -7020,7 +7133,7 @@ static struct bpf_test tests[] = {
7020 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), 7133 BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
7021 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 7134 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7022 BPF_FUNC_map_lookup_elem), 7135 BPF_FUNC_map_lookup_elem),
7023 BPF_MOV64_REG(BPF_REG_0, 0), 7136 BPF_MOV64_IMM(BPF_REG_0, 0),
7024 BPF_EXIT_INSN(), 7137 BPF_EXIT_INSN(),
7025 }, 7138 },
7026 .fixup_map_in_map = { 3 }, 7139 .fixup_map_in_map = { 3 },
@@ -7042,7 +7155,7 @@ static struct bpf_test tests[] = {
7042 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), 7155 BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
7043 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 7156 BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
7044 BPF_FUNC_map_lookup_elem), 7157 BPF_FUNC_map_lookup_elem),
7045 BPF_MOV64_REG(BPF_REG_0, 0), 7158 BPF_MOV64_IMM(BPF_REG_0, 0),
7046 BPF_EXIT_INSN(), 7159 BPF_EXIT_INSN(),
7047 }, 7160 },
7048 .fixup_map_in_map = { 3 }, 7161 .fixup_map_in_map = { 3 },
@@ -12372,6 +12485,32 @@ static struct bpf_test tests[] = {
12372 .result = REJECT, 12485 .result = REJECT,
12373 .errstr = "variable ctx access var_off=(0x0; 0x4)", 12486 .errstr = "variable ctx access var_off=(0x0; 0x4)",
12374 }, 12487 },
12488 {
12489 "mov64 src == dst",
12490 .insns = {
12491 BPF_MOV64_IMM(BPF_REG_2, 0),
12492 BPF_MOV64_REG(BPF_REG_2, BPF_REG_2),
12493 // Check bounds are OK
12494 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
12495 BPF_MOV64_IMM(BPF_REG_0, 0),
12496 BPF_EXIT_INSN(),
12497 },
12498 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
12499 .result = ACCEPT,
12500 },
12501 {
12502 "mov64 src != dst",
12503 .insns = {
12504 BPF_MOV64_IMM(BPF_REG_3, 0),
12505 BPF_MOV64_REG(BPF_REG_2, BPF_REG_3),
12506 // Check bounds are OK
12507 BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
12508 BPF_MOV64_IMM(BPF_REG_0, 0),
12509 BPF_EXIT_INSN(),
12510 },
12511 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
12512 .result = ACCEPT,
12513 },
12375}; 12514};
12376 12515
12377static int probe_filter_length(const struct bpf_insn *fp) 12516static int probe_filter_length(const struct bpf_insn *fp)
@@ -12476,6 +12615,19 @@ static int create_map_in_map(void)
12476 return outer_map_fd; 12615 return outer_map_fd;
12477} 12616}
12478 12617
12618static int create_cgroup_storage(void)
12619{
12620 int fd;
12621
12622 fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE,
12623 sizeof(struct bpf_cgroup_storage_key),
12624 TEST_DATA_LEN, 0, 0);
12625 if (fd < 0)
12626 printf("Failed to create array '%s'!\n", strerror(errno));
12627
12628 return fd;
12629}
12630
12479static char bpf_vlog[UINT_MAX >> 8]; 12631static char bpf_vlog[UINT_MAX >> 8];
12480 12632
12481static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, 12633static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
@@ -12488,6 +12640,7 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
12488 int *fixup_prog1 = test->fixup_prog1; 12640 int *fixup_prog1 = test->fixup_prog1;
12489 int *fixup_prog2 = test->fixup_prog2; 12641 int *fixup_prog2 = test->fixup_prog2;
12490 int *fixup_map_in_map = test->fixup_map_in_map; 12642 int *fixup_map_in_map = test->fixup_map_in_map;
12643 int *fixup_cgroup_storage = test->fixup_cgroup_storage;
12491 12644
12492 if (test->fill_helper) 12645 if (test->fill_helper)
12493 test->fill_helper(test); 12646 test->fill_helper(test);
@@ -12555,6 +12708,14 @@ static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog,
12555 fixup_map_in_map++; 12708 fixup_map_in_map++;
12556 } while (*fixup_map_in_map); 12709 } while (*fixup_map_in_map);
12557 } 12710 }
12711
12712 if (*fixup_cgroup_storage) {
12713 map_fds[7] = create_cgroup_storage();
12714 do {
12715 prog[*fixup_cgroup_storage].imm = map_fds[7];
12716 fixup_cgroup_storage++;
12717 } while (*fixup_cgroup_storage);
12718 }
12558} 12719}
12559 12720
12560static void do_test_single(struct bpf_test *test, bool unpriv, 12721static void do_test_single(struct bpf_test *test, bool unpriv,
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
index 3868dcb63420..cabe2a3a3b30 100644
--- a/tools/testing/selftests/bpf/trace_helpers.c
+++ b/tools/testing/selftests/bpf/trace_helpers.c
@@ -88,7 +88,7 @@ static int page_size;
88static int page_cnt = 8; 88static int page_cnt = 8;
89static struct perf_event_mmap_page *header; 89static struct perf_event_mmap_page *header;
90 90
91int perf_event_mmap(int fd) 91int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header)
92{ 92{
93 void *base; 93 void *base;
94 int mmap_size; 94 int mmap_size;
@@ -102,10 +102,15 @@ int perf_event_mmap(int fd)
102 return -1; 102 return -1;
103 } 103 }
104 104
105 header = base; 105 *header = base;
106 return 0; 106 return 0;
107} 107}
108 108
109int perf_event_mmap(int fd)
110{
111 return perf_event_mmap_header(fd, &header);
112}
113
109static int perf_event_poll(int fd) 114static int perf_event_poll(int fd)
110{ 115{
111 struct pollfd pfd = { .fd = fd, .events = POLLIN }; 116 struct pollfd pfd = { .fd = fd, .events = POLLIN };
@@ -163,3 +168,42 @@ int perf_event_poller(int fd, perf_event_print_fn output_fn)
163 168
164 return ret; 169 return ret;
165} 170}
171
172int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
173 int num_fds, perf_event_print_fn output_fn)
174{
175 enum bpf_perf_event_ret ret;
176 struct pollfd *pfds;
177 void *buf = NULL;
178 size_t len = 0;
179 int i;
180
181 pfds = calloc(num_fds, sizeof(*pfds));
182 if (!pfds)
183 return LIBBPF_PERF_EVENT_ERROR;
184
185 for (i = 0; i < num_fds; i++) {
186 pfds[i].fd = fds[i];
187 pfds[i].events = POLLIN;
188 }
189
190 for (;;) {
191 poll(pfds, num_fds, 1000);
192 for (i = 0; i < num_fds; i++) {
193 if (!pfds[i].revents)
194 continue;
195
196 ret = bpf_perf_event_read_simple(headers[i],
197 page_cnt * page_size,
198 page_size, &buf, &len,
199 bpf_perf_event_print,
200 output_fn);
201 if (ret != LIBBPF_PERF_EVENT_CONT)
202 break;
203 }
204 }
205 free(buf);
206 free(pfds);
207
208 return ret;
209}
diff --git a/tools/testing/selftests/bpf/trace_helpers.h b/tools/testing/selftests/bpf/trace_helpers.h
index 3b4bcf7f5084..18924f23db1b 100644
--- a/tools/testing/selftests/bpf/trace_helpers.h
+++ b/tools/testing/selftests/bpf/trace_helpers.h
@@ -3,6 +3,7 @@
3#define __TRACE_HELPER_H 3#define __TRACE_HELPER_H
4 4
5#include <libbpf.h> 5#include <libbpf.h>
6#include <linux/perf_event.h>
6 7
7struct ksym { 8struct ksym {
8 long addr; 9 long addr;
@@ -16,6 +17,9 @@ long ksym_get_addr(const char *name);
16typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size); 17typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size);
17 18
18int perf_event_mmap(int fd); 19int perf_event_mmap(int fd);
20int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header);
19/* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */ 21/* return LIBBPF_PERF_EVENT_DONE or LIBBPF_PERF_EVENT_ERROR */
20int perf_event_poller(int fd, perf_event_print_fn output_fn); 22int perf_event_poller(int fd, perf_event_print_fn output_fn);
23int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
24 int num_fds, perf_event_print_fn output_fn);
21#endif 25#endif
diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh
new file mode 100755
index 000000000000..76f1ab4898d9
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre.sh
@@ -0,0 +1,217 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test uses standard topology for testing gretap. See
5# ../../../net/forwarding/mirror_gre_topo_lib.sh for more details.
6#
7# Test offloading various features of offloading gretap mirrors specific to
8# mlxsw.
9
10lib_dir=$(dirname $0)/../../../net/forwarding
11
12NUM_NETIFS=6
13source $lib_dir/lib.sh
14source $lib_dir/mirror_lib.sh
15source $lib_dir/mirror_gre_lib.sh
16source $lib_dir/mirror_gre_topo_lib.sh
17
18setup_keyful()
19{
20 tunnel_create gt6-key ip6gretap 2001:db8:3::1 2001:db8:3::2 \
21 ttl 100 tos inherit allow-localremote \
22 key 1234
23
24 tunnel_create h3-gt6-key ip6gretap 2001:db8:3::2 2001:db8:3::1 \
25 key 1234
26 ip link set h3-gt6-key vrf v$h3
27 matchall_sink_create h3-gt6-key
28
29 ip address add dev $swp3 2001:db8:3::1/64
30 ip address add dev $h3 2001:db8:3::2/64
31}
32
33cleanup_keyful()
34{
35 ip address del dev $h3 2001:db8:3::2/64
36 ip address del dev $swp3 2001:db8:3::1/64
37
38 tunnel_destroy h3-gt6-key
39 tunnel_destroy gt6-key
40}
41
42setup_soft()
43{
44 # Set up a topology for testing underlay routes that point at an
45 # unsupported soft device.
46
47 tunnel_create gt6-soft ip6gretap 2001:db8:4::1 2001:db8:4::2 \
48 ttl 100 tos inherit allow-localremote
49
50 tunnel_create h3-gt6-soft ip6gretap 2001:db8:4::2 2001:db8:4::1
51 ip link set h3-gt6-soft vrf v$h3
52 matchall_sink_create h3-gt6-soft
53
54 ip link add name v1 type veth peer name v2
55 ip link set dev v1 up
56 ip address add dev v1 2001:db8:4::1/64
57
58 ip link set dev v2 vrf v$h3
59 ip link set dev v2 up
60 ip address add dev v2 2001:db8:4::2/64
61}
62
63cleanup_soft()
64{
65 ip link del dev v1
66
67 tunnel_destroy h3-gt6-soft
68 tunnel_destroy gt6-soft
69}
70
71setup_prepare()
72{
73 h1=${NETIFS[p1]}
74 swp1=${NETIFS[p2]}
75
76 swp2=${NETIFS[p3]}
77 h2=${NETIFS[p4]}
78
79 swp3=${NETIFS[p5]}
80 h3=${NETIFS[p6]}
81
82 vrf_prepare
83 mirror_gre_topo_create
84
85 ip address add dev $swp3 2001:db8:2::1/64
86 ip address add dev $h3 2001:db8:2::2/64
87
88 ip address add dev $swp3 192.0.2.129/28
89 ip address add dev $h3 192.0.2.130/28
90
91 setup_keyful
92 setup_soft
93}
94
95cleanup()
96{
97 pre_cleanup
98
99 cleanup_soft
100 cleanup_keyful
101
102 ip address del dev $h3 2001:db8:2::2/64
103 ip address del dev $swp3 2001:db8:2::1/64
104
105 ip address del dev $h3 192.0.2.130/28
106 ip address del dev $swp3 192.0.2.129/28
107
108 mirror_gre_topo_destroy
109 vrf_cleanup
110}
111
112test_span_gre_ttl_inherit()
113{
114 local tundev=$1; shift
115 local type=$1; shift
116 local what=$1; shift
117
118 RET=0
119
120 ip link set dev $tundev type $type ttl inherit
121 mirror_install $swp1 ingress $tundev "matchall $tcflags"
122 fail_test_span_gre_dir $tundev ingress
123
124 ip link set dev $tundev type $type ttl 100
125
126 quick_test_span_gre_dir $tundev ingress
127 mirror_uninstall $swp1 ingress
128
129 log_test "$what: no offload on TTL of inherit ($tcflags)"
130}
131
132test_span_gre_tos_fixed()
133{
134 local tundev=$1; shift
135 local type=$1; shift
136 local what=$1; shift
137
138 RET=0
139
140 ip link set dev $tundev type $type tos 0x10
141 mirror_install $swp1 ingress $tundev "matchall $tcflags"
142 fail_test_span_gre_dir $tundev ingress
143
144 ip link set dev $tundev type $type tos inherit
145 quick_test_span_gre_dir $tundev ingress
146 mirror_uninstall $swp1 ingress
147
148 log_test "$what: no offload on a fixed TOS ($tcflags)"
149}
150
151test_span_failable()
152{
153 local should_fail=$1; shift
154 local tundev=$1; shift
155 local what=$1; shift
156
157 RET=0
158
159 mirror_install $swp1 ingress $tundev "matchall $tcflags"
160 if ((should_fail)); then
161 fail_test_span_gre_dir $tundev ingress
162 else
163 quick_test_span_gre_dir $tundev ingress
164 fi
165 mirror_uninstall $swp1 ingress
166
167 log_test "$what: should_fail=$should_fail ($tcflags)"
168}
169
170test_failable()
171{
172 local should_fail=$1; shift
173
174 test_span_failable $should_fail gt6-key "mirror to keyful gretap"
175 test_span_failable $should_fail gt6-soft "mirror to gretap w/ soft underlay"
176}
177
178test_sw()
179{
180 slow_path_trap_install $swp1 ingress
181 slow_path_trap_install $swp1 egress
182
183 test_failable 0
184
185 slow_path_trap_uninstall $swp1 egress
186 slow_path_trap_uninstall $swp1 ingress
187}
188
189test_hw()
190{
191 test_failable 1
192
193 test_span_gre_tos_fixed gt4 gretap "mirror to gretap"
194 test_span_gre_tos_fixed gt6 ip6gretap "mirror to ip6gretap"
195
196 test_span_gre_ttl_inherit gt4 gretap "mirror to gretap"
197 test_span_gre_ttl_inherit gt6 ip6gretap "mirror to ip6gretap"
198}
199
200trap cleanup EXIT
201
202setup_prepare
203setup_wait
204
205if ! tc_offload_check; then
206 check_err 1 "Could not test offloaded functionality"
207 log_test "mlxsw-specific tests for mirror to gretap"
208 exit
209fi
210
211tcflags="skip_hw"
212test_sw
213
214tcflags="skip_sw"
215test_hw
216
217exit $EXIT_STATUS
diff --git a/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
new file mode 100644
index 000000000000..6f3a70df63bc
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/mirror_gre_scale.sh
@@ -0,0 +1,197 @@
1# SPDX-License-Identifier: GPL-2.0
2
3# Test offloading a number of mirrors-to-gretap. The test creates a number of
4# tunnels. Then it adds one flower mirror for each of the tunnels, matching a
5# given host IP. Then it generates traffic at each of the host IPs and checks
6# that the traffic has been mirrored at the appropriate tunnel.
7#
8# +--------------------------+ +--------------------------+
9# | H1 | | H2 |
10# | + $h1 | | $h2 + |
11# | | 2001:db8:1:X::1/64 | | 2001:db8:1:X::2/64 | |
12# +-----|--------------------+ +--------------------|-----+
13# | |
14# +-----|-------------------------------------------------------------|-----+
15# | SW o--> mirrors | |
16# | +---|-------------------------------------------------------------|---+ |
17# | | + $swp1 BR $swp2 + | |
18# | +---------------------------------------------------------------------+ |
19# | |
20# | + $swp3 + gt6-<X> (ip6gretap) |
21# | | 2001:db8:2:X::1/64 : loc=2001:db8:2:X::1 |
22# | | : rem=2001:db8:2:X::2 |
23# | | : ttl=100 |
24# | | : tos=inherit |
25# | | : |
26# +-----|--------------------------------:----------------------------------+
27# | :
28# +-----|--------------------------------:----------------------------------+
29# | H3 + $h3 + h3-gt6-<X> (ip6gretap) |
30# | 2001:db8:2:X::2/64 loc=2001:db8:2:X::2 |
31# | rem=2001:db8:2:X::1 |
32# | ttl=100 |
33# | tos=inherit |
34# | |
35# +-------------------------------------------------------------------------+
36
37source ../../../../net/forwarding/mirror_lib.sh
38
39MIRROR_NUM_NETIFS=6
40
41mirror_gre_ipv6_addr()
42{
43 local net=$1; shift
44 local num=$1; shift
45
46 printf "2001:db8:%x:%x" $net $num
47}
48
49mirror_gre_tunnels_create()
50{
51 local count=$1; shift
52 local should_fail=$1; shift
53
54 MIRROR_GRE_BATCH_FILE="$(mktemp)"
55 for ((i=0; i < count; ++i)); do
56 local match_dip=$(mirror_gre_ipv6_addr 1 $i)::2
57 local htun=h3-gt6-$i
58 local tun=gt6-$i
59
60 ((mirror_gre_tunnels++))
61
62 ip address add dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64
63 ip address add dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64
64
65 ip address add dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64
66 ip address add dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64
67
68 tunnel_create $tun ip6gretap \
69 $(mirror_gre_ipv6_addr 2 $i)::1 \
70 $(mirror_gre_ipv6_addr 2 $i)::2 \
71 ttl 100 tos inherit allow-localremote
72
73 tunnel_create $htun ip6gretap \
74 $(mirror_gre_ipv6_addr 2 $i)::2 \
75 $(mirror_gre_ipv6_addr 2 $i)::1
76 ip link set $htun vrf v$h3
77 matchall_sink_create $htun
78
79 cat >> $MIRROR_GRE_BATCH_FILE <<-EOF
80 filter add dev $swp1 ingress pref 1000 \
81 protocol ipv6 \
82 flower $tcflags dst_ip $match_dip \
83 action mirred egress mirror dev $tun
84 EOF
85 done
86
87 tc -b $MIRROR_GRE_BATCH_FILE
88 check_err_fail $should_fail $? "Mirror rule insertion"
89}
90
91mirror_gre_tunnels_destroy()
92{
93 local count=$1; shift
94
95 for ((i=0; i < count; ++i)); do
96 local htun=h3-gt6-$i
97 local tun=gt6-$i
98
99 ip address del dev $h3 $(mirror_gre_ipv6_addr 2 $i)::2/64
100 ip address del dev $swp3 $(mirror_gre_ipv6_addr 2 $i)::1/64
101
102 ip address del dev $h2 $(mirror_gre_ipv6_addr 1 $i)::2/64
103 ip address del dev $h1 $(mirror_gre_ipv6_addr 1 $i)::1/64
104
105 tunnel_destroy $htun
106 tunnel_destroy $tun
107 done
108}
109
110__mirror_gre_test()
111{
112 local count=$1; shift
113 local should_fail=$1; shift
114
115 mirror_gre_tunnels_create $count $should_fail
116 if ((should_fail)); then
117 return
118 fi
119
120 sleep 5
121
122 for ((i = 0; i < count; ++i)); do
123 local dip=$(mirror_gre_ipv6_addr 1 $i)::2
124 local htun=h3-gt6-$i
125 local message
126
127 icmp6_capture_install $htun
128 mirror_test v$h1 "" $dip $htun 100 10
129 icmp6_capture_uninstall $htun
130 done
131}
132
133mirror_gre_test()
134{
135 local count=$1; shift
136 local should_fail=$1; shift
137
138 if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then
139 check_err 1 "Could not test offloaded functionality"
140 return
141 fi
142
143 tcflags="skip_sw"
144 __mirror_gre_test $count $should_fail
145}
146
147mirror_gre_setup_prepare()
148{
149 h1=${NETIFS[p1]}
150 swp1=${NETIFS[p2]}
151
152 swp2=${NETIFS[p3]}
153 h2=${NETIFS[p4]}
154
155 swp3=${NETIFS[p5]}
156 h3=${NETIFS[p6]}
157
158 mirror_gre_tunnels=0
159
160 vrf_prepare
161
162 simple_if_init $h1
163 simple_if_init $h2
164 simple_if_init $h3
165
166 ip link add name br1 type bridge vlan_filtering 1
167 ip link set dev br1 up
168
169 ip link set dev $swp1 master br1
170 ip link set dev $swp1 up
171 tc qdisc add dev $swp1 clsact
172
173 ip link set dev $swp2 master br1
174 ip link set dev $swp2 up
175
176 ip link set dev $swp3 up
177}
178
179mirror_gre_cleanup()
180{
181 mirror_gre_tunnels_destroy $mirror_gre_tunnels
182
183 ip link set dev $swp3 down
184
185 ip link set dev $swp2 down
186
187 tc qdisc del dev $swp1 clsact
188 ip link set dev $swp1 down
189
190 ip link del dev br1
191
192 simple_if_fini $h3
193 simple_if_fini $h2
194 simple_if_fini $h1
195
196 vrf_cleanup
197}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
new file mode 100755
index 000000000000..1ca631d5aaba
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_bridge.sh
@@ -0,0 +1,189 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for DSCP prioritization and rewrite. Packets ingress $swp1 with a DSCP
5# tag and are prioritized according to the map at $swp1. They egress $swp2 and
6# the DSCP value is updated to match the map at that interface. The updated DSCP
7# tag is verified at $h2.
8#
9# ICMP responses are produced with the same DSCP tag that arrived at $h2. They
10# go through prioritization at $swp2 and DSCP retagging at $swp1. The tag is
11# verified at $h1--it should match the original tag.
12#
13# +----------------------+ +----------------------+
14# | H1 | | H2 |
15# | + $h1 | | $h2 + |
16# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
17# +----|-----------------+ +----------------|-----+
18# | |
19# +----|----------------------------------------------------------------|-----+
20# | SW | | |
21# | +-|----------------------------------------------------------------|-+ |
22# | | + $swp1 BR $swp2 + | |
23# | | APP=0,5,10 .. 7,5,17 APP=0,5,20 .. 7,5,27 | |
24# | +--------------------------------------------------------------------+ |
25# +---------------------------------------------------------------------------+
26
27ALL_TESTS="
28 ping_ipv4
29 test_dscp
30"
31
32lib_dir=$(dirname $0)/../../../net/forwarding
33
34NUM_NETIFS=4
35source $lib_dir/lib.sh
36
37h1_create()
38{
39 local dscp;
40
41 simple_if_init $h1 192.0.2.1/28
42 tc qdisc add dev $h1 clsact
43 dscp_capture_install $h1 10
44}
45
46h1_destroy()
47{
48 dscp_capture_uninstall $h1 10
49 tc qdisc del dev $h1 clsact
50 simple_if_fini $h1 192.0.2.1/28
51}
52
53h2_create()
54{
55 simple_if_init $h2 192.0.2.2/28
56 tc qdisc add dev $h2 clsact
57 dscp_capture_install $h2 20
58}
59
60h2_destroy()
61{
62 dscp_capture_uninstall $h2 20
63 tc qdisc del dev $h2 clsact
64 simple_if_fini $h2 192.0.2.2/28
65}
66
67dscp_map()
68{
69 local base=$1; shift
70
71 for prio in {0..7}; do
72 echo app=$prio,5,$((base + prio))
73 done
74}
75
76switch_create()
77{
78 ip link add name br1 type bridge vlan_filtering 1
79 ip link set dev br1 up
80 ip link set dev $swp1 master br1
81 ip link set dev $swp1 up
82 ip link set dev $swp2 master br1
83 ip link set dev $swp2 up
84
85 lldptool -T -i $swp1 -V APP $(dscp_map 10) >/dev/null
86 lldptool -T -i $swp2 -V APP $(dscp_map 20) >/dev/null
87 lldpad_app_wait_set $swp1
88 lldpad_app_wait_set $swp2
89}
90
91switch_destroy()
92{
93 lldptool -T -i $swp2 -V APP -d $(dscp_map 20) >/dev/null
94 lldptool -T -i $swp1 -V APP -d $(dscp_map 10) >/dev/null
95 lldpad_app_wait_del
96
97 ip link set dev $swp2 nomaster
98 ip link set dev $swp1 nomaster
99 ip link del dev br1
100}
101
102setup_prepare()
103{
104 h1=${NETIFS[p1]}
105 swp1=${NETIFS[p2]}
106
107 swp2=${NETIFS[p3]}
108 h2=${NETIFS[p4]}
109
110 vrf_prepare
111
112 h1_create
113 h2_create
114 switch_create
115}
116
117cleanup()
118{
119 pre_cleanup
120
121 switch_destroy
122 h2_destroy
123 h1_destroy
124
125 vrf_cleanup
126}
127
128ping_ipv4()
129{
130 ping_test $h1 192.0.2.2
131}
132
133dscp_ping_test()
134{
135 local vrf_name=$1; shift
136 local sip=$1; shift
137 local dip=$1; shift
138 local prio=$1; shift
139 local dev_10=$1; shift
140 local dev_20=$1; shift
141
142 local dscp_10=$(((prio + 10) << 2))
143 local dscp_20=$(((prio + 20) << 2))
144
145 RET=0
146
147 local -A t0s
148 eval "t0s=($(dscp_fetch_stats $dev_10 10)
149 $(dscp_fetch_stats $dev_20 20))"
150
151 ip vrf exec $vrf_name \
152 ${PING} -Q $dscp_10 ${sip:+-I $sip} $dip \
153 -c 10 -i 0.1 -w 2 &> /dev/null
154
155 local -A t1s
156 eval "t1s=($(dscp_fetch_stats $dev_10 10)
157 $(dscp_fetch_stats $dev_20 20))"
158
159 for key in ${!t0s[@]}; do
160 local expect
161 if ((key == prio+10 || key == prio+20)); then
162 expect=10
163 else
164 expect=0
165 fi
166
167 local delta=$((t1s[$key] - t0s[$key]))
168 ((expect == delta))
169 check_err $? "DSCP $key: Expected to capture $expect packets, got $delta."
170 done
171
172 log_test "DSCP rewrite: $dscp_10-(prio $prio)-$dscp_20"
173}
174
175test_dscp()
176{
177 for prio in {0..7}; do
178 dscp_ping_test v$h1 192.0.2.1 192.0.2.2 $prio $h1 $h2
179 done
180}
181
182trap cleanup EXIT
183
184setup_prepare
185setup_wait
186
187tests_run
188
189exit $EXIT_STATUS
diff --git a/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh
new file mode 100755
index 000000000000..281d90766e12
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/qos_dscp_router.sh
@@ -0,0 +1,233 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for DSCP prioritization in the router.
5#
6# With ip_forward_update_priority disabled, the packets are expected to keep
7# their DSCP (which in this test uses only values 0..7) intact as they are
8# forwarded by the switch. That is verified at $h2. ICMP responses are formed
9# with the same DSCP as the requests, and likewise pass through the switch
10# intact, which is verified at $h1.
11#
12# With ip_forward_update_priority enabled, router reprioritizes the packets
13# according to the table in reprioritize(). Thus, say, DSCP 7 maps to priority
14# 4, which on egress maps back to DSCP 4. The response packet then gets
15# reprioritized to 6, getting DSCP 6 on egress.
16#
17# +----------------------+ +----------------------+
18# | H1 | | H2 |
19# | + $h1 | | $h2 + |
20# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
21# +----|-----------------+ +----------------|-----+
22# | |
23# +----|----------------------------------------------------------------|-----+
24# | SW | | |
25# | + $swp1 $swp2 + |
26# | 192.0.2.2/28 192.0.2.17/28 |
27# | APP=0,5,0 .. 7,5,7 APP=0,5,0 .. 7,5,7 |
28# +---------------------------------------------------------------------------+
29
30ALL_TESTS="
31 ping_ipv4
32 test_update
33 test_no_update
34"
35
36lib_dir=$(dirname $0)/../../../net/forwarding
37
38NUM_NETIFS=4
39source $lib_dir/lib.sh
40
41reprioritize()
42{
43 local in=$1; shift
44
45 # This is based on rt_tos2priority in include/net/route.h. Assuming 1:1
46 # mapping between priorities and TOS, it yields a new priority for a
47 # packet with ingress priority of $in.
48 local -a reprio=(0 0 2 2 6 6 4 4)
49
50 echo ${reprio[$in]}
51}
52
53h1_create()
54{
55 local dscp;
56
57 simple_if_init $h1 192.0.2.1/28
58 tc qdisc add dev $h1 clsact
59 dscp_capture_install $h1 0
60 ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2
61}
62
63h1_destroy()
64{
65 ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2
66 dscp_capture_uninstall $h1 0
67 tc qdisc del dev $h1 clsact
68 simple_if_fini $h1 192.0.2.1/28
69}
70
71h2_create()
72{
73 simple_if_init $h2 192.0.2.18/28
74 tc qdisc add dev $h2 clsact
75 dscp_capture_install $h2 0
76 ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17
77}
78
79h2_destroy()
80{
81 ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17
82 dscp_capture_uninstall $h2 0
83 tc qdisc del dev $h2 clsact
84 simple_if_fini $h2 192.0.2.18/28
85}
86
87dscp_map()
88{
89 local base=$1; shift
90
91 for prio in {0..7}; do
92 echo app=$prio,5,$((base + prio))
93 done
94}
95
96switch_create()
97{
98 simple_if_init $swp1 192.0.2.2/28
99 __simple_if_init $swp2 v$swp1 192.0.2.17/28
100
101 lldptool -T -i $swp1 -V APP $(dscp_map 0) >/dev/null
102 lldptool -T -i $swp2 -V APP $(dscp_map 0) >/dev/null
103 lldpad_app_wait_set $swp1
104 lldpad_app_wait_set $swp2
105}
106
107switch_destroy()
108{
109 lldptool -T -i $swp2 -V APP -d $(dscp_map 0) >/dev/null
110 lldptool -T -i $swp1 -V APP -d $(dscp_map 0) >/dev/null
111 lldpad_app_wait_del
112
113 __simple_if_fini $swp2 192.0.2.17/28
114 simple_if_fini $swp1 192.0.2.2/28
115}
116
117setup_prepare()
118{
119 h1=${NETIFS[p1]}
120 swp1=${NETIFS[p2]}
121
122 swp2=${NETIFS[p3]}
123 h2=${NETIFS[p4]}
124
125 vrf_prepare
126
127 sysctl_set net.ipv4.ip_forward_update_priority 1
128 h1_create
129 h2_create
130 switch_create
131}
132
133cleanup()
134{
135 pre_cleanup
136
137 switch_destroy
138 h2_destroy
139 h1_destroy
140 sysctl_restore net.ipv4.ip_forward_update_priority
141
142 vrf_cleanup
143}
144
145ping_ipv4()
146{
147 ping_test $h1 192.0.2.18
148}
149
150dscp_ping_test()
151{
152 local vrf_name=$1; shift
153 local sip=$1; shift
154 local dip=$1; shift
155 local prio=$1; shift
156 local reprio=$1; shift
157 local dev1=$1; shift
158 local dev2=$1; shift
159
160 local prio2=$($reprio $prio) # ICMP Request egress prio
161 local prio3=$($reprio $prio2) # ICMP Response egress prio
162
163 local dscp=$((prio << 2)) # ICMP Request ingress DSCP
164 local dscp2=$((prio2 << 2)) # ICMP Request egress DSCP
165 local dscp3=$((prio3 << 2)) # ICMP Response egress DSCP
166
167 RET=0
168
169 eval "local -A dev1_t0s=($(dscp_fetch_stats $dev1 0))"
170 eval "local -A dev2_t0s=($(dscp_fetch_stats $dev2 0))"
171
172 ip vrf exec $vrf_name \
173 ${PING} -Q $dscp ${sip:+-I $sip} $dip \
174 -c 10 -i 0.1 -w 2 &> /dev/null
175
176 eval "local -A dev1_t1s=($(dscp_fetch_stats $dev1 0))"
177 eval "local -A dev2_t1s=($(dscp_fetch_stats $dev2 0))"
178
179 for i in {0..7}; do
180 local dscpi=$((i << 2))
181 local expect2=0
182 local expect3=0
183
184 if ((i == prio2)); then
185 expect2=10
186 fi
187 if ((i == prio3)); then
188 expect3=10
189 fi
190
191 local delta=$((dev2_t1s[$i] - dev2_t0s[$i]))
192 ((expect2 == delta))
193 check_err $? "DSCP $dscpi@$dev2: Expected to capture $expect2 packets, got $delta."
194
195 delta=$((dev1_t1s[$i] - dev1_t0s[$i]))
196 ((expect3 == delta))
197 check_err $? "DSCP $dscpi@$dev1: Expected to capture $expect3 packets, got $delta."
198 done
199
200 log_test "DSCP rewrite: $dscp-(prio $prio2)-$dscp2-(prio $prio3)-$dscp3"
201}
202
203__test_update()
204{
205 local update=$1; shift
206 local reprio=$1; shift
207
208 sysctl_restore net.ipv4.ip_forward_update_priority
209 sysctl_set net.ipv4.ip_forward_update_priority $update
210
211 for prio in {0..7}; do
212 dscp_ping_test v$h1 192.0.2.1 192.0.2.18 $prio $reprio $h1 $h2
213 done
214}
215
216test_update()
217{
218 __test_update 1 reprioritize
219}
220
221test_no_update()
222{
223 __test_update 0 echo
224}
225
226trap cleanup EXIT
227
228setup_prepare
229setup_wait
230
231tests_run
232
233exit $EXIT_STATUS
diff --git a/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh
new file mode 100644
index 000000000000..d231649b4f01
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/router_scale.sh
@@ -0,0 +1,167 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ROUTER_NUM_NETIFS=4
5
6router_h1_create()
7{
8 simple_if_init $h1 192.0.1.1/24
9 ip route add 193.0.0.0/8 via 192.0.1.2 dev $h1
10}
11
12router_h1_destroy()
13{
14 ip route del 193.0.0.0/8 via 192.0.1.2 dev $h1
15 simple_if_fini $h1 192.0.1.1/24
16}
17
18router_h2_create()
19{
20 simple_if_init $h2 192.0.2.1/24
21 tc qdisc add dev $h2 handle ffff: ingress
22}
23
24router_h2_destroy()
25{
26 tc qdisc del dev $h2 handle ffff: ingress
27 simple_if_fini $h2 192.0.2.1/24
28}
29
30router_create()
31{
32 ip link set dev $rp1 up
33 ip link set dev $rp2 up
34
35 ip address add 192.0.1.2/24 dev $rp1
36 ip address add 192.0.2.2/24 dev $rp2
37}
38
39router_destroy()
40{
41 ip address del 192.0.2.2/24 dev $rp2
42 ip address del 192.0.1.2/24 dev $rp1
43
44 ip link set dev $rp2 down
45 ip link set dev $rp1 down
46}
47
48router_setup_prepare()
49{
50 h1=${NETIFS[p1]}
51 rp1=${NETIFS[p2]}
52
53 rp2=${NETIFS[p3]}
54 h2=${NETIFS[p4]}
55
56 h1mac=$(mac_get $h1)
57 rp1mac=$(mac_get $rp1)
58
59 vrf_prepare
60
61 router_h1_create
62 router_h2_create
63
64 router_create
65}
66
67router_offload_validate()
68{
69 local route_count=$1
70 local offloaded_count
71
72 offloaded_count=$(ip route | grep -o 'offload' | wc -l)
73 [[ $offloaded_count -ge $route_count ]]
74}
75
76router_routes_create()
77{
78 local route_count=$1
79 local count=0
80
81 ROUTE_FILE="$(mktemp)"
82
83 for i in {0..255}
84 do
85 for j in {0..255}
86 do
87 for k in {0..255}
88 do
89 if [[ $count -eq $route_count ]]; then
90 break 3
91 fi
92
93 echo route add 193.${i}.${j}.${k}/32 via \
94 192.0.2.1 dev $rp2 >> $ROUTE_FILE
95 ((count++))
96 done
97 done
98 done
99
100 ip -b $ROUTE_FILE &> /dev/null
101}
102
103router_routes_destroy()
104{
105 if [[ -v ROUTE_FILE ]]; then
106 rm -f $ROUTE_FILE
107 fi
108}
109
110router_test()
111{
112 local route_count=$1
113 local should_fail=$2
114 local count=0
115
116 RET=0
117
118 router_routes_create $route_count
119
120 router_offload_validate $route_count
121 check_err_fail $should_fail $? "Offload of $route_count routes"
122 if [[ $RET -ne 0 ]] || [[ $should_fail -eq 1 ]]; then
123 return
124 fi
125
126 tc filter add dev $h2 ingress protocol ip pref 1 flower \
127 skip_sw dst_ip 193.0.0.0/8 action drop
128
129 for i in {0..255}
130 do
131 for j in {0..255}
132 do
133 for k in {0..255}
134 do
135 if [[ $count -eq $route_count ]]; then
136 break 3
137 fi
138
139 $MZ $h1 -c 1 -p 64 -a $h1mac -b $rp1mac \
140 -A 192.0.1.1 -B 193.${i}.${j}.${k} \
141 -t ip -q
142 ((count++))
143 done
144 done
145 done
146
147 tc_check_packets "dev $h2 ingress" 1 $route_count
148 check_err $? "Offload mismatch"
149
150 tc filter del dev $h2 ingress protocol ip pref 1 flower \
151 skip_sw dst_ip 193.0.0.0/8 action drop
152
153 router_routes_destroy
154}
155
156router_cleanup()
157{
158 pre_cleanup
159
160 router_routes_destroy
161 router_destroy
162
163 router_h2_destroy
164 router_h1_destroy
165
166 vrf_cleanup
167}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh
new file mode 100755
index 000000000000..3b75180f455d
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum-2/tc_flower.sh
@@ -0,0 +1,366 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is for checking the A-TCAM and C-TCAM operation in Spectrum-2.
5# It tries to exercise as many code paths in the eRP state machine as
6# possible.
7
8lib_dir=$(dirname $0)/../../../../net/forwarding
9
10ALL_TESTS="single_mask_test identical_filters_test two_masks_test \
11 multiple_masks_test ctcam_edge_cases_test"
12NUM_NETIFS=2
13source $lib_dir/tc_common.sh
14source $lib_dir/lib.sh
15
16tcflags="skip_hw"
17
18h1_create()
19{
20 simple_if_init $h1 192.0.2.1/24 198.51.100.1/24
21}
22
23h1_destroy()
24{
25 simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24
26}
27
28h2_create()
29{
30 simple_if_init $h2 192.0.2.2/24 198.51.100.2/24
31 tc qdisc add dev $h2 clsact
32}
33
34h2_destroy()
35{
36 tc qdisc del dev $h2 clsact
37 simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24
38}
39
40single_mask_test()
41{
42 # When only a single mask is required, the device uses the master
43 # mask and not the eRP table. Verify that under this mode the right
44 # filter is matched
45
46 RET=0
47
48 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
49 $tcflags dst_ip 192.0.2.2 action drop
50
51 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
52 -t ip -q
53
54 tc_check_packets "dev $h2 ingress" 101 1
55 check_err $? "Single filter - did not match"
56
57 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
58 $tcflags dst_ip 198.51.100.2 action drop
59
60 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
61 -t ip -q
62
63 tc_check_packets "dev $h2 ingress" 101 2
64 check_err $? "Two filters - did not match highest priority"
65
66 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
67 -t ip -q
68
69 tc_check_packets "dev $h2 ingress" 102 1
70 check_err $? "Two filters - did not match lowest priority"
71
72 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
73
74 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 198.51.100.1 -B 198.51.100.2 \
75 -t ip -q
76
77 tc_check_packets "dev $h2 ingress" 102 2
78 check_err $? "Single filter - did not match after delete"
79
80 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
81
82 log_test "single mask test ($tcflags)"
83}
84
85identical_filters_test()
86{
87 # When two filters that only differ in their priority are used,
88 # one needs to be inserted into the C-TCAM. This test verifies
89 # that filters are correctly spilled to C-TCAM and that the right
90 # filter is matched
91
92 RET=0
93
94 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
95 $tcflags dst_ip 192.0.2.2 action drop
96 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
97 $tcflags dst_ip 192.0.2.2 action drop
98
99 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
100 -t ip -q
101
102 tc_check_packets "dev $h2 ingress" 101 1
103 check_err $? "Did not match A-TCAM filter"
104
105 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
106
107 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
108 -t ip -q
109
110 tc_check_packets "dev $h2 ingress" 102 1
111 check_err $? "Did not match C-TCAM filter after A-TCAM delete"
112
113 tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
114 $tcflags dst_ip 192.0.2.2 action drop
115
116 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
117 -t ip -q
118
119 tc_check_packets "dev $h2 ingress" 102 2
120 check_err $? "Did not match C-TCAM filter after A-TCAM add"
121
122 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
123
124 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
125 -t ip -q
126
127 tc_check_packets "dev $h2 ingress" 103 1
128 check_err $? "Did not match A-TCAM filter after C-TCAM delete"
129
130 tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
131
132 log_test "identical filters test ($tcflags)"
133}
134
135two_masks_test()
136{
137 # When more than one mask is required, the eRP table is used. This
138 # test verifies that the eRP table is correctly allocated and used
139
140 RET=0
141
142 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
143 $tcflags dst_ip 192.0.2.2 action drop
144 tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
145 $tcflags dst_ip 192.0.0.0/16 action drop
146
147 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
148 -t ip -q
149
150 tc_check_packets "dev $h2 ingress" 101 1
151 check_err $? "Two filters - did not match highest priority"
152
153 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
154
155 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
156 -t ip -q
157
158 tc_check_packets "dev $h2 ingress" 103 1
159 check_err $? "Single filter - did not match"
160
161 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
162 $tcflags dst_ip 192.0.2.0/24 action drop
163
164 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
165 -t ip -q
166
167 tc_check_packets "dev $h2 ingress" 102 1
168 check_err $? "Two filters - did not match highest priority after add"
169
170 tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
171 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
172
173 log_test "two masks test ($tcflags)"
174}
175
176multiple_masks_test()
177{
178 # The number of masks in a region is limited. Once the maximum
179 # number of masks has been reached filters that require new
180 # masks are spilled to the C-TCAM. This test verifies that
181 # spillage is performed correctly and that the right filter is
182 # matched
183
184 local index
185
186 RET=0
187
188 NUM_MASKS=32
189 BASE_INDEX=100
190
191 for i in $(eval echo {1..$NUM_MASKS}); do
192 index=$((BASE_INDEX - i))
193
194 tc filter add dev $h2 ingress protocol ip pref $index \
195 handle $index \
196 flower $tcflags dst_ip 192.0.2.2/${i} src_ip 192.0.2.1 \
197 action drop
198
199 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
200 -B 192.0.2.2 -t ip -q
201
202 tc_check_packets "dev $h2 ingress" $index 1
203 check_err $? "$i filters - did not match highest priority (add)"
204 done
205
206 for i in $(eval echo {$NUM_MASKS..1}); do
207 index=$((BASE_INDEX - i))
208
209 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 \
210 -B 192.0.2.2 -t ip -q
211
212 tc_check_packets "dev $h2 ingress" $index 2
213 check_err $? "$i filters - did not match highest priority (del)"
214
215 tc filter del dev $h2 ingress protocol ip pref $index \
216 handle $index flower
217 done
218
219 log_test "multiple masks test ($tcflags)"
220}
221
222ctcam_two_atcam_masks_test()
223{
224 RET=0
225
226 # First case: C-TCAM is disabled when there are two A-TCAM masks.
227 # We push a filter into the C-TCAM by using two identical filters
228 # as in identical_filters_test()
229
230 # Filter goes into A-TCAM
231 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
232 $tcflags dst_ip 192.0.2.2 action drop
233 # Filter goes into C-TCAM
234 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
235 $tcflags dst_ip 192.0.2.2 action drop
236 # Filter goes into A-TCAM
237 tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \
238 $tcflags dst_ip 192.0.2.0/24 action drop
239
240 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
241 -t ip -q
242
243 tc_check_packets "dev $h2 ingress" 101 1
244 check_err $? "Did not match A-TCAM filter"
245
246 # Delete both A-TCAM and C-TCAM filters and make sure the remaining
247 # A-TCAM filter still works
248 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
249 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
250
251 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
252 -t ip -q
253
254 tc_check_packets "dev $h2 ingress" 103 1
255 check_err $? "Did not match A-TCAM filter"
256
257 tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower
258
259 log_test "ctcam with two atcam masks test ($tcflags)"
260}
261
262ctcam_one_atcam_mask_test()
263{
264 RET=0
265
266 # Second case: C-TCAM is disabled when there is one A-TCAM mask.
267 # The test is similar to identical_filters_test()
268
269 # Filter goes into A-TCAM
270 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
271 $tcflags dst_ip 192.0.2.2 action drop
272 # Filter goes into C-TCAM
273 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
274 $tcflags dst_ip 192.0.2.2 action drop
275
276 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
277 -t ip -q
278
279 tc_check_packets "dev $h2 ingress" 101 1
280 check_err $? "Did not match C-TCAM filter"
281
282 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
283
284 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
285 -t ip -q
286
287 tc_check_packets "dev $h2 ingress" 102 1
288 check_err $? "Did not match A-TCAM filter"
289
290 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
291
292 log_test "ctcam with one atcam mask test ($tcflags)"
293}
294
295ctcam_no_atcam_masks_test()
296{
297 RET=0
298
299 # Third case: C-TCAM is disabled when there are no A-TCAM masks
300 # This test exercises the code path that transitions the eRP table
301 # to its initial state after deleting the last C-TCAM mask
302
303 # Filter goes into A-TCAM
304 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
305 $tcflags dst_ip 192.0.2.2 action drop
306 # Filter goes into C-TCAM
307 tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \
308 $tcflags dst_ip 192.0.2.2 action drop
309
310 tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
311 tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower
312
313 log_test "ctcam with no atcam masks test ($tcflags)"
314}
315
316ctcam_edge_cases_test()
317{
318 # When the C-TCAM is disabled after deleting the last C-TCAM
319 # mask, we want to make sure the eRP state machine is put in
320 # the correct state
321
322 ctcam_two_atcam_masks_test
323 ctcam_one_atcam_mask_test
324 ctcam_no_atcam_masks_test
325}
326
327setup_prepare()
328{
329 h1=${NETIFS[p1]}
330 h2=${NETIFS[p2]}
331 h1mac=$(mac_get $h1)
332 h2mac=$(mac_get $h2)
333
334 vrf_prepare
335
336 h1_create
337 h2_create
338}
339
340cleanup()
341{
342 pre_cleanup
343
344 h2_destroy
345 h1_destroy
346
347 vrf_cleanup
348}
349
350trap cleanup EXIT
351
352setup_prepare
353setup_wait
354
355tests_run
356
357if ! tc_offload_check; then
358 check_err 1 "Could not test offloaded functionality"
359 log_test "mlxsw-specific tests for tc flower"
360 exit
361else
362 tcflags="skip_sw"
363 tests_run
364fi
365
366exit $EXIT_STATUS
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh
new file mode 100644
index 000000000000..73035e25085d
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_lib_spectrum.sh
@@ -0,0 +1,119 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4source "../../../../net/forwarding/devlink_lib.sh"
5
6if [ "$DEVLINK_VIDDID" != "15b3:cb84" ]; then
7 echo "SKIP: test is tailored for Mellanox Spectrum"
8 exit 1
9fi
10
11# Needed for returning to default
12declare -A KVD_DEFAULTS
13
14KVD_CHILDREN="linear hash_single hash_double"
15KVDL_CHILDREN="singles chunks large_chunks"
16
17devlink_sp_resource_minimize()
18{
19 local size
20 local i
21
22 for i in $KVD_CHILDREN; do
23 size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]')
24 devlink_resource_size_set "$size" kvd "$i"
25 done
26
27 for i in $KVDL_CHILDREN; do
28 size=$(devlink_resource_get kvd linear "$i" | \
29 jq '.["size_min"]')
30 devlink_resource_size_set "$size" kvd linear "$i"
31 done
32}
33
34devlink_sp_size_kvd_to_default()
35{
36 local need_reload=0
37 local i
38
39 for i in $KVD_CHILDREN; do
40 local size=$(echo "${KVD_DEFAULTS[kvd_$i]}" | jq '.["size"]')
41 current_size=$(devlink_resource_size_get kvd "$i")
42
43 if [ "$size" -ne "$current_size" ]; then
44 devlink_resource_size_set "$size" kvd "$i"
45 need_reload=1
46 fi
47 done
48
49 for i in $KVDL_CHILDREN; do
50 local size=$(echo "${KVD_DEFAULTS[kvd_linear_$i]}" | \
51 jq '.["size"]')
52 current_size=$(devlink_resource_size_get kvd linear "$i")
53
54 if [ "$size" -ne "$current_size" ]; then
55 devlink_resource_size_set "$size" kvd linear "$i"
56 need_reload=1
57 fi
58 done
59
60 if [ "$need_reload" -ne "0" ]; then
61 devlink_reload
62 fi
63}
64
65devlink_sp_read_kvd_defaults()
66{
67 local key
68 local i
69
70 KVD_DEFAULTS[kvd]=$(devlink_resource_get "kvd")
71 for i in $KVD_CHILDREN; do
72 key=kvd_$i
73 KVD_DEFAULTS[$key]=$(devlink_resource_get kvd "$i")
74 done
75
76 for i in $KVDL_CHILDREN; do
77 key=kvd_linear_$i
78 KVD_DEFAULTS[$key]=$(devlink_resource_get kvd linear "$i")
79 done
80}
81
82KVD_PROFILES="default scale ipv4_max"
83
84devlink_sp_resource_kvd_profile_set()
85{
86 local profile=$1
87
88 case "$profile" in
89 scale)
90 devlink_resource_size_set 64000 kvd linear
91 devlink_resource_size_set 15616 kvd linear singles
92 devlink_resource_size_set 32000 kvd linear chunks
93 devlink_resource_size_set 16384 kvd linear large_chunks
94 devlink_resource_size_set 128000 kvd hash_single
95 devlink_resource_size_set 48000 kvd hash_double
96 devlink_reload
97 ;;
98 ipv4_max)
99 devlink_resource_size_set 64000 kvd linear
100 devlink_resource_size_set 15616 kvd linear singles
101 devlink_resource_size_set 32000 kvd linear chunks
102 devlink_resource_size_set 16384 kvd linear large_chunks
103 devlink_resource_size_set 144000 kvd hash_single
104 devlink_resource_size_set 32768 kvd hash_double
105 devlink_reload
106 ;;
107 default)
108 devlink_resource_size_set 98304 kvd linear
109 devlink_resource_size_set 16384 kvd linear singles
110 devlink_resource_size_set 49152 kvd linear chunks
111 devlink_resource_size_set 32768 kvd linear large_chunks
112 devlink_resource_size_set 87040 kvd hash_single
113 devlink_resource_size_set 60416 kvd hash_double
114 devlink_reload
115 ;;
116 *)
117 check_err 1 "Unknown profile $profile"
118 esac
119}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh
new file mode 100755
index 000000000000..b1fe960e398a
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/devlink_resources.sh
@@ -0,0 +1,117 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4NUM_NETIFS=1
5source devlink_lib_spectrum.sh
6
7setup_prepare()
8{
9 devlink_sp_read_kvd_defaults
10}
11
12cleanup()
13{
14 pre_cleanup
15 devlink_sp_size_kvd_to_default
16}
17
18trap cleanup EXIT
19
20setup_prepare
21
22profiles_test()
23{
24 local i
25
26 log_info "Running profile tests"
27
28 for i in $KVD_PROFILES; do
29 RET=0
30 devlink_sp_resource_kvd_profile_set $i
31 log_test "'$i' profile"
32 done
33
34 # Default is explicitly tested at end to ensure it's actually applied
35 RET=0
36 devlink_sp_resource_kvd_profile_set "default"
37 log_test "'default' profile"
38}
39
40resources_min_test()
41{
42 local size
43 local i
44 local j
45
46 log_info "Running KVD-minimum tests"
47
48 for i in $KVD_CHILDREN; do
49 RET=0
50 size=$(devlink_resource_get kvd "$i" | jq '.["size_min"]')
51 devlink_resource_size_set "$size" kvd "$i"
52
53 # In case of linear, need to minimize sub-resources as well
54 if [[ "$i" == "linear" ]]; then
55 for j in $KVDL_CHILDREN; do
56 devlink_resource_size_set 0 kvd linear "$j"
57 done
58 fi
59
60 devlink_reload
61 devlink_sp_size_kvd_to_default
62 log_test "'$i' minimize [$size]"
63 done
64}
65
66resources_max_test()
67{
68 local min_size
69 local size
70 local i
71 local j
72
73 log_info "Running KVD-maximum tests"
74 for i in $KVD_CHILDREN; do
75 RET=0
76 devlink_sp_resource_minimize
77
78 # Calculate the maximum possible size for the given partition
79 size=$(devlink_resource_size_get kvd)
80 for j in $KVD_CHILDREN; do
81 if [ "$i" != "$j" ]; then
82 min_size=$(devlink_resource_get kvd "$j" | \
83 jq '.["size_min"]')
84 size=$((size - min_size))
85 fi
86 done
87
88 # Test almost maximum size
89 devlink_resource_size_set "$((size - 128))" kvd "$i"
90 devlink_reload
91 log_test "'$i' almost maximize [$((size - 128))]"
92
93 # Test above maximum size
94 devlink resource set "$DEVLINK_DEV" \
95 path "kvd/$i" size $((size + 128)) &> /dev/null
96 check_fail $? "Set kvd/$i to size $((size + 128)) should fail"
97 log_test "'$i' Overflow rejection [$((size + 128))]"
98
99 # Test maximum size
100 if [ "$i" == "hash_single" ] || [ "$i" == "hash_double" ]; then
101 echo "SKIP: Observed problem with exact max $i"
102 continue
103 fi
104
105 devlink_resource_size_set "$size" kvd "$i"
106 devlink_reload
107 log_test "'$i' maximize [$size]"
108
109 devlink_sp_size_kvd_to_default
110 done
111}
112
113profiles_test
114resources_min_test
115resources_max_test
116
117exit "$RET"
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh
new file mode 100644
index 000000000000..8d2186c7c62b
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/mirror_gre_scale.sh
@@ -0,0 +1,13 @@
1# SPDX-License-Identifier: GPL-2.0
2source ../mirror_gre_scale.sh
3
4mirror_gre_get_target()
5{
6 local should_fail=$1; shift
7
8 if ((! should_fail)); then
9 echo 3
10 else
11 echo 4
12 fi
13}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
new file mode 100755
index 000000000000..a0a80e1a69e8
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
@@ -0,0 +1,55 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4NUM_NETIFS=6
5source ../../../../net/forwarding/lib.sh
6source ../../../../net/forwarding/tc_common.sh
7source devlink_lib_spectrum.sh
8
9current_test=""
10
11cleanup()
12{
13 pre_cleanup
14 if [ ! -z $current_test ]; then
15 ${current_test}_cleanup
16 fi
17 devlink_sp_size_kvd_to_default
18}
19
20devlink_sp_read_kvd_defaults
21trap cleanup EXIT
22
23ALL_TESTS="router tc_flower mirror_gre"
24for current_test in ${TESTS:-$ALL_TESTS}; do
25 source ${current_test}_scale.sh
26
27 num_netifs_var=${current_test^^}_NUM_NETIFS
28 num_netifs=${!num_netifs_var:-$NUM_NETIFS}
29
30 for profile in $KVD_PROFILES; do
31 RET=0
32 devlink_sp_resource_kvd_profile_set $profile
33 if [[ $RET -gt 0 ]]; then
34 log_test "'$current_test' [$profile] setting"
35 continue
36 fi
37
38 for should_fail in 0 1; do
39 RET=0
40 target=$(${current_test}_get_target "$should_fail")
41 ${current_test}_setup_prepare
42 setup_wait $num_netifs
43 ${current_test}_test "$target" "$should_fail"
44 ${current_test}_cleanup
45 if [[ "$should_fail" -eq 0 ]]; then
46 log_test "'$current_test' [$profile] $target"
47 else
48 log_test "'$current_test' [$profile] overflow $target"
49 fi
50 done
51 done
52done
53current_test=""
54
55exit "$RET"
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh
new file mode 100644
index 000000000000..21c4697d5bab
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/router_scale.sh
@@ -0,0 +1,18 @@
1# SPDX-License-Identifier: GPL-2.0
2source ../router_scale.sh
3
4router_get_target()
5{
6 local should_fail=$1
7 local target
8
9 target=$(devlink_resource_size_get kvd hash_single)
10
11 if [[ $should_fail -eq 0 ]]; then
12 target=$((target * 85 / 100))
13 else
14 target=$((target + 1))
15 fi
16
17 echo $target
18}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh
new file mode 100644
index 000000000000..f9bfd8937765
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/spectrum/tc_flower_scale.sh
@@ -0,0 +1,19 @@
1# SPDX-License-Identifier: GPL-2.0
2source ../tc_flower_scale.sh
3
4tc_flower_get_target()
5{
6 local should_fail=$1; shift
7
8 # 6144 (6x1024) is the theoretical maximum.
9 # One bank of 512 rules is taken by the 18-byte MC router rule.
10 # One rule is the ACL catch-all.
11 # 6144 - 512 - 1 = 5631
12 local target=5631
13
14 if ((! should_fail)); then
15 echo $target
16 else
17 echo $((target + 1))
18 fi
19}
diff --git a/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh b/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh
new file mode 100644
index 000000000000..a6d733d2a4b4
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/mlxsw/tc_flower_scale.sh
@@ -0,0 +1,134 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for resource limit of offloaded flower rules. The test adds a given
5# number of flower matches for different IPv6 addresses, then generates traffic,
6# and ensures each was hit exactly once. This file contains functions to set up
7# a testing topology and run the test, and is meant to be sourced from a test
8# script that calls the testing routine with a given number of rules.
9
10TC_FLOWER_NUM_NETIFS=2
11
12tc_flower_h1_create()
13{
14 simple_if_init $h1
15 tc qdisc add dev $h1 clsact
16}
17
18tc_flower_h1_destroy()
19{
20 tc qdisc del dev $h1 clsact
21 simple_if_fini $h1
22}
23
24tc_flower_h2_create()
25{
26 simple_if_init $h2
27 tc qdisc add dev $h2 clsact
28}
29
30tc_flower_h2_destroy()
31{
32 tc qdisc del dev $h2 clsact
33 simple_if_fini $h2
34}
35
36tc_flower_setup_prepare()
37{
38 h1=${NETIFS[p1]}
39 h2=${NETIFS[p2]}
40
41 vrf_prepare
42
43 tc_flower_h1_create
44 tc_flower_h2_create
45}
46
47tc_flower_cleanup()
48{
49 pre_cleanup
50
51 tc_flower_h2_destroy
52 tc_flower_h1_destroy
53
54 vrf_cleanup
55
56 if [[ -v TC_FLOWER_BATCH_FILE ]]; then
57 rm -f $TC_FLOWER_BATCH_FILE
58 fi
59}
60
61tc_flower_addr()
62{
63 local num=$1; shift
64
65 printf "2001:db8:1::%x" $num
66}
67
68tc_flower_rules_create()
69{
70 local count=$1; shift
71 local should_fail=$1; shift
72
73 TC_FLOWER_BATCH_FILE="$(mktemp)"
74
75 for ((i = 0; i < count; ++i)); do
76 cat >> $TC_FLOWER_BATCH_FILE <<-EOF
77 filter add dev $h2 ingress \
78 prot ipv6 \
79 pref 1000 \
80 flower $tcflags dst_ip $(tc_flower_addr $i) \
81 action drop
82 EOF
83 done
84
85 tc -b $TC_FLOWER_BATCH_FILE
86 check_err_fail $should_fail $? "Rule insertion"
87}
88
89__tc_flower_test()
90{
91 local count=$1; shift
92 local should_fail=$1; shift
93 local last=$((count - 1))
94
95 tc_flower_rules_create $count $should_fail
96
97 for ((i = 0; i < count; ++i)); do
98 $MZ $h1 -q -c 1 -t ip -p 20 -b bc -6 \
99 -A 2001:db8:2::1 \
100 -B $(tc_flower_addr $i)
101 done
102
103 MISMATCHES=$(
104 tc -j -s filter show dev $h2 ingress |
105 jq -r '[ .[] | select(.kind == "flower") | .options |
106 values as $rule | .actions[].stats.packets |
107 select(. != 1) | "\(.) on \($rule.keys.dst_ip)" ] |
108 join(", ")'
109 )
110
111 test -z "$MISMATCHES"
112 check_err $? "Expected to capture 1 packet for each IP, but got $MISMATCHES"
113}
114
115tc_flower_test()
116{
117 local count=$1; shift
118 local should_fail=$1; shift
119
120 # We use lower 16 bits of IPv6 address for match. Also there are only 16
121 # bits of rule priority space.
122 if ((count > 65536)); then
123 check_err 1 "Invalid count of $count. At most 65536 rules supported"
124 return
125 fi
126
127 if ! tc_offload_check $TC_FLOWER_NUM_NETIFS; then
128 check_err 1 "Could not test offloaded functionality"
129 return
130 fi
131
132 tcflags="skip_sw"
133 __tc_flower_test $count $should_fail
134}
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore
index 1a0ac3a29ec5..78b24cf76f40 100644
--- a/tools/testing/selftests/net/.gitignore
+++ b/tools/testing/selftests/net/.gitignore
@@ -13,3 +13,4 @@ udpgso
13udpgso_bench_rx 13udpgso_bench_rx
14udpgso_bench_tx 14udpgso_bench_tx
15tcp_inq 15tcp_inq
16tls
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 663e11e85727..9cca68e440a0 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -13,7 +13,7 @@ TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy
13TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd 13TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd
14TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx 14TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx
15TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa 15TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
16TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict 16TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
17 17
18include ../lib.mk 18include ../lib.mk
19 19
diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README
index 4a0964c42860..b8a2af8fcfb7 100644
--- a/tools/testing/selftests/net/forwarding/README
+++ b/tools/testing/selftests/net/forwarding/README
@@ -46,6 +46,8 @@ Guidelines for Writing Tests
46 46
47o Where possible, reuse an existing topology for different tests instead 47o Where possible, reuse an existing topology for different tests instead
48 of recreating the same topology. 48 of recreating the same topology.
49o Tests that use anything but the most trivial topologies should include
50 an ASCII art showing the topology.
49o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and 51o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and
50 RFC 5737, respectively. 52 RFC 5737, respectively.
51o Where possible, tests shall be written so that they can be reused by 53o Where possible, tests shall be written so that they can be reused by
diff --git a/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh b/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh
new file mode 100755
index 000000000000..a43b4645c4de
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/bridge_port_isolation.sh
@@ -0,0 +1,151 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="ping_ipv4 ping_ipv6 flooding"
5NUM_NETIFS=6
6CHECK_TC="yes"
7source lib.sh
8
9h1_create()
10{
11 simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
12}
13
14h1_destroy()
15{
16 simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
17}
18
19h2_create()
20{
21 simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
22}
23
24h2_destroy()
25{
26 simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
27}
28
29h3_create()
30{
31 simple_if_init $h3 192.0.2.3/24 2001:db8:1::3/64
32}
33
34h3_destroy()
35{
36 simple_if_fini $h3 192.0.2.3/24 2001:db8:1::3/64
37}
38
39switch_create()
40{
41 ip link add dev br0 type bridge
42
43 ip link set dev $swp1 master br0
44 ip link set dev $swp2 master br0
45 ip link set dev $swp3 master br0
46
47 ip link set dev $swp1 type bridge_slave isolated on
48 check_err $? "Can't set isolation on port $swp1"
49 ip link set dev $swp2 type bridge_slave isolated on
50 check_err $? "Can't set isolation on port $swp2"
51 ip link set dev $swp3 type bridge_slave isolated off
52 check_err $? "Can't disable isolation on port $swp3"
53
54 ip link set dev br0 up
55 ip link set dev $swp1 up
56 ip link set dev $swp2 up
57 ip link set dev $swp3 up
58}
59
60switch_destroy()
61{
62 ip link set dev $swp3 down
63 ip link set dev $swp2 down
64 ip link set dev $swp1 down
65
66 ip link del dev br0
67}
68
69setup_prepare()
70{
71 h1=${NETIFS[p1]}
72 swp1=${NETIFS[p2]}
73
74 swp2=${NETIFS[p3]}
75 h2=${NETIFS[p4]}
76
77 swp3=${NETIFS[p5]}
78 h3=${NETIFS[p6]}
79
80 vrf_prepare
81
82 h1_create
83 h2_create
84 h3_create
85
86 switch_create
87}
88
89cleanup()
90{
91 pre_cleanup
92
93 switch_destroy
94
95 h3_destroy
96 h2_destroy
97 h1_destroy
98
99 vrf_cleanup
100}
101
102ping_ipv4()
103{
104 RET=0
105 ping_do $h1 192.0.2.2
106 check_fail $? "Ping worked when it should not have"
107
108 RET=0
109 ping_do $h3 192.0.2.2
110 check_err $? "Ping didn't work when it should have"
111
112 log_test "Isolated port ping"
113}
114
115ping_ipv6()
116{
117 RET=0
118 ping6_do $h1 2001:db8:1::2
119 check_fail $? "Ping6 worked when it should not have"
120
121 RET=0
122 ping6_do $h3 2001:db8:1::2
123 check_err $? "Ping6 didn't work when it should have"
124
125 log_test "Isolated port ping6"
126}
127
128flooding()
129{
130 local mac=de:ad:be:ef:13:37
131 local ip=192.0.2.100
132
133 RET=0
134 flood_test_do false $mac $ip $h1 $h2
135 check_err $? "Packet was flooded when it should not have been"
136
137 RET=0
138 flood_test_do true $mac $ip $h3 $h2
139 check_err $? "Packet was not flooded when it should have been"
140
141 log_test "Isolated port flooding"
142}
143
144trap cleanup EXIT
145
146setup_prepare
147setup_wait
148
149tests_run
150
151exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/devlink_lib.sh b/tools/testing/selftests/net/forwarding/devlink_lib.sh
new file mode 100644
index 000000000000..5ab1e5f43022
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/devlink_lib.sh
@@ -0,0 +1,108 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Source library
6
7relative_path="${BASH_SOURCE%/*}"
8if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
9 relative_path="."
10fi
11
12source "$relative_path/lib.sh"
13
14##############################################################################
15# Defines
16
17DEVLINK_DEV=$(devlink port show | grep "${NETIFS[p1]}" | \
18 grep -v "${NETIFS[p1]}[0-9]" | cut -d" " -f1 | \
19 rev | cut -d"/" -f2- | rev)
20if [ -z "$DEVLINK_DEV" ]; then
21 echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it"
22 exit 1
23fi
24if [[ "$(echo $DEVLINK_DEV | grep -c pci)" -eq 0 ]]; then
25 echo "SKIP: devlink device's bus is not PCI"
26 exit 1
27fi
28
29DEVLINK_VIDDID=$(lspci -s $(echo $DEVLINK_DEV | cut -d"/" -f2) \
30 -n | cut -d" " -f3)
31
32##############################################################################
33# Sanity checks
34
35devlink -j resource show "$DEVLINK_DEV" &> /dev/null
36if [ $? -ne 0 ]; then
37 echo "SKIP: iproute2 too old, missing devlink resource support"
38 exit 1
39fi
40
41##############################################################################
42# Devlink helpers
43
44devlink_resource_names_to_path()
45{
46 local resource
47 local path=""
48
49 for resource in "${@}"; do
50 if [ "$path" == "" ]; then
51 path="$resource"
52 else
53 path="${path}/$resource"
54 fi
55 done
56
57 echo "$path"
58}
59
60devlink_resource_get()
61{
62 local name=$1
63 local resource_name=.[][\"$DEVLINK_DEV\"]
64
65 resource_name="$resource_name | .[] | select (.name == \"$name\")"
66
67 shift
68 for resource in "${@}"; do
69 resource_name="${resource_name} | .[\"resources\"][] | \
70 select (.name == \"$resource\")"
71 done
72
73 devlink -j resource show "$DEVLINK_DEV" | jq "$resource_name"
74}
75
76devlink_resource_size_get()
77{
78 local size=$(devlink_resource_get "$@" | jq '.["size_new"]')
79
80 if [ "$size" == "null" ]; then
81 devlink_resource_get "$@" | jq '.["size"]'
82 else
83 echo "$size"
84 fi
85}
86
87devlink_resource_size_set()
88{
89 local new_size=$1
90 local path
91
92 shift
93 path=$(devlink_resource_names_to_path "$@")
94 devlink resource set "$DEVLINK_DEV" path "$path" size "$new_size"
95 check_err $? "Failed setting path $path to size $size"
96}
97
98devlink_reload()
99{
100 local still_pending
101
102 devlink dev reload "$DEVLINK_DEV" &> /dev/null
103 check_err $? "Failed reload"
104
105 still_pending=$(devlink resource show "$DEVLINK_DEV" | \
106 grep -c "size_new")
107 check_err $still_pending "Failed reload - There are still unset sizes"
108}
diff --git a/tools/testing/selftests/net/forwarding/gre_multipath.sh b/tools/testing/selftests/net/forwarding/gre_multipath.sh
new file mode 100755
index 000000000000..cca2baa03fb8
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/gre_multipath.sh
@@ -0,0 +1,253 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test traffic distribution when a wECMP route forwards traffic to two GRE
5# tunnels.
6#
7# +-------------------------+
8# | H1 |
9# | $h1 + |
10# | 192.0.2.1/28 | |
11# +-------------------|-----+
12# |
13# +-------------------|------------------------+
14# | SW1 | |
15# | $ol1 + |
16# | 192.0.2.2/28 |
17# | |
18# | + g1a (gre) + g1b (gre) |
19# | loc=192.0.2.65 loc=192.0.2.81 |
20# | rem=192.0.2.66 --. rem=192.0.2.82 --. |
21# | tos=inherit | tos=inherit | |
22# | .------------------' | |
23# | | .------------------' |
24# | v v |
25# | + $ul1.111 (vlan) + $ul1.222 (vlan) |
26# | | 192.0.2.129/28 | 192.0.2.145/28 |
27# | \ / |
28# | \________________/ |
29# | | |
30# | + $ul1 |
31# +------------|-------------------------------+
32# |
33# +------------|-------------------------------+
34# | SW2 + $ul2 |
35# | _______|________ |
36# | / \ |
37# | / \ |
38# | + $ul2.111 (vlan) + $ul2.222 (vlan) |
39# | ^ 192.0.2.130/28 ^ 192.0.2.146/28 |
40# | | | |
41# | | '------------------. |
42# | '------------------. | |
43# | + g2a (gre) | + g2b (gre) | |
44# | loc=192.0.2.66 | loc=192.0.2.82 | |
45# | rem=192.0.2.65 --' rem=192.0.2.81 --' |
46# | tos=inherit tos=inherit |
47# | |
48# | $ol2 + |
49# | 192.0.2.17/28 | |
50# +-------------------|------------------------+
51# |
52# +-------------------|-----+
53# | H2 | |
54# | $h2 + |
55# | 192.0.2.18/28 |
56# +-------------------------+
57
58ALL_TESTS="
59 ping_ipv4
60 multipath_ipv4
61"
62
63NUM_NETIFS=6
64source lib.sh
65
66h1_create()
67{
68 simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
69 ip route add vrf v$h1 192.0.2.16/28 via 192.0.2.2
70}
71
72h1_destroy()
73{
74 ip route del vrf v$h1 192.0.2.16/28 via 192.0.2.2
75 simple_if_fini $h1 192.0.2.1/28
76}
77
78sw1_create()
79{
80 simple_if_init $ol1 192.0.2.2/28
81 __simple_if_init $ul1 v$ol1
82 vlan_create $ul1 111 v$ol1 192.0.2.129/28
83 vlan_create $ul1 222 v$ol1 192.0.2.145/28
84
85 tunnel_create g1a gre 192.0.2.65 192.0.2.66 tos inherit dev v$ol1
86 __simple_if_init g1a v$ol1 192.0.2.65/32
87 ip route add vrf v$ol1 192.0.2.66/32 via 192.0.2.130
88
89 tunnel_create g1b gre 192.0.2.81 192.0.2.82 tos inherit dev v$ol1
90 __simple_if_init g1b v$ol1 192.0.2.81/32
91 ip route add vrf v$ol1 192.0.2.82/32 via 192.0.2.146
92
93 ip route add vrf v$ol1 192.0.2.16/28 \
94 nexthop dev g1a \
95 nexthop dev g1b
96
97 tc qdisc add dev $ul1 clsact
98 tc filter add dev $ul1 egress pref 111 prot ipv4 \
99 flower dst_ip 192.0.2.66 action pass
100 tc filter add dev $ul1 egress pref 222 prot ipv4 \
101 flower dst_ip 192.0.2.82 action pass
102}
103
104sw1_destroy()
105{
106 tc qdisc del dev $ul1 clsact
107
108 ip route del vrf v$ol1 192.0.2.16/28
109
110 ip route del vrf v$ol1 192.0.2.82/32 via 192.0.2.146
111 __simple_if_fini g1b 192.0.2.81/32
112 tunnel_destroy g1b
113
114 ip route del vrf v$ol1 192.0.2.66/32 via 192.0.2.130
115 __simple_if_fini g1a 192.0.2.65/32
116 tunnel_destroy g1a
117
118 vlan_destroy $ul1 222
119 vlan_destroy $ul1 111
120 __simple_if_fini $ul1
121 simple_if_fini $ol1 192.0.2.2/28
122}
123
124sw2_create()
125{
126 simple_if_init $ol2 192.0.2.17/28
127 __simple_if_init $ul2 v$ol2
128 vlan_create $ul2 111 v$ol2 192.0.2.130/28
129 vlan_create $ul2 222 v$ol2 192.0.2.146/28
130
131 tunnel_create g2a gre 192.0.2.66 192.0.2.65 tos inherit dev v$ol2
132 __simple_if_init g2a v$ol2 192.0.2.66/32
133 ip route add vrf v$ol2 192.0.2.65/32 via 192.0.2.129
134
135 tunnel_create g2b gre 192.0.2.82 192.0.2.81 tos inherit dev v$ol2
136 __simple_if_init g2b v$ol2 192.0.2.82/32
137 ip route add vrf v$ol2 192.0.2.81/32 via 192.0.2.145
138
139 ip route add vrf v$ol2 192.0.2.0/28 \
140 nexthop dev g2a \
141 nexthop dev g2b
142}
143
144sw2_destroy()
145{
146 ip route del vrf v$ol2 192.0.2.0/28
147
148 ip route del vrf v$ol2 192.0.2.81/32 via 192.0.2.145
149 __simple_if_fini g2b 192.0.2.82/32
150 tunnel_destroy g2b
151
152 ip route del vrf v$ol2 192.0.2.65/32 via 192.0.2.129
153 __simple_if_fini g2a 192.0.2.66/32
154 tunnel_destroy g2a
155
156 vlan_destroy $ul2 222
157 vlan_destroy $ul2 111
158 __simple_if_fini $ul2
159 simple_if_fini $ol2 192.0.2.17/28
160}
161
162h2_create()
163{
164 simple_if_init $h2 192.0.2.18/28
165 ip route add vrf v$h2 192.0.2.0/28 via 192.0.2.17
166}
167
168h2_destroy()
169{
170 ip route del vrf v$h2 192.0.2.0/28 via 192.0.2.17
171 simple_if_fini $h2 192.0.2.18/28
172}
173
174setup_prepare()
175{
176 h1=${NETIFS[p1]}
177 ol1=${NETIFS[p2]}
178
179 ul1=${NETIFS[p3]}
180 ul2=${NETIFS[p4]}
181
182 ol2=${NETIFS[p5]}
183 h2=${NETIFS[p6]}
184
185 vrf_prepare
186 h1_create
187 sw1_create
188 sw2_create
189 h2_create
190}
191
192cleanup()
193{
194 pre_cleanup
195
196 h2_destroy
197 sw2_destroy
198 sw1_destroy
199 h1_destroy
200 vrf_cleanup
201}
202
203multipath4_test()
204{
205 local what=$1; shift
206 local weight1=$1; shift
207 local weight2=$1; shift
208
209 sysctl_set net.ipv4.fib_multipath_hash_policy 1
210 ip route replace vrf v$ol1 192.0.2.16/28 \
211 nexthop dev g1a weight $weight1 \
212 nexthop dev g1b weight $weight2
213
214 local t0_111=$(tc_rule_stats_get $ul1 111 egress)
215 local t0_222=$(tc_rule_stats_get $ul1 222 egress)
216
217 ip vrf exec v$h1 \
218 $MZ $h1 -q -p 64 -A 192.0.2.1 -B 192.0.2.18 \
219 -d 1msec -t udp "sp=1024,dp=0-32768"
220
221 local t1_111=$(tc_rule_stats_get $ul1 111 egress)
222 local t1_222=$(tc_rule_stats_get $ul1 222 egress)
223
224 local d111=$((t1_111 - t0_111))
225 local d222=$((t1_222 - t0_222))
226 multipath_eval "$what" $weight1 $weight2 $d111 $d222
227
228 ip route replace vrf v$ol1 192.0.2.16/28 \
229 nexthop dev g1a \
230 nexthop dev g1b
231 sysctl_restore net.ipv4.fib_multipath_hash_policy
232}
233
234ping_ipv4()
235{
236 ping_test $h1 192.0.2.18
237}
238
239multipath_ipv4()
240{
241 log_info "Running IPv4 multipath tests"
242 multipath4_test "ECMP" 1 1
243 multipath4_test "Weighted MP 2:1" 2 1
244 multipath4_test "Weighted MP 11:45" 11 45
245}
246
247trap cleanup EXIT
248
249setup_prepare
250setup_wait
251tests_run
252
253exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
index 7b18a53aa556..ca53b539aa2d 100644
--- a/tools/testing/selftests/net/forwarding/lib.sh
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -8,14 +8,21 @@
8PING=${PING:=ping} 8PING=${PING:=ping}
9PING6=${PING6:=ping6} 9PING6=${PING6:=ping6}
10MZ=${MZ:=mausezahn} 10MZ=${MZ:=mausezahn}
11ARPING=${ARPING:=arping}
12TEAMD=${TEAMD:=teamd}
11WAIT_TIME=${WAIT_TIME:=5} 13WAIT_TIME=${WAIT_TIME:=5}
12PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} 14PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
13PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} 15PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
14NETIF_TYPE=${NETIF_TYPE:=veth} 16NETIF_TYPE=${NETIF_TYPE:=veth}
15NETIF_CREATE=${NETIF_CREATE:=yes} 17NETIF_CREATE=${NETIF_CREATE:=yes}
16 18
17if [[ -f forwarding.config ]]; then 19relative_path="${BASH_SOURCE%/*}"
18 source forwarding.config 20if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then
21 relative_path="."
22fi
23
24if [[ -f $relative_path/forwarding.config ]]; then
25 source "$relative_path/forwarding.config"
19fi 26fi
20 27
21############################################################################## 28##############################################################################
@@ -28,7 +35,10 @@ check_tc_version()
28 echo "SKIP: iproute2 too old; tc is missing JSON support" 35 echo "SKIP: iproute2 too old; tc is missing JSON support"
29 exit 1 36 exit 1
30 fi 37 fi
38}
31 39
40check_tc_shblock_support()
41{
32 tc filter help 2>&1 | grep block &> /dev/null 42 tc filter help 2>&1 | grep block &> /dev/null
33 if [[ $? -ne 0 ]]; then 43 if [[ $? -ne 0 ]]; then
34 echo "SKIP: iproute2 too old; tc is missing shared block support" 44 echo "SKIP: iproute2 too old; tc is missing shared block support"
@@ -36,6 +46,15 @@ check_tc_version()
36 fi 46 fi
37} 47}
38 48
49check_tc_chain_support()
50{
51 tc help 2>&1|grep chain &> /dev/null
52 if [[ $? -ne 0 ]]; then
53 echo "SKIP: iproute2 too old; tc is missing chain support"
54 exit 1
55 fi
56}
57
39if [[ "$(id -u)" -ne 0 ]]; then 58if [[ "$(id -u)" -ne 0 ]]; then
40 echo "SKIP: need root privileges" 59 echo "SKIP: need root privileges"
41 exit 0 60 exit 0
@@ -45,15 +64,18 @@ if [[ "$CHECK_TC" = "yes" ]]; then
45 check_tc_version 64 check_tc_version
46fi 65fi
47 66
48if [[ ! -x "$(command -v jq)" ]]; then 67require_command()
49 echo "SKIP: jq not installed" 68{
50 exit 1 69 local cmd=$1; shift
51fi
52 70
53if [[ ! -x "$(command -v $MZ)" ]]; then 71 if [[ ! -x "$(command -v "$cmd")" ]]; then
54 echo "SKIP: $MZ not installed" 72 echo "SKIP: $cmd not installed"
55 exit 1 73 exit 1
56fi 74 fi
75}
76
77require_command jq
78require_command $MZ
57 79
58if [[ ! -v NUM_NETIFS ]]; then 80if [[ ! -v NUM_NETIFS ]]; then
59 echo "SKIP: importer does not define \"NUM_NETIFS\"" 81 echo "SKIP: importer does not define \"NUM_NETIFS\""
@@ -151,6 +173,19 @@ check_fail()
151 fi 173 fi
152} 174}
153 175
176check_err_fail()
177{
178 local should_fail=$1; shift
179 local err=$1; shift
180 local what=$1; shift
181
182 if ((should_fail)); then
183 check_fail $err "$what succeeded, but should have failed"
184 else
185 check_err $err "$what failed"
186 fi
187}
188
154log_test() 189log_test()
155{ 190{
156 local test_name=$1 191 local test_name=$1
@@ -185,24 +220,54 @@ log_info()
185 echo "INFO: $msg" 220 echo "INFO: $msg"
186} 221}
187 222
223setup_wait_dev()
224{
225 local dev=$1; shift
226
227 while true; do
228 ip link show dev $dev up \
229 | grep 'state UP' &> /dev/null
230 if [[ $? -ne 0 ]]; then
231 sleep 1
232 else
233 break
234 fi
235 done
236}
237
188setup_wait() 238setup_wait()
189{ 239{
190 for i in $(eval echo {1..$NUM_NETIFS}); do 240 local num_netifs=${1:-$NUM_NETIFS}
191 while true; do 241
192 ip link show dev ${NETIFS[p$i]} up \ 242 for ((i = 1; i <= num_netifs; ++i)); do
193 | grep 'state UP' &> /dev/null 243 setup_wait_dev ${NETIFS[p$i]}
194 if [[ $? -ne 0 ]]; then
195 sleep 1
196 else
197 break
198 fi
199 done
200 done 244 done
201 245
202 # Make sure links are ready. 246 # Make sure links are ready.
203 sleep $WAIT_TIME 247 sleep $WAIT_TIME
204} 248}
205 249
250lldpad_app_wait_set()
251{
252 local dev=$1; shift
253
254 while lldptool -t -i $dev -V APP -c app | grep -q pending; do
255 echo "$dev: waiting for lldpad to push pending APP updates"
256 sleep 5
257 done
258}
259
260lldpad_app_wait_del()
261{
262 # Give lldpad a chance to push down the changes. If the device is downed
263 # too soon, the updates will be left pending. However, they will have
264 # been struck off the lldpad's DB already, so we won't be able to tell
265 # they are pending. Then on next test iteration this would cause
266 # weirdness as newly-added APP rules conflict with the old ones,
267 # sometimes getting stuck in an "unknown" state.
268 sleep 5
269}
270
206pre_cleanup() 271pre_cleanup()
207{ 272{
208 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then 273 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
@@ -287,6 +352,29 @@ __addr_add_del()
287 done 352 done
288} 353}
289 354
355__simple_if_init()
356{
357 local if_name=$1; shift
358 local vrf_name=$1; shift
359 local addrs=("${@}")
360
361 ip link set dev $if_name master $vrf_name
362 ip link set dev $if_name up
363
364 __addr_add_del $if_name add "${addrs[@]}"
365}
366
367__simple_if_fini()
368{
369 local if_name=$1; shift
370 local addrs=("${@}")
371
372 __addr_add_del $if_name del "${addrs[@]}"
373
374 ip link set dev $if_name down
375 ip link set dev $if_name nomaster
376}
377
290simple_if_init() 378simple_if_init()
291{ 379{
292 local if_name=$1 380 local if_name=$1
@@ -298,11 +386,8 @@ simple_if_init()
298 array=("${@}") 386 array=("${@}")
299 387
300 vrf_create $vrf_name 388 vrf_create $vrf_name
301 ip link set dev $if_name master $vrf_name
302 ip link set dev $vrf_name up 389 ip link set dev $vrf_name up
303 ip link set dev $if_name up 390 __simple_if_init $if_name $vrf_name "${array[@]}"
304
305 __addr_add_del $if_name add "${array[@]}"
306} 391}
307 392
308simple_if_fini() 393simple_if_fini()
@@ -315,9 +400,7 @@ simple_if_fini()
315 vrf_name=v$if_name 400 vrf_name=v$if_name
316 array=("${@}") 401 array=("${@}")
317 402
318 __addr_add_del $if_name del "${array[@]}" 403 __simple_if_fini $if_name "${array[@]}"
319
320 ip link set dev $if_name down
321 vrf_destroy $vrf_name 404 vrf_destroy $vrf_name
322} 405}
323 406
@@ -365,6 +448,28 @@ vlan_destroy()
365 ip link del dev $name 448 ip link del dev $name
366} 449}
367 450
451team_create()
452{
453 local if_name=$1; shift
454 local mode=$1; shift
455
456 require_command $TEAMD
457 $TEAMD -t $if_name -d -c '{"runner": {"name": "'$mode'"}}'
458 for slave in "$@"; do
459 ip link set dev $slave down
460 ip link set dev $slave master $if_name
461 ip link set dev $slave up
462 done
463 ip link set dev $if_name up
464}
465
466team_destroy()
467{
468 local if_name=$1; shift
469
470 $TEAMD -t $if_name -k
471}
472
368master_name_get() 473master_name_get()
369{ 474{
370 local if_name=$1 475 local if_name=$1
@@ -383,9 +488,10 @@ tc_rule_stats_get()
383{ 488{
384 local dev=$1; shift 489 local dev=$1; shift
385 local pref=$1; shift 490 local pref=$1; shift
491 local dir=$1; shift
386 492
387 tc -j -s filter show dev $dev ingress pref $pref | 493 tc -j -s filter show dev $dev ${dir:-ingress} pref $pref \
388 jq '.[1].options.actions[].stats.packets' 494 | jq '.[1].options.actions[].stats.packets'
389} 495}
390 496
391mac_get() 497mac_get()
@@ -437,7 +543,9 @@ forwarding_restore()
437 543
438tc_offload_check() 544tc_offload_check()
439{ 545{
440 for i in $(eval echo {1..$NUM_NETIFS}); do 546 local num_netifs=${1:-$NUM_NETIFS}
547
548 for ((i = 1; i <= num_netifs; ++i)); do
441 ethtool -k ${NETIFS[p$i]} \ 549 ethtool -k ${NETIFS[p$i]} \
442 | grep "hw-tc-offload: on" &> /dev/null 550 | grep "hw-tc-offload: on" &> /dev/null
443 if [[ $? -ne 0 ]]; then 551 if [[ $? -ne 0 ]]; then
@@ -453,9 +561,15 @@ trap_install()
453 local dev=$1; shift 561 local dev=$1; shift
454 local direction=$1; shift 562 local direction=$1; shift
455 563
456 # For slow-path testing, we need to install a trap to get to 564 # Some devices may not support or need in-hardware trapping of traffic
457 # slow path the packets that would otherwise be switched in HW. 565 # (e.g. the veth pairs that this library creates for non-existent
458 tc filter add dev $dev $direction pref 1 flower skip_sw action trap 566 # loopbacks). Use continue instead, so that there is a filter in there
567 # (some tests check counters), and so that other filters are still
568 # processed.
569 tc filter add dev $dev $direction pref 1 \
570 flower skip_sw action trap 2>/dev/null \
571 || tc filter add dev $dev $direction pref 1 \
572 flower action continue
459} 573}
460 574
461trap_uninstall() 575trap_uninstall()
@@ -463,11 +577,13 @@ trap_uninstall()
463 local dev=$1; shift 577 local dev=$1; shift
464 local direction=$1; shift 578 local direction=$1; shift
465 579
466 tc filter del dev $dev $direction pref 1 flower skip_sw 580 tc filter del dev $dev $direction pref 1 flower
467} 581}
468 582
469slow_path_trap_install() 583slow_path_trap_install()
470{ 584{
585 # For slow-path testing, we need to install a trap to get to
586 # slow path the packets that would otherwise be switched in HW.
471 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then 587 if [ "${tcflags/skip_hw}" != "$tcflags" ]; then
472 trap_install "$@" 588 trap_install "$@"
473 fi 589 fi
@@ -537,6 +653,48 @@ vlan_capture_uninstall()
537 __vlan_capture_add_del del 100 "$@" 653 __vlan_capture_add_del del 100 "$@"
538} 654}
539 655
656__dscp_capture_add_del()
657{
658 local add_del=$1; shift
659 local dev=$1; shift
660 local base=$1; shift
661 local dscp;
662
663 for prio in {0..7}; do
664 dscp=$((base + prio))
665 __icmp_capture_add_del $add_del $((dscp + 100)) "" $dev \
666 "skip_hw ip_tos $((dscp << 2))"
667 done
668}
669
670dscp_capture_install()
671{
672 local dev=$1; shift
673 local base=$1; shift
674
675 __dscp_capture_add_del add $dev $base
676}
677
678dscp_capture_uninstall()
679{
680 local dev=$1; shift
681 local base=$1; shift
682
683 __dscp_capture_add_del del $dev $base
684}
685
686dscp_fetch_stats()
687{
688 local dev=$1; shift
689 local base=$1; shift
690
691 for prio in {0..7}; do
692 local dscp=$((base + prio))
693 local t=$(tc_rule_stats_get $dev $((dscp + 100)))
694 echo "[$dscp]=$t "
695 done
696}
697
540matchall_sink_create() 698matchall_sink_create()
541{ 699{
542 local dev=$1; shift 700 local dev=$1; shift
@@ -557,33 +715,86 @@ tests_run()
557 done 715 done
558} 716}
559 717
718multipath_eval()
719{
720 local desc="$1"
721 local weight_rp12=$2
722 local weight_rp13=$3
723 local packets_rp12=$4
724 local packets_rp13=$5
725 local weights_ratio packets_ratio diff
726
727 RET=0
728
729 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
730 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
731 | bc -l)
732 else
733 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" \
734 | bc -l)
735 fi
736
737 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
738 check_err 1 "Packet difference is 0"
739 log_test "Multipath"
740 log_info "Expected ratio $weights_ratio"
741 return
742 fi
743
744 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
745 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
746 | bc -l)
747 else
748 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" \
749 | bc -l)
750 fi
751
752 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
753 diff=${diff#-}
754
755 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
756 check_err $? "Too large discrepancy between expected and measured ratios"
757 log_test "$desc"
758 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
759}
760
560############################################################################## 761##############################################################################
561# Tests 762# Tests
562 763
563ping_test() 764ping_do()
564{ 765{
565 local if_name=$1 766 local if_name=$1
566 local dip=$2 767 local dip=$2
567 local vrf_name 768 local vrf_name
568 769
569 RET=0
570
571 vrf_name=$(master_name_get $if_name) 770 vrf_name=$(master_name_get $if_name)
572 ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null 771 ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null
772}
773
774ping_test()
775{
776 RET=0
777
778 ping_do $1 $2
573 check_err $? 779 check_err $?
574 log_test "ping" 780 log_test "ping"
575} 781}
576 782
577ping6_test() 783ping6_do()
578{ 784{
579 local if_name=$1 785 local if_name=$1
580 local dip=$2 786 local dip=$2
581 local vrf_name 787 local vrf_name
582 788
583 RET=0
584
585 vrf_name=$(master_name_get $if_name) 789 vrf_name=$(master_name_get $if_name)
586 ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null 790 ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null
791}
792
793ping6_test()
794{
795 RET=0
796
797 ping6_do $1 $2
587 check_err $? 798 check_err $?
588 log_test "ping6" 799 log_test "ping6"
589} 800}
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
new file mode 100755
index 000000000000..c5095da7f6bf
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d.sh
@@ -0,0 +1,132 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for "tc action mirred egress mirror" when the underlay route points at a
5# bridge device without vlan filtering (802.1d).
6#
7# This test uses standard topology for testing mirror-to-gretap. See
8# mirror_gre_topo_lib.sh for more details. The full topology is as follows:
9#
10# +---------------------+ +---------------------+
11# | H1 | | H2 |
12# | + $h1 | | $h2 + |
13# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
14# +-----|---------------+ +---------------|-----+
15# | |
16# +-----|-------------------------------------------------------------|-----+
17# | SW o---> mirror | |
18# | +---|-------------------------------------------------------------|---+ |
19# | | + $swp1 + br1 (802.1q bridge) $swp2 + | |
20# | +---------------------------------------------------------------------+ |
21# | |
22# | +---------------------------------------------------------------------+ |
23# | | + br2 (802.1d bridge) | |
24# | | 192.0.2.129/28 | |
25# | | + $swp3 2001:db8:2::1/64 | |
26# | +---|-----------------------------------------------------------------+ |
27# | | ^ ^ |
28# | | + gt6 (ip6gretap) | + gt4 (gretap) | |
29# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | |
30# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ |
31# | | : ttl=100 : ttl=100 |
32# | | : tos=inherit : tos=inherit |
33# +-----|---------------------:----------------------:----------------------+
34# | : :
35# +-----|---------------------:----------------------:----------------------+
36# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) |
37# | 192.0.2.130/28 loc=2001:db8:2::2 loc=192.0.2.130 |
38# | 2001:db8:2::2/64 rem=2001:db8:2::1 rem=192.0.2.129 |
39# | ttl=100 ttl=100 |
40# | tos=inherit tos=inherit |
41# +-------------------------------------------------------------------------+
42
43ALL_TESTS="
44 test_gretap
45 test_ip6gretap
46"
47
48NUM_NETIFS=6
49source lib.sh
50source mirror_lib.sh
51source mirror_gre_lib.sh
52source mirror_gre_topo_lib.sh
53
54setup_prepare()
55{
56 h1=${NETIFS[p1]}
57 swp1=${NETIFS[p2]}
58
59 swp2=${NETIFS[p3]}
60 h2=${NETIFS[p4]}
61
62 swp3=${NETIFS[p5]}
63 h3=${NETIFS[p6]}
64
65 vrf_prepare
66 mirror_gre_topo_create
67
68 ip link add name br2 type bridge vlan_filtering 0
69 ip link set dev br2 up
70
71 ip link set dev $swp3 master br2
72 ip route add 192.0.2.130/32 dev br2
73 ip -6 route add 2001:db8:2::2/128 dev br2
74
75 ip address add dev br2 192.0.2.129/28
76 ip address add dev br2 2001:db8:2::1/64
77
78 ip address add dev $h3 192.0.2.130/28
79 ip address add dev $h3 2001:db8:2::2/64
80}
81
82cleanup()
83{
84 pre_cleanup
85
86 ip address del dev $h3 2001:db8:2::2/64
87 ip address del dev $h3 192.0.2.130/28
88 ip link del dev br2
89
90 mirror_gre_topo_destroy
91 vrf_cleanup
92}
93
94test_gretap()
95{
96 full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
97 full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
98}
99
100test_ip6gretap()
101{
102 full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
103 full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
104}
105
106test_all()
107{
108 slow_path_trap_install $swp1 ingress
109 slow_path_trap_install $swp1 egress
110
111 tests_run
112
113 slow_path_trap_uninstall $swp1 egress
114 slow_path_trap_uninstall $swp1 ingress
115}
116
117trap cleanup EXIT
118
119setup_prepare
120setup_wait
121
122tcflags="skip_hw"
123test_all
124
125if ! tc_offload_check; then
126 echo "WARN: Could not test offloaded functionality"
127else
128 tcflags="skip_sw"
129 test_all
130fi
131
132exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
index 3bb4c2ba7b14..197e769c2ed1 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1d_vlan.sh
@@ -74,12 +74,14 @@ test_vlan_match()
74 74
75test_gretap() 75test_gretap()
76{ 76{
77 test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap" 77 test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \
78 "mirror to gretap"
78} 79}
79 80
80test_ip6gretap() 81test_ip6gretap()
81{ 82{
82 test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap" 83 test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \
84 "mirror to ip6gretap"
83} 85}
84 86
85test_gretap_stp() 87test_gretap_stp()
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
new file mode 100755
index 000000000000..a3402cd8d5b6
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q.sh
@@ -0,0 +1,126 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for "tc action mirred egress mirror" when the underlay route points at a
5# bridge device with vlan filtering (802.1q).
6#
7# This test uses standard topology for testing mirror-to-gretap. See
8# mirror_gre_topo_lib.sh for more details. The full topology is as follows:
9#
10# +---------------------+ +---------------------+
11# | H1 | | H2 |
12# | + $h1 | | $h2 + |
13# | | 192.0.2.1/28 | | 192.0.2.2/28 | |
14# +-----|---------------+ +---------------|-----+
15# | |
16# +-----|---------------------------------------------------------------|-----+
17# | SW o---> mirror | |
18# | +---|---------------------------------------------------------------|---+ |
19# | | + $swp1 + br1 (802.1q bridge) $swp2 + | |
20# | | 192.0.2.129/28 | |
21# | | + $swp3 2001:db8:2::1/64 | |
22# | | | vid555 vid555[pvid,untagged] | |
23# | +---|-------------------------------------------------------------------+ |
24# | | ^ ^ |
25# | | + gt6 (ip6gretap) | + gt4 (gretap) | |
26# | | : loc=2001:db8:2::1 | : loc=192.0.2.129 | |
27# | | : rem=2001:db8:2::2 -+ : rem=192.0.2.130 -+ |
28# | | : ttl=100 : ttl=100 |
29# | | : tos=inherit : tos=inherit |
30# +-----|---------------------:------------------------:----------------------+
31# | : :
32# +-----|---------------------:------------------------:----------------------+
33# | H3 + $h3 + h3-gt6(ip6gretap) + h3-gt4 (gretap) |
34# | | loc=2001:db8:2::2 loc=192.0.2.130 |
35# | + $h3.555 rem=2001:db8:2::1 rem=192.0.2.129 |
36# | 192.0.2.130/28 ttl=100 ttl=100 |
37# | 2001:db8:2::2/64 tos=inherit tos=inherit |
38# +---------------------------------------------------------------------------+
39
40ALL_TESTS="
41 test_gretap
42 test_ip6gretap
43"
44
45NUM_NETIFS=6
46source lib.sh
47source mirror_lib.sh
48source mirror_gre_lib.sh
49source mirror_gre_topo_lib.sh
50
51setup_prepare()
52{
53 h1=${NETIFS[p1]}
54 swp1=${NETIFS[p2]}
55
56 swp2=${NETIFS[p3]}
57 h2=${NETIFS[p4]}
58
59 swp3=${NETIFS[p5]}
60 h3=${NETIFS[p6]}
61
62 vrf_prepare
63 mirror_gre_topo_create
64
65 ip link set dev $swp3 master br1
66 bridge vlan add dev br1 vid 555 pvid untagged self
67 ip address add dev br1 192.0.2.129/28
68 ip address add dev br1 2001:db8:2::1/64
69
70 ip -4 route add 192.0.2.130/32 dev br1
71 ip -6 route add 2001:db8:2::2/128 dev br1
72
73 vlan_create $h3 555 v$h3 192.0.2.130/28 2001:db8:2::2/64
74 bridge vlan add dev $swp3 vid 555
75}
76
77cleanup()
78{
79 pre_cleanup
80
81 ip link set dev $swp3 nomaster
82 vlan_destroy $h3 555
83
84 mirror_gre_topo_destroy
85 vrf_cleanup
86}
87
88test_gretap()
89{
90 full_test_span_gre_dir gt4 ingress 8 0 "mirror to gretap"
91 full_test_span_gre_dir gt4 egress 0 8 "mirror to gretap"
92}
93
94test_ip6gretap()
95{
96 full_test_span_gre_dir gt6 ingress 8 0 "mirror to ip6gretap"
97 full_test_span_gre_dir gt6 egress 0 8 "mirror to ip6gretap"
98}
99
100tests()
101{
102 slow_path_trap_install $swp1 ingress
103 slow_path_trap_install $swp1 egress
104
105 tests_run
106
107 slow_path_trap_uninstall $swp1 egress
108 slow_path_trap_uninstall $swp1 ingress
109}
110
111trap cleanup EXIT
112
113setup_prepare
114setup_wait
115
116tcflags="skip_hw"
117tests
118
119if ! tc_offload_check; then
120 echo "WARN: Could not test offloaded functionality"
121else
122 tcflags="skip_sw"
123 tests
124fi
125
126exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
new file mode 100755
index 000000000000..61844caf671e
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_bridge_1q_lag.sh
@@ -0,0 +1,283 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for "tc action mirred egress mirror" when the underlay route points at a
5# bridge device with vlan filtering (802.1q), and the egress device is a team
6# device.
7#
8# +----------------------+ +----------------------+
9# | H1 | | H2 |
10# | + $h1.333 | | $h1.555 + |
11# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
12# +-----|----------------+ +----------------|-----+
13# | $h1 |
14# +--------------------------------+------------------------------+
15# |
16# +--------------------------------------|------------------------------------+
17# | SW o---> mirror |
18# | | |
19# | +--------------------------------+------------------------------+ |
20# | | $swp1 | |
21# | + $swp1.333 $swp1.555 + |
22# | 192.0.2.2/28 192.0.2.17/28 |
23# | |
24# | +-----------------------------------------------------------------------+ |
25# | | BR1 (802.1q) | |
26# | | + lag (team) 192.0.2.129/28 | |
27# | | / \ 2001:db8:2::1/64 | |
28# | +---/---\---------------------------------------------------------------+ |
29# | / \ ^ |
30# | | \ + gt4 (gretap) | |
31# | | \ loc=192.0.2.129 | |
32# | | \ rem=192.0.2.130 -+ |
33# | | \ ttl=100 |
34# | | \ tos=inherit |
35# | | \ |
36# | | \_________________________________ |
37# | | \ |
38# | + $swp3 + $swp4 |
39# +---|------------------------------------------------|----------------------+
40# | |
41# +---|----------------------+ +---|----------------------+
42# | + $h3 H3 | | + $h4 H4 |
43# | 192.0.2.130/28 | | 192.0.2.130/28 |
44# | 2001:db8:2::2/64 | | 2001:db8:2::2/64 |
45# +--------------------------+ +--------------------------+
46
47ALL_TESTS="
48 test_mirror_gretap_first
49 test_mirror_gretap_second
50"
51
52NUM_NETIFS=6
53source lib.sh
54source mirror_lib.sh
55source mirror_gre_lib.sh
56
57require_command $ARPING
58
59vlan_host_create()
60{
61 local if_name=$1; shift
62 local vid=$1; shift
63 local vrf_name=$1; shift
64 local ips=("${@}")
65
66 vrf_create $vrf_name
67 ip link set dev $vrf_name up
68 vlan_create $if_name $vid $vrf_name "${ips[@]}"
69}
70
71vlan_host_destroy()
72{
73 local if_name=$1; shift
74 local vid=$1; shift
75 local vrf_name=$1; shift
76
77 vlan_destroy $if_name $vid
78 ip link set dev $vrf_name down
79 vrf_destroy $vrf_name
80}
81
82h1_create()
83{
84 vlan_host_create $h1 333 vrf-h1 192.0.2.1/28
85 ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2
86}
87
88h1_destroy()
89{
90 ip -4 route del 192.0.2.16/28 vrf vrf-h1
91 vlan_host_destroy $h1 333 vrf-h1
92}
93
94h2_create()
95{
96 vlan_host_create $h1 555 vrf-h2 192.0.2.18/28
97 ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17
98}
99
100h2_destroy()
101{
102 ip -4 route del 192.0.2.0/28 vrf vrf-h2
103 vlan_host_destroy $h1 555 vrf-h2
104}
105
106h3_create()
107{
108 simple_if_init $h3 192.0.2.130/28
109 tc qdisc add dev $h3 clsact
110}
111
112h3_destroy()
113{
114 tc qdisc del dev $h3 clsact
115 simple_if_fini $h3 192.0.2.130/28
116}
117
118h4_create()
119{
120 simple_if_init $h4 192.0.2.130/28
121 tc qdisc add dev $h4 clsact
122}
123
124h4_destroy()
125{
126 tc qdisc del dev $h4 clsact
127 simple_if_fini $h4 192.0.2.130/28
128}
129
130switch_create()
131{
132 ip link set dev $swp1 up
133 tc qdisc add dev $swp1 clsact
134 vlan_create $swp1 333 "" 192.0.2.2/28
135 vlan_create $swp1 555 "" 192.0.2.17/28
136
137 tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \
138 ttl 100 tos inherit
139
140 ip link set dev $swp3 up
141 ip link set dev $swp4 up
142
143 ip link add name br1 type bridge vlan_filtering 1
144 ip link set dev br1 up
145 __addr_add_del br1 add 192.0.2.129/32
146 ip -4 route add 192.0.2.130/32 dev br1
147
148 team_create lag loadbalance $swp3 $swp4
149 ip link set dev lag master br1
150}
151
152switch_destroy()
153{
154 ip link set dev lag nomaster
155 team_destroy lag
156
157 ip -4 route del 192.0.2.130/32 dev br1
158 __addr_add_del br1 del 192.0.2.129/32
159 ip link set dev br1 down
160 ip link del dev br1
161
162 ip link set dev $swp4 down
163 ip link set dev $swp3 down
164
165 tunnel_destroy gt4
166
167 vlan_destroy $swp1 555
168 vlan_destroy $swp1 333
169 tc qdisc del dev $swp1 clsact
170 ip link set dev $swp1 down
171}
172
173setup_prepare()
174{
175 h1=${NETIFS[p1]}
176 swp1=${NETIFS[p2]}
177
178 swp3=${NETIFS[p3]}
179 h3=${NETIFS[p4]}
180
181 swp4=${NETIFS[p5]}
182 h4=${NETIFS[p6]}
183
184 vrf_prepare
185
186 ip link set dev $h1 up
187 h1_create
188 h2_create
189 h3_create
190 h4_create
191 switch_create
192
193 trap_install $h3 ingress
194 trap_install $h4 ingress
195}
196
197cleanup()
198{
199 pre_cleanup
200
201 trap_uninstall $h4 ingress
202 trap_uninstall $h3 ingress
203
204 switch_destroy
205 h4_destroy
206 h3_destroy
207 h2_destroy
208 h1_destroy
209 ip link set dev $h1 down
210
211 vrf_cleanup
212}
213
214test_lag_slave()
215{
216 local host_dev=$1; shift
217 local up_dev=$1; shift
218 local down_dev=$1; shift
219 local what=$1; shift
220
221 RET=0
222
223 mirror_install $swp1 ingress gt4 \
224 "proto 802.1q flower vlan_id 333 $tcflags"
225
226 # Test connectivity through $up_dev when $down_dev is set down.
227 ip link set dev $down_dev down
228 setup_wait_dev $up_dev
229 setup_wait_dev $host_dev
230 $ARPING -I br1 192.0.2.130 -qfc 1
231 sleep 2
232 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $host_dev 1 10
233
234 # Test lack of connectivity when both slaves are down.
235 ip link set dev $up_dev down
236 sleep 2
237 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0
238 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0
239
240 ip link set dev $up_dev up
241 ip link set dev $down_dev up
242 mirror_uninstall $swp1 ingress
243
244 log_test "$what ($tcflags)"
245}
246
247test_mirror_gretap_first()
248{
249 test_lag_slave $h3 $swp3 $swp4 "mirror to gretap: LAG first slave"
250}
251
252test_mirror_gretap_second()
253{
254 test_lag_slave $h4 $swp4 $swp3 "mirror to gretap: LAG second slave"
255}
256
257test_all()
258{
259 slow_path_trap_install $swp1 ingress
260 slow_path_trap_install $swp1 egress
261
262 tests_run
263
264 slow_path_trap_uninstall $swp1 egress
265 slow_path_trap_uninstall $swp1 ingress
266}
267
268trap cleanup EXIT
269
270setup_prepare
271setup_wait
272
273tcflags="skip_hw"
274test_all
275
276if ! tc_offload_check; then
277 echo "WARN: Could not test offloaded functionality"
278else
279 tcflags="skip_sw"
280 test_all
281fi
282
283exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh b/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh
index aa29d46186a8..135902aa8b11 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_changes.sh
@@ -122,15 +122,8 @@ test_span_gre_egress_up()
122 # After setting the device up, wait for neighbor to get resolved so that 122 # After setting the device up, wait for neighbor to get resolved so that
123 # we can expect mirroring to work. 123 # we can expect mirroring to work.
124 ip link set dev $swp3 up 124 ip link set dev $swp3 up
125 while true; do 125 setup_wait_dev $swp3
126 ip neigh sh dev $swp3 $remote_ip nud reachable | 126 ping -c 1 -I $swp3 $remote_ip &>/dev/null
127 grep -q ^
128 if [[ $? -ne 0 ]]; then
129 sleep 1
130 else
131 break
132 fi
133 done
134 127
135 quick_test_span_gre_dir $tundev ingress 128 quick_test_span_gre_dir $tundev ingress
136 mirror_uninstall $swp1 ingress 129 mirror_uninstall $swp1 ingress
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh b/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh
new file mode 100755
index 000000000000..9edf4cb104a8
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_lag_lacp.sh
@@ -0,0 +1,285 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# Test for "tc action mirred egress mirror" when the underlay route points at a
5# team device.
6#
7# +----------------------+ +----------------------+
8# | H1 | | H2 |
9# | + $h1.333 | | $h1.555 + |
10# | | 192.0.2.1/28 | | 192.0.2.18/28 | |
11# +----|-----------------+ +----------------|-----+
12# | $h1 |
13# +---------------------------------+------------------------------+
14# |
15# +--------------------------------------|------------------------------------+
16# | SW o---> mirror |
17# | | |
18# | +----------------------------------+------------------------------+ |
19# | | $swp1 | |
20# | + $swp1.333 $swp1.555 + |
21# | 192.0.2.2/28 192.0.2.17/28 |
22# | |
23# | |
24# | + gt4 (gretap) ,-> + lag1 (team) |
25# | loc=192.0.2.129 | | 192.0.2.129/28 |
26# | rem=192.0.2.130 --' | |
27# | ttl=100 | |
28# | tos=inherit | |
29# | _____________________|______________________ |
30# | / \ |
31# | / \ |
32# | + $swp3 + $swp4 |
33# +---|------------------------------------------------|----------------------+
34# | |
35# +---|------------------------------------------------|----------------------+
36# | + $h3 + $h4 H3 |
37# | \ / |
38# | \____________________________________________/ |
39# | | |
40# | + lag2 (team) |
41# | 192.0.2.130/28 |
42# | |
43# +---------------------------------------------------------------------------+
44
45ALL_TESTS="
46 test_mirror_gretap_first
47 test_mirror_gretap_second
48"
49
50NUM_NETIFS=6
51source lib.sh
52source mirror_lib.sh
53source mirror_gre_lib.sh
54
55require_command $ARPING
56
57vlan_host_create()
58{
59 local if_name=$1; shift
60 local vid=$1; shift
61 local vrf_name=$1; shift
62 local ips=("${@}")
63
64 vrf_create $vrf_name
65 ip link set dev $vrf_name up
66 vlan_create $if_name $vid $vrf_name "${ips[@]}"
67}
68
69vlan_host_destroy()
70{
71 local if_name=$1; shift
72 local vid=$1; shift
73 local vrf_name=$1; shift
74
75 vlan_destroy $if_name $vid
76 ip link set dev $vrf_name down
77 vrf_destroy $vrf_name
78}
79
80h1_create()
81{
82 vlan_host_create $h1 333 vrf-h1 192.0.2.1/28
83 ip -4 route add 192.0.2.16/28 vrf vrf-h1 nexthop via 192.0.2.2
84}
85
86h1_destroy()
87{
88 ip -4 route del 192.0.2.16/28 vrf vrf-h1
89 vlan_host_destroy $h1 333 vrf-h1
90}
91
92h2_create()
93{
94 vlan_host_create $h1 555 vrf-h2 192.0.2.18/28
95 ip -4 route add 192.0.2.0/28 vrf vrf-h2 nexthop via 192.0.2.17
96}
97
98h2_destroy()
99{
100 ip -4 route del 192.0.2.0/28 vrf vrf-h2
101 vlan_host_destroy $h1 555 vrf-h2
102}
103
104h3_create_team()
105{
106 team_create lag2 lacp $h3 $h4
107 __simple_if_init lag2 vrf-h3 192.0.2.130/32
108 ip -4 route add vrf vrf-h3 192.0.2.129/32 dev lag2
109}
110
111h3_destroy_team()
112{
113 ip -4 route del vrf vrf-h3 192.0.2.129/32 dev lag2
114 __simple_if_fini lag2 192.0.2.130/32
115 team_destroy lag2
116
117 ip link set dev $h3 down
118 ip link set dev $h4 down
119}
120
121h3_create()
122{
123 vrf_create vrf-h3
124 ip link set dev vrf-h3 up
125 tc qdisc add dev $h3 clsact
126 tc qdisc add dev $h4 clsact
127 h3_create_team
128}
129
130h3_destroy()
131{
132 h3_destroy_team
133 tc qdisc del dev $h4 clsact
134 tc qdisc del dev $h3 clsact
135 ip link set dev vrf-h3 down
136 vrf_destroy vrf-h3
137}
138
139switch_create()
140{
141 ip link set dev $swp1 up
142 tc qdisc add dev $swp1 clsact
143 vlan_create $swp1 333 "" 192.0.2.2/28
144 vlan_create $swp1 555 "" 192.0.2.17/28
145
146 tunnel_create gt4 gretap 192.0.2.129 192.0.2.130 \
147 ttl 100 tos inherit
148
149 ip link set dev $swp3 up
150 ip link set dev $swp4 up
151 team_create lag1 lacp $swp3 $swp4
152 __addr_add_del lag1 add 192.0.2.129/32
153 ip -4 route add 192.0.2.130/32 dev lag1
154}
155
156switch_destroy()
157{
158 ip -4 route del 192.0.2.130/32 dev lag1
159 __addr_add_del lag1 del 192.0.2.129/32
160 team_destroy lag1
161
162 ip link set dev $swp4 down
163 ip link set dev $swp3 down
164
165 tunnel_destroy gt4
166
167 vlan_destroy $swp1 555
168 vlan_destroy $swp1 333
169 tc qdisc del dev $swp1 clsact
170 ip link set dev $swp1 down
171}
172
173setup_prepare()
174{
175 h1=${NETIFS[p1]}
176 swp1=${NETIFS[p2]}
177
178 swp3=${NETIFS[p3]}
179 h3=${NETIFS[p4]}
180
181 swp4=${NETIFS[p5]}
182 h4=${NETIFS[p6]}
183
184 vrf_prepare
185
186 ip link set dev $h1 up
187 h1_create
188 h2_create
189 h3_create
190 switch_create
191
192 trap_install $h3 ingress
193 trap_install $h4 ingress
194}
195
196cleanup()
197{
198 pre_cleanup
199
200 trap_uninstall $h4 ingress
201 trap_uninstall $h3 ingress
202
203 switch_destroy
204 h3_destroy
205 h2_destroy
206 h1_destroy
207 ip link set dev $h1 down
208
209 vrf_cleanup
210}
211
212test_lag_slave()
213{
214 local up_dev=$1; shift
215 local down_dev=$1; shift
216 local what=$1; shift
217
218 RET=0
219
220 mirror_install $swp1 ingress gt4 \
221 "proto 802.1q flower vlan_id 333 $tcflags"
222
223 # Move $down_dev away from the team. That will prompt change in
224 # txability of the connected device, without changing its upness. The
225 # driver should notice the txability change and move the traffic to the
226 # other slave.
227 ip link set dev $down_dev nomaster
228 sleep 2
229 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $up_dev 1 10
230
231 # Test lack of connectivity when neither slave is txable.
232 ip link set dev $up_dev nomaster
233 sleep 2
234 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h3 1 0
235 mirror_test vrf-h1 192.0.2.1 192.0.2.18 $h4 1 0
236 mirror_uninstall $swp1 ingress
237
238 # Recreate H3's team device, because mlxsw, which this test is
239 # predominantly mean to test, requires a bottom-up construction and
240 # doesn't allow enslavement to a device that already has an upper.
241 h3_destroy_team
242 h3_create_team
243 # Wait for ${h,swp}{3,4}.
244 setup_wait
245
246 log_test "$what ($tcflags)"
247}
248
249test_mirror_gretap_first()
250{
251 test_lag_slave $h3 $h4 "mirror to gretap: LAG first slave"
252}
253
254test_mirror_gretap_second()
255{
256 test_lag_slave $h4 $h3 "mirror to gretap: LAG second slave"
257}
258
259test_all()
260{
261 slow_path_trap_install $swp1 ingress
262 slow_path_trap_install $swp1 egress
263
264 tests_run
265
266 slow_path_trap_uninstall $swp1 egress
267 slow_path_trap_uninstall $swp1 ingress
268}
269
270trap cleanup EXIT
271
272setup_prepare
273setup_wait
274
275tcflags="skip_hw"
276test_all
277
278if ! tc_offload_check; then
279 echo "WARN: Could not test offloaded functionality"
280else
281 tcflags="skip_sw"
282 test_all
283fi
284
285exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh
index 619b469365be..fac486178ef7 100644
--- a/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_lib.sh
@@ -1,6 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0 1# SPDX-License-Identifier: GPL-2.0
2 2
3source mirror_lib.sh 3source "$relative_path/mirror_lib.sh"
4 4
5quick_test_span_gre_dir_ips() 5quick_test_span_gre_dir_ips()
6{ 6{
@@ -62,7 +62,7 @@ full_test_span_gre_dir_vlan_ips()
62 "$backward_type" "$ip1" "$ip2" 62 "$backward_type" "$ip1" "$ip2"
63 63
64 tc filter add dev $h3 ingress pref 77 prot 802.1q \ 64 tc filter add dev $h3 ingress pref 77 prot 802.1q \
65 flower $vlan_match ip_proto 0x2f \ 65 flower $vlan_match \
66 action pass 66 action pass
67 mirror_test v$h1 $ip1 $ip2 $h3 77 10 67 mirror_test v$h1 $ip1 $ip2 $h3 77 10
68 tc filter del dev $h3 ingress pref 77 68 tc filter del dev $h3 ingress pref 77
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh b/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh
index 8fa681eb90e7..6f9ef1820e93 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_nh.sh
@@ -35,6 +35,8 @@ setup_prepare()
35 vrf_prepare 35 vrf_prepare
36 mirror_gre_topo_create 36 mirror_gre_topo_create
37 37
38 sysctl_set net.ipv4.conf.v$h3.rp_filter 0
39
38 ip address add dev $swp3 192.0.2.161/28 40 ip address add dev $swp3 192.0.2.161/28
39 ip address add dev $h3 192.0.2.162/28 41 ip address add dev $h3 192.0.2.162/28
40 ip address add dev gt4 192.0.2.129/32 42 ip address add dev gt4 192.0.2.129/32
@@ -61,6 +63,8 @@ cleanup()
61 ip address del dev $h3 192.0.2.162/28 63 ip address del dev $h3 192.0.2.162/28
62 ip address del dev $swp3 192.0.2.161/28 64 ip address del dev $swp3 192.0.2.161/28
63 65
66 sysctl_restore net.ipv4.conf.v$h3.rp_filter 0
67
64 mirror_gre_topo_destroy 68 mirror_gre_topo_destroy
65 vrf_cleanup 69 vrf_cleanup
66 70
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh
index 253419564708..39c03e2867f4 100644
--- a/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_topo_lib.sh
@@ -33,7 +33,7 @@
33# | | 33# | |
34# +-------------------------------------------------------------------------+ 34# +-------------------------------------------------------------------------+
35 35
36source mirror_topo_lib.sh 36source "$relative_path/mirror_topo_lib.sh"
37 37
38mirror_gre_topo_h3_create() 38mirror_gre_topo_h3_create()
39{ 39{
diff --git a/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh b/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh
index 5dbc7a08f4bd..204b25f13934 100755
--- a/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_gre_vlan_bridge_1q.sh
@@ -28,6 +28,8 @@ source mirror_lib.sh
28source mirror_gre_lib.sh 28source mirror_gre_lib.sh
29source mirror_gre_topo_lib.sh 29source mirror_gre_topo_lib.sh
30 30
31require_command $ARPING
32
31setup_prepare() 33setup_prepare()
32{ 34{
33 h1=${NETIFS[p1]} 35 h1=${NETIFS[p1]}
@@ -39,6 +41,12 @@ setup_prepare()
39 swp3=${NETIFS[p5]} 41 swp3=${NETIFS[p5]}
40 h3=${NETIFS[p6]} 42 h3=${NETIFS[p6]}
41 43
44 # gt4's remote address is at $h3.555, not $h3. Thus the packets arriving
45 # directly to $h3 for test_gretap_untagged_egress() are rejected by
46 # rp_filter and the test spuriously fails.
47 sysctl_set net.ipv4.conf.all.rp_filter 0
48 sysctl_set net.ipv4.conf.$h3.rp_filter 0
49
42 vrf_prepare 50 vrf_prepare
43 mirror_gre_topo_create 51 mirror_gre_topo_create
44 52
@@ -65,6 +73,9 @@ cleanup()
65 73
66 mirror_gre_topo_destroy 74 mirror_gre_topo_destroy
67 vrf_cleanup 75 vrf_cleanup
76
77 sysctl_restore net.ipv4.conf.$h3.rp_filter
78 sysctl_restore net.ipv4.conf.all.rp_filter
68} 79}
69 80
70test_vlan_match() 81test_vlan_match()
@@ -79,12 +90,14 @@ test_vlan_match()
79 90
80test_gretap() 91test_gretap()
81{ 92{
82 test_vlan_match gt4 'vlan_id 555 vlan_ethtype ip' "mirror to gretap" 93 test_vlan_match gt4 'skip_hw vlan_id 555 vlan_ethtype ip' \
94 "mirror to gretap"
83} 95}
84 96
85test_ip6gretap() 97test_ip6gretap()
86{ 98{
87 test_vlan_match gt6 'vlan_id 555 vlan_ethtype ipv6' "mirror to ip6gretap" 99 test_vlan_match gt6 'skip_hw vlan_id 555 vlan_ethtype ip' \
100 "mirror to ip6gretap"
88} 101}
89 102
90test_span_gre_forbidden_cpu() 103test_span_gre_forbidden_cpu()
@@ -138,7 +151,7 @@ test_span_gre_forbidden_egress()
138 151
139 bridge vlan add dev $swp3 vid 555 152 bridge vlan add dev $swp3 vid 555
140 # Re-prime FDB 153 # Re-prime FDB
141 arping -I br1.555 192.0.2.130 -fqc 1 154 $ARPING -I br1.555 192.0.2.130 -fqc 1
142 sleep 1 155 sleep 1
143 quick_test_span_gre_dir $tundev ingress 156 quick_test_span_gre_dir $tundev ingress
144 157
@@ -212,7 +225,7 @@ test_span_gre_fdb_roaming()
212 225
213 bridge fdb del dev $swp2 $h3mac vlan 555 master 226 bridge fdb del dev $swp2 $h3mac vlan 555 master
214 # Re-prime FDB 227 # Re-prime FDB
215 arping -I br1.555 192.0.2.130 -fqc 1 228 $ARPING -I br1.555 192.0.2.130 -fqc 1
216 sleep 1 229 sleep 1
217 quick_test_span_gre_dir $tundev ingress 230 quick_test_span_gre_dir $tundev ingress
218 231
diff --git a/tools/testing/selftests/net/forwarding/mirror_lib.sh b/tools/testing/selftests/net/forwarding/mirror_lib.sh
index d36dc26c6c51..07991e1025c7 100644
--- a/tools/testing/selftests/net/forwarding/mirror_lib.sh
+++ b/tools/testing/selftests/net/forwarding/mirror_lib.sh
@@ -105,7 +105,7 @@ do_test_span_vlan_dir_ips()
105 # Install the capture as skip_hw to avoid double-counting of packets. 105 # Install the capture as skip_hw to avoid double-counting of packets.
106 # The traffic is meant for local box anyway, so will be trapped to 106 # The traffic is meant for local box anyway, so will be trapped to
107 # kernel. 107 # kernel.
108 vlan_capture_install $dev "skip_hw vlan_id $vid" 108 vlan_capture_install $dev "skip_hw vlan_id $vid vlan_ethtype ip"
109 mirror_test v$h1 $ip1 $ip2 $dev 100 $expect 109 mirror_test v$h1 $ip1 $ip2 $dev 100 $expect
110 mirror_test v$h2 $ip2 $ip1 $dev 100 $expect 110 mirror_test v$h2 $ip2 $ip1 $dev 100 $expect
111 vlan_capture_uninstall $dev 111 vlan_capture_uninstall $dev
diff --git a/tools/testing/selftests/net/forwarding/router_bridge.sh b/tools/testing/selftests/net/forwarding/router_bridge.sh
new file mode 100755
index 000000000000..ebc596a272f7
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/router_bridge.sh
@@ -0,0 +1,113 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5 ping_ipv4
6 ping_ipv6
7"
8NUM_NETIFS=4
9source lib.sh
10
11h1_create()
12{
13 simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
14 ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2
15 ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
16}
17
18h1_destroy()
19{
20 ip -6 route del 2001:db8:2::/64 vrf v$h1
21 ip -4 route del 192.0.2.128/28 vrf v$h1
22 simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
23}
24
25h2_create()
26{
27 simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
28 ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
29 ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
30}
31
32h2_destroy()
33{
34 ip -6 route del 2001:db8:1::/64 vrf v$h2
35 ip -4 route del 192.0.2.0/28 vrf v$h2
36 simple_if_fini $h2 192.0.2.130/28 2001:db8:2::2/64
37}
38
39router_create()
40{
41 ip link add name br1 type bridge vlan_filtering 1
42 ip link set dev br1 up
43
44 ip link set dev $swp1 master br1
45 ip link set dev $swp1 up
46 __addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
47
48 ip link set dev $swp2 up
49 __addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
50}
51
52router_destroy()
53{
54 __addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
55 ip link set dev $swp2 down
56
57 __addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
58 ip link set dev $swp1 down
59 ip link set dev $swp1 nomaster
60
61 ip link del dev br1
62}
63
64setup_prepare()
65{
66 h1=${NETIFS[p1]}
67 swp1=${NETIFS[p2]}
68
69 swp2=${NETIFS[p3]}
70 h2=${NETIFS[p4]}
71
72 vrf_prepare
73
74 h1_create
75 h2_create
76
77 router_create
78
79 forwarding_enable
80}
81
82cleanup()
83{
84 pre_cleanup
85
86 forwarding_restore
87
88 router_destroy
89
90 h2_destroy
91 h1_destroy
92
93 vrf_cleanup
94}
95
96ping_ipv4()
97{
98 ping_test $h1 192.0.2.130
99}
100
101ping_ipv6()
102{
103 ping6_test $h1 2001:db8:2::2
104}
105
106trap cleanup EXIT
107
108setup_prepare
109setup_wait
110
111tests_run
112
113exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
new file mode 100755
index 000000000000..fef88eb4b873
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/router_bridge_vlan.sh
@@ -0,0 +1,132 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5 ping_ipv4
6 ping_ipv6
7 vlan
8"
9NUM_NETIFS=4
10source lib.sh
11
12h1_create()
13{
14 simple_if_init $h1
15 vlan_create $h1 555 v$h1 192.0.2.1/28 2001:db8:1::1/64
16 ip -4 route add 192.0.2.128/28 vrf v$h1 nexthop via 192.0.2.2
17 ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
18}
19
20h1_destroy()
21{
22 ip -6 route del 2001:db8:2::/64 vrf v$h1
23 ip -4 route del 192.0.2.128/28 vrf v$h1
24 vlan_destroy $h1 555
25 simple_if_fini $h1
26}
27
28h2_create()
29{
30 simple_if_init $h2 192.0.2.130/28 2001:db8:2::2/64
31 ip -4 route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.129
32 ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::1
33}
34
35h2_destroy()
36{
37 ip -6 route del 2001:db8:1::/64 vrf v$h2
38 ip -4 route del 192.0.2.0/28 vrf v$h2
39 simple_if_fini $h2 192.0.2.130/28
40}
41
42router_create()
43{
44 ip link add name br1 type bridge vlan_filtering 1
45 ip link set dev br1 up
46
47 ip link set dev $swp1 master br1
48 ip link set dev $swp1 up
49
50 bridge vlan add dev br1 vid 555 self pvid untagged
51 bridge vlan add dev $swp1 vid 555
52
53 __addr_add_del br1 add 192.0.2.2/28 2001:db8:1::2/64
54
55 ip link set dev $swp2 up
56 __addr_add_del $swp2 add 192.0.2.129/28 2001:db8:2::1/64
57}
58
59router_destroy()
60{
61 __addr_add_del $swp2 del 192.0.2.129/28 2001:db8:2::1/64
62 ip link set dev $swp2 down
63
64 __addr_add_del br1 del 192.0.2.2/28 2001:db8:1::2/64
65 ip link set dev $swp1 down
66 ip link set dev $swp1 nomaster
67
68 ip link del dev br1
69}
70
71setup_prepare()
72{
73 h1=${NETIFS[p1]}
74 swp1=${NETIFS[p2]}
75
76 swp2=${NETIFS[p3]}
77 h2=${NETIFS[p4]}
78
79 vrf_prepare
80
81 h1_create
82 h2_create
83
84 router_create
85
86 forwarding_enable
87}
88
89cleanup()
90{
91 pre_cleanup
92
93 forwarding_restore
94
95 router_destroy
96
97 h2_destroy
98 h1_destroy
99
100 vrf_cleanup
101}
102
103vlan()
104{
105 RET=0
106
107 bridge vlan add dev br1 vid 333 self
108 check_err $? "Can't add a non-PVID VLAN"
109 bridge vlan del dev br1 vid 333 self
110 check_err $? "Can't remove a non-PVID VLAN"
111
112 log_test "vlan"
113}
114
115ping_ipv4()
116{
117 ping_test $h1 192.0.2.130
118}
119
120ping_ipv6()
121{
122 ping6_test $h1 2001:db8:2::2
123}
124
125trap cleanup EXIT
126
127setup_prepare
128setup_wait
129
130tests_run
131
132exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/router_broadcast.sh b/tools/testing/selftests/net/forwarding/router_broadcast.sh
new file mode 100755
index 000000000000..7bd2ebb6e9de
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/router_broadcast.sh
@@ -0,0 +1,233 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="ping_ipv4"
5NUM_NETIFS=6
6source lib.sh
7
8h1_create()
9{
10 vrf_create "vrf-h1"
11 ip link set dev $h1 master vrf-h1
12
13 ip link set dev vrf-h1 up
14 ip link set dev $h1 up
15
16 ip address add 192.0.2.2/24 dev $h1
17
18 ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1
19 ip route add 198.51.200.0/24 vrf vrf-h1 nexthop via 192.0.2.1
20}
21
22h1_destroy()
23{
24 ip route del 198.51.200.0/24 vrf vrf-h1
25 ip route del 198.51.100.0/24 vrf vrf-h1
26
27 ip address del 192.0.2.2/24 dev $h1
28
29 ip link set dev $h1 down
30 vrf_destroy "vrf-h1"
31}
32
33h2_create()
34{
35 vrf_create "vrf-h2"
36 ip link set dev $h2 master vrf-h2
37
38 ip link set dev vrf-h2 up
39 ip link set dev $h2 up
40
41 ip address add 198.51.100.2/24 dev $h2
42
43 ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1
44 ip route add 198.51.200.0/24 vrf vrf-h2 nexthop via 198.51.100.1
45}
46
47h2_destroy()
48{
49 ip route del 198.51.200.0/24 vrf vrf-h2
50 ip route del 192.0.2.0/24 vrf vrf-h2
51
52 ip address del 198.51.100.2/24 dev $h2
53
54 ip link set dev $h2 down
55 vrf_destroy "vrf-h2"
56}
57
58h3_create()
59{
60 vrf_create "vrf-h3"
61 ip link set dev $h3 master vrf-h3
62
63 ip link set dev vrf-h3 up
64 ip link set dev $h3 up
65
66 ip address add 198.51.200.2/24 dev $h3
67
68 ip route add 192.0.2.0/24 vrf vrf-h3 nexthop via 198.51.200.1
69 ip route add 198.51.100.0/24 vrf vrf-h3 nexthop via 198.51.200.1
70}
71
72h3_destroy()
73{
74 ip route del 198.51.100.0/24 vrf vrf-h3
75 ip route del 192.0.2.0/24 vrf vrf-h3
76
77 ip address del 198.51.200.2/24 dev $h3
78
79 ip link set dev $h3 down
80 vrf_destroy "vrf-h3"
81}
82
83router_create()
84{
85 ip link set dev $rp1 up
86 ip link set dev $rp2 up
87 ip link set dev $rp3 up
88
89 ip address add 192.0.2.1/24 dev $rp1
90
91 ip address add 198.51.100.1/24 dev $rp2
92 ip address add 198.51.200.1/24 dev $rp3
93}
94
95router_destroy()
96{
97 ip address del 198.51.200.1/24 dev $rp3
98 ip address del 198.51.100.1/24 dev $rp2
99
100 ip address del 192.0.2.1/24 dev $rp1
101
102 ip link set dev $rp3 down
103 ip link set dev $rp2 down
104 ip link set dev $rp1 down
105}
106
107setup_prepare()
108{
109 h1=${NETIFS[p1]}
110 rp1=${NETIFS[p2]}
111
112 rp2=${NETIFS[p3]}
113 h2=${NETIFS[p4]}
114
115 rp3=${NETIFS[p5]}
116 h3=${NETIFS[p6]}
117
118 vrf_prepare
119
120 h1_create
121 h2_create
122 h3_create
123
124 router_create
125
126 forwarding_enable
127}
128
129cleanup()
130{
131 pre_cleanup
132
133 forwarding_restore
134
135 router_destroy
136
137 h3_destroy
138 h2_destroy
139 h1_destroy
140
141 vrf_cleanup
142}
143
144bc_forwarding_disable()
145{
146 sysctl_set net.ipv4.conf.all.bc_forwarding 0
147 sysctl_set net.ipv4.conf.$rp1.bc_forwarding 0
148}
149
150bc_forwarding_enable()
151{
152 sysctl_set net.ipv4.conf.all.bc_forwarding 1
153 sysctl_set net.ipv4.conf.$rp1.bc_forwarding 1
154}
155
156bc_forwarding_restore()
157{
158 sysctl_restore net.ipv4.conf.$rp1.bc_forwarding
159 sysctl_restore net.ipv4.conf.all.bc_forwarding
160}
161
162ping_test_from()
163{
164 local oif=$1
165 local dip=$2
166 local from=$3
167 local fail=${4:-0}
168
169 RET=0
170
171 log_info "ping $dip, expected reply from $from"
172 ip vrf exec $(master_name_get $oif) \
173 $PING -I $oif $dip -c 10 -i 0.1 -w 2 -b 2>&1 | grep $from &> /dev/null
174 check_err_fail $fail $?
175}
176
177ping_ipv4()
178{
179 sysctl_set net.ipv4.icmp_echo_ignore_broadcasts 0
180
181 bc_forwarding_disable
182 log_info "bc_forwarding disabled on r1 =>"
183 ping_test_from $h1 198.51.100.255 192.0.2.1
184 log_test "h1 -> net2: reply from r1 (not forwarding)"
185 ping_test_from $h1 198.51.200.255 192.0.2.1
186 log_test "h1 -> net3: reply from r1 (not forwarding)"
187 ping_test_from $h1 192.0.2.255 192.0.2.1
188 log_test "h1 -> net1: reply from r1 (not dropping)"
189 ping_test_from $h1 255.255.255.255 192.0.2.1
190 log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
191
192 ping_test_from $h2 192.0.2.255 198.51.100.1
193 log_test "h2 -> net1: reply from r1 (not forwarding)"
194 ping_test_from $h2 198.51.200.255 198.51.100.1
195 log_test "h2 -> net3: reply from r1 (not forwarding)"
196 ping_test_from $h2 198.51.100.255 198.51.100.1
197 log_test "h2 -> net2: reply from r1 (not dropping)"
198 ping_test_from $h2 255.255.255.255 198.51.100.1
199 log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
200 bc_forwarding_restore
201
202 bc_forwarding_enable
203 log_info "bc_forwarding enabled on r1 =>"
204 ping_test_from $h1 198.51.100.255 198.51.100.2
205 log_test "h1 -> net2: reply from h2 (forwarding)"
206 ping_test_from $h1 198.51.200.255 198.51.200.2
207 log_test "h1 -> net3: reply from h3 (forwarding)"
208 ping_test_from $h1 192.0.2.255 192.0.2.1 1
209 log_test "h1 -> net1: no reply (dropping)"
210 ping_test_from $h1 255.255.255.255 192.0.2.1
211 log_test "h1 -> 255.255.255.255: reply from r1 (not forwarding)"
212
213 ping_test_from $h2 192.0.2.255 192.0.2.2
214 log_test "h2 -> net1: reply from h1 (forwarding)"
215 ping_test_from $h2 198.51.200.255 198.51.200.2
216 log_test "h2 -> net3: reply from h3 (forwarding)"
217 ping_test_from $h2 198.51.100.255 198.51.100.1 1
218 log_test "h2 -> net2: no reply (dropping)"
219 ping_test_from $h2 255.255.255.255 198.51.100.1
220 log_test "h2 -> 255.255.255.255: reply from r1 (not forwarding)"
221 bc_forwarding_restore
222
223 sysctl_restore net.ipv4.icmp_echo_ignore_broadcasts
224}
225
226trap cleanup EXIT
227
228setup_prepare
229setup_wait
230
231tests_run
232
233exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh
index 8b6d0fb6d604..79a209927962 100755
--- a/tools/testing/selftests/net/forwarding/router_multipath.sh
+++ b/tools/testing/selftests/net/forwarding/router_multipath.sh
@@ -159,45 +159,6 @@ router2_destroy()
159 vrf_destroy "vrf-r2" 159 vrf_destroy "vrf-r2"
160} 160}
161 161
162multipath_eval()
163{
164 local desc="$1"
165 local weight_rp12=$2
166 local weight_rp13=$3
167 local packets_rp12=$4
168 local packets_rp13=$5
169 local weights_ratio packets_ratio diff
170
171 RET=0
172
173 if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then
174 check_err 1 "Packet difference is 0"
175 log_test "Multipath"
176 log_info "Expected ratio $weights_ratio"
177 return
178 fi
179
180 if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then
181 weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \
182 | bc -l)
183 packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \
184 | bc -l)
185 else
186 weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" | \
187 bc -l)
188 packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" | \
189 bc -l)
190 fi
191
192 diff=$(echo $weights_ratio - $packets_ratio | bc -l)
193 diff=${diff#-}
194
195 test "$(echo "$diff / $weights_ratio > 0.15" | bc -l)" -eq 0
196 check_err $? "Too large discrepancy between expected and measured ratios"
197 log_test "$desc"
198 log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio"
199}
200
201multipath4_test() 162multipath4_test()
202{ 163{
203 local desc="$1" 164 local desc="$1"
diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh
index d2c783e94df3..2934fb5ed2a2 100755
--- a/tools/testing/selftests/net/forwarding/tc_chains.sh
+++ b/tools/testing/selftests/net/forwarding/tc_chains.sh
@@ -1,7 +1,8 @@
1#!/bin/bash 1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0 2# SPDX-License-Identifier: GPL-2.0
3 3
4ALL_TESTS="unreachable_chain_test gact_goto_chain_test" 4ALL_TESTS="unreachable_chain_test gact_goto_chain_test create_destroy_chain \
5 template_filter_fits"
5NUM_NETIFS=2 6NUM_NETIFS=2
6source tc_common.sh 7source tc_common.sh
7source lib.sh 8source lib.sh
@@ -80,6 +81,87 @@ gact_goto_chain_test()
80 log_test "gact goto chain ($tcflags)" 81 log_test "gact goto chain ($tcflags)"
81} 82}
82 83
84create_destroy_chain()
85{
86 RET=0
87
88 tc chain add dev $h2 ingress
89 check_err $? "Failed to create default chain"
90
91 output="$(tc -j chain get dev $h2 ingress)"
92 check_err $? "Failed to get default chain"
93
94 echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null
95 check_err $? "Unexpected output for default chain"
96
97 tc chain add dev $h2 ingress chain 1
98 check_err $? "Failed to create chain 1"
99
100 output="$(tc -j chain get dev $h2 ingress chain 1)"
101 check_err $? "Failed to get chain 1"
102
103 echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null
104 check_err $? "Unexpected output for chain 1"
105
106 output="$(tc -j chain show dev $h2 ingress)"
107 check_err $? "Failed to dump chains"
108
109 echo $output | jq -e ".[] | select(.chain == 0)" &> /dev/null
110 check_err $? "Can't find default chain in dump"
111
112 echo $output | jq -e ".[] | select(.chain == 1)" &> /dev/null
113 check_err $? "Can't find chain 1 in dump"
114
115 tc chain del dev $h2 ingress
116 check_err $? "Failed to destroy default chain"
117
118 tc chain del dev $h2 ingress chain 1
119 check_err $? "Failed to destroy chain 1"
120
121 log_test "create destroy chain"
122}
123
124template_filter_fits()
125{
126 RET=0
127
128 tc chain add dev $h2 ingress protocol ip \
129 flower dst_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
130 tc chain add dev $h2 ingress chain 1 protocol ip \
131 flower src_mac 00:00:00:00:00:00/FF:FF:FF:FF:FF:FF &> /dev/null
132
133 tc filter add dev $h2 ingress protocol ip pref 1 handle 1101 \
134 flower dst_mac $h2mac action drop
135 check_err $? "Failed to insert filter which fits template"
136
137 tc filter add dev $h2 ingress protocol ip pref 1 handle 1102 \
138 flower src_mac $h2mac action drop &> /dev/null
139 check_fail $? "Incorrectly succeded to insert filter which does not template"
140
141 tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \
142 flower src_mac $h2mac action drop
143 check_err $? "Failed to insert filter which fits template"
144
145 tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \
146 flower dst_mac $h2mac action drop &> /dev/null
147 check_fail $? "Incorrectly succeded to insert filter which does not template"
148
149 tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1102 \
150 flower &> /dev/null
151 tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \
152 flower &> /dev/null
153
154 tc filter del dev $h2 ingress protocol ip pref 1 handle 1102 \
155 flower &> /dev/null
156 tc filter del dev $h2 ingress protocol ip pref 1 handle 1101 \
157 flower &> /dev/null
158
159 tc chain del dev $h2 ingress chain 1
160 tc chain del dev $h2 ingress
161
162 log_test "template filter fits"
163}
164
83setup_prepare() 165setup_prepare()
84{ 166{
85 h1=${NETIFS[p1]} 167 h1=${NETIFS[p1]}
@@ -103,6 +185,8 @@ cleanup()
103 vrf_cleanup 185 vrf_cleanup
104} 186}
105 187
188check_tc_chain_support
189
106trap cleanup EXIT 190trap cleanup EXIT
107 191
108setup_prepare 192setup_prepare
diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh
index b5b917203815..9826a446e2c0 100755
--- a/tools/testing/selftests/net/forwarding/tc_shblocks.sh
+++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh
@@ -105,6 +105,8 @@ cleanup()
105 ip link set $swp2 address $swp2origmac 105 ip link set $swp2 address $swp2origmac
106} 106}
107 107
108check_tc_shblock_support
109
108trap cleanup EXIT 110trap cleanup EXIT
109 111
110setup_prepare 112setup_prepare
diff --git a/tools/testing/selftests/net/ip6_gre_headroom.sh b/tools/testing/selftests/net/ip6_gre_headroom.sh
new file mode 100755
index 000000000000..5b41e8bb6e2d
--- /dev/null
+++ b/tools/testing/selftests/net/ip6_gre_headroom.sh
@@ -0,0 +1,65 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test that enough headroom is reserved for the first packet passing through an
5# IPv6 GRE-like netdevice.
6
7setup_prepare()
8{
9 ip link add h1 type veth peer name swp1
10 ip link add h3 type veth peer name swp3
11
12 ip link set dev h1 up
13 ip address add 192.0.2.1/28 dev h1
14
15 ip link add dev vh3 type vrf table 20
16 ip link set dev h3 master vh3
17 ip link set dev vh3 up
18 ip link set dev h3 up
19
20 ip link set dev swp3 up
21 ip address add dev swp3 2001:db8:2::1/64
22 ip address add dev swp3 2001:db8:2::3/64
23
24 ip link set dev swp1 up
25 tc qdisc add dev swp1 clsact
26
27 ip link add name er6 type ip6erspan \
28 local 2001:db8:2::1 remote 2001:db8:2::2 oseq okey 123
29 ip link set dev er6 up
30
31 ip link add name gt6 type ip6gretap \
32 local 2001:db8:2::3 remote 2001:db8:2::4
33 ip link set dev gt6 up
34
35 sleep 1
36}
37
38cleanup()
39{
40 ip link del dev gt6
41 ip link del dev er6
42 ip link del dev swp1
43 ip link del dev swp3
44 ip link del dev vh3
45}
46
47test_headroom()
48{
49 local type=$1; shift
50 local tundev=$1; shift
51
52 tc filter add dev swp1 ingress pref 1000 matchall skip_hw \
53 action mirred egress mirror dev $tundev
54 ping -I h1 192.0.2.2 -c 1 -w 2 &> /dev/null
55 tc filter del dev swp1 ingress pref 1000
56
57 # If it doesn't panic, it passes.
58 printf "TEST: %-60s [PASS]\n" "$type headroom"
59}
60
61trap cleanup EXIT
62
63setup_prepare
64test_headroom ip6gretap gt6
65test_headroom ip6erspan er6
diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh
index 0d7a44fa30af..08c341b49760 100755
--- a/tools/testing/selftests/net/rtnetlink.sh
+++ b/tools/testing/selftests/net/rtnetlink.sh
@@ -525,18 +525,21 @@ kci_test_macsec()
525#------------------------------------------------------------------- 525#-------------------------------------------------------------------
526kci_test_ipsec() 526kci_test_ipsec()
527{ 527{
528 srcip="14.0.0.52" 528 ret=0
529 dstip="14.0.0.70"
530 algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128" 529 algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128"
530 srcip=192.168.123.1
531 dstip=192.168.123.2
532 spi=7
533
534 ip addr add $srcip dev $devdummy
531 535
532 # flush to be sure there's nothing configured 536 # flush to be sure there's nothing configured
533 ip x s flush ; ip x p flush 537 ip x s flush ; ip x p flush
534 check_err $? 538 check_err $?
535 539
536 # start the monitor in the background 540 # start the monitor in the background
537 tmpfile=`mktemp ipsectestXXX` 541 tmpfile=`mktemp /var/run/ipsectestXXX`
538 ip x m > $tmpfile & 542 mpid=`(ip x m > $tmpfile & echo $!) 2>/dev/null`
539 mpid=$!
540 sleep 0.2 543 sleep 0.2
541 544
542 ipsecid="proto esp src $srcip dst $dstip spi 0x07" 545 ipsecid="proto esp src $srcip dst $dstip spi 0x07"
@@ -599,6 +602,7 @@ kci_test_ipsec()
599 check_err $? 602 check_err $?
600 ip x p flush 603 ip x p flush
601 check_err $? 604 check_err $?
605 ip addr del $srcip/32 dev $devdummy
602 606
603 if [ $ret -ne 0 ]; then 607 if [ $ret -ne 0 ]; then
604 echo "FAIL: ipsec" 608 echo "FAIL: ipsec"
@@ -607,6 +611,119 @@ kci_test_ipsec()
607 echo "PASS: ipsec" 611 echo "PASS: ipsec"
608} 612}
609 613
614#-------------------------------------------------------------------
615# Example commands
616# ip x s add proto esp src 14.0.0.52 dst 14.0.0.70 \
617# spi 0x07 mode transport reqid 0x07 replay-window 32 \
618# aead 'rfc4106(gcm(aes))' 1234567890123456dcba 128 \
619# sel src 14.0.0.52/24 dst 14.0.0.70/24
620# offload dev sim1 dir out
621# ip x p add dir out src 14.0.0.52/24 dst 14.0.0.70/24 \
622# tmpl proto esp src 14.0.0.52 dst 14.0.0.70 \
623# spi 0x07 mode transport reqid 0x07
624#
625#-------------------------------------------------------------------
626kci_test_ipsec_offload()
627{
628 ret=0
629 algo="aead rfc4106(gcm(aes)) 0x3132333435363738393031323334353664636261 128"
630 srcip=192.168.123.3
631 dstip=192.168.123.4
632 dev=simx1
633 sysfsd=/sys/kernel/debug/netdevsim/$dev
634 sysfsf=$sysfsd/ipsec
635
636 # setup netdevsim since dummydev doesn't have offload support
637 modprobe netdevsim
638 check_err $?
639 if [ $ret -ne 0 ]; then
640 echo "FAIL: ipsec_offload can't load netdevsim"
641 return 1
642 fi
643
644 ip link add $dev type netdevsim
645 ip addr add $srcip dev $dev
646 ip link set $dev up
647 if [ ! -d $sysfsd ] ; then
648 echo "FAIL: ipsec_offload can't create device $dev"
649 return 1
650 fi
651 if [ ! -f $sysfsf ] ; then
652 echo "FAIL: ipsec_offload netdevsim doesn't support IPsec offload"
653 return 1
654 fi
655
656 # flush to be sure there's nothing configured
657 ip x s flush ; ip x p flush
658
659 # create offloaded SAs, both in and out
660 ip x p add dir out src $srcip/24 dst $dstip/24 \
661 tmpl proto esp src $srcip dst $dstip spi 9 \
662 mode transport reqid 42
663 check_err $?
664 ip x p add dir out src $dstip/24 dst $srcip/24 \
665 tmpl proto esp src $dstip dst $srcip spi 9 \
666 mode transport reqid 42
667 check_err $?
668
669 ip x s add proto esp src $srcip dst $dstip spi 9 \
670 mode transport reqid 42 $algo sel src $srcip/24 dst $dstip/24 \
671 offload dev $dev dir out
672 check_err $?
673 ip x s add proto esp src $dstip dst $srcip spi 9 \
674 mode transport reqid 42 $algo sel src $dstip/24 dst $srcip/24 \
675 offload dev $dev dir in
676 check_err $?
677 if [ $ret -ne 0 ]; then
678 echo "FAIL: ipsec_offload can't create SA"
679 return 1
680 fi
681
682 # does offload show up in ip output
683 lines=`ip x s list | grep -c "crypto offload parameters: dev $dev dir"`
684 if [ $lines -ne 2 ] ; then
685 echo "FAIL: ipsec_offload SA offload missing from list output"
686 check_err 1
687 fi
688
689 # use ping to exercise the Tx path
690 ping -I $dev -c 3 -W 1 -i 0 $dstip >/dev/null
691
692 # does driver have correct offload info
693 diff $sysfsf - << EOF
694SA count=2 tx=3
695sa[0] tx ipaddr=0x00000000 00000000 00000000 00000000
696sa[0] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1
697sa[0] key=0x34333231 38373635 32313039 36353433
698sa[1] rx ipaddr=0x00000000 00000000 00000000 037ba8c0
699sa[1] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1
700sa[1] key=0x34333231 38373635 32313039 36353433
701EOF
702 if [ $? -ne 0 ] ; then
703 echo "FAIL: ipsec_offload incorrect driver data"
704 check_err 1
705 fi
706
707 # does offload get removed from driver
708 ip x s flush
709 ip x p flush
710 lines=`grep -c "SA count=0" $sysfsf`
711 if [ $lines -ne 1 ] ; then
712 echo "FAIL: ipsec_offload SA not removed from driver"
713 check_err 1
714 fi
715
716 # clean up any leftovers
717 ip link del $dev
718 rmmod netdevsim
719
720 if [ $ret -ne 0 ]; then
721 echo "FAIL: ipsec_offload"
722 return 1
723 fi
724 echo "PASS: ipsec_offload"
725}
726
610kci_test_gretap() 727kci_test_gretap()
611{ 728{
612 testns="testns" 729 testns="testns"
@@ -861,6 +978,7 @@ kci_test_rtnl()
861 kci_test_encap 978 kci_test_encap
862 kci_test_macsec 979 kci_test_macsec
863 kci_test_ipsec 980 kci_test_ipsec
981 kci_test_ipsec_offload
864 982
865 kci_del_dummy 983 kci_del_dummy
866} 984}
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
new file mode 100644
index 000000000000..b3ebf2646e52
--- /dev/null
+++ b/tools/testing/selftests/net/tls.c
@@ -0,0 +1,692 @@
1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4
5#include <arpa/inet.h>
6#include <errno.h>
7#include <error.h>
8#include <fcntl.h>
9#include <poll.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <unistd.h>
13
14#include <linux/tls.h>
15#include <linux/tcp.h>
16#include <linux/socket.h>
17
18#include <sys/types.h>
19#include <sys/sendfile.h>
20#include <sys/socket.h>
21#include <sys/stat.h>
22
23#include "../kselftest_harness.h"
24
25#define TLS_PAYLOAD_MAX_LEN 16384
26#define SOL_TLS 282
27
28FIXTURE(tls)
29{
30 int fd, cfd;
31 bool notls;
32};
33
34FIXTURE_SETUP(tls)
35{
36 struct tls12_crypto_info_aes_gcm_128 tls12;
37 struct sockaddr_in addr;
38 socklen_t len;
39 int sfd, ret;
40
41 self->notls = false;
42 len = sizeof(addr);
43
44 memset(&tls12, 0, sizeof(tls12));
45 tls12.info.version = TLS_1_2_VERSION;
46 tls12.info.cipher_type = TLS_CIPHER_AES_GCM_128;
47
48 addr.sin_family = AF_INET;
49 addr.sin_addr.s_addr = htonl(INADDR_ANY);
50 addr.sin_port = 0;
51
52 self->fd = socket(AF_INET, SOCK_STREAM, 0);
53 sfd = socket(AF_INET, SOCK_STREAM, 0);
54
55 ret = bind(sfd, &addr, sizeof(addr));
56 ASSERT_EQ(ret, 0);
57 ret = listen(sfd, 10);
58 ASSERT_EQ(ret, 0);
59
60 ret = getsockname(sfd, &addr, &len);
61 ASSERT_EQ(ret, 0);
62
63 ret = connect(self->fd, &addr, sizeof(addr));
64 ASSERT_EQ(ret, 0);
65
66 ret = setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
67 if (ret != 0) {
68 self->notls = true;
69 printf("Failure setting TCP_ULP, testing without tls\n");
70 }
71
72 if (!self->notls) {
73 ret = setsockopt(self->fd, SOL_TLS, TLS_TX, &tls12,
74 sizeof(tls12));
75 ASSERT_EQ(ret, 0);
76 }
77
78 self->cfd = accept(sfd, &addr, &len);
79 ASSERT_GE(self->cfd, 0);
80
81 if (!self->notls) {
82 ret = setsockopt(self->cfd, IPPROTO_TCP, TCP_ULP, "tls",
83 sizeof("tls"));
84 ASSERT_EQ(ret, 0);
85
86 ret = setsockopt(self->cfd, SOL_TLS, TLS_RX, &tls12,
87 sizeof(tls12));
88 ASSERT_EQ(ret, 0);
89 }
90
91 close(sfd);
92}
93
94FIXTURE_TEARDOWN(tls)
95{
96 close(self->fd);
97 close(self->cfd);
98}
99
100TEST_F(tls, sendfile)
101{
102 int filefd = open("/proc/self/exe", O_RDONLY);
103 struct stat st;
104
105 EXPECT_GE(filefd, 0);
106 fstat(filefd, &st);
107 EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
108}
109
110TEST_F(tls, send_then_sendfile)
111{
112 int filefd = open("/proc/self/exe", O_RDONLY);
113 char const *test_str = "test_send";
114 int to_send = strlen(test_str) + 1;
115 char recv_buf[10];
116 struct stat st;
117 char *buf;
118
119 EXPECT_GE(filefd, 0);
120 fstat(filefd, &st);
121 buf = (char *)malloc(st.st_size);
122
123 EXPECT_EQ(send(self->fd, test_str, to_send, 0), to_send);
124 EXPECT_EQ(recv(self->cfd, recv_buf, to_send, 0), to_send);
125 EXPECT_EQ(memcmp(test_str, recv_buf, to_send), 0);
126
127 EXPECT_GE(sendfile(self->fd, filefd, 0, st.st_size), 0);
128 EXPECT_EQ(recv(self->cfd, buf, st.st_size, 0), st.st_size);
129}
130
131TEST_F(tls, recv_max)
132{
133 unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
134 char recv_mem[TLS_PAYLOAD_MAX_LEN];
135 char buf[TLS_PAYLOAD_MAX_LEN];
136
137 EXPECT_GE(send(self->fd, buf, send_len, 0), 0);
138 EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
139 EXPECT_EQ(memcmp(buf, recv_mem, send_len), 0);
140}
141
142TEST_F(tls, recv_small)
143{
144 char const *test_str = "test_read";
145 int send_len = 10;
146 char buf[10];
147
148 send_len = strlen(test_str) + 1;
149 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
150 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
151 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
152}
153
154TEST_F(tls, msg_more)
155{
156 char const *test_str = "test_read";
157 int send_len = 10;
158 char buf[10 * 2];
159
160 EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len);
161 EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1);
162 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
163 EXPECT_EQ(recv(self->cfd, buf, send_len * 2, MSG_DONTWAIT),
164 send_len * 2);
165 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
166}
167
168TEST_F(tls, sendmsg_single)
169{
170 struct msghdr msg;
171
172 char const *test_str = "test_sendmsg";
173 size_t send_len = 13;
174 struct iovec vec;
175 char buf[13];
176
177 vec.iov_base = (char *)test_str;
178 vec.iov_len = send_len;
179 memset(&msg, 0, sizeof(struct msghdr));
180 msg.msg_iov = &vec;
181 msg.msg_iovlen = 1;
182 EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
183 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
184 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
185}
186
187TEST_F(tls, sendmsg_large)
188{
189 void *mem = malloc(16384);
190 size_t send_len = 16384;
191 size_t sends = 128;
192 struct msghdr msg;
193 size_t recvs = 0;
194 size_t sent = 0;
195
196 memset(&msg, 0, sizeof(struct msghdr));
197 while (sent++ < sends) {
198 struct iovec vec = { (void *)mem, send_len };
199
200 msg.msg_iov = &vec;
201 msg.msg_iovlen = 1;
202 EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
203 }
204
205 while (recvs++ < sends)
206 EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
207
208 free(mem);
209}
210
211TEST_F(tls, sendmsg_multiple)
212{
213 char const *test_str = "test_sendmsg_multiple";
214 struct iovec vec[5];
215 char *test_strs[5];
216 struct msghdr msg;
217 int total_len = 0;
218 int len_cmp = 0;
219 int iov_len = 5;
220 char *buf;
221 int i;
222
223 memset(&msg, 0, sizeof(struct msghdr));
224 for (i = 0; i < iov_len; i++) {
225 test_strs[i] = (char *)malloc(strlen(test_str) + 1);
226 snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
227 vec[i].iov_base = (void *)test_strs[i];
228 vec[i].iov_len = strlen(test_strs[i]) + 1;
229 total_len += vec[i].iov_len;
230 }
231 msg.msg_iov = vec;
232 msg.msg_iovlen = iov_len;
233
234 EXPECT_EQ(sendmsg(self->cfd, &msg, 0), total_len);
235 buf = malloc(total_len);
236 EXPECT_NE(recv(self->fd, buf, total_len, 0), -1);
237 for (i = 0; i < iov_len; i++) {
238 EXPECT_EQ(memcmp(test_strs[i], buf + len_cmp,
239 strlen(test_strs[i])),
240 0);
241 len_cmp += strlen(buf + len_cmp) + 1;
242 }
243 for (i = 0; i < iov_len; i++)
244 free(test_strs[i]);
245 free(buf);
246}
247
248TEST_F(tls, sendmsg_multiple_stress)
249{
250 char const *test_str = "abcdefghijklmno";
251 struct iovec vec[1024];
252 char *test_strs[1024];
253 int iov_len = 1024;
254 int total_len = 0;
255 char buf[1 << 14];
256 struct msghdr msg;
257 int len_cmp = 0;
258 int i;
259
260 memset(&msg, 0, sizeof(struct msghdr));
261 for (i = 0; i < iov_len; i++) {
262 test_strs[i] = (char *)malloc(strlen(test_str) + 1);
263 snprintf(test_strs[i], strlen(test_str) + 1, "%s", test_str);
264 vec[i].iov_base = (void *)test_strs[i];
265 vec[i].iov_len = strlen(test_strs[i]) + 1;
266 total_len += vec[i].iov_len;
267 }
268 msg.msg_iov = vec;
269 msg.msg_iovlen = iov_len;
270
271 EXPECT_EQ(sendmsg(self->fd, &msg, 0), total_len);
272 EXPECT_NE(recv(self->cfd, buf, total_len, 0), -1);
273
274 for (i = 0; i < iov_len; i++)
275 len_cmp += strlen(buf + len_cmp) + 1;
276
277 for (i = 0; i < iov_len; i++)
278 free(test_strs[i]);
279}
280
281TEST_F(tls, splice_from_pipe)
282{
283 int send_len = TLS_PAYLOAD_MAX_LEN;
284 char mem_send[TLS_PAYLOAD_MAX_LEN];
285 char mem_recv[TLS_PAYLOAD_MAX_LEN];
286 int p[2];
287
288 ASSERT_GE(pipe(p), 0);
289 EXPECT_GE(write(p[1], mem_send, send_len), 0);
290 EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), 0);
291 EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
292 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
293}
294
295TEST_F(tls, splice_from_pipe2)
296{
297 int send_len = 16000;
298 char mem_send[16000];
299 char mem_recv[16000];
300 int p2[2];
301 int p[2];
302
303 ASSERT_GE(pipe(p), 0);
304 ASSERT_GE(pipe(p2), 0);
305 EXPECT_GE(write(p[1], mem_send, 8000), 0);
306 EXPECT_GE(splice(p[0], NULL, self->fd, NULL, 8000, 0), 0);
307 EXPECT_GE(write(p2[1], mem_send + 8000, 8000), 0);
308 EXPECT_GE(splice(p2[0], NULL, self->fd, NULL, 8000, 0), 0);
309 EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
310 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
311}
312
313TEST_F(tls, send_and_splice)
314{
315 int send_len = TLS_PAYLOAD_MAX_LEN;
316 char mem_send[TLS_PAYLOAD_MAX_LEN];
317 char mem_recv[TLS_PAYLOAD_MAX_LEN];
318 char const *test_str = "test_read";
319 int send_len2 = 10;
320 char buf[10];
321 int p[2];
322
323 ASSERT_GE(pipe(p), 0);
324 EXPECT_EQ(send(self->fd, test_str, send_len2, 0), send_len2);
325 EXPECT_NE(recv(self->cfd, buf, send_len2, 0), -1);
326 EXPECT_EQ(memcmp(test_str, buf, send_len2), 0);
327
328 EXPECT_GE(write(p[1], mem_send, send_len), send_len);
329 EXPECT_GE(splice(p[0], NULL, self->fd, NULL, send_len, 0), send_len);
330
331 EXPECT_GE(recv(self->cfd, mem_recv, send_len, 0), 0);
332 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
333}
334
335TEST_F(tls, splice_to_pipe)
336{
337 int send_len = TLS_PAYLOAD_MAX_LEN;
338 char mem_send[TLS_PAYLOAD_MAX_LEN];
339 char mem_recv[TLS_PAYLOAD_MAX_LEN];
340 int p[2];
341
342 ASSERT_GE(pipe(p), 0);
343 EXPECT_GE(send(self->fd, mem_send, send_len, 0), 0);
344 EXPECT_GE(splice(self->cfd, NULL, p[1], NULL, send_len, 0), 0);
345 EXPECT_GE(read(p[0], mem_recv, send_len), 0);
346 EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);
347}
348
349TEST_F(tls, recvmsg_single)
350{
351 char const *test_str = "test_recvmsg_single";
352 int send_len = strlen(test_str) + 1;
353 char buf[20];
354 struct msghdr hdr;
355 struct iovec vec;
356
357 memset(&hdr, 0, sizeof(hdr));
358 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
359 vec.iov_base = (char *)buf;
360 vec.iov_len = send_len;
361 hdr.msg_iovlen = 1;
362 hdr.msg_iov = &vec;
363 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
364 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
365}
366
367TEST_F(tls, recvmsg_single_max)
368{
369 int send_len = TLS_PAYLOAD_MAX_LEN;
370 char send_mem[TLS_PAYLOAD_MAX_LEN];
371 char recv_mem[TLS_PAYLOAD_MAX_LEN];
372 struct iovec vec;
373 struct msghdr hdr;
374
375 EXPECT_EQ(send(self->fd, send_mem, send_len, 0), send_len);
376 vec.iov_base = (char *)recv_mem;
377 vec.iov_len = TLS_PAYLOAD_MAX_LEN;
378
379 hdr.msg_iovlen = 1;
380 hdr.msg_iov = &vec;
381 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
382 EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
383}
384
385TEST_F(tls, recvmsg_multiple)
386{
387 unsigned int msg_iovlen = 1024;
388 unsigned int len_compared = 0;
389 struct iovec vec[1024];
390 char *iov_base[1024];
391 unsigned int iov_len = 16;
392 int send_len = 1 << 14;
393 char buf[1 << 14];
394 struct msghdr hdr;
395 int i;
396
397 EXPECT_EQ(send(self->fd, buf, send_len, 0), send_len);
398 for (i = 0; i < msg_iovlen; i++) {
399 iov_base[i] = (char *)malloc(iov_len);
400 vec[i].iov_base = iov_base[i];
401 vec[i].iov_len = iov_len;
402 }
403
404 hdr.msg_iovlen = msg_iovlen;
405 hdr.msg_iov = vec;
406 EXPECT_NE(recvmsg(self->cfd, &hdr, 0), -1);
407 for (i = 0; i < msg_iovlen; i++)
408 len_compared += iov_len;
409
410 for (i = 0; i < msg_iovlen; i++)
411 free(iov_base[i]);
412}
413
414TEST_F(tls, single_send_multiple_recv)
415{
416 unsigned int total_len = TLS_PAYLOAD_MAX_LEN * 2;
417 unsigned int send_len = TLS_PAYLOAD_MAX_LEN;
418 char send_mem[TLS_PAYLOAD_MAX_LEN * 2];
419 char recv_mem[TLS_PAYLOAD_MAX_LEN * 2];
420
421 EXPECT_GE(send(self->fd, send_mem, total_len, 0), 0);
422 memset(recv_mem, 0, total_len);
423
424 EXPECT_NE(recv(self->cfd, recv_mem, send_len, 0), -1);
425 EXPECT_NE(recv(self->cfd, recv_mem + send_len, send_len, 0), -1);
426 EXPECT_EQ(memcmp(send_mem, recv_mem, total_len), 0);
427}
428
429TEST_F(tls, multiple_send_single_recv)
430{
431 unsigned int total_len = 2 * 10;
432 unsigned int send_len = 10;
433 char recv_mem[2 * 10];
434 char send_mem[10];
435
436 EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
437 EXPECT_GE(send(self->fd, send_mem, send_len, 0), 0);
438 memset(recv_mem, 0, total_len);
439 EXPECT_EQ(recv(self->cfd, recv_mem, total_len, 0), total_len);
440
441 EXPECT_EQ(memcmp(send_mem, recv_mem, send_len), 0);
442 EXPECT_EQ(memcmp(send_mem, recv_mem + send_len, send_len), 0);
443}
444
445TEST_F(tls, recv_partial)
446{
447 char const *test_str = "test_read_partial";
448 char const *test_str_first = "test_read";
449 char const *test_str_second = "_partial";
450 int send_len = strlen(test_str) + 1;
451 char recv_mem[18];
452
453 memset(recv_mem, 0, sizeof(recv_mem));
454 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
455 EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_first), 0), -1);
456 EXPECT_EQ(memcmp(test_str_first, recv_mem, strlen(test_str_first)), 0);
457 memset(recv_mem, 0, sizeof(recv_mem));
458 EXPECT_NE(recv(self->cfd, recv_mem, strlen(test_str_second), 0), -1);
459 EXPECT_EQ(memcmp(test_str_second, recv_mem, strlen(test_str_second)),
460 0);
461}
462
463TEST_F(tls, recv_nonblock)
464{
465 char buf[4096];
466 bool err;
467
468 EXPECT_EQ(recv(self->cfd, buf, sizeof(buf), MSG_DONTWAIT), -1);
469 err = (errno == EAGAIN || errno == EWOULDBLOCK);
470 EXPECT_EQ(err, true);
471}
472
473TEST_F(tls, recv_peek)
474{
475 char const *test_str = "test_read_peek";
476 int send_len = strlen(test_str) + 1;
477 char buf[15];
478
479 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
480 EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
481 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
482 memset(buf, 0, sizeof(buf));
483 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
484 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
485}
486
487TEST_F(tls, recv_peek_multiple)
488{
489 char const *test_str = "test_read_peek";
490 int send_len = strlen(test_str) + 1;
491 unsigned int num_peeks = 100;
492 char buf[15];
493 int i;
494
495 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
496 for (i = 0; i < num_peeks; i++) {
497 EXPECT_NE(recv(self->cfd, buf, send_len, MSG_PEEK), -1);
498 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
499 memset(buf, 0, sizeof(buf));
500 }
501 EXPECT_NE(recv(self->cfd, buf, send_len, 0), -1);
502 EXPECT_EQ(memcmp(test_str, buf, send_len), 0);
503}
504
505TEST_F(tls, pollin)
506{
507 char const *test_str = "test_poll";
508 struct pollfd fd = { 0, 0, 0 };
509 char buf[10];
510 int send_len = 10;
511
512 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
513 fd.fd = self->cfd;
514 fd.events = POLLIN;
515
516 EXPECT_EQ(poll(&fd, 1, 20), 1);
517 EXPECT_EQ(fd.revents & POLLIN, 1);
518 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), send_len);
519 /* Test timing out */
520 EXPECT_EQ(poll(&fd, 1, 20), 0);
521}
522
523TEST_F(tls, poll_wait)
524{
525 char const *test_str = "test_poll_wait";
526 int send_len = strlen(test_str) + 1;
527 struct pollfd fd = { 0, 0, 0 };
528 char recv_mem[15];
529
530 fd.fd = self->cfd;
531 fd.events = POLLIN;
532 EXPECT_EQ(send(self->fd, test_str, send_len, 0), send_len);
533 /* Set timeout to inf. secs */
534 EXPECT_EQ(poll(&fd, 1, -1), 1);
535 EXPECT_EQ(fd.revents & POLLIN, 1);
536 EXPECT_EQ(recv(self->cfd, recv_mem, send_len, 0), send_len);
537}
538
539TEST_F(tls, blocking)
540{
541 size_t data = 100000;
542 int res = fork();
543
544 EXPECT_NE(res, -1);
545
546 if (res) {
547 /* parent */
548 size_t left = data;
549 char buf[16384];
550 int status;
551 int pid2;
552
553 while (left) {
554 int res = send(self->fd, buf,
555 left > 16384 ? 16384 : left, 0);
556
557 EXPECT_GE(res, 0);
558 left -= res;
559 }
560
561 pid2 = wait(&status);
562 EXPECT_EQ(status, 0);
563 EXPECT_EQ(res, pid2);
564 } else {
565 /* child */
566 size_t left = data;
567 char buf[16384];
568
569 while (left) {
570 int res = recv(self->cfd, buf,
571 left > 16384 ? 16384 : left, 0);
572
573 EXPECT_GE(res, 0);
574 left -= res;
575 }
576 }
577}
578
579TEST_F(tls, nonblocking)
580{
581 size_t data = 100000;
582 int sendbuf = 100;
583 int flags;
584 int res;
585
586 flags = fcntl(self->fd, F_GETFL, 0);
587 fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
588 fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK);
589
590 /* Ensure nonblocking behavior by imposing a small send
591 * buffer.
592 */
593 EXPECT_EQ(setsockopt(self->fd, SOL_SOCKET, SO_SNDBUF,
594 &sendbuf, sizeof(sendbuf)), 0);
595
596 res = fork();
597 EXPECT_NE(res, -1);
598
599 if (res) {
600 /* parent */
601 bool eagain = false;
602 size_t left = data;
603 char buf[16384];
604 int status;
605 int pid2;
606
607 while (left) {
608 int res = send(self->fd, buf,
609 left > 16384 ? 16384 : left, 0);
610
611 if (res == -1 && errno == EAGAIN) {
612 eagain = true;
613 usleep(10000);
614 continue;
615 }
616 EXPECT_GE(res, 0);
617 left -= res;
618 }
619
620 EXPECT_TRUE(eagain);
621 pid2 = wait(&status);
622
623 EXPECT_EQ(status, 0);
624 EXPECT_EQ(res, pid2);
625 } else {
626 /* child */
627 bool eagain = false;
628 size_t left = data;
629 char buf[16384];
630
631 while (left) {
632 int res = recv(self->cfd, buf,
633 left > 16384 ? 16384 : left, 0);
634
635 if (res == -1 && errno == EAGAIN) {
636 eagain = true;
637 usleep(10000);
638 continue;
639 }
640 EXPECT_GE(res, 0);
641 left -= res;
642 }
643 EXPECT_TRUE(eagain);
644 }
645}
646
647TEST_F(tls, control_msg)
648{
649 if (self->notls)
650 return;
651
652 char cbuf[CMSG_SPACE(sizeof(char))];
653 char const *test_str = "test_read";
654 int cmsg_len = sizeof(char);
655 char record_type = 100;
656 struct cmsghdr *cmsg;
657 struct msghdr msg;
658 int send_len = 10;
659 struct iovec vec;
660 char buf[10];
661
662 vec.iov_base = (char *)test_str;
663 vec.iov_len = 10;
664 memset(&msg, 0, sizeof(struct msghdr));
665 msg.msg_iov = &vec;
666 msg.msg_iovlen = 1;
667 msg.msg_control = cbuf;
668 msg.msg_controllen = sizeof(cbuf);
669 cmsg = CMSG_FIRSTHDR(&msg);
670 cmsg->cmsg_level = SOL_TLS;
671 /* test sending non-record types. */
672 cmsg->cmsg_type = TLS_SET_RECORD_TYPE;
673 cmsg->cmsg_len = CMSG_LEN(cmsg_len);
674 *CMSG_DATA(cmsg) = record_type;
675 msg.msg_controllen = cmsg->cmsg_len;
676
677 EXPECT_EQ(sendmsg(self->fd, &msg, 0), send_len);
678 /* Should fail because we didn't provide a control message */
679 EXPECT_EQ(recv(self->cfd, buf, send_len, 0), -1);
680
681 vec.iov_base = buf;
682 EXPECT_EQ(recvmsg(self->cfd, &msg, 0), send_len);
683 cmsg = CMSG_FIRSTHDR(&msg);
684 EXPECT_NE(cmsg, NULL);
685 EXPECT_EQ(cmsg->cmsg_level, SOL_TLS);
686 EXPECT_EQ(cmsg->cmsg_type, TLS_GET_RECORD_TYPE);
687 record_type = *((unsigned char *)CMSG_DATA(cmsg));
688 EXPECT_EQ(record_type, 100);
689 EXPECT_EQ(memcmp(buf, test_str, send_len), 0);
690}
691
692TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README
index 3a0336782d2d..49a6f8c3fdae 100644
--- a/tools/testing/selftests/tc-testing/README
+++ b/tools/testing/selftests/tc-testing/README
@@ -17,6 +17,10 @@ REQUIREMENTS
17* The kernel must have veth support available, as a veth pair is created 17* The kernel must have veth support available, as a veth pair is created
18 prior to running the tests. 18 prior to running the tests.
19 19
20* The kernel must have the appropriate infrastructure enabled to run all tdc
21 unit tests. See the config file in this directory for minimum required
22 features. As new tests will be added, config options list will be updated.
23
20* All tc-related features being tested must be built in or available as 24* All tc-related features being tested must be built in or available as
21 modules. To check what is required in current setup run: 25 modules. To check what is required in current setup run:
22 ./tdc.py -c 26 ./tdc.py -c
@@ -109,8 +113,8 @@ COMMAND LINE ARGUMENTS
109Run tdc.py -h to see the full list of available arguments. 113Run tdc.py -h to see the full list of available arguments.
110 114
111usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]] 115usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]]
112 [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] 116 [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] [-N]
113 [-d DEVICE] [-n NS] [-V] 117 [-d DEVICE] [-P] [-n] [-V]
114 118
115Linux TC unit tests 119Linux TC unit tests
116 120
@@ -118,8 +122,10 @@ optional arguments:
118 -h, --help show this help message and exit 122 -h, --help show this help message and exit
119 -p PATH, --path PATH The full path to the tc executable to use 123 -p PATH, --path PATH The full path to the tc executable to use
120 -v, --verbose Show the commands that are being run 124 -v, --verbose Show the commands that are being run
125 -N, --notap Suppress tap results for command under test
121 -d DEVICE, --device DEVICE 126 -d DEVICE, --device DEVICE
122 Execute the test case in flower category 127 Execute the test case in flower category
128 -P, --pause Pause execution just before post-suite stage
123 129
124selection: 130selection:
125 select which test cases: files plus directories; filtered by categories 131 select which test cases: files plus directories; filtered by categories
@@ -146,10 +152,10 @@ action:
146 -i, --id Generate ID numbers for new test cases 152 -i, --id Generate ID numbers for new test cases
147 153
148netns: 154netns:
149 options for nsPlugin(run commands in net namespace) 155 options for nsPlugin (run commands in net namespace)
150 156
151 -n NS, --namespace NS 157 -n, --namespace
152 Run commands in namespace NS 158 Run commands in namespace as specified in tdc_config.py
153 159
154valgrind: 160valgrind:
155 options for valgrindPlugin (run command under test under Valgrind) 161 options for valgrindPlugin (run command under test under Valgrind)
diff --git a/tools/testing/selftests/tc-testing/config b/tools/testing/selftests/tc-testing/config
new file mode 100644
index 000000000000..203302065458
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/config
@@ -0,0 +1,48 @@
1CONFIG_NET_SCHED=y
2
3#
4# Queueing/Scheduling
5#
6CONFIG_NET_SCH_PRIO=m
7CONFIG_NET_SCH_INGRESS=m
8
9#
10# Classification
11#
12CONFIG_NET_CLS=y
13CONFIG_NET_CLS_FW=m
14CONFIG_NET_CLS_U32=m
15CONFIG_CLS_U32_PERF=y
16CONFIG_CLS_U32_MARK=y
17CONFIG_NET_EMATCH=y
18CONFIG_NET_EMATCH_STACK=32
19CONFIG_NET_EMATCH_CMP=m
20CONFIG_NET_EMATCH_NBYTE=m
21CONFIG_NET_EMATCH_U32=m
22CONFIG_NET_EMATCH_META=m
23CONFIG_NET_EMATCH_TEXT=m
24CONFIG_NET_EMATCH_IPSET=m
25CONFIG_NET_EMATCH_IPT=m
26CONFIG_NET_CLS_ACT=y
27CONFIG_NET_ACT_POLICE=m
28CONFIG_NET_ACT_GACT=m
29CONFIG_GACT_PROB=y
30CONFIG_NET_ACT_MIRRED=m
31CONFIG_NET_ACT_SAMPLE=m
32CONFIG_NET_ACT_IPT=m
33CONFIG_NET_ACT_NAT=m
34CONFIG_NET_ACT_PEDIT=m
35CONFIG_NET_ACT_SIMP=m
36CONFIG_NET_ACT_SKBEDIT=m
37CONFIG_NET_ACT_CSUM=m
38CONFIG_NET_ACT_VLAN=m
39CONFIG_NET_ACT_BPF=m
40CONFIG_NET_ACT_CONNMARK=m
41CONFIG_NET_ACT_SKBMOD=m
42CONFIG_NET_ACT_IFE=m
43CONFIG_NET_ACT_TUNNEL_KEY=m
44CONFIG_NET_IFE_SKBMARK=m
45CONFIG_NET_IFE_SKBPRIO=m
46CONFIG_NET_IFE_SKBTCINDEX=m
47CONFIG_NET_CLS_IND=y
48CONFIG_NET_SCH_FIFO=y
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json
index 70952bd98ff9..13147a1f5731 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json
@@ -17,7 +17,7 @@
17 "cmdUnderTest": "$TC actions add action connmark", 17 "cmdUnderTest": "$TC actions add action connmark",
18 "expExitCode": "0", 18 "expExitCode": "0",
19 "verifyCmd": "$TC actions list action connmark", 19 "verifyCmd": "$TC actions list action connmark",
20 "matchPattern": "action order [0-9]+: connmark zone 0 pipe", 20 "matchPattern": "action order [0-9]+: connmark zone 0 pipe",
21 "matchCount": "1", 21 "matchCount": "1",
22 "teardown": [ 22 "teardown": [
23 "$TC actions flush action connmark" 23 "$TC actions flush action connmark"
@@ -41,7 +41,7 @@
41 "cmdUnderTest": "$TC actions add action connmark pass index 1", 41 "cmdUnderTest": "$TC actions add action connmark pass index 1",
42 "expExitCode": "0", 42 "expExitCode": "0",
43 "verifyCmd": "$TC actions get action connmark index 1", 43 "verifyCmd": "$TC actions get action connmark index 1",
44 "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref", 44 "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref",
45 "matchCount": "1", 45 "matchCount": "1",
46 "teardown": [ 46 "teardown": [
47 "$TC actions flush action connmark" 47 "$TC actions flush action connmark"
@@ -65,7 +65,7 @@
65 "cmdUnderTest": "$TC actions add action connmark drop index 100", 65 "cmdUnderTest": "$TC actions add action connmark drop index 100",
66 "expExitCode": "0", 66 "expExitCode": "0",
67 "verifyCmd": "$TC actions get action connmark index 100", 67 "verifyCmd": "$TC actions get action connmark index 100",
68 "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref", 68 "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref",
69 "matchCount": "1", 69 "matchCount": "1",
70 "teardown": [ 70 "teardown": [
71 "$TC actions flush action connmark" 71 "$TC actions flush action connmark"
@@ -89,7 +89,7 @@
89 "cmdUnderTest": "$TC actions add action connmark pipe index 455", 89 "cmdUnderTest": "$TC actions add action connmark pipe index 455",
90 "expExitCode": "0", 90 "expExitCode": "0",
91 "verifyCmd": "$TC actions get action connmark index 455", 91 "verifyCmd": "$TC actions get action connmark index 455",
92 "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref", 92 "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref",
93 "matchCount": "1", 93 "matchCount": "1",
94 "teardown": [ 94 "teardown": [
95 "$TC actions flush action connmark" 95 "$TC actions flush action connmark"
@@ -113,7 +113,7 @@
113 "cmdUnderTest": "$TC actions add action connmark reclassify index 7", 113 "cmdUnderTest": "$TC actions add action connmark reclassify index 7",
114 "expExitCode": "0", 114 "expExitCode": "0",
115 "verifyCmd": "$TC actions list action connmark", 115 "verifyCmd": "$TC actions list action connmark",
116 "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref", 116 "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref",
117 "matchCount": "1", 117 "matchCount": "1",
118 "teardown": [ 118 "teardown": [
119 "$TC actions flush action connmark" 119 "$TC actions flush action connmark"
@@ -137,7 +137,7 @@
137 "cmdUnderTest": "$TC actions add action connmark continue index 17", 137 "cmdUnderTest": "$TC actions add action connmark continue index 17",
138 "expExitCode": "0", 138 "expExitCode": "0",
139 "verifyCmd": "$TC actions list action connmark", 139 "verifyCmd": "$TC actions list action connmark",
140 "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref", 140 "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref",
141 "matchCount": "1", 141 "matchCount": "1",
142 "teardown": [ 142 "teardown": [
143 "$TC actions flush action connmark" 143 "$TC actions flush action connmark"
@@ -161,7 +161,7 @@
161 "cmdUnderTest": "$TC actions add action connmark jump 10 index 17", 161 "cmdUnderTest": "$TC actions add action connmark jump 10 index 17",
162 "expExitCode": "0", 162 "expExitCode": "0",
163 "verifyCmd": "$TC actions list action connmark", 163 "verifyCmd": "$TC actions list action connmark",
164 "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref", 164 "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref",
165 "matchCount": "1", 165 "matchCount": "1",
166 "teardown": [ 166 "teardown": [
167 "$TC actions flush action connmark" 167 "$TC actions flush action connmark"
@@ -185,7 +185,7 @@
185 "cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1", 185 "cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1",
186 "expExitCode": "0", 186 "expExitCode": "0",
187 "verifyCmd": "$TC actions get action connmark index 1", 187 "verifyCmd": "$TC actions get action connmark index 1",
188 "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref", 188 "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref",
189 "matchCount": "1", 189 "matchCount": "1",
190 "teardown": [ 190 "teardown": [
191 "$TC actions flush action connmark" 191 "$TC actions flush action connmark"
@@ -209,7 +209,7 @@
209 "cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21", 209 "cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21",
210 "expExitCode": "255", 210 "expExitCode": "255",
211 "verifyCmd": "$TC actions get action connmark index 1", 211 "verifyCmd": "$TC actions get action connmark index 1",
212 "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref", 212 "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref",
213 "matchCount": "0", 213 "matchCount": "0",
214 "teardown": [ 214 "teardown": [
215 "$TC actions flush action connmark" 215 "$TC actions flush action connmark"
@@ -233,7 +233,7 @@
233 "cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2", 233 "cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2",
234 "expExitCode": "255", 234 "expExitCode": "255",
235 "verifyCmd": "$TC actions get action connmark index 2", 235 "verifyCmd": "$TC actions get action connmark index 2",
236 "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref", 236 "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref",
237 "matchCount": "0", 237 "matchCount": "0",
238 "teardown": [ 238 "teardown": [
239 "$TC actions flush action connmark" 239 "$TC actions flush action connmark"
@@ -258,7 +258,7 @@
258 "cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555", 258 "cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555",
259 "expExitCode": "0", 259 "expExitCode": "0",
260 "verifyCmd": "$TC actions get action connmark index 555", 260 "verifyCmd": "$TC actions get action connmark index 555",
261 "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref", 261 "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref",
262 "matchCount": "1", 262 "matchCount": "1",
263 "teardown": [ 263 "teardown": [
264 "$TC actions flush action connmark" 264 "$TC actions flush action connmark"
@@ -282,7 +282,7 @@
282 "cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1", 282 "cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1",
283 "expExitCode": "0", 283 "expExitCode": "0",
284 "verifyCmd": "$TC actions get action connmark index 5", 284 "verifyCmd": "$TC actions get action connmark index 5",
285 "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1", 285 "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1",
286 "matchCount": "1", 286 "matchCount": "1",
287 "teardown": [ 287 "teardown": [
288 "$TC actions flush action connmark" 288 "$TC actions flush action connmark"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json
index 3a2f51fc7fd4..a022792d392a 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json
@@ -336,6 +336,30 @@
336 ] 336 ]
337 }, 337 },
338 { 338 {
339 "id": "b10b",
340 "name": "Add all 7 csum actions",
341 "category": [
342 "actions",
343 "csum"
344 ],
345 "setup": [
346 [
347 "$TC actions flush action csum",
348 0,
349 1,
350 255
351 ]
352 ],
353 "cmdUnderTest": "$TC actions add action csum icmp ip4h sctp igmp udplite udp tcp index 7",
354 "expExitCode": "0",
355 "verifyCmd": "$TC actions get action csum index 7",
356 "matchPattern": "action order [0-9]*: csum \\(iph, icmp, igmp, tcp, udp, udplite, sctp\\).*index 7 ref",
357 "matchCount": "1",
358 "teardown": [
359 "$TC actions flush action csum"
360 ]
361 },
362 {
339 "id": "ce92", 363 "id": "ce92",
340 "name": "Add csum udp action with cookie", 364 "name": "Add csum udp action with cookie",
341 "category": [ 365 "category": [
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
index 6e4edfae1799..db49fd0f8445 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json
@@ -44,7 +44,8 @@
44 "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref", 44 "matchPattern": "action order [0-9]*: mirred \\(Egress Redirect to device lo\\).*index 2 ref",
45 "matchCount": "1", 45 "matchCount": "1",
46 "teardown": [ 46 "teardown": [
47 "$TC actions flush action mirred" 47 "$TC actions flush action mirred",
48 "$TC actions flush action gact"
48 ] 49 ]
49 }, 50 },
50 { 51 {
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json b/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json
new file mode 100644
index 000000000000..0080dc2fd41c
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/nat.json
@@ -0,0 +1,593 @@
1[
2 {
3 "id": "7565",
4 "name": "Add nat action on ingress with default control action",
5 "category": [
6 "actions",
7 "nat"
8 ],
9 "setup": [
10 [
11 "$TC actions flush action nat",
12 0,
13 1,
14 255
15 ]
16 ],
17 "cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 200.200.200.1",
18 "expExitCode": "0",
19 "verifyCmd": "$TC actions ls action nat",
20 "matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 200.200.200.1 pass",
21 "matchCount": "1",
22 "teardown": [
23 "$TC actions flush action nat"
24 ]
25 },
26 {
27 "id": "fd79",
28 "name": "Add nat action on ingress with pipe control action",
29 "category": [
30 "actions",
31 "nat"
32 ],
33 "setup": [
34 [
35 "$TC actions flush action nat",
36 0,
37 1,
38 255
39 ]
40 ],
41 "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 2.2.2.1 pipe index 77",
42 "expExitCode": "0",
43 "verifyCmd": "$TC actions get action nat index 77",
44 "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 2.2.2.1 pipe.*index 77 ref",
45 "matchCount": "1",
46 "teardown": [
47 "$TC actions flush action nat"
48 ]
49 },
50 {
51 "id": "eab9",
52 "name": "Add nat action on ingress with continue control action",
53 "category": [
54 "actions",
55 "nat"
56 ],
57 "setup": [
58 [
59 "$TC actions flush action nat",
60 0,
61 1,
62 255
63 ]
64 ],
65 "cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 continue index 1000",
66 "expExitCode": "0",
67 "verifyCmd": "$TC actions get action nat index 1000",
68 "matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 continue.*index 1000 ref",
69 "matchCount": "1",
70 "teardown": [
71 "$TC actions flush action nat"
72 ]
73 },
74 {
75 "id": "c53a",
76 "name": "Add nat action on ingress with reclassify control action",
77 "category": [
78 "actions",
79 "nat"
80 ],
81 "setup": [
82 [
83 "$TC actions flush action nat",
84 0,
85 1,
86 255
87 ]
88 ],
89 "cmdUnderTest": "$TC actions add action nat ingress 192.168.10.10 192.168.20.20 reclassify index 1000",
90 "expExitCode": "0",
91 "verifyCmd": "$TC actions get action nat index 1000",
92 "matchPattern": "action order [0-9]+: nat ingress 192.168.10.10/32 192.168.20.20 reclassify.*index 1000 ref",
93 "matchCount": "1",
94 "teardown": [
95 "$TC actions flush action nat"
96 ]
97 },
98 {
99 "id": "76c9",
100 "name": "Add nat action on ingress with jump control action",
101 "category": [
102 "actions",
103 "nat"
104 ],
105 "setup": [
106 [
107 "$TC actions flush action nat",
108 0,
109 1,
110 255
111 ]
112 ],
113 "cmdUnderTest": "$TC actions add action nat ingress 12.18.10.10 12.18.20.20 jump 10 index 22",
114 "expExitCode": "0",
115 "verifyCmd": "$TC actions get action nat index 22",
116 "matchPattern": "action order [0-9]+: nat ingress 12.18.10.10/32 12.18.20.20 jump 10.*index 22 ref",
117 "matchCount": "1",
118 "teardown": [
119 "$TC actions flush action nat"
120 ]
121 },
122 {
123 "id": "24c6",
124 "name": "Add nat action on ingress with drop control action",
125 "category": [
126 "actions",
127 "nat"
128 ],
129 "setup": [
130 [
131 "$TC actions flush action nat",
132 0,
133 1,
134 255
135 ]
136 ],
137 "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 drop index 722",
138 "expExitCode": "0",
139 "verifyCmd": "$TC actions get action nat index 722",
140 "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 drop.*index 722 ref",
141 "matchCount": "1",
142 "teardown": [
143 "$TC actions flush action nat"
144 ]
145 },
146 {
147 "id": "2120",
148 "name": "Add nat action on ingress with maximum index value",
149 "category": [
150 "actions",
151 "nat"
152 ],
153 "setup": [
154 [
155 "$TC actions flush action nat",
156 0,
157 1,
158 255
159 ]
160 ],
161 "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295",
162 "expExitCode": "0",
163 "verifyCmd": "$TC actions get action nat index 4294967295",
164 "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295 ref",
165 "matchCount": "1",
166 "teardown": [
167 "$TC actions flush action nat"
168 ]
169 },
170 {
171 "id": "3e9d",
172 "name": "Add nat action on ingress with invalid index value",
173 "category": [
174 "actions",
175 "nat"
176 ],
177 "setup": [
178 [
179 "$TC actions flush action nat",
180 0,
181 1,
182 255
183 ]
184 ],
185 "cmdUnderTest": "$TC actions add action nat ingress 1.18.1.1 1.18.2.2 index 4294967295555",
186 "expExitCode": "255",
187 "verifyCmd": "$TC actions get action nat index 4294967295555",
188 "matchPattern": "action order [0-9]+: nat ingress 1.18.1.1/32 1.18.2.2 pass.*index 4294967295555 ref",
189 "matchCount": "0",
190 "teardown": [
191 [
192 "$TC actions flush action nat",
193 0,
194 1,
195 255
196 ]
197 ]
198 },
199 {
200 "id": "f6c9",
201 "name": "Add nat action on ingress with invalid IP address",
202 "category": [
203 "actions",
204 "nat"
205 ],
206 "setup": [
207 [
208 "$TC actions flush action nat",
209 0,
210 1,
211 255
212 ]
213 ],
214 "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.1888.2.2 index 7",
215 "expExitCode": "255",
216 "verifyCmd": "$TC actions get action nat index 7",
217 "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.1888.2.2 pass.*index 7 ref",
218 "matchCount": "0",
219 "teardown": [
220 [
221 "$TC actions flush action nat",
222 0,
223 1,
224 255
225 ]
226 ]
227 },
228 {
229 "id": "be25",
230 "name": "Add nat action on ingress with invalid argument",
231 "category": [
232 "actions",
233 "nat"
234 ],
235 "setup": [
236 [
237 "$TC actions flush action nat",
238 0,
239 1,
240 255
241 ]
242 ],
243 "cmdUnderTest": "$TC actions add action nat ingress 1.1.1.1 1.18.2.2 another_arg index 12",
244 "expExitCode": "255",
245 "verifyCmd": "$TC actions get action nat index 12",
246 "matchPattern": "action order [0-9]+: nat ingress 1.1.1.1/32 1.18.2.2 pass.*another_arg.*index 12 ref",
247 "matchCount": "0",
248 "teardown": [
249 [
250 "$TC actions flush action nat",
251 0,
252 1,
253 255
254 ]
255 ]
256 },
257 {
258 "id": "a7bd",
259 "name": "Add nat action on ingress with DEFAULT IP address",
260 "category": [
261 "actions",
262 "nat"
263 ],
264 "setup": [
265 [
266 "$TC actions flush action nat",
267 0,
268 1,
269 255
270 ]
271 ],
272 "cmdUnderTest": "$TC actions add action nat ingress default 10.10.10.1 index 12",
273 "expExitCode": "0",
274 "verifyCmd": "$TC actions get action nat index 12",
275 "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
276 "matchCount": "1",
277 "teardown": [
278 "$TC actions flush action nat"
279 ]
280 },
281 {
282 "id": "ee1e",
283 "name": "Add nat action on ingress with ANY IP address",
284 "category": [
285 "actions",
286 "nat"
287 ],
288 "setup": [
289 [
290 "$TC actions flush action nat",
291 0,
292 1,
293 255
294 ]
295 ],
296 "cmdUnderTest": "$TC actions add action nat ingress any 10.10.10.1 index 12",
297 "expExitCode": "0",
298 "verifyCmd": "$TC actions get action nat index 12",
299 "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
300 "matchCount": "1",
301 "teardown": [
302 "$TC actions flush action nat"
303 ]
304 },
305 {
306 "id": "1de8",
307 "name": "Add nat action on ingress with ALL IP address",
308 "category": [
309 "actions",
310 "nat"
311 ],
312 "setup": [
313 [
314 "$TC actions flush action nat",
315 0,
316 1,
317 255
318 ]
319 ],
320 "cmdUnderTest": "$TC actions add action nat ingress all 10.10.10.1 index 12",
321 "expExitCode": "0",
322 "verifyCmd": "$TC actions get action nat index 12",
323 "matchPattern": "action order [0-9]+: nat ingress 0.0.0.0/32 10.10.10.1 pass.*index 12 ref",
324 "matchCount": "1",
325 "teardown": [
326 "$TC actions flush action nat"
327 ]
328 },
329 {
330 "id": "8dba",
331 "name": "Add nat action on egress with default control action",
332 "category": [
333 "actions",
334 "nat"
335 ],
336 "setup": [
337 [
338 "$TC actions flush action nat",
339 0,
340 1,
341 255
342 ]
343 ],
344 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1",
345 "expExitCode": "0",
346 "verifyCmd": "$TC actions ls action nat",
347 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pass",
348 "matchCount": "1",
349 "teardown": [
350 "$TC actions flush action nat"
351 ]
352 },
353 {
354 "id": "19a7",
355 "name": "Add nat action on egress with pipe control action",
356 "category": [
357 "actions",
358 "nat"
359 ],
360 "setup": [
361 [
362 "$TC actions flush action nat",
363 0,
364 1,
365 255
366 ]
367 ],
368 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 pipe",
369 "expExitCode": "0",
370 "verifyCmd": "$TC actions ls action nat",
371 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 pipe",
372 "matchCount": "1",
373 "teardown": [
374 "$TC actions flush action nat"
375 ]
376 },
377 {
378 "id": "f1d9",
379 "name": "Add nat action on egress with continue control action",
380 "category": [
381 "actions",
382 "nat"
383 ],
384 "setup": [
385 [
386 "$TC actions flush action nat",
387 0,
388 1,
389 255
390 ]
391 ],
392 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 continue",
393 "expExitCode": "0",
394 "verifyCmd": "$TC actions ls action nat",
395 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 continue",
396 "matchCount": "1",
397 "teardown": [
398 "$TC actions flush action nat"
399 ]
400 },
401 {
402 "id": "6d4a",
403 "name": "Add nat action on egress with reclassify control action",
404 "category": [
405 "actions",
406 "nat"
407 ],
408 "setup": [
409 [
410 "$TC actions flush action nat",
411 0,
412 1,
413 255
414 ]
415 ],
416 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 reclassify",
417 "expExitCode": "0",
418 "verifyCmd": "$TC actions ls action nat",
419 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 reclassify",
420 "matchCount": "1",
421 "teardown": [
422 "$TC actions flush action nat"
423 ]
424 },
425 {
426 "id": "b313",
427 "name": "Add nat action on egress with jump control action",
428 "category": [
429 "actions",
430 "nat"
431 ],
432 "setup": [
433 [
434 "$TC actions flush action nat",
435 0,
436 1,
437 255
438 ]
439 ],
440 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 jump 777",
441 "expExitCode": "0",
442 "verifyCmd": "$TC actions ls action nat",
443 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 jump 777",
444 "matchCount": "1",
445 "teardown": [
446 "$TC actions flush action nat"
447 ]
448 },
449 {
450 "id": "d9fc",
451 "name": "Add nat action on egress with drop control action",
452 "category": [
453 "actions",
454 "nat"
455 ],
456 "setup": [
457 [
458 "$TC actions flush action nat",
459 0,
460 1,
461 255
462 ]
463 ],
464 "cmdUnderTest": "$TC actions add action nat egress 10.10.10.1 20.20.20.1 drop",
465 "expExitCode": "0",
466 "verifyCmd": "$TC actions ls action nat",
467 "matchPattern": "action order [0-9]+: nat egress 10.10.10.1/32 20.20.20.1 drop",
468 "matchCount": "1",
469 "teardown": [
470 "$TC actions flush action nat"
471 ]
472 },
473 {
474 "id": "a895",
475 "name": "Add nat action on egress with DEFAULT IP address",
476 "category": [
477 "actions",
478 "nat"
479 ],
480 "setup": [
481 [
482 "$TC actions flush action nat",
483 0,
484 1,
485 255
486 ]
487 ],
488 "cmdUnderTest": "$TC actions add action nat egress default 20.20.20.1 pipe index 10",
489 "expExitCode": "0",
490 "verifyCmd": "$TC actions get action nat index 10",
491 "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
492 "matchCount": "1",
493 "teardown": [
494 "$TC actions flush action nat"
495 ]
496 },
497 {
498 "id": "2572",
499 "name": "Add nat action on egress with ANY IP address",
500 "category": [
501 "actions",
502 "nat"
503 ],
504 "setup": [
505 [
506 "$TC actions flush action nat",
507 0,
508 1,
509 255
510 ]
511 ],
512 "cmdUnderTest": "$TC actions add action nat egress any 20.20.20.1 pipe index 10",
513 "expExitCode": "0",
514 "verifyCmd": "$TC actions get action nat index 10",
515 "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
516 "matchCount": "1",
517 "teardown": [
518 "$TC actions flush action nat"
519 ]
520 },
521 {
522 "id": "37f3",
523 "name": "Add nat action on egress with ALL IP address",
524 "category": [
525 "actions",
526 "nat"
527 ],
528 "setup": [
529 [
530 "$TC actions flush action nat",
531 0,
532 1,
533 255
534 ]
535 ],
536 "cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10",
537 "expExitCode": "0",
538 "verifyCmd": "$TC actions get action nat index 10",
539 "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref",
540 "matchCount": "1",
541 "teardown": [
542 "$TC actions flush action nat"
543 ]
544 },
545 {
546 "id": "6054",
547 "name": "Add nat action on egress with cookie",
548 "category": [
549 "actions",
550 "nat"
551 ],
552 "setup": [
553 [
554 "$TC actions flush action nat",
555 0,
556 1,
557 255
558 ]
559 ],
560 "cmdUnderTest": "$TC actions add action nat egress all 20.20.20.1 pipe index 10 cookie aa1bc2d3eeff112233445566778800a1",
561 "expExitCode": "0",
562 "verifyCmd": "$TC actions get action nat index 10",
563 "matchPattern": "action order [0-9]+: nat egress 0.0.0.0/32 20.20.20.1 pipe.*index 10 ref.*cookie aa1bc2d3eeff112233445566778800a1",
564 "matchCount": "1",
565 "teardown": [
566 "$TC actions flush action nat"
567 ]
568 },
569 {
570 "id": "79d6",
571 "name": "Add nat action on ingress with cookie",
572 "category": [
573 "actions",
574 "nat"
575 ],
576 "setup": [
577 [
578 "$TC actions flush action nat",
579 0,
580 1,
581 255
582 ]
583 ],
584 "cmdUnderTest": "$TC actions add action nat ingress 192.168.1.1 10.10.10.1 reclassify index 1 cookie 112233445566778899aabbccddeeff11",
585 "expExitCode": "0",
586 "verifyCmd": "$TC actions get action nat index 1",
587 "matchPattern": "action order [0-9]+: nat ingress 192.168.1.1/32 10.10.10.1 reclassify.*index 1 ref.*cookie 112233445566778899aabbccddeeff11",
588 "matchCount": "1",
589 "teardown": [
590 "$TC actions flush action nat"
591 ]
592 }
593]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json
index 37ecc2716fee..5aaf593b914a 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json
@@ -17,7 +17,7 @@
17 "cmdUnderTest": "$TC actions add action skbedit mark 1", 17 "cmdUnderTest": "$TC actions add action skbedit mark 1",
18 "expExitCode": "0", 18 "expExitCode": "0",
19 "verifyCmd": "$TC actions list action skbedit", 19 "verifyCmd": "$TC actions list action skbedit",
20 "matchPattern": "action order [0-9]*: skbedit mark 1", 20 "matchPattern": "action order [0-9]*: skbedit mark 1",
21 "matchCount": "1", 21 "matchCount": "1",
22 "teardown": [ 22 "teardown": [
23 "$TC actions flush action skbedit" 23 "$TC actions flush action skbedit"
@@ -65,7 +65,7 @@
65 "cmdUnderTest": "$TC actions add action skbedit prio 99", 65 "cmdUnderTest": "$TC actions add action skbedit prio 99",
66 "expExitCode": "0", 66 "expExitCode": "0",
67 "verifyCmd": "$TC actions list action skbedit", 67 "verifyCmd": "$TC actions list action skbedit",
68 "matchPattern": "action order [0-9]*: skbedit priority :99", 68 "matchPattern": "action order [0-9]*: skbedit priority :99",
69 "matchCount": "1", 69 "matchCount": "1",
70 "teardown": [ 70 "teardown": [
71 "$TC actions flush action skbedit" 71 "$TC actions flush action skbedit"
@@ -113,7 +113,7 @@
113 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909", 113 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 909",
114 "expExitCode": "0", 114 "expExitCode": "0",
115 "verifyCmd": "$TC actions list action skbedit", 115 "verifyCmd": "$TC actions list action skbedit",
116 "matchPattern": "action order [0-9]*: skbedit queue_mapping 909", 116 "matchPattern": "action order [0-9]*: skbedit queue_mapping 909",
117 "matchCount": "1", 117 "matchCount": "1",
118 "teardown": [ 118 "teardown": [
119 "$TC actions flush action skbedit" 119 "$TC actions flush action skbedit"
@@ -161,7 +161,7 @@
161 "cmdUnderTest": "$TC actions add action skbedit ptype host", 161 "cmdUnderTest": "$TC actions add action skbedit ptype host",
162 "expExitCode": "0", 162 "expExitCode": "0",
163 "verifyCmd": "$TC actions list action skbedit", 163 "verifyCmd": "$TC actions list action skbedit",
164 "matchPattern": "action order [0-9]*: skbedit ptype host", 164 "matchPattern": "action order [0-9]*: skbedit ptype host",
165 "matchCount": "1", 165 "matchCount": "1",
166 "teardown": [ 166 "teardown": [
167 "$TC actions flush action skbedit" 167 "$TC actions flush action skbedit"
@@ -185,7 +185,7 @@
185 "cmdUnderTest": "$TC actions add action skbedit ptype otherhost", 185 "cmdUnderTest": "$TC actions add action skbedit ptype otherhost",
186 "expExitCode": "0", 186 "expExitCode": "0",
187 "verifyCmd": "$TC actions list action skbedit", 187 "verifyCmd": "$TC actions list action skbedit",
188 "matchPattern": "action order [0-9]*: skbedit ptype otherhost", 188 "matchPattern": "action order [0-9]*: skbedit ptype otherhost",
189 "matchCount": "1", 189 "matchCount": "1",
190 "teardown": [ 190 "teardown": [
191 "$TC actions flush action skbedit" 191 "$TC actions flush action skbedit"
@@ -233,7 +233,7 @@
233 "cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11", 233 "cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11",
234 "expExitCode": "0", 234 "expExitCode": "0",
235 "verifyCmd": "$TC actions get action skbedit index 11", 235 "verifyCmd": "$TC actions get action skbedit index 11",
236 "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref", 236 "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref",
237 "matchCount": "1", 237 "matchCount": "1",
238 "teardown": [ 238 "teardown": [
239 "$TC actions flush action skbedit" 239 "$TC actions flush action skbedit"
@@ -257,7 +257,7 @@
257 "cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90", 257 "cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90",
258 "expExitCode": "0", 258 "expExitCode": "0",
259 "verifyCmd": "$TC actions get action skbedit index 90", 259 "verifyCmd": "$TC actions get action skbedit index 90",
260 "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref", 260 "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref",
261 "matchCount": "1", 261 "matchCount": "1",
262 "teardown": [ 262 "teardown": [
263 "$TC actions flush action skbedit" 263 "$TC actions flush action skbedit"
@@ -281,7 +281,7 @@
281 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271", 281 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271",
282 "expExitCode": "0", 282 "expExitCode": "0",
283 "verifyCmd": "$TC actions get action skbedit index 271", 283 "verifyCmd": "$TC actions get action skbedit index 271",
284 "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref", 284 "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref",
285 "matchCount": "1", 285 "matchCount": "1",
286 "teardown": [ 286 "teardown": [
287 "$TC actions flush action skbedit" 287 "$TC actions flush action skbedit"
@@ -305,7 +305,7 @@
305 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271", 305 "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271",
306 "expExitCode": "0", 306 "expExitCode": "0",
307 "verifyCmd": "$TC actions get action skbedit index 271", 307 "verifyCmd": "$TC actions get action skbedit index 271",
308 "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref", 308 "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref",
309 "matchCount": "1", 309 "matchCount": "1",
310 "teardown": [ 310 "teardown": [
311 "$TC actions flush action skbedit" 311 "$TC actions flush action skbedit"
@@ -329,7 +329,7 @@
329 "cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2", 329 "cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2",
330 "expExitCode": "0", 330 "expExitCode": "0",
331 "verifyCmd": "$TC actions get action skbedit index 2", 331 "verifyCmd": "$TC actions get action skbedit index 2",
332 "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref", 332 "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref",
333 "matchCount": "1", 333 "matchCount": "1",
334 "teardown": [ 334 "teardown": [
335 "$TC actions flush action skbedit" 335 "$TC actions flush action skbedit"
@@ -353,7 +353,7 @@
353 "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32", 353 "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32",
354 "expExitCode": "0", 354 "expExitCode": "0",
355 "verifyCmd": "$TC actions get action skbedit index 32", 355 "verifyCmd": "$TC actions get action skbedit index 32",
356 "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref", 356 "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref",
357 "matchCount": "1", 357 "matchCount": "1",
358 "teardown": [ 358 "teardown": [
359 "$TC actions flush action skbedit" 359 "$TC actions flush action skbedit"
@@ -377,7 +377,7 @@
377 "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef", 377 "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef",
378 "expExitCode": "0", 378 "expExitCode": "0",
379 "verifyCmd": "$TC actions get action skbedit index 32", 379 "verifyCmd": "$TC actions get action skbedit index 32",
380 "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef", 380 "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef",
381 "matchCount": "1", 381 "matchCount": "1",
382 "teardown": [ 382 "teardown": [
383 "$TC actions flush action skbedit" 383 "$TC actions flush action skbedit"
@@ -405,7 +405,7 @@
405 "cmdUnderTest": "$TC actions list action skbedit", 405 "cmdUnderTest": "$TC actions list action skbedit",
406 "expExitCode": "0", 406 "expExitCode": "0",
407 "verifyCmd": "$TC actions list action skbedit", 407 "verifyCmd": "$TC actions list action skbedit",
408 "matchPattern": "action order [0-9]*: skbedit", 408 "matchPattern": "action order [0-9]*: skbedit",
409 "matchCount": "4", 409 "matchCount": "4",
410 "teardown": [ 410 "teardown": [
411 "$TC actions flush action skbedit" 411 "$TC actions flush action skbedit"
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json
new file mode 100644
index 000000000000..10b2d894e436
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/tunnel_key.json
@@ -0,0 +1,917 @@
1[
2 {
3 "id": "2b11",
4 "name": "Add tunnel_key set action with mandatory parameters",
5 "category": [
6 "actions",
7 "tunnel_key"
8 ],
9 "setup": [
10 [
11 "$TC actions flush action tunnel_key",
12 0,
13 1,
14 255
15 ]
16 ],
17 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1",
18 "expExitCode": "0",
19 "verifyCmd": "$TC actions list action tunnel_key",
20 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1",
21 "matchCount": "1",
22 "teardown": [
23 "$TC actions flush action tunnel_key"
24 ]
25 },
26 {
27 "id": "dc6b",
28 "name": "Add tunnel_key set action with missing mandatory src_ip parameter",
29 "category": [
30 "actions",
31 "tunnel_key"
32 ],
33 "setup": [
34 [
35 "$TC actions flush action tunnel_key",
36 0,
37 1,
38 255
39 ]
40 ],
41 "cmdUnderTest": "$TC actions add action tunnel_key set dst_ip 20.20.20.2 id 100",
42 "expExitCode": "255",
43 "verifyCmd": "$TC actions list action tunnel_key",
44 "matchPattern": "action order [0-9]+: tunnel_key set.*dst_ip 20.20.20.2.*key_id 100",
45 "matchCount": "0",
46 "teardown": [
47 [
48 "$TC actions flush action tunnel_key",
49 0,
50 1,
51 255
52 ]
53 ]
54 },
55 {
56 "id": "7f25",
57 "name": "Add tunnel_key set action with missing mandatory dst_ip parameter",
58 "category": [
59 "actions",
60 "tunnel_key"
61 ],
62 "setup": [
63 [
64 "$TC actions flush action tunnel_key",
65 0,
66 1,
67 255
68 ]
69 ],
70 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 id 100",
71 "expExitCode": "255",
72 "verifyCmd": "$TC actions list action tunnel_key",
73 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*key_id 100",
74 "matchCount": "0",
75 "teardown": [
76 [
77 "$TC actions flush action tunnel_key",
78 0,
79 1,
80 255
81 ]
82 ]
83 },
84 {
85 "id": "ba4e",
86 "name": "Add tunnel_key set action with missing mandatory id parameter",
87 "category": [
88 "actions",
89 "tunnel_key"
90 ],
91 "setup": [
92 [
93 "$TC actions flush action tunnel_key",
94 0,
95 1,
96 255
97 ]
98 ],
99 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2",
100 "expExitCode": "255",
101 "verifyCmd": "$TC actions list action tunnel_key",
102 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2",
103 "matchCount": "0",
104 "teardown": [
105 [
106 "$TC actions flush action tunnel_key",
107 0,
108 1,
109 255
110 ]
111 ]
112 },
113 {
114 "id": "a5e0",
115 "name": "Add tunnel_key set action with invalid src_ip parameter",
116 "category": [
117 "actions",
118 "tunnel_key"
119 ],
120 "setup": [
121 [
122 "$TC actions flush action tunnel_key",
123 0,
124 1,
125 255
126 ]
127 ],
128 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 300.168.100.1 dst_ip 192.168.200.1 id 7 index 1",
129 "expExitCode": "1",
130 "verifyCmd": "$TC actions get action tunnel_key index 1",
131 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 300.168.100.1.*dst_ip 192.168.200.1.*key_id 7.*index 1 ref",
132 "matchCount": "0",
133 "teardown": [
134 [
135 "$TC actions flush action tunnel_key",
136 0,
137 1,
138 255
139 ]
140 ]
141 },
142 {
143 "id": "eaa8",
144 "name": "Add tunnel_key set action with invalid dst_ip parameter",
145 "category": [
146 "actions",
147 "tunnel_key"
148 ],
149 "setup": [
150 [
151 "$TC actions flush action tunnel_key",
152 0,
153 1,
154 255
155 ]
156 ],
157 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.800.1 id 10 index 11",
158 "expExitCode": "1",
159 "verifyCmd": "$TC actions get action tunnel_key index 11",
160 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 192.168.100.1.*dst_ip 192.168.800.1.*key_id 10.*index 11 ref",
161 "matchCount": "0",
162 "teardown": [
163 [
164 "$TC actions flush action tunnel_key",
165 0,
166 1,
167 255
168 ]
169 ]
170 },
171 {
172 "id": "3b09",
173 "name": "Add tunnel_key set action with invalid id parameter",
174 "category": [
175 "actions",
176 "tunnel_key"
177 ],
178 "setup": [
179 [
180 "$TC actions flush action tunnel_key",
181 0,
182 1,
183 255
184 ]
185 ],
186 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 112233445566778899 index 1",
187 "expExitCode": "255",
188 "verifyCmd": "$TC actions get action tunnel_key index 1",
189 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 112233445566778899.*index 1 ref",
190 "matchCount": "0",
191 "teardown": [
192 [
193 "$TC actions flush action tunnel_key",
194 0,
195 1,
196 255
197 ]
198 ]
199 },
200 {
201 "id": "9625",
202 "name": "Add tunnel_key set action with invalid dst_port parameter",
203 "category": [
204 "actions",
205 "tunnel_key"
206 ],
207 "setup": [
208 [
209 "$TC actions flush action tunnel_key",
210 0,
211 1,
212 255
213 ]
214 ],
215 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 dst_port 998877 index 1",
216 "expExitCode": "255",
217 "verifyCmd": "$TC actions get action tunnel_key index 1",
218 "matchPattern": "action order [0-9]+: tunnel_key set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 11.*dst_port 998877.*index 1 ref",
219 "matchCount": "0",
220 "teardown": [
221 [
222 "$TC actions flush action tunnel_key",
223 0,
224 1,
225 255
226 ]
227 ]
228 },
229 {
230 "id": "05af",
231 "name": "Add tunnel_key set action with optional dst_port parameter",
232 "category": [
233 "actions",
234 "tunnel_key"
235 ],
236 "setup": [
237 [
238 "$TC actions flush action tunnel_key",
239 0,
240 1,
241 255
242 ]
243 ],
244 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.100.1 dst_ip 192.168.200.1 id 789 dst_port 4000 index 10",
245 "expExitCode": "0",
246 "verifyCmd": "$TC actions get action tunnel_key index 10",
247 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.100.1.*dst_ip 192.168.200.1.*key_id 789.*dst_port 4000.*index 10 ref",
248 "matchCount": "1",
249 "teardown": [
250 "$TC actions flush action tunnel_key"
251 ]
252 },
253 {
254 "id": "da80",
255 "name": "Add tunnel_key set action with index at 32-bit maximum",
256 "category": [
257 "actions",
258 "tunnel_key"
259 ],
260 "setup": [
261 [
262 "$TC actions flush action tunnel_key",
263 0,
264 1,
265 255
266 ]
267 ],
268 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295",
269 "expExitCode": "0",
270 "verifyCmd": "$TC actions get action tunnel_key index 4294967295",
271 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*id 11.*index 4294967295 ref",
272 "matchCount": "1",
273 "teardown": [
274 "$TC actions flush action tunnel_key"
275 ]
276 },
277 {
278 "id": "d407",
279 "name": "Add tunnel_key set action with index exceeding 32-bit maximum",
280 "category": [
281 "actions",
282 "tunnel_key"
283 ],
284 "setup": [
285 [
286 "$TC actions flush action tunnel_key",
287 0,
288 1,
289 255
290 ]
291 ],
292 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 11 index 4294967295678",
293 "expExitCode": "255",
294 "verifyCmd": "$TC actions get action tunnel_key index 4294967295678",
295 "matchPattern": "action order [0-9]+: tunnel_key set.*index 4294967295678 ref",
296 "matchCount": "0",
297 "teardown": [
298 [
299 "$TC actions flush action tunnel_key",
300 0,
301 1,
302 255
303 ]
304 ]
305 },
306 {
307 "id": "5cba",
308 "name": "Add tunnel_key set action with id value at 32-bit maximum",
309 "category": [
310 "actions",
311 "tunnel_key"
312 ],
313 "setup": [
314 [
315 "$TC actions flush action tunnel_key",
316 0,
317 1,
318 255
319 ]
320 ],
321 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 4294967295 index 1",
322 "expExitCode": "0",
323 "verifyCmd": "$TC actions get action tunnel_key index 1",
324 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 4294967295.*index 1",
325 "matchCount": "1",
326 "teardown": [
327 "$TC actions flush action tunnel_key"
328 ]
329 },
330 {
331 "id": "e84a",
332 "name": "Add tunnel_key set action with id value exceeding 32-bit maximum",
333 "category": [
334 "actions",
335 "tunnel_key"
336 ],
337 "setup": [
338 [
339 "$TC actions flush action tunnel_key",
340 0,
341 1,
342 255
343 ]
344 ],
345 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42949672955 index 1",
346 "expExitCode": "255",
347 "verifyCmd": "$TC actions get action tunnel_key index 4294967295",
348 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42949672955.*index 1",
349 "matchCount": "0",
350 "teardown": [
351 [
352 "$TC actions flush action tunnel_key",
353 0,
354 1,
355 255
356 ]
357 ]
358 },
359 {
360 "id": "9c19",
361 "name": "Add tunnel_key set action with dst_port value at 16-bit maximum",
362 "category": [
363 "actions",
364 "tunnel_key"
365 ],
366 "setup": [
367 [
368 "$TC actions flush action tunnel_key",
369 0,
370 1,
371 255
372 ]
373 ],
374 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535 index 1",
375 "expExitCode": "0",
376 "verifyCmd": "$TC actions get action tunnel_key index 1",
377 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535.*index 1",
378 "matchCount": "1",
379 "teardown": [
380 "$TC actions flush action tunnel_key"
381 ]
382 },
383 {
384 "id": "3bd9",
385 "name": "Add tunnel_key set action with dst_port value exceeding 16-bit maximum",
386 "category": [
387 "actions",
388 "tunnel_key"
389 ],
390 "setup": [
391 [
392 "$TC actions flush action tunnel_key",
393 0,
394 1,
395 255
396 ]
397 ],
398 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 429 dst_port 65535789 index 1",
399 "expExitCode": "255",
400 "verifyCmd": "$TC actions get action tunnel_key index 1",
401 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 429.*dst_port 65535789.*index 1",
402 "matchCount": "0",
403 "teardown": [
404 [
405 "$TC actions flush action tunnel_key",
406 0,
407 1,
408 255
409 ]
410 ]
411 },
412 {
413 "id": "68e2",
414 "name": "Add tunnel_key unset action",
415 "category": [
416 "actions",
417 "tunnel_key"
418 ],
419 "setup": [
420 [
421 "$TC actions flush action tunnel_key",
422 0,
423 1,
424 255
425 ]
426 ],
427 "cmdUnderTest": "$TC actions add action tunnel_key unset index 1",
428 "expExitCode": "0",
429 "verifyCmd": "$TC actions get action tunnel_key index 1",
430 "matchPattern": "action order [0-9]+: tunnel_key.*unset.*index 1 ref",
431 "matchCount": "1",
432 "teardown": [
433 "$TC actions flush action tunnel_key"
434 ]
435 },
436 {
437 "id": "6192",
438 "name": "Add tunnel_key unset continue action",
439 "category": [
440 "actions",
441 "tunnel_key"
442 ],
443 "setup": [
444 [
445 "$TC actions flush action tunnel_key",
446 0,
447 1,
448 255
449 ]
450 ],
451 "cmdUnderTest": "$TC actions add action tunnel_key unset continue index 1",
452 "expExitCode": "0",
453 "verifyCmd": "$TC actions get action tunnel_key index 1",
454 "matchPattern": "action order [0-9]+: tunnel_key.*unset continue.*index 1 ref",
455 "matchCount": "1",
456 "teardown": [
457 "$TC actions flush action tunnel_key"
458 ]
459 },
460 {
461 "id": "061d",
462 "name": "Add tunnel_key set continue action with cookie",
463 "category": [
464 "actions",
465 "tunnel_key"
466 ],
467 "setup": [
468 [
469 "$TC actions flush action tunnel_key",
470 0,
471 1,
472 255
473 ]
474 ],
475 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
476 "expExitCode": "0",
477 "verifyCmd": "$TC actions get action tunnel_key index 1",
478 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
479 "matchCount": "1",
480 "teardown": [
481 "$TC actions flush action tunnel_key"
482 ]
483 },
484 {
485 "id": "8acb",
486 "name": "Add tunnel_key set continue action with invalid cookie",
487 "category": [
488 "actions",
489 "tunnel_key"
490 ],
491 "setup": [
492 [
493 "$TC actions flush action tunnel_key",
494 0,
495 1,
496 255
497 ]
498 ],
499 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 192.168.10.1 dst_ip 192.168.20.2 id 123 continue index 1 cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
500 "expExitCode": "255",
501 "verifyCmd": "$TC actions get action tunnel_key index 1",
502 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 192.168.10.1.*dst_ip 192.168.20.2.*key_id 123.*csum continue.*index 1.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
503 "matchCount": "0",
504 "teardown": [
505 [
506 "$TC actions flush action tunnel_key",
507 0,
508 1,
509 255
510 ]
511 ]
512 },
513 {
514 "id": "a07e",
515 "name": "Add tunnel_key action with no set/unset command specified",
516 "category": [
517 "actions",
518 "tunnel_key"
519 ],
520 "setup": [
521 [
522 "$TC actions flush action tunnel_key",
523 0,
524 1,
525 255
526 ]
527 ],
528 "cmdUnderTest": "$TC actions add action tunnel_key src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1",
529 "expExitCode": "255",
530 "verifyCmd": "$TC actions get action tunnel_key index 1",
531 "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1",
532 "matchCount": "0",
533 "teardown": [
534 [
535 "$TC actions flush action tunnel_key",
536 0,
537 1,
538 255
539 ]
540 ]
541 },
542 {
543 "id": "b227",
544 "name": "Add tunnel_key action with csum option",
545 "category": [
546 "actions",
547 "tunnel_key"
548 ],
549 "setup": [
550 [
551 "$TC actions flush action tunnel_key",
552 0,
553 1,
554 255
555 ]
556 ],
557 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 id 1 csum index 99",
558 "expExitCode": "0",
559 "verifyCmd": "$TC actions get action tunnel_key index 99",
560 "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*csum pipe.*index 99",
561 "matchCount": "1",
562 "teardown": [
563 "$TC actions flush action tunnel_key"
564 ]
565 },
566 {
567 "id": "58a7",
568 "name": "Add tunnel_key action with nocsum option",
569 "category": [
570 "actions",
571 "tunnel_key"
572 ],
573 "setup": [
574 [
575 "$TC actions flush action tunnel_key",
576 0,
577 1,
578 255
579 ]
580 ],
581 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7823 nocsum index 234",
582 "expExitCode": "0",
583 "verifyCmd": "$TC actions get action tunnel_key index 234",
584 "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7823.*nocsum pipe.*index 234",
585 "matchCount": "1",
586 "teardown": [
587 "$TC actions flush action tunnel_key"
588 ]
589 },
590 {
591 "id": "2575",
592 "name": "Add tunnel_key action with not-supported parameter",
593 "category": [
594 "actions",
595 "tunnel_key"
596 ],
597 "setup": [
598 [
599 "$TC actions flush action tunnel_key",
600 0,
601 1,
602 255
603 ]
604 ],
605 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 foobar 999 index 4",
606 "expExitCode": "255",
607 "verifyCmd": "$TC actions get action tunnel_key index 4",
608 "matchPattern": "action order [0-9]+: tunnel_key.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*foobar 999.*index 4",
609 "matchCount": "0",
610 "teardown": [
611 [
612 "$TC actions flush action tunnel_key",
613 0,
614 1,
615 255
616 ]
617 ]
618 },
619 {
620 "id": "7a88",
621 "name": "Add tunnel_key action with cookie parameter",
622 "category": [
623 "actions",
624 "tunnel_key"
625 ],
626 "setup": [
627 [
628 "$TC actions flush action tunnel_key",
629 0,
630 1,
631 255
632 ]
633 ],
634 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 10.10.10.2 id 7 index 4 cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
635 "expExitCode": "0",
636 "verifyCmd": "$TC actions get action tunnel_key index 4",
637 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 10.10.10.2.*key_id 7.*dst_port 0.*csum pipe.*index 4 ref.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
638 "matchCount": "1",
639 "teardown": [
640 "$TC actions flush action tunnel_key"
641 ]
642 },
643 {
644 "id": "4f20",
645 "name": "Add tunnel_key action with a single geneve option parameter",
646 "category": [
647 "actions",
648 "tunnel_key"
649 ],
650 "setup": [
651 [
652 "$TC actions flush action tunnel_key",
653 0,
654 1,
655 255
656 ]
657 ],
658 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022 index 1",
659 "expExitCode": "0",
660 "verifyCmd": "$TC actions get action tunnel_key index 1",
661 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022.*index 1",
662 "matchCount": "1",
663 "teardown": [
664 "$TC actions flush action tunnel_key"
665 ]
666 },
667 {
668 "id": "e33d",
669 "name": "Add tunnel_key action with multiple geneve options parameter",
670 "category": [
671 "actions",
672 "tunnel_key"
673 ],
674 "setup": [
675 [
676 "$TC actions flush action tunnel_key",
677 0,
678 1,
679 255
680 ]
681 ],
682 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344 index 1",
683 "expExitCode": "0",
684 "verifyCmd": "$TC actions get action tunnel_key index 1",
685 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:0040007611223344,0111:02:1020304011223344.*index 1",
686 "matchCount": "1",
687 "teardown": [
688 "$TC actions flush action tunnel_key"
689 ]
690 },
691 {
692 "id": "0778",
693 "name": "Add tunnel_key action with invalid class geneve option parameter",
694 "category": [
695 "actions",
696 "tunnel_key"
697 ],
698 "setup": [
699 [
700 "$TC actions flush action tunnel_key",
701 0,
702 1,
703 255
704 ]
705 ],
706 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 824212:80:00880022 index 1",
707 "expExitCode": "255",
708 "verifyCmd": "$TC actions get action tunnel_key index 1",
709 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 824212:80:00880022.*index 1",
710 "matchCount": "0",
711 "teardown": [
712 "$TC actions flush action tunnel_key"
713 ]
714 },
715 {
716 "id": "4ae8",
717 "name": "Add tunnel_key action with invalid type geneve option parameter",
718 "category": [
719 "actions",
720 "tunnel_key"
721 ],
722 "setup": [
723 [
724 "$TC actions flush action tunnel_key",
725 0,
726 1,
727 255
728 ]
729 ],
730 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:4224:00880022 index 1",
731 "expExitCode": "255",
732 "verifyCmd": "$TC actions get action tunnel_key index 1",
733 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:4224:00880022.*index 1",
734 "matchCount": "0",
735 "teardown": [
736 "$TC actions flush action tunnel_key"
737 ]
738 },
739 {
740 "id": "4039",
741 "name": "Add tunnel_key action with short data length geneve option parameter",
742 "category": [
743 "actions",
744 "tunnel_key"
745 ],
746 "setup": [
747 [
748 "$TC actions flush action tunnel_key",
749 0,
750 1,
751 255
752 ]
753 ],
754 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288 index 1",
755 "expExitCode": "255",
756 "verifyCmd": "$TC actions get action tunnel_key index 1",
757 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288.*index 1",
758 "matchCount": "0",
759 "teardown": [
760 "$TC actions flush action tunnel_key"
761 ]
762 },
763 {
764 "id": "26a6",
765 "name": "Add tunnel_key action with non-multiple of 4 data length geneve option parameter",
766 "category": [
767 "actions",
768 "tunnel_key"
769 ],
770 "setup": [
771 [
772 "$TC actions flush action tunnel_key",
773 0,
774 1,
775 255
776 ]
777 ],
778 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:4288428822 index 1",
779 "expExitCode": "255",
780 "verifyCmd": "$TC actions get action tunnel_key index 1",
781 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:4288428822.*index 1",
782 "matchCount": "0",
783 "teardown": [
784 "$TC actions flush action tunnel_key"
785 ]
786 },
787 {
788 "id": "f44d",
789 "name": "Add tunnel_key action with incomplete geneve options parameter",
790 "category": [
791 "actions",
792 "tunnel_key"
793 ],
794 "setup": [
795 [
796 "$TC actions flush action tunnel_key",
797 0,
798 1,
799 255
800 ]
801 ],
802 "cmdUnderTest": "$TC actions add action tunnel_key set src_ip 1.1.1.1 dst_ip 2.2.2.2 id 42 dst_port 6081 geneve_opts 0102:80:00880022,0408:42: index 1",
803 "expExitCode": "255",
804 "verifyCmd": "$TC actions get action tunnel_key index 1",
805 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 1.1.1.1.*dst_ip 2.2.2.2.*key_id 42.*dst_port 6081.*geneve_opt 0102:80:00880022,0408:42:.*index 1",
806 "matchCount": "0",
807 "teardown": [
808 "$TC actions flush action tunnel_key"
809 ]
810 },
811 {
812 "id": "7afc",
813 "name": "Replace tunnel_key set action with all parameters",
814 "category": [
815 "actions",
816 "tunnel_key"
817 ],
818 "setup": [
819 [
820 "$TC actions flush action tunnel_key",
821 0,
822 1,
823 255
824 ],
825 "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 csum id 1 index 1"
826 ],
827 "cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 nocsum id 11 index 1",
828 "expExitCode": "0",
829 "verifyCmd": "$TC actions get action tunnel_key index 1",
830 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*nocsum pipe.*index 1",
831 "matchCount": "1",
832 "teardown": [
833 "$TC actions flush action tunnel_key"
834 ]
835 },
836 {
837 "id": "364d",
838 "name": "Replace tunnel_key set action with all parameters and cookie",
839 "category": [
840 "actions",
841 "tunnel_key"
842 ],
843 "setup": [
844 [
845 "$TC actions flush action tunnel_key",
846 0,
847 1,
848 255
849 ],
850 "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 index 1 cookie aabbccddeeff112233445566778800a"
851 ],
852 "cmdUnderTest": "$TC actions replace action tunnel_key set src_ip 11.11.11.1 dst_ip 21.21.21.2 dst_port 3129 id 11 csum reclassify index 1 cookie a1b1c1d1",
853 "expExitCode": "0",
854 "verifyCmd": "$TC actions get action tunnel_key index 1",
855 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 11.11.11.1.*dst_ip 21.21.21.2.*key_id 11.*dst_port 3129.*csum reclassify.*index 1.*cookie a1b1c1d1",
856 "matchCount": "1",
857 "teardown": [
858 "$TC actions flush action tunnel_key"
859 ]
860 },
861 {
862 "id": "937c",
863 "name": "Fetch all existing tunnel_key actions",
864 "category": [
865 "actions",
866 "tunnel_key"
867 ],
868 "setup": [
869 [
870 "$TC actions flush action tunnel_key",
871 0,
872 1,
873 255
874 ],
875 "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1",
876 "$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 jump 10 index 2",
877 "$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3",
878 "$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4"
879 ],
880 "cmdUnderTest": "$TC actions list action tunnel_key",
881 "expExitCode": "0",
882 "verifyCmd": "$TC actions list action tunnel_key",
883 "matchPattern": "action order [0-9]+: tunnel_key.*set.*src_ip 10.10.10.1.*dst_ip 20.20.20.2.*key_id 1.*dst_port 3128.*nocsum pipe.*index 1.*set.*src_ip 11.10.10.1.*dst_ip 21.20.20.2.*key_id 2.*dst_port 3129.*csum jump 10.*index 2.*set.*src_ip 12.10.10.1.*dst_ip 22.20.20.2.*key_id 3.*dst_port 3130.*csum pass.*index 3.*set.*src_ip 13.10.10.1.*dst_ip 23.20.20.2.*key_id 4.*dst_port 3131.*nocsum continue.*index 4",
884 "matchCount": "1",
885 "teardown": [
886 "$TC actions flush action tunnel_key"
887 ]
888 },
889 {
890 "id": "6783",
891 "name": "Flush all existing tunnel_key actions",
892 "category": [
893 "actions",
894 "tunnel_key"
895 ],
896 "setup": [
897 [
898 "$TC actions flush action tunnel_key",
899 0,
900 1,
901 255
902 ],
903 "$TC actions add action tunnel_key set src_ip 10.10.10.1 dst_ip 20.20.20.2 dst_port 3128 nocsum id 1 pipe index 1",
904 "$TC actions add action tunnel_key set src_ip 11.10.10.1 dst_ip 21.20.20.2 dst_port 3129 csum id 2 reclassify index 2",
905 "$TC actions add action tunnel_key set src_ip 12.10.10.1 dst_ip 22.20.20.2 dst_port 3130 csum id 3 pass index 3",
906 "$TC actions add action tunnel_key set src_ip 13.10.10.1 dst_ip 23.20.20.2 dst_port 3131 nocsum id 4 continue index 4"
907 ],
908 "cmdUnderTest": "$TC actions flush action tunnel_key",
909 "expExitCode": "0",
910 "verifyCmd": "$TC actions list action tunnel_key",
911 "matchPattern": "action order [0-9]+:.*",
912 "matchCount": "0",
913 "teardown": [
914 "$TC actions flush action tunnel_key"
915 ]
916 }
917]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json b/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json
new file mode 100644
index 000000000000..3b97cfd7e0f8
--- /dev/null
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/fw.json
@@ -0,0 +1,1049 @@
1[
2 {
3 "id": "901f",
4 "name": "Add fw filter with prio at 32-bit maxixum",
5 "category": [
6 "filter",
7 "fw"
8 ],
9 "setup": [
10 "$TC qdisc add dev $DEV1 ingress"
11 ],
12 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65535 fw action ok",
13 "expExitCode": "0",
14 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 65535 protocol all fw",
15 "matchPattern": "pref 65535 fw.*handle 0x1.*gact action pass",
16 "matchCount": "1",
17 "teardown": [
18 "$TC qdisc del dev $DEV1 ingress"
19 ]
20 },
21 {
22 "id": "51e2",
23 "name": "Add fw filter with prio exceeding 32-bit maxixum",
24 "category": [
25 "filter",
26 "fw"
27 ],
28 "setup": [
29 "$TC qdisc add dev $DEV1 ingress"
30 ],
31 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 65536 fw action ok",
32 "expExitCode": "255",
33 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 65536 protocol all fw",
34 "matchPattern": "pref 65536 fw.*handle 0x1.*gact action pass",
35 "matchCount": "0",
36 "teardown": [
37 "$TC qdisc del dev $DEV1 ingress"
38 ]
39 },
40 {
41 "id": "d987",
42 "name": "Add fw filter with action ok",
43 "category": [
44 "filter",
45 "fw"
46 ],
47 "setup": [
48 "$TC qdisc add dev $DEV1 ingress"
49 ],
50 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action ok",
51 "expExitCode": "0",
52 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
53 "matchPattern": "handle 0x1.*gact action pass",
54 "matchCount": "1",
55 "teardown": [
56 "$TC qdisc del dev $DEV1 ingress"
57 ]
58 },
59 {
60 "id": "affe",
61 "name": "Add fw filter with action continue",
62 "category": [
63 "filter",
64 "fw"
65 ],
66 "setup": [
67 "$TC qdisc add dev $DEV1 ingress"
68 ],
69 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action continue",
70 "expExitCode": "0",
71 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
72 "matchPattern": "handle 0x1.*gact action continue",
73 "matchCount": "1",
74 "teardown": [
75 "$TC qdisc del dev $DEV1 ingress"
76 ]
77 },
78 {
79 "id": "28bc",
80 "name": "Add fw filter with action pipe",
81 "category": [
82 "filter",
83 "fw"
84 ],
85 "setup": [
86 "$TC qdisc add dev $DEV1 ingress"
87 ],
88 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action pipe",
89 "expExitCode": "0",
90 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
91 "matchPattern": "handle 0x1.*gact action pipe",
92 "matchCount": "1",
93 "teardown": [
94 "$TC qdisc del dev $DEV1 ingress"
95 ]
96 },
97 {
98 "id": "8da2",
99 "name": "Add fw filter with action drop",
100 "category": [
101 "filter",
102 "fw"
103 ],
104 "setup": [
105 "$TC qdisc add dev $DEV1 ingress"
106 ],
107 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action drop",
108 "expExitCode": "0",
109 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 protocol all prio 1 fw",
110 "matchPattern": "handle 0x1.*gact action drop",
111 "matchCount": "1",
112 "teardown": [
113 "$TC qdisc del dev $DEV1 ingress"
114 ]
115 },
116 {
117 "id": "9436",
118 "name": "Add fw filter with action reclassify",
119 "category": [
120 "filter",
121 "fw"
122 ],
123 "setup": [
124 "$TC qdisc add dev $DEV1 ingress"
125 ],
126 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action reclassify",
127 "expExitCode": "0",
128 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
129 "matchPattern": "handle 0x1.*gact action reclassify",
130 "matchCount": "1",
131 "teardown": [
132 "$TC qdisc del dev $DEV1 ingress"
133 ]
134 },
135 {
136 "id": "95bb",
137 "name": "Add fw filter with action jump 10",
138 "category": [
139 "filter",
140 "fw"
141 ],
142 "setup": [
143 "$TC qdisc add dev $DEV1 ingress"
144 ],
145 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action jump 10",
146 "expExitCode": "0",
147 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
148 "matchPattern": "handle 0x1.*gact action jump 10",
149 "matchCount": "1",
150 "teardown": [
151 "$TC qdisc del dev $DEV1 ingress"
152 ]
153 },
154 {
155 "id": "3d74",
156 "name": "Add fw filter with action goto chain 5",
157 "category": [
158 "filter",
159 "fw"
160 ],
161 "setup": [
162 "$TC qdisc add dev $DEV1 ingress"
163 ],
164 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action goto chain 5",
165 "expExitCode": "0",
166 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
167 "matchPattern": "handle 0x1.*gact action goto chain 5",
168 "matchCount": "1",
169 "teardown": [
170 "$TC qdisc del dev $DEV1 ingress"
171 ]
172 },
173 {
174 "id": "eb8f",
175 "name": "Add fw filter with invalid action",
176 "category": [
177 "filter",
178 "fw"
179 ],
180 "setup": [
181 "$TC qdisc add dev $DEV1 ingress"
182 ],
183 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw action pump",
184 "expExitCode": "255",
185 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
186 "matchPattern": "handle 0x1.*gact action pump",
187 "matchCount": "0",
188 "teardown": [
189 "$TC qdisc del dev $DEV1 ingress"
190 ]
191 },
192 {
193 "id": "6a79",
194 "name": "Add fw filter with missing mandatory action",
195 "category": [
196 "filter",
197 "fw"
198 ],
199 "setup": [
200 "$TC qdisc add dev $DEV1 ingress"
201 ],
202 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw",
203 "expExitCode": "2",
204 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
205 "matchPattern": "filter protocol all pref [0-9]+ fw.*handle 0x1",
206 "matchCount": "0",
207 "teardown": [
208 "$TC qdisc del dev $DEV1 ingress"
209 ]
210 },
211 {
212 "id": "8298",
213 "name": "Add fw filter with cookie",
214 "category": [
215 "filter",
216 "fw"
217 ],
218 "setup": [
219 "$TC qdisc add dev $DEV1 ingress"
220 ],
221 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
222 "expExitCode": "0",
223 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 2 protocol all fw",
224 "matchPattern": "pref 2 fw.*handle 0x1.*gact action pipe.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2",
225 "matchCount": "1",
226 "teardown": [
227 "$TC qdisc del dev $DEV1 ingress"
228 ]
229 },
230 {
231 "id": "a88c",
232 "name": "Add fw filter with invalid cookie",
233 "category": [
234 "filter",
235 "fw"
236 ],
237 "setup": [
238 "$TC qdisc add dev $DEV1 ingress"
239 ],
240 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action continue cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
241 "expExitCode": "255",
242 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 2 protocol all fw",
243 "matchPattern": "pref 2 fw.*handle 0x1.*gact action continue.*cookie aa11bb22cc33dd44ee55ff66aa11b1b2777888",
244 "matchCount": "0",
245 "teardown": [
246 "$TC qdisc del dev $DEV1 ingress"
247 ]
248 },
249 {
250 "id": "10f6",
251 "name": "Add fw filter with handle in hex",
252 "category": [
253 "filter",
254 "fw"
255 ],
256 "setup": [
257 "$TC qdisc add dev $DEV1 ingress"
258 ],
259 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0xa1b2ff prio 1 fw action ok",
260 "expExitCode": "0",
261 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xa1b2ff prio 1 protocol all fw",
262 "matchPattern": "fw.*handle 0xa1b2ff.*gact action pass",
263 "matchCount": "1",
264 "teardown": [
265 "$TC qdisc del dev $DEV1 ingress"
266 ]
267 },
268 {
269 "id": "9d51",
270 "name": "Add fw filter with handle at 32-bit maximum",
271 "category": [
272 "filter",
273 "fw"
274 ],
275 "setup": [
276 "$TC qdisc add dev $DEV1 ingress"
277 ],
278 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967295 prio 1 fw action ok",
279 "expExitCode": "0",
280 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4294967295 prio 1 protocol all fw",
281 "matchPattern": "fw.*handle 0xffffffff.*gact action pass",
282 "matchCount": "1",
283 "teardown": [
284 "$TC qdisc del dev $DEV1 ingress"
285 ]
286 },
287 {
288 "id": "d939",
289 "name": "Add fw filter with handle exceeding 32-bit maximum",
290 "category": [
291 "filter",
292 "fw"
293 ],
294 "setup": [
295 "$TC qdisc add dev $DEV1 ingress"
296 ],
297 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967296 prio 1 fw action ok",
298 "expExitCode": "1",
299 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4294967296 prio 1 protocol all fw",
300 "matchPattern": "fw.*handle 0x.*gact action pass",
301 "matchCount": "0",
302 "teardown": [
303 "$TC qdisc del dev $DEV1 ingress"
304 ]
305 },
306 {
307 "id": "658c",
308 "name": "Add fw filter with mask in hex",
309 "category": [
310 "filter",
311 "fw"
312 ],
313 "setup": [
314 "$TC qdisc add dev $DEV1 ingress"
315 ],
316 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/0xa1b2f prio 1 fw action ok",
317 "expExitCode": "0",
318 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw",
319 "matchPattern": "fw.*handle 0xa/0xa1b2f",
320 "matchCount": "1",
321 "teardown": [
322 "$TC qdisc del dev $DEV1 ingress"
323 ]
324 },
325 {
326 "id": "86be",
327 "name": "Add fw filter with mask at 32-bit maximum",
328 "category": [
329 "filter",
330 "fw"
331 ],
332 "setup": [
333 "$TC qdisc add dev $DEV1 ingress"
334 ],
335 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/4294967295 prio 1 fw action ok",
336 "expExitCode": "0",
337 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw",
338 "matchPattern": "fw.*handle 0xa[^/]",
339 "matchCount": "1",
340 "teardown": [
341 "$TC qdisc del dev $DEV1 ingress"
342 ]
343 },
344 {
345 "id": "e635",
346 "name": "Add fw filter with mask exceeding 32-bit maximum",
347 "category": [
348 "filter",
349 "fw"
350 ],
351 "setup": [
352 "$TC qdisc add dev $DEV1 ingress"
353 ],
354 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10/4294967296 prio 1 fw action ok",
355 "expExitCode": "1",
356 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw",
357 "matchPattern": "fw.*handle 0xa",
358 "matchCount": "0",
359 "teardown": [
360 "$TC qdisc del dev $DEV1 ingress"
361 ]
362 },
363 {
364 "id": "6cab",
365 "name": "Add fw filter with handle/mask in hex",
366 "category": [
367 "filter",
368 "fw"
369 ],
370 "setup": [
371 "$TC qdisc add dev $DEV1 ingress"
372 ],
373 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 0xa1b2cdff/0x1a2bffdc prio 1 fw action ok",
374 "expExitCode": "0",
375 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xa1b2cdff prio 1 protocol all fw",
376 "matchPattern": "fw.*handle 0xa1b2cdff/0x1a2bffdc",
377 "matchCount": "1",
378 "teardown": [
379 "$TC qdisc del dev $DEV1 ingress"
380 ]
381 },
382 {
383 "id": "8700",
384 "name": "Add fw filter with handle/mask at 32-bit maximum",
385 "category": [
386 "filter",
387 "fw"
388 ],
389 "setup": [
390 "$TC qdisc add dev $DEV1 ingress"
391 ],
392 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967295/4294967295 prio 1 fw action ok",
393 "expExitCode": "0",
394 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 0xffffffff prio 1 protocol all fw",
395 "matchPattern": "fw.*handle 0xffffffff[^/]",
396 "matchCount": "1",
397 "teardown": [
398 "$TC qdisc del dev $DEV1 ingress"
399 ]
400 },
401 {
402 "id": "7d62",
403 "name": "Add fw filter with handle/mask exceeding 32-bit maximum",
404 "category": [
405 "filter",
406 "fw"
407 ],
408 "setup": [
409 "$TC qdisc add dev $DEV1 ingress"
410 ],
411 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 4294967296/4294967296 prio 1 fw action ok",
412 "expExitCode": "1",
413 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw",
414 "matchPattern": "fw.*handle",
415 "matchCount": "0",
416 "teardown": [
417 "$TC qdisc del dev $DEV1 ingress"
418 ]
419 },
420 {
421 "id": "7b69",
422 "name": "Add fw filter with missing mandatory handle",
423 "category": [
424 "filter",
425 "fw"
426 ],
427 "setup": [
428 "$TC qdisc add dev $DEV1 ingress"
429 ],
430 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 1 fw action ok",
431 "expExitCode": "2",
432 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
433 "matchPattern": "filter protocol all.*fw.*handle.*gact action pass",
434 "matchCount": "0",
435 "teardown": [
436 "$TC qdisc del dev $DEV1 ingress"
437 ]
438 },
439 {
440 "id": "d68b",
441 "name": "Add fw filter with invalid parent",
442 "category": [
443 "filter",
444 "fw"
445 ],
446 "setup": [
447 "$TC qdisc add dev $DEV1 ingress"
448 ],
449 "cmdUnderTest": "$TC filter add dev $DEV1 parent aa11b1b2: handle 1 prio 1 fw action ok",
450 "expExitCode": "255",
451 "verifyCmd": "$TC filter dev $DEV1 parent aa11b1b2: handle 1 prio 1 protocol all fw",
452 "matchPattern": "filter protocol all pref 1 fw.*handle 0x1.*gact action pass",
453 "matchCount": "0",
454 "teardown": [
455 "$TC qdisc del dev $DEV1 ingress"
456 ]
457 },
458 {
459 "id": "66e0",
460 "name": "Add fw filter with missing mandatory parent id",
461 "category": [
462 "filter",
463 "fw"
464 ],
465 "setup": [
466 "$TC qdisc add dev $DEV1 ingress"
467 ],
468 "cmdUnderTest": "$TC filter add dev $DEV1 handle 1 prio 1 fw action ok",
469 "expExitCode": "2",
470 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
471 "matchPattern": "pref [0-9]+ fw.*handle 0x1.*gact action pass",
472 "matchCount": "0",
473 "teardown": [
474 "$TC qdisc del dev $DEV1 ingress"
475 ]
476 },
477 {
478 "id": "0ff3",
479 "name": "Add fw filter with classid",
480 "category": [
481 "filter",
482 "fw"
483 ],
484 "setup": [
485 "$TC qdisc add dev $DEV1 ingress"
486 ],
487 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 3 action ok",
488 "expExitCode": "0",
489 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
490 "matchPattern": "fw.*handle 0x1 classid :3.*gact action pass",
491 "matchCount": "1",
492 "teardown": [
493 "$TC qdisc del dev $DEV1 ingress"
494 ]
495 },
496 {
497 "id": "9849",
498 "name": "Add fw filter with classid at root",
499 "category": [
500 "filter",
501 "fw"
502 ],
503 "setup": [
504 "$TC qdisc add dev $DEV1 ingress"
505 ],
506 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid ffff:ffff action ok",
507 "expExitCode": "0",
508 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
509 "matchPattern": "pref 1 fw.*handle 0x1 classid root.*gact action pass",
510 "matchCount": "1",
511 "teardown": [
512 "$TC qdisc del dev $DEV1 ingress"
513 ]
514 },
515 {
516 "id": "b7ff",
517 "name": "Add fw filter with classid - keeps last 8 (hex) digits",
518 "category": [
519 "filter",
520 "fw"
521 ],
522 "setup": [
523 "$TC qdisc add dev $DEV1 ingress"
524 ],
525 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 98765fedcb action ok",
526 "expExitCode": "0",
527 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
528 "matchPattern": "fw.*handle 0x1 classid 765f:edcb.*gact action pass",
529 "matchCount": "1",
530 "teardown": [
531 "$TC qdisc del dev $DEV1 ingress"
532 ]
533 },
534 {
535 "id": "2b18",
536 "name": "Add fw filter with invalid classid",
537 "category": [
538 "filter",
539 "fw"
540 ],
541 "setup": [
542 "$TC qdisc add dev $DEV1 ingress"
543 ],
544 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 1 prio 1 fw classid 6789defg action ok",
545 "expExitCode": "1",
546 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol all fw",
547 "matchPattern": "fw.*handle 0x1 classid 6789:defg.*gact action pass",
548 "matchCount": "0",
549 "teardown": [
550 "$TC qdisc del dev $DEV1 ingress"
551 ]
552 },
553 {
554 "id": "fade",
555 "name": "Add fw filter with flowid",
556 "category": [
557 "filter",
558 "fw"
559 ],
560 "setup": [
561 "$TC qdisc add dev $DEV1 ingress"
562 ],
563 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 10 prio 1 fw flowid 1:10 action ok",
564 "expExitCode": "0",
565 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 1 protocol all fw",
566 "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xa classid 1:10.*gact action pass",
567 "matchCount": "1",
568 "teardown": [
569 "$TC qdisc del dev $DEV1 ingress"
570 ]
571 },
572 {
573 "id": "33af",
574 "name": "Add fw filter with flowid then classid (same arg, takes second)",
575 "category": [
576 "filter",
577 "fw"
578 ],
579 "setup": [
580 "$TC qdisc add dev $DEV1 ingress"
581 ],
582 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 11 prio 1 fw flowid 10 classid 4 action ok",
583 "expExitCode": "0",
584 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 11 prio 1 protocol all fw",
585 "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xb classid :4.*gact action pass",
586 "matchCount": "1",
587 "teardown": [
588 "$TC qdisc del dev $DEV1 ingress"
589 ]
590 },
591 {
592 "id": "8a8c",
593 "name": "Add fw filter with classid then flowid (same arg, takes second)",
594 "category": [
595 "filter",
596 "fw"
597 ],
598 "setup": [
599 "$TC qdisc add dev $DEV1 ingress"
600 ],
601 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: handle 11 prio 1 fw classid 4 flowid 10 action ok",
602 "expExitCode": "0",
603 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 11 prio 1 protocol all fw",
604 "matchPattern": "filter parent ffff: protocol all pref 1 fw.*handle 0xb classid :10.*gact action pass",
605 "matchCount": "1",
606 "teardown": [
607 "$TC qdisc del dev $DEV1 ingress"
608 ]
609 },
610 {
611 "id": "b50d",
612 "name": "Add fw filter with handle val/mask and flowid 10:1000",
613 "category": [
614 "filter",
615 "fw"
616 ],
617 "setup": [
618 "$TC qdisc add dev $DEV1 ingress"
619 ],
620 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 10/0xff fw flowid 10:1000 action ok",
621 "expExitCode": "0",
622 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 10 prio 3 protocol all fw",
623 "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0xa/0xff classid 10:1000.*gact action pass",
624 "matchCount": "1",
625 "teardown": [
626 "$TC qdisc del dev $DEV1 ingress"
627 ]
628 },
629 {
630 "id": "7207",
631 "name": "Add fw filter with protocol ip",
632 "category": [
633 "filter",
634 "fw"
635 ],
636 "setup": [
637 "$TC qdisc add dev $DEV1 ingress"
638 ],
639 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 handle 3 fw action ok",
640 "expExitCode": "0",
641 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 3 prio 1 protocol ip fw",
642 "matchPattern": "filter parent ffff: protocol ip pref 1 fw.*handle 0x3.*gact action pass.*index [0-9]+ ref [0-9]+ bind [0-9]+",
643 "matchCount": "1",
644 "teardown": [
645 "$TC qdisc del dev $DEV1 ingress"
646 ]
647 },
648 {
649 "id": "306d",
650 "name": "Add fw filter with protocol ipv6",
651 "category": [
652 "filter",
653 "fw"
654 ],
655 "setup": [
656 "$TC qdisc add dev $DEV1 ingress"
657 ],
658 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ipv6 prio 2 handle 4 fw action ok",
659 "expExitCode": "0",
660 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 2 protocol ipv6 fw",
661 "matchPattern": "filter parent ffff: protocol ipv6 pref 2 fw.*handle 0x4.*gact action pass.*index [0-9]+ ref [0-9]+ bind [0-9]+",
662 "matchCount": "1",
663 "teardown": [
664 "$TC qdisc del dev $DEV1 ingress"
665 ]
666 },
667 {
668 "id": "9a78",
669 "name": "Add fw filter with protocol arp",
670 "category": [
671 "filter",
672 "fw"
673 ],
674 "setup": [
675 "$TC qdisc add dev $DEV1 ingress"
676 ],
677 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol arp prio 5 handle 7 fw action drop",
678 "expExitCode": "0",
679 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 7 prio 5 protocol arp fw",
680 "matchPattern": "filter parent ffff: protocol arp pref 5 fw.*handle 0x7.*gact action drop.*index [0-9]+ ref [0-9]+ bind [0-9]+",
681 "matchCount": "1",
682 "teardown": [
683 "$TC qdisc del dev $DEV1 ingress"
684 ]
685 },
686 {
687 "id": "1821",
688 "name": "Add fw filter with protocol 802_3",
689 "category": [
690 "filter",
691 "fw"
692 ],
693 "setup": [
694 "$TC qdisc add dev $DEV1 ingress"
695 ],
696 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol 802_3 handle 1 prio 1 fw action ok",
697 "expExitCode": "0",
698 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol 802_3 fw",
699 "matchPattern": "filter parent ffff: protocol 802_3 pref 1 fw.*handle 0x1.*gact action pass",
700 "matchCount": "1",
701 "teardown": [
702 "$TC qdisc del dev $DEV1 ingress"
703 ]
704 },
705 {
706 "id": "2260",
707 "name": "Add fw filter with invalid protocol",
708 "category": [
709 "filter",
710 "fw"
711 ],
712 "setup": [
713 "$TC qdisc add dev $DEV1 ingress"
714 ],
715 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol igmp handle 1 prio 1 fw action ok",
716 "expExitCode": "255",
717 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 1 prio 1 protocol igmp fw",
718 "matchPattern": "filter parent ffff: protocol igmp pref 1 fw.*handle 0x1.*gact action pass",
719 "matchCount": "0",
720 "teardown": [
721 "$TC qdisc del dev $DEV1 ingress"
722 ]
723 },
724 {
725 "id": "09d7",
726 "name": "Add fw filters protocol 802_3 and ip with conflicting priorities",
727 "category": [
728 "filter",
729 "fw"
730 ],
731 "setup": [
732 "$TC qdisc add dev $DEV1 ingress",
733 "$TC filter add dev $DEV1 parent ffff: protocol 802_3 prio 3 handle 7 fw action ok"
734 ],
735 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 3 handle 8 fw action ok",
736 "expExitCode": "2",
737 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 8 prio 3 protocol ip fw",
738 "matchPattern": "filter parent ffff: protocol ip pref 3 fw.*handle 0x8",
739 "matchCount": "0",
740 "teardown": [
741 "$TC qdisc del dev $DEV1 ingress"
742 ]
743 },
744 {
745 "id": "6973",
746 "name": "Add fw filters with same index, same action",
747 "category": [
748 "filter",
749 "fw"
750 ],
751 "setup": [
752 "$TC qdisc add dev $DEV1 ingress",
753 "$TC filter add dev $DEV1 parent ffff: prio 6 handle 2 fw action continue index 5"
754 ],
755 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 8 handle 4 fw action continue index 5",
756 "expExitCode": "0",
757 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 8 protocol all fw",
758 "matchPattern": "filter parent ffff: protocol all pref 8 fw.*handle 0x4.*gact action continue.*index 5 ref 2 bind 2",
759 "matchCount": "1",
760 "teardown": [
761 "$TC qdisc del dev $DEV1 ingress"
762 ]
763 },
764 {
765 "id": "fc06",
766 "name": "Add fw filters with action police",
767 "category": [
768 "filter",
769 "fw"
770 ],
771 "setup": [
772 "$TC qdisc add dev $DEV1 ingress"
773 ],
774 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 4 fw action police rate 1kbit burst 10k index 5",
775 "expExitCode": "0",
776 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 3 protocol all fw",
777 "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0x4.*police 0x5 rate 1Kbit burst 10Kb mtu 2Kb action reclassify overhead 0b.*ref 1 bind 1",
778 "matchCount": "1",
779 "teardown": [
780 "$TC qdisc del dev $DEV1 ingress"
781 ]
782 },
783 {
784 "id": "aac7",
785 "name": "Add fw filters with action police linklayer atm",
786 "category": [
787 "filter",
788 "fw"
789 ],
790 "setup": [
791 "$TC qdisc add dev $DEV1 ingress"
792 ],
793 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: prio 3 handle 4 fw action police rate 2mbit burst 200k linklayer atm index 8",
794 "expExitCode": "0",
795 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 3 protocol all fw",
796 "matchPattern": "filter parent ffff: protocol all pref 3 fw.*handle 0x4.*police 0x8 rate 2Mbit burst 200Kb mtu 2Kb action reclassify overhead 0b linklayer atm.*ref 1 bind 1",
797 "matchCount": "1",
798 "teardown": [
799 "$TC qdisc del dev $DEV1 ingress"
800 ]
801 },
802 {
803 "id": "5339",
804 "name": "Del entire fw filter",
805 "category": [
806 "filter",
807 "fw"
808 ],
809 "setup": [
810 "$TC qdisc add dev $DEV1 ingress",
811 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass",
812 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass"
813 ],
814 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff:",
815 "expExitCode": "0",
816 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
817 "matchPattern": "protocol all pref.*handle.*gact action pass",
818 "matchCount": "0",
819 "teardown": [
820 "$TC qdisc del dev $DEV1 ingress"
821 ]
822 },
823 {
824 "id": "0e99",
825 "name": "Del single fw filter x1",
826 "__comment__": "First of two tests to check that one filter is there and the other isn't",
827 "category": [
828 "filter",
829 "fw"
830 ],
831 "setup": [
832 "$TC qdisc add dev $DEV1 ingress",
833 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass",
834 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass"
835 ],
836 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 prio 9 fw action pass",
837 "expExitCode": "0",
838 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
839 "matchPattern": "protocol all pref 7.*handle 0x5.*gact action pass",
840 "matchCount": "1",
841 "teardown": [
842 "$TC qdisc del dev $DEV1 ingress"
843 ]
844 },
845 {
846 "id": "f54c",
847 "name": "Del single fw filter x2",
848 "__comment__": "Second of two tests to check that one filter is there and the other isn't",
849 "category": [
850 "filter",
851 "fw"
852 ],
853 "setup": [
854 "$TC qdisc add dev $DEV1 ingress",
855 "$TC filter add dev $DEV1 parent ffff: handle 5 prio 7 fw action pass",
856 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 9 fw action pass"
857 ],
858 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 prio 9 fw action pass",
859 "expExitCode": "0",
860 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
861 "matchPattern": "protocol all pref 9.*handle 0x3.*gact action pass",
862 "matchCount": "0",
863 "teardown": [
864 "$TC qdisc del dev $DEV1 ingress"
865 ]
866 },
867 {
868 "id": "ba94",
869 "name": "Del fw filter by prio",
870 "category": [
871 "filter",
872 "fw"
873 ],
874 "setup": [
875 "$TC qdisc add dev $DEV1 ingress",
876 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 4 fw action ok",
877 "$TC filter add dev $DEV1 parent ffff: handle 2 prio 4 fw action ok"
878 ],
879 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: prio 4",
880 "expExitCode": "0",
881 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
882 "matchPattern": "pref 4 fw.*gact action pass",
883 "matchCount": "0",
884 "teardown": [
885 "$TC qdisc del dev $DEV1 ingress"
886 ]
887 },
888 {
889 "id": "4acb",
890 "name": "Del fw filter by chain",
891 "category": [
892 "filter",
893 "fw"
894 ],
895 "setup": [
896 "$TC qdisc add dev $DEV1 ingress",
897 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 chain 13 fw action pipe",
898 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 5 chain 13 fw action pipe"
899 ],
900 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: chain 13",
901 "expExitCode": "0",
902 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
903 "matchPattern": "fw chain 13 handle.*gact action pipe",
904 "matchCount": "0",
905 "teardown": [
906 "$TC qdisc del dev $DEV1 ingress"
907 ]
908 },
909 {
910 "id": "3424",
911 "name": "Del fw filter by action (invalid)",
912 "category": [
913 "filter",
914 "fw"
915 ],
916 "setup": [
917 "$TC qdisc add dev $DEV1 ingress",
918 "$TC filter add dev $DEV1 parent ffff: handle 2 prio 4 fw action drop"
919 ],
920 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: fw action drop",
921 "expExitCode": "2",
922 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 2 prio 4 protocol all fw",
923 "matchPattern": "handle 0x2.*gact action drop",
924 "matchCount": "1",
925 "teardown": [
926 "$TC qdisc del dev $DEV1 ingress"
927 ]
928 },
929 {
930 "id": "da89",
931 "name": "Del fw filter by handle (invalid)",
932 "category": [
933 "filter",
934 "fw"
935 ],
936 "setup": [
937 "$TC qdisc add dev $DEV1 ingress",
938 "$TC filter add dev $DEV1 parent ffff: handle 3 prio 4 fw action continue"
939 ],
940 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: handle 3 fw",
941 "expExitCode": "2",
942 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 3 prio 4 protocol all fw",
943 "matchPattern": "handle 0x3.*gact action continue",
944 "matchCount": "1",
945 "teardown": [
946 "$TC qdisc del dev $DEV1 ingress"
947 ]
948 },
949 {
950 "id": "4d95",
951 "name": "Del fw filter by protocol (invalid)",
952 "category": [
953 "filter",
954 "fw"
955 ],
956 "setup": [
957 "$TC qdisc add dev $DEV1 ingress",
958 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 protocol arp fw action pipe"
959 ],
960 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: protocol arp fw",
961 "expExitCode": "2",
962 "verifyCmd": "$TC filter get dev $DEV1 parent ffff: handle 4 prio 2 protocol arp fw",
963 "matchPattern": "filter parent ffff: protocol arp.*handle 0x4.*gact action pipe",
964 "matchCount": "1",
965 "teardown": [
966 "$TC qdisc del dev $DEV1 ingress"
967 ]
968 },
969 {
970 "id": "4736",
971 "name": "Del fw filter by flowid (invalid)",
972 "category": [
973 "filter",
974 "fw"
975 ],
976 "setup": [
977 "$TC qdisc add dev $DEV1 ingress",
978 "$TC filter add dev $DEV1 parent ffff: handle 4 prio 2 fw action pipe flowid 45"
979 ],
980 "cmdUnderTest": "$TC filter del dev $DEV1 parent ffff: fw flowid 45",
981 "expExitCode": "2",
982 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
983 "matchPattern": "handle 0x4.*gact action pipe",
984 "matchCount": "1",
985 "teardown": [
986 "$TC qdisc del dev $DEV1 ingress"
987 ]
988 },
989 {
990 "id": "3dcb",
991 "name": "Replace fw filter action",
992 "category": [
993 "filter",
994 "fw"
995 ],
996 "setup": [
997 "$TC qdisc add dev $DEV1 ingress",
998 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok"
999 ],
1000 "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe",
1001 "expExitCode": "0",
1002 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
1003 "matchPattern": "pref 2 fw.*handle 0x1.*gact action pipe",
1004 "matchCount": "1",
1005 "teardown": [
1006 "$TC qdisc del dev $DEV1 ingress"
1007 ]
1008 },
1009 {
1010 "id": "eb4d",
1011 "name": "Replace fw filter classid",
1012 "category": [
1013 "filter",
1014 "fw"
1015 ],
1016 "setup": [
1017 "$TC qdisc add dev $DEV1 ingress",
1018 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok"
1019 ],
1020 "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action pipe classid 2",
1021 "expExitCode": "0",
1022 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
1023 "matchPattern": "pref 2 fw.*handle 0x1 classid :2.*gact action pipe",
1024 "matchCount": "1",
1025 "teardown": [
1026 "$TC qdisc del dev $DEV1 ingress"
1027 ]
1028 },
1029 {
1030 "id": "67ec",
1031 "name": "Replace fw filter index",
1032 "category": [
1033 "filter",
1034 "fw"
1035 ],
1036 "setup": [
1037 "$TC qdisc add dev $DEV1 ingress",
1038 "$TC filter add dev $DEV1 parent ffff: handle 1 prio 2 fw action ok index 3"
1039 ],
1040 "cmdUnderTest": "$TC filter replace dev $DEV1 parent ffff: handle 1 prio 2 fw action ok index 16",
1041 "expExitCode": "0",
1042 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
1043 "matchPattern": "pref 2 fw.*handle 0x1.*gact action pass.*index 16",
1044 "matchCount": "1",
1045 "teardown": [
1046 "$TC qdisc del dev $DEV1 ingress"
1047 ]
1048 }
1049]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
index 5fa02d86b35f..99a5ffca1088 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/filters/tests.json
@@ -12,8 +12,8 @@
12 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 u32 match ip src 127.0.0.1/32 flowid 1:1 action ok", 12 "cmdUnderTest": "$TC filter add dev $DEV1 parent ffff: protocol ip prio 1 u32 match ip src 127.0.0.1/32 flowid 1:1 action ok",
13 "expExitCode": "0", 13 "expExitCode": "0",
14 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:", 14 "verifyCmd": "$TC filter show dev $DEV1 parent ffff:",
15 "matchPattern": "match 7f000002/ffffffff at 12", 15 "matchPattern": "match 7f000001/ffffffff at 12",
16 "matchCount": "0", 16 "matchCount": "1",
17 "teardown": [ 17 "teardown": [
18 "$TC qdisc del dev $DEV1 ingress" 18 "$TC qdisc del dev $DEV1 ingress"
19 ] 19 ]