diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:04:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-15 18:04:25 -0400 |
commit | 9a76aba02a37718242d7cdc294f0a3901928aa57 (patch) | |
tree | 2040d038f85d2120f21af83b0793efd5af1864e3 /tools | |
parent | 0a957467c5fd46142bc9c52758ffc552d4c5e2f7 (diff) | |
parent | 26a1ccc6c117be8e33e0410fce8c5298b0015b99 (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')
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 @@ | |||
1 | FEATURE-DUMP.bpf | ||
2 | bpf_asm | ||
3 | bpf_dbg | ||
4 | bpf_exp.yacc.* | ||
5 | bpf_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 @@ | |||
1 | ifndef allow-override | ||
2 | include ../scripts/Makefile.include | ||
3 | include ../scripts/utilities.mak | ||
4 | else | ||
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 := ../../ | ||
9 | endif | ||
10 | |||
11 | INSTALL ?= install | ||
12 | RM ?= rm -f | ||
13 | RMDIR ?= rmdir --ignore-fail-on-non-empty | ||
14 | |||
15 | ifeq ($(V),1) | ||
16 | Q = | ||
17 | else | ||
18 | Q = @ | ||
19 | endif | ||
20 | |||
21 | prefix ?= /usr/local | ||
22 | mandir ?= $(prefix)/man | ||
23 | man7dir = $(mandir)/man7 | ||
24 | |||
25 | HELPERS_RST = bpf-helpers.rst | ||
26 | MAN7_RST = $(HELPERS_RST) | ||
27 | |||
28 | _DOC_MAN7 = $(patsubst %.rst,%.7,$(MAN7_RST)) | ||
29 | DOC_MAN7 = $(addprefix $(OUTPUT),$(_DOC_MAN7)) | ||
30 | |||
31 | helpers: man7 | ||
32 | man7: $(DOC_MAN7) | ||
33 | |||
34 | RST2MAN_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 | ||
40 | ifndef RST2MAN_DEP | ||
41 | $(error "rst2man not found, but required to generate man pages") | ||
42 | endif | ||
43 | $(QUIET_GEN)rst2man $< > $@ | ||
44 | |||
45 | helpers-clean: | ||
46 | $(call QUIET_CLEAN, eBPF_helpers-manpage) | ||
47 | $(Q)$(RM) $(DOC_MAN7) $(OUTPUT)$(HELPERS_RST) | ||
48 | |||
49 | helpers-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 | |||
54 | helpers-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 |
2 | bpftool | 2 | bpftool |
3 | bpftool*.8 | ||
4 | bpf-helpers.* | ||
3 | FEATURE-DUMP.bpftool | 5 | FEATURE-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 | |||
15 | mandir ?= $(prefix)/man | 15 | mandir ?= $(prefix)/man |
16 | man8dir = $(mandir)/man8 | 16 | man8dir = $(mandir)/man8 |
17 | 17 | ||
18 | MAN8_RST = $(wildcard *.rst) | 18 | # Load targets for building eBPF helpers man page. |
19 | include ../../Makefile.helpers | ||
20 | |||
21 | MAN8_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)) |
21 | DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) | 24 | DOC_MAN8 = $(addprefix $(OUTPUT),$(_DOC_MAN8)) |
22 | 25 | ||
23 | man: man8 | 26 | man: man8 helpers |
24 | man8: $(DOC_MAN8) | 27 | man8: $(DOC_MAN8) |
25 | 28 | ||
26 | RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) | 29 | RST2MAN_DEP := $(shell command -v rst2man 2>/dev/null) |
@@ -31,16 +34,16 @@ ifndef RST2MAN_DEP | |||
31 | endif | 34 | endif |
32 | $(QUIET_GEN)rst2man $< > $@ | 35 | $(QUIET_GEN)rst2man $< > $@ |
33 | 36 | ||
34 | clean: | 37 | clean: helpers-clean |
35 | $(call QUIET_CLEAN, Documentation) | 38 | $(call QUIET_CLEAN, Documentation) |
36 | $(Q)$(RM) $(DOC_MAN8) | 39 | $(Q)$(RM) $(DOC_MAN8) |
37 | 40 | ||
38 | install: man | 41 | install: 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 | ||
43 | uninstall: | 46 | uninstall: 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 | ||
20 | MAP COMMANDS | 20 | MAP 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 | ||
32 | DESCRIPTION | 42 | DESCRIPTION |
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 | ||
163 | SEE ALSO | 192 | SEE 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 | ||
24 | LIBBPF = $(BPF_PATH)libbpf.a | 24 | LIBBPF = $(BPF_PATH)libbpf.a |
25 | 25 | ||
26 | BPFTOOL_VERSION=$(shell make --no-print-directory -sC ../../.. kernelversion) | 26 | BPFTOOL_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 | |||
52 | RM ?= rm -f | 52 | RM ?= rm -f |
53 | 53 | ||
54 | FEATURE_USER = .bpftool | 54 | FEATURE_USER = .bpftool |
55 | FEATURE_TESTS = libbfd disassembler-four-args | 55 | FEATURE_TESTS = libbfd disassembler-four-args reallocarray |
56 | FEATURE_DISPLAY = libbfd disassembler-four-args | 56 | FEATURE_DISPLAY = libbfd disassembler-four-args |
57 | 57 | ||
58 | check_feat := 1 | 58 | check_feat := 1 |
@@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1) | |||
75 | CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE | 75 | CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE |
76 | endif | 76 | endif |
77 | 77 | ||
78 | ifeq ($(feature-reallocarray), 0) | ||
79 | CFLAGS += -DCOMPAT_NEED_REALLOCARRAY | ||
80 | endif | ||
81 | |||
78 | include $(wildcard $(OUTPUT)*.d) | 82 | include $(wildcard $(OUTPUT)*.d) |
79 | 83 | ||
80 | all: $(OUTPUT)bpftool | 84 | all: $(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 | |||
22 | static int btf_dumper_do_type(const struct btf_dumper *d, __u32 type_id, | ||
23 | __u8 bit_offset, const void *data); | ||
24 | |||
25 | static 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 | |||
34 | static 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 | |||
46 | static void btf_dumper_enum(const void *data, json_writer_t *jw) | ||
47 | { | ||
48 | jsonw_printf(jw, "%d", *(int *)data); | ||
49 | } | ||
50 | |||
51 | static 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 | |||
76 | static 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 | |||
112 | static 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 | |||
177 | static 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 | |||
209 | static 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 | |||
247 | int 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 | ||
55 | static int show_bpf_prog(int id, const char *attach_type_str, | 60 | static 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 | ||
91 | static int show_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type) | 98 | static 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 | |||
110 | static 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 | ||
203 | static 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 | |||
261 | static 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 | |||
281 | static 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 | |||
176 | static int do_attach(int argc, char **argv) | 333 | static 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) | |||
307 | static const struct cmd cmds[] = { | 466 | static 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 | ||
65 | enum bpf_obj_type { | 81 | enum bpf_obj_type { |
66 | BPF_OBJ_UNKNOWN, | 82 | BPF_OBJ_UNKNOWN, |
@@ -122,6 +138,7 @@ int do_cgroup(int argc, char **arg); | |||
122 | int do_perf(int argc, char **arg); | 138 | int do_perf(int argc, char **arg); |
123 | 139 | ||
124 | int prog_parse_fd(int *argc, char ***argv); | 140 | int prog_parse_fd(int *argc, char ***argv); |
141 | int map_parse_fd(int *argc, char ***argv); | ||
125 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); | 142 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); |
126 | 143 | ||
127 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 144 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
@@ -133,4 +150,19 @@ unsigned int get_page_size(void); | |||
133 | unsigned int get_possible_cpus(void); | 150 | unsigned int get_possible_cpus(void); |
134 | const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino); | 151 | const char *ifindex_to_bfd_name_ns(__u32 ifindex, __u64 ns_dev, __u64 ns_ino); |
135 | 152 | ||
153 | struct 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 | */ | ||
166 | int 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 | ||
52 | static const char * const map_type_name[] = { | 53 | static 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 | ||
73 | static bool map_is_per_cpu(__u32 type) | 75 | static 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 | ||
100 | static int map_parse_fd(int *argc, char ***argv) | 102 | int 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 | ||
157 | static 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 | |||
176 | err_end_obj: | ||
177 | /* end of key-value pair */ | ||
178 | jsonw_end_object(d->jw); | ||
179 | |||
180 | return ret; | ||
181 | } | ||
182 | |||
183 | static 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 | |||
240 | exit_free: | ||
241 | close(btf_fd); | ||
242 | free(ptr); | ||
243 | |||
244 | return err; | ||
245 | } | ||
246 | |||
247 | static 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 | |||
155 | static void print_entry_json(struct bpf_map_info *info, unsigned char *key, | 258 | static 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 | ||
515 | static int do_dump(int argc, char **argv) | 628 | static 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 | ||
587 | exit_free: | 735 | exit_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 | ||
687 | exit_free: | 870 | exit_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 | ||
686 | struct map_replace { | ||
687 | int idx; | ||
688 | int fd; | ||
689 | char *name; | ||
690 | }; | ||
691 | |||
692 | int 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 | |||
684 | static int do_load(int argc, char **argv) | 699 | static 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 | ||
707 | err_close_obj: | 921 | err_close_obj: |
708 | bpf_object__close(obj); | 922 | bpf_object__close(obj); |
923 | err_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) { |
73 | out: | 73 | out: |
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 | |||
5 | int 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 | */ | ||
216 | static 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 | */ | ||
238 | static 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 | |||
250 | static 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 | ||
11 | static 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 | ||
78 | struct 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. */ |
79 | enum bpf_cmd { | 84 | enum 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 | ||
125 | enum bpf_prog_type { | 132 | enum 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 | ||
149 | enum bpf_attach_type { | 157 | enum 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 | ||
2446 | struct 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 | ||
2381 | struct bpf_prog_info { | 2472 | struct 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 | |||
66 | endif | 66 | endif |
67 | 67 | ||
68 | FEATURE_USER = .libbpf | 68 | FEATURE_USER = .libbpf |
69 | FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf | 69 | FEATURE_TESTS = libelf libelf-mmap bpf reallocarray |
70 | FEATURE_DISPLAY = libelf bpf | 70 | FEATURE_DISPLAY = libelf bpf |
71 | 71 | ||
72 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf | 72 | INCLUDES = -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 |
117 | endif | 117 | endif |
118 | 118 | ||
119 | ifeq ($(feature-libelf-getphdrnum), 1) | 119 | ifeq ($(feature-reallocarray), 0) |
120 | override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | 120 | override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY |
121 | endif | 121 | endif |
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 | ||
44 | int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); | 45 | int 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 | |||
19 | static struct btf_type btf_void; | 24 | static struct btf_type btf_void; |
20 | 25 | ||
21 | struct btf { | 26 | struct btf { |
@@ -32,14 +37,6 @@ struct btf { | |||
32 | int fd; | 37 | int fd; |
33 | }; | 38 | }; |
34 | 39 | ||
35 | static 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 | |||
43 | static int btf_add_type(struct btf *btf, struct btf_type *t) | 40 | static 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 | ||
269 | int 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 | |||
389 | const 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); |
20 | const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); | 20 | const 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); |
22 | int btf__resolve_type(const struct btf *btf, __u32 type_id); | ||
22 | int btf__fd(const struct btf *btf); | 23 | int btf__fd(const struct btf *btf); |
24 | const 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 | |||
103 | static 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 | |||
118 | int 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 | } |
435 | skip_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 | ||
880 | struct bpf_program * | ||
881 | bpf_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 | |||
923 | static int | 892 | static int |
924 | bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, | 893 | bpf_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 | ||
1058 | int 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 | |||
1098 | err_close_new_fd: | ||
1099 | close(new_fd); | ||
1100 | err_free_new_name: | ||
1101 | free(new_name); | ||
1102 | return -errno; | ||
1103 | } | ||
1104 | |||
1088 | static int | 1105 | static int |
1089 | bpf_object__create_maps(struct bpf_object *obj) | 1106 | bpf_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 | ||
1461 | static 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 | |||
1434 | static int | 1467 | static int |
1435 | bpf_object__load_progs(struct bpf_object *obj) | 1468 | bpf_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 | ||
1521 | struct bpf_object *bpf_object__open(const char *path) | 1555 | struct 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 | |||
1567 | struct 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 | ||
1532 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, | 1577 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, |
@@ -1595,6 +1640,7 @@ out: | |||
1595 | 1640 | ||
1596 | static int check_path(const char *path) | 1641 | static 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) | |||
1624 | int bpf_program__pin_instance(struct bpf_program *prog, const char *path, | 1671 | int 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 | ||
1653 | static int make_dir(const char *path) | 1702 | static 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 | ||
1706 | int bpf_map__pin(struct bpf_map *map, const char *path) | 1758 | int 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 | ||
1866 | struct bpf_program * | 1920 | static struct bpf_program * |
1867 | bpf_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 | ||
1942 | struct bpf_program * | ||
1943 | bpf_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 | |||
1888 | int bpf_program__set_priv(struct bpf_program *prog, void *priv, | 1954 | int 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 | ||
1970 | void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex) | ||
1971 | { | ||
1972 | prog->prog_ifindex = ifindex; | ||
1973 | } | ||
1974 | |||
1904 | const char *bpf_program__title(struct bpf_program *prog, bool needs_copy) | 1975 | const 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 | ||
2063 | static int bpf_program__identify_section(struct bpf_program *prog) | 2139 | int 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 | ||
2075 | err: | 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; | 2157 | static int |
2158 | bpf_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 | ||
2082 | int bpf_map__fd(struct bpf_map *map) | 2166 | int 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 | ||
2212 | bool bpf_map__is_offload_neutral(struct bpf_map *map) | ||
2213 | { | ||
2214 | return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY; | ||
2215 | } | ||
2216 | |||
2217 | void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex) | ||
2218 | { | ||
2219 | map->map_ifindex = ifindex; | ||
2220 | } | ||
2221 | |||
2128 | struct bpf_map * | 2222 | struct bpf_map * |
2129 | bpf_map__next(struct bpf_map *prev, struct bpf_object *obj) | 2223 | bpf_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, | |||
2199 | int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, | 2293 | int 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 */ |
67 | struct bpf_object; | 67 | struct bpf_object; |
68 | 68 | ||
69 | struct bpf_object_open_attr { | ||
70 | const char *file; | ||
71 | enum bpf_prog_type prog_type; | ||
72 | }; | ||
73 | |||
69 | struct bpf_object *bpf_object__open(const char *path); | 74 | struct bpf_object *bpf_object__open(const char *path); |
75 | struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr); | ||
70 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, | 76 | struct 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); | |||
80 | unsigned int bpf_object__kversion(struct bpf_object *obj); | 86 | unsigned int bpf_object__kversion(struct bpf_object *obj); |
81 | int bpf_object__btf_fd(const struct bpf_object *obj); | 87 | int bpf_object__btf_fd(const struct bpf_object *obj); |
82 | 88 | ||
89 | struct bpf_program * | ||
90 | bpf_object__find_program_by_title(struct bpf_object *obj, const char *title); | ||
91 | |||
83 | struct bpf_object *bpf_object__next(struct bpf_object *prev); | 92 | struct 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); |
93 | void *bpf_object__priv(struct bpf_object *prog); | 102 | void *bpf_object__priv(struct bpf_object *prog); |
94 | 103 | ||
104 | int 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 */ |
96 | struct bpf_program; | 108 | struct bpf_program; |
97 | struct bpf_program *bpf_program__next(struct bpf_program *prog, | 109 | struct 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 | ||
111 | void *bpf_program__priv(struct bpf_program *prog); | 123 | void *bpf_program__priv(struct bpf_program *prog); |
124 | void bpf_program__set_ifindex(struct bpf_program *prog, __u32 ifindex); | ||
112 | 125 | ||
113 | const char *bpf_program__title(struct bpf_program *prog, bool needs_copy); | 126 | const 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 *); | |||
251 | int bpf_map__set_priv(struct bpf_map *map, void *priv, | 264 | int 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); |
253 | void *bpf_map__priv(struct bpf_map *map); | 266 | void *bpf_map__priv(struct bpf_map *map); |
267 | int bpf_map__reuse_fd(struct bpf_map *map, int fd); | ||
268 | bool bpf_map__is_offload_neutral(struct bpf_map *map); | ||
269 | void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex); | ||
254 | int bpf_map__pin(struct bpf_map *map, const char *path); | 270 | int bpf_map__pin(struct bpf_map *map, const char *path); |
255 | 271 | ||
256 | long libbpf_get_error(const void *ptr); | 272 | long 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 | |||
32 | static 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 | |||
47 | int 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 |
23 | TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ | 23 | TEST_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 | ||
27 | TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ | 28 | TEST_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 |
39 | TEST_PROGS := test_kmod.sh \ | 41 | TEST_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' |
50 | TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr | 53 | TEST_GEN_PROGS_EXTENDED = test_libbpf_open test_sock_addr test_skb_cgroup_id_user |
51 | 54 | ||
52 | include ../lib.mk | 55 | include ../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; |
66 | static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = | 66 | static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = |
67 | (void *) BPF_FUNC_xdp_adjust_meta; | 67 | (void *) BPF_FUNC_xdp_adjust_meta; |
68 | static int (*bpf_get_socket_cookie)(void *ctx) = | ||
69 | (void *) BPF_FUNC_get_socket_cookie; | ||
68 | static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, | 70 | static 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) = | |||
109 | static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, | 111 | static 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; |
114 | static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) = | ||
115 | (void *) BPF_FUNC_sk_select_reuseport; | ||
112 | static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = | 116 | static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = |
113 | (void *) BPF_FUNC_get_stack; | 117 | (void *) BPF_FUNC_get_stack; |
114 | static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, | 118 | static 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; |
134 | static unsigned long long (*bpf_get_current_cgroup_id)(void) = | 138 | static 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; |
140 | static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) = | ||
141 | (void *) BPF_FUNC_get_local_storage; | ||
142 | static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = | ||
143 | (void *) BPF_FUNC_skb_cgroup_id; | ||
144 | static 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 | ||
170 | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = | 180 | static 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; |
182 | static 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; | ||
172 | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = | 184 | static 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; |
174 | static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = | 186 | static 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 | */ |
121 | int join_cgroup(char *path) | 121 | int 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 | */ |
161 | int create_and_get_cgroup(char *path) | 161 | int 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 | */ |
189 | unsigned long long get_cgroup_id(char *path) | 189 | unsigned 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 | ||
12 | int create_and_get_cgroup(char *path); | 12 | int create_and_get_cgroup(const char *path); |
13 | int join_cgroup(char *path); | 13 | int join_cgroup(const char *path); |
14 | int setup_cgroup_environment(void); | 14 | int setup_cgroup_environment(void); |
15 | void cleanup_cgroup_environment(void); | 15 | void cleanup_cgroup_environment(void); |
16 | unsigned long long get_cgroup_id(char *path); | 16 | unsigned 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 | |||
10 | struct 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 | |||
17 | SEC("cgroup/connect6") | ||
18 | int 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 | |||
33 | SEC("sockops") | ||
34 | int 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 | |||
58 | int _version SEC("version") = 1; | ||
59 | |||
60 | char _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 | |||
9 | import select | 9 | import select |
10 | 10 | ||
11 | def read(sock, n): | 11 | def 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: | |||
39 | except socket.error as e: | 39 | except socket.error as e: |
40 | sys.exit(1) | 40 | sys.exit(1) |
41 | 41 | ||
42 | buf = '' | 42 | buf = b'' |
43 | n = 0 | 43 | n = 0 |
44 | while n < 1000: | 44 | while n < 1000: |
45 | buf += '+' | 45 | buf += b'+' |
46 | n += 1 | 46 | n += 1 |
47 | 47 | ||
48 | sock.settimeout(1); | 48 | sock.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 | |||
9 | import select | 9 | import select |
10 | 10 | ||
11 | def read(sock, n): | 11 | def 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 | ||
44 | try: serverSocket.bind((host, 0)) | 44 | try: serverSocket.bind((host, 0)) |
45 | except socket.error as msg: | 45 | except socket.error as msg: |
46 | print 'bind fails: ', msg | 46 | print('bind fails: ' + str(msg)) |
47 | 47 | ||
48 | sn = serverSocket.getsockname() | 48 | sn = serverSocket.getsockname() |
49 | serverPort = sn[1] | 49 | serverPort = sn[1] |
@@ -51,10 +51,10 @@ serverPort = sn[1] | |||
51 | cmdStr = ("./tcp_client.py %d &") % (serverPort) | 51 | cmdStr = ("./tcp_client.py %d &") % (serverPort) |
52 | os.system(cmdStr) | 52 | os.system(cmdStr) |
53 | 53 | ||
54 | buf = '' | 54 | buf = b'' |
55 | n = 0 | 55 | n = 0 |
56 | while n < 500: | 56 | while n < 500: |
57 | buf += '.' | 57 | buf += b'.' |
58 | n += 1 | 58 | n += 1 |
59 | 59 | ||
60 | serverSocket.listen(MAX_PORTS) | 60 | serverSocket.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 | ||
23 | static uint32_t pass_cnt; | 24 | static uint32_t pass_cnt; |
24 | static uint32_t error_cnt; | 25 | static 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 | |||
100 | static struct args { | 97 | static 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 | ||
2096 | static struct btf_raw_test pprint_test = { | 2095 | static 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 | ||
2154 | static 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 | |||
2158 | static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i) | 2188 | static 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 | ||
2169 | static int test_pprint(void) | 2199 | static 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 | ||
2353 | static 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 | |||
2317 | static void usage(const char *cmd) | 2371 | static 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 | |||
10 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; | ||
11 | |||
12 | #define TEST_CGROUP "/test-bpf-cgroup-storage-buf/" | ||
13 | |||
14 | int 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 | |||
125 | err: | ||
126 | cleanup_cgroup_environment(); | ||
127 | |||
128 | out: | ||
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 | |||
29 | static int map_flags; | 34 | static 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 | |||
31 | static void test_hashmap(int task, void *data) | 45 | static 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 | ||
1167 | static 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 | |||
1244 | static 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 | |||
1153 | static void run_all_tests(void) | 1411 | static 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 | ||
1175 | int main(void) | 1435 | int 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 | ||
161 | def bpftool(args, JSON=True, ns="", fail=True): | 161 | def 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 | ||
164 | def bpftool_prog_list(expected=None, ns=""): | 165 | def 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 | ||
205 | def 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 | |||
204 | def ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): | 220 | def 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 | ||
553 | def check_extack_nsim(output, reference, args): | 578 | def check_extack_nsim(output, reference, args): |
554 | check_extack(output, "Error: netdevsim: " + reference, args) | 579 | check_extack(output, "netdevsim: " + reference, args) |
555 | 580 | ||
556 | def check_no_extack(res, needle): | 581 | def 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 | ||
1090 | finally: | 1284 | finally: |
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 | |||
32 | static int result_map, tmp_index_ovr_map, linum_map, data_check_map; | ||
33 | static enum result expected_results[NR_RESULTS]; | ||
34 | static int sk_fds[REUSEPORT_ARRAY_SIZE]; | ||
35 | static int reuseport_array, outer_map; | ||
36 | static int select_by_skb_data_prog; | ||
37 | static int saved_tcp_syncookie; | ||
38 | static struct bpf_object *obj; | ||
39 | static int saved_tcp_fo; | ||
40 | static __u32 index_zero; | ||
41 | static int epfd; | ||
42 | |||
43 | static 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 | |||
58 | static 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 | |||
85 | static 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 | |||
140 | static 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 | |||
150 | static 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 | |||
160 | static 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 | |||
177 | static 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 | |||
193 | static 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 | |||
199 | static 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 | |||
207 | static void enable_syncookie(void) | ||
208 | { | ||
209 | write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 2); | ||
210 | } | ||
211 | |||
212 | static void disable_syncookie(void) | ||
213 | { | ||
214 | write_int_sysctl(TCP_SYNCOOKIE_SYSCTL, 0); | ||
215 | } | ||
216 | |||
217 | static __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 | |||
229 | static 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 | |||
305 | static 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 | |||
346 | static 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 | |||
368 | static 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 | |||
424 | static 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 | |||
437 | static 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 | |||
445 | static 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 | |||
458 | static 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 | |||
473 | static 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 | |||
513 | static 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 | |||
526 | static 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 | |||
600 | static 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 | |||
611 | static 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 | |||
624 | static void cleanup(void) | ||
625 | { | ||
626 | close(outer_map); | ||
627 | close(reuseport_array); | ||
628 | bpf_object__close(obj); | ||
629 | } | ||
630 | |||
631 | static 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 | |||
674 | int 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 | |||
9 | enum 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 | |||
19 | struct cmd { | ||
20 | __u32 reuseport_index; | ||
21 | __u32 pass_on_failure; | ||
22 | }; | ||
23 | |||
24 | struct 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 | |||
18 | int _version SEC("version") = 1; | ||
19 | |||
20 | #ifndef offsetof | ||
21 | #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) | ||
22 | #endif | ||
23 | |||
24 | struct 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 | |||
31 | struct 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 | |||
38 | struct 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 | |||
45 | struct 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 | |||
52 | struct 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 | |||
65 | SEC("select_by_skb_data") | ||
66 | int _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 | |||
168 | done: | ||
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 | |||
180 | char _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 | |||
5 | set -eu | ||
6 | |||
7 | wait_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 | |||
23 | setup() | ||
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 | |||
40 | cleanup() | ||
41 | { | ||
42 | ip link del ${TEST_IF} 2>/dev/null || : | ||
43 | ip link del ${TEST_IF_PEER} 2>/dev/null || : | ||
44 | } | ||
45 | |||
46 | main() | ||
47 | { | ||
48 | trap cleanup EXIT 2 3 6 15 | ||
49 | setup | ||
50 | ${PROG} ${TEST_IF} ${BPF_PROG_ID} | ||
51 | } | ||
52 | |||
53 | DIR=$(dirname $0) | ||
54 | TEST_IF="test_cgid_1" | ||
55 | TEST_IF_PEER="test_cgid_2" | ||
56 | MAX_PING_TRIES=5 | ||
57 | BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o" | ||
58 | BPF_PROG_SECTION="cgroup_id_logger" | ||
59 | BPF_PROG_ID=0 | ||
60 | PROG="${DIR}/test_skb_cgroup_id_user" | ||
61 | |||
62 | main | ||
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 | |||
13 | struct 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 | |||
20 | static __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 | |||
31 | SEC("cgroup_id_logger") | ||
32 | int 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 | |||
45 | int _version SEC("version") = 1; | ||
46 | |||
47 | char _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 | |||
27 | static 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 | |||
49 | static 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; | ||
72 | err: | ||
73 | err = -1; | ||
74 | out: | ||
75 | if (fd >= 0) | ||
76 | close(fd); | ||
77 | return err; | ||
78 | } | ||
79 | |||
80 | int 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]); | ||
110 | err: | ||
111 | if (prog_fd >= 0) | ||
112 | close(prog_fd); | ||
113 | return map_fd; | ||
114 | } | ||
115 | |||
116 | int 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; | ||
145 | err: | ||
146 | err = -1; | ||
147 | out: | ||
148 | if (map_fd >= 0) | ||
149 | close(map_fd); | ||
150 | return err; | ||
151 | } | ||
152 | |||
153 | int 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; | ||
180 | err: | ||
181 | err = -1; | ||
182 | out: | ||
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 | ||
1001 | static int sendmsg_to_server(const struct sockaddr_storage *addr, | 998 | static 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 | ||
1067 | static 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 | |||
1069 | static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr) | 1076 | static 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; |
1189 | err: | 1210 | err: |
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 | |||
21 | static 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 | |||
49 | close_out: | ||
50 | close(fd); | ||
51 | fd = -1; | ||
52 | out: | ||
53 | return fd; | ||
54 | } | ||
55 | |||
56 | static 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 | |||
80 | close_out: | ||
81 | close(fd); | ||
82 | fd = -1; | ||
83 | out: | ||
84 | return fd; | ||
85 | } | ||
86 | |||
87 | static 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; | ||
130 | err: | ||
131 | err = -1; | ||
132 | out: | ||
133 | return err; | ||
134 | } | ||
135 | |||
136 | static 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; | ||
190 | err: | ||
191 | err = -1; | ||
192 | out: | ||
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 | |||
200 | int 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; | ||
219 | err: | ||
220 | err = -1; | ||
221 | out: | ||
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 | |||
30 | int 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; | ||
53 | err: | ||
54 | return -1; | ||
55 | } | ||
56 | |||
25 | static int bpf_find_map(const char *test, struct bpf_object *obj, | 57 | static 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 | |||
45 | int main(int argc, char **argv) | 70 | int 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; |
124 | err: | 126 | err: |
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 | ||
12377 | static int probe_filter_length(const struct bpf_insn *fp) | 12516 | static 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 | ||
12618 | static 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 | |||
12479 | static char bpf_vlog[UINT_MAX >> 8]; | 12631 | static char bpf_vlog[UINT_MAX >> 8]; |
12480 | 12632 | ||
12481 | static void do_test_fixup(struct bpf_test *test, struct bpf_insn *prog, | 12633 | static 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 | ||
12560 | static void do_test_single(struct bpf_test *test, bool unpriv, | 12721 | static 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; | |||
88 | static int page_cnt = 8; | 88 | static int page_cnt = 8; |
89 | static struct perf_event_mmap_page *header; | 89 | static struct perf_event_mmap_page *header; |
90 | 90 | ||
91 | int perf_event_mmap(int fd) | 91 | int 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 | ||
109 | int perf_event_mmap(int fd) | ||
110 | { | ||
111 | return perf_event_mmap_header(fd, &header); | ||
112 | } | ||
113 | |||
109 | static int perf_event_poll(int fd) | 114 | static 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 | |||
172 | int 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 | ||
7 | struct ksym { | 8 | struct ksym { |
8 | long addr; | 9 | long addr; |
@@ -16,6 +17,9 @@ long ksym_get_addr(const char *name); | |||
16 | typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size); | 17 | typedef enum bpf_perf_event_ret (*perf_event_print_fn)(void *data, int size); |
17 | 18 | ||
18 | int perf_event_mmap(int fd); | 19 | int perf_event_mmap(int fd); |
20 | int 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 */ |
20 | int perf_event_poller(int fd, perf_event_print_fn output_fn); | 22 | int perf_event_poller(int fd, perf_event_print_fn output_fn); |
23 | int 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 | |||
10 | lib_dir=$(dirname $0)/../../../net/forwarding | ||
11 | |||
12 | NUM_NETIFS=6 | ||
13 | source $lib_dir/lib.sh | ||
14 | source $lib_dir/mirror_lib.sh | ||
15 | source $lib_dir/mirror_gre_lib.sh | ||
16 | source $lib_dir/mirror_gre_topo_lib.sh | ||
17 | |||
18 | setup_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 | |||
33 | cleanup_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 | |||
42 | setup_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 | |||
63 | cleanup_soft() | ||
64 | { | ||
65 | ip link del dev v1 | ||
66 | |||
67 | tunnel_destroy h3-gt6-soft | ||
68 | tunnel_destroy gt6-soft | ||
69 | } | ||
70 | |||
71 | setup_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 | |||
95 | cleanup() | ||
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 | |||
112 | test_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 | |||
132 | test_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 | |||
151 | test_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 | |||
170 | test_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 | |||
178 | test_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 | |||
189 | test_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 | |||
200 | trap cleanup EXIT | ||
201 | |||
202 | setup_prepare | ||
203 | setup_wait | ||
204 | |||
205 | if ! 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 | ||
209 | fi | ||
210 | |||
211 | tcflags="skip_hw" | ||
212 | test_sw | ||
213 | |||
214 | tcflags="skip_sw" | ||
215 | test_hw | ||
216 | |||
217 | exit $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 | |||
37 | source ../../../../net/forwarding/mirror_lib.sh | ||
38 | |||
39 | MIRROR_NUM_NETIFS=6 | ||
40 | |||
41 | mirror_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 | |||
49 | mirror_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 | |||
91 | mirror_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 | |||
133 | mirror_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 | |||
147 | mirror_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 | |||
179 | mirror_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 | |||
27 | ALL_TESTS=" | ||
28 | ping_ipv4 | ||
29 | test_dscp | ||
30 | " | ||
31 | |||
32 | lib_dir=$(dirname $0)/../../../net/forwarding | ||
33 | |||
34 | NUM_NETIFS=4 | ||
35 | source $lib_dir/lib.sh | ||
36 | |||
37 | h1_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 | |||
46 | h1_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 | |||
53 | h2_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 | |||
60 | h2_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 | |||
67 | dscp_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 | |||
76 | switch_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 | |||
91 | switch_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 | |||
102 | setup_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 | |||
117 | cleanup() | ||
118 | { | ||
119 | pre_cleanup | ||
120 | |||
121 | switch_destroy | ||
122 | h2_destroy | ||
123 | h1_destroy | ||
124 | |||
125 | vrf_cleanup | ||
126 | } | ||
127 | |||
128 | ping_ipv4() | ||
129 | { | ||
130 | ping_test $h1 192.0.2.2 | ||
131 | } | ||
132 | |||
133 | dscp_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 | |||
175 | test_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 | |||
182 | trap cleanup EXIT | ||
183 | |||
184 | setup_prepare | ||
185 | setup_wait | ||
186 | |||
187 | tests_run | ||
188 | |||
189 | exit $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 | |||
30 | ALL_TESTS=" | ||
31 | ping_ipv4 | ||
32 | test_update | ||
33 | test_no_update | ||
34 | " | ||
35 | |||
36 | lib_dir=$(dirname $0)/../../../net/forwarding | ||
37 | |||
38 | NUM_NETIFS=4 | ||
39 | source $lib_dir/lib.sh | ||
40 | |||
41 | reprioritize() | ||
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 | |||
53 | h1_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 | |||
63 | h1_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 | |||
71 | h2_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 | |||
79 | h2_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 | |||
87 | dscp_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 | |||
96 | switch_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 | |||
107 | switch_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 | |||
117 | setup_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 | |||
133 | cleanup() | ||
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 | |||
145 | ping_ipv4() | ||
146 | { | ||
147 | ping_test $h1 192.0.2.18 | ||
148 | } | ||
149 | |||
150 | dscp_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 | |||
216 | test_update() | ||
217 | { | ||
218 | __test_update 1 reprioritize | ||
219 | } | ||
220 | |||
221 | test_no_update() | ||
222 | { | ||
223 | __test_update 0 echo | ||
224 | } | ||
225 | |||
226 | trap cleanup EXIT | ||
227 | |||
228 | setup_prepare | ||
229 | setup_wait | ||
230 | |||
231 | tests_run | ||
232 | |||
233 | exit $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 | |||
4 | ROUTER_NUM_NETIFS=4 | ||
5 | |||
6 | router_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 | |||
12 | router_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 | |||
18 | router_h2_create() | ||
19 | { | ||
20 | simple_if_init $h2 192.0.2.1/24 | ||
21 | tc qdisc add dev $h2 handle ffff: ingress | ||
22 | } | ||
23 | |||
24 | router_h2_destroy() | ||
25 | { | ||
26 | tc qdisc del dev $h2 handle ffff: ingress | ||
27 | simple_if_fini $h2 192.0.2.1/24 | ||
28 | } | ||
29 | |||
30 | router_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 | |||
39 | router_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 | |||
48 | router_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 | |||
67 | router_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 | |||
76 | router_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 | |||
103 | router_routes_destroy() | ||
104 | { | ||
105 | if [[ -v ROUTE_FILE ]]; then | ||
106 | rm -f $ROUTE_FILE | ||
107 | fi | ||
108 | } | ||
109 | |||
110 | router_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 | |||
156 | router_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 | |||
8 | lib_dir=$(dirname $0)/../../../../net/forwarding | ||
9 | |||
10 | ALL_TESTS="single_mask_test identical_filters_test two_masks_test \ | ||
11 | multiple_masks_test ctcam_edge_cases_test" | ||
12 | NUM_NETIFS=2 | ||
13 | source $lib_dir/tc_common.sh | ||
14 | source $lib_dir/lib.sh | ||
15 | |||
16 | tcflags="skip_hw" | ||
17 | |||
18 | h1_create() | ||
19 | { | ||
20 | simple_if_init $h1 192.0.2.1/24 198.51.100.1/24 | ||
21 | } | ||
22 | |||
23 | h1_destroy() | ||
24 | { | ||
25 | simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24 | ||
26 | } | ||
27 | |||
28 | h2_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 | |||
34 | h2_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 | |||
40 | single_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 | |||
85 | identical_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 | |||
135 | two_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 | |||
176 | multiple_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 | |||
222 | ctcam_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 | |||
262 | ctcam_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 | |||
295 | ctcam_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 | |||
316 | ctcam_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 | |||
327 | setup_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 | |||
340 | cleanup() | ||
341 | { | ||
342 | pre_cleanup | ||
343 | |||
344 | h2_destroy | ||
345 | h1_destroy | ||
346 | |||
347 | vrf_cleanup | ||
348 | } | ||
349 | |||
350 | trap cleanup EXIT | ||
351 | |||
352 | setup_prepare | ||
353 | setup_wait | ||
354 | |||
355 | tests_run | ||
356 | |||
357 | if ! tc_offload_check; then | ||
358 | check_err 1 "Could not test offloaded functionality" | ||
359 | log_test "mlxsw-specific tests for tc flower" | ||
360 | exit | ||
361 | else | ||
362 | tcflags="skip_sw" | ||
363 | tests_run | ||
364 | fi | ||
365 | |||
366 | exit $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 | |||
4 | source "../../../../net/forwarding/devlink_lib.sh" | ||
5 | |||
6 | if [ "$DEVLINK_VIDDID" != "15b3:cb84" ]; then | ||
7 | echo "SKIP: test is tailored for Mellanox Spectrum" | ||
8 | exit 1 | ||
9 | fi | ||
10 | |||
11 | # Needed for returning to default | ||
12 | declare -A KVD_DEFAULTS | ||
13 | |||
14 | KVD_CHILDREN="linear hash_single hash_double" | ||
15 | KVDL_CHILDREN="singles chunks large_chunks" | ||
16 | |||
17 | devlink_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 | |||
34 | devlink_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 | |||
65 | devlink_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 | |||
82 | KVD_PROFILES="default scale ipv4_max" | ||
83 | |||
84 | devlink_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 | |||
4 | NUM_NETIFS=1 | ||
5 | source devlink_lib_spectrum.sh | ||
6 | |||
7 | setup_prepare() | ||
8 | { | ||
9 | devlink_sp_read_kvd_defaults | ||
10 | } | ||
11 | |||
12 | cleanup() | ||
13 | { | ||
14 | pre_cleanup | ||
15 | devlink_sp_size_kvd_to_default | ||
16 | } | ||
17 | |||
18 | trap cleanup EXIT | ||
19 | |||
20 | setup_prepare | ||
21 | |||
22 | profiles_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 | |||
40 | resources_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 | |||
66 | resources_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 | |||
113 | profiles_test | ||
114 | resources_min_test | ||
115 | resources_max_test | ||
116 | |||
117 | exit "$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 | ||
2 | source ../mirror_gre_scale.sh | ||
3 | |||
4 | mirror_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 | |||
4 | NUM_NETIFS=6 | ||
5 | source ../../../../net/forwarding/lib.sh | ||
6 | source ../../../../net/forwarding/tc_common.sh | ||
7 | source devlink_lib_spectrum.sh | ||
8 | |||
9 | current_test="" | ||
10 | |||
11 | cleanup() | ||
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 | |||
20 | devlink_sp_read_kvd_defaults | ||
21 | trap cleanup EXIT | ||
22 | |||
23 | ALL_TESTS="router tc_flower mirror_gre" | ||
24 | for 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 | ||
52 | done | ||
53 | current_test="" | ||
54 | |||
55 | exit "$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 | ||
2 | source ../router_scale.sh | ||
3 | |||
4 | router_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 | ||
2 | source ../tc_flower_scale.sh | ||
3 | |||
4 | tc_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 | |||
10 | TC_FLOWER_NUM_NETIFS=2 | ||
11 | |||
12 | tc_flower_h1_create() | ||
13 | { | ||
14 | simple_if_init $h1 | ||
15 | tc qdisc add dev $h1 clsact | ||
16 | } | ||
17 | |||
18 | tc_flower_h1_destroy() | ||
19 | { | ||
20 | tc qdisc del dev $h1 clsact | ||
21 | simple_if_fini $h1 | ||
22 | } | ||
23 | |||
24 | tc_flower_h2_create() | ||
25 | { | ||
26 | simple_if_init $h2 | ||
27 | tc qdisc add dev $h2 clsact | ||
28 | } | ||
29 | |||
30 | tc_flower_h2_destroy() | ||
31 | { | ||
32 | tc qdisc del dev $h2 clsact | ||
33 | simple_if_fini $h2 | ||
34 | } | ||
35 | |||
36 | tc_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 | |||
47 | tc_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 | |||
61 | tc_flower_addr() | ||
62 | { | ||
63 | local num=$1; shift | ||
64 | |||
65 | printf "2001:db8:1::%x" $num | ||
66 | } | ||
67 | |||
68 | tc_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 | |||
115 | tc_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 | |||
13 | udpgso_bench_rx | 13 | udpgso_bench_rx |
14 | udpgso_bench_tx | 14 | udpgso_bench_tx |
15 | tcp_inq | 15 | tcp_inq |
16 | tls | ||
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 | |||
13 | TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd | 13 | TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd |
14 | TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx | 14 | TEST_GEN_FILES += udpgso udpgso_bench_tx udpgso_bench_rx |
15 | TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa | 15 | TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa |
16 | TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict | 16 | TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls |
17 | 17 | ||
18 | include ../lib.mk | 18 | include ../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 | ||
47 | o Where possible, reuse an existing topology for different tests instead | 47 | o Where possible, reuse an existing topology for different tests instead |
48 | of recreating the same topology. | 48 | of recreating the same topology. |
49 | o Tests that use anything but the most trivial topologies should include | ||
50 | an ASCII art showing the topology. | ||
49 | o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and | 51 | o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and |
50 | RFC 5737, respectively. | 52 | RFC 5737, respectively. |
51 | o Where possible, tests shall be written so that they can be reused by | 53 | o 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 | |||
4 | ALL_TESTS="ping_ipv4 ping_ipv6 flooding" | ||
5 | NUM_NETIFS=6 | ||
6 | CHECK_TC="yes" | ||
7 | source lib.sh | ||
8 | |||
9 | h1_create() | ||
10 | { | ||
11 | simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 | ||
12 | } | ||
13 | |||
14 | h1_destroy() | ||
15 | { | ||
16 | simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 | ||
17 | } | ||
18 | |||
19 | h2_create() | ||
20 | { | ||
21 | simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 | ||
22 | } | ||
23 | |||
24 | h2_destroy() | ||
25 | { | ||
26 | simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 | ||
27 | } | ||
28 | |||
29 | h3_create() | ||
30 | { | ||
31 | simple_if_init $h3 192.0.2.3/24 2001:db8:1::3/64 | ||
32 | } | ||
33 | |||
34 | h3_destroy() | ||
35 | { | ||
36 | simple_if_fini $h3 192.0.2.3/24 2001:db8:1::3/64 | ||
37 | } | ||
38 | |||
39 | switch_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 | |||
60 | switch_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 | |||
69 | setup_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 | |||
89 | cleanup() | ||
90 | { | ||
91 | pre_cleanup | ||
92 | |||
93 | switch_destroy | ||
94 | |||
95 | h3_destroy | ||
96 | h2_destroy | ||
97 | h1_destroy | ||
98 | |||
99 | vrf_cleanup | ||
100 | } | ||
101 | |||
102 | ping_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 | |||
115 | ping_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 | |||
128 | flooding() | ||
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 | |||
144 | trap cleanup EXIT | ||
145 | |||
146 | setup_prepare | ||
147 | setup_wait | ||
148 | |||
149 | tests_run | ||
150 | |||
151 | exit $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 | |||
7 | relative_path="${BASH_SOURCE%/*}" | ||
8 | if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then | ||
9 | relative_path="." | ||
10 | fi | ||
11 | |||
12 | source "$relative_path/lib.sh" | ||
13 | |||
14 | ############################################################################## | ||
15 | # Defines | ||
16 | |||
17 | DEVLINK_DEV=$(devlink port show | grep "${NETIFS[p1]}" | \ | ||
18 | grep -v "${NETIFS[p1]}[0-9]" | cut -d" " -f1 | \ | ||
19 | rev | cut -d"/" -f2- | rev) | ||
20 | if [ -z "$DEVLINK_DEV" ]; then | ||
21 | echo "SKIP: ${NETIFS[p1]} has no devlink device registered for it" | ||
22 | exit 1 | ||
23 | fi | ||
24 | if [[ "$(echo $DEVLINK_DEV | grep -c pci)" -eq 0 ]]; then | ||
25 | echo "SKIP: devlink device's bus is not PCI" | ||
26 | exit 1 | ||
27 | fi | ||
28 | |||
29 | DEVLINK_VIDDID=$(lspci -s $(echo $DEVLINK_DEV | cut -d"/" -f2) \ | ||
30 | -n | cut -d" " -f3) | ||
31 | |||
32 | ############################################################################## | ||
33 | # Sanity checks | ||
34 | |||
35 | devlink -j resource show "$DEVLINK_DEV" &> /dev/null | ||
36 | if [ $? -ne 0 ]; then | ||
37 | echo "SKIP: iproute2 too old, missing devlink resource support" | ||
38 | exit 1 | ||
39 | fi | ||
40 | |||
41 | ############################################################################## | ||
42 | # Devlink helpers | ||
43 | |||
44 | devlink_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 | |||
60 | devlink_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 | |||
76 | devlink_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 | |||
87 | devlink_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 | |||
98 | devlink_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 | |||
58 | ALL_TESTS=" | ||
59 | ping_ipv4 | ||
60 | multipath_ipv4 | ||
61 | " | ||
62 | |||
63 | NUM_NETIFS=6 | ||
64 | source lib.sh | ||
65 | |||
66 | h1_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 | |||
72 | h1_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 | |||
78 | sw1_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 | |||
104 | sw1_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 | |||
124 | sw2_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 | |||
144 | sw2_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 | |||
162 | h2_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 | |||
168 | h2_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 | |||
174 | setup_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 | |||
192 | cleanup() | ||
193 | { | ||
194 | pre_cleanup | ||
195 | |||
196 | h2_destroy | ||
197 | sw2_destroy | ||
198 | sw1_destroy | ||
199 | h1_destroy | ||
200 | vrf_cleanup | ||
201 | } | ||
202 | |||
203 | multipath4_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 | |||
234 | ping_ipv4() | ||
235 | { | ||
236 | ping_test $h1 192.0.2.18 | ||
237 | } | ||
238 | |||
239 | multipath_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 | |||
247 | trap cleanup EXIT | ||
248 | |||
249 | setup_prepare | ||
250 | setup_wait | ||
251 | tests_run | ||
252 | |||
253 | exit $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 @@ | |||
8 | PING=${PING:=ping} | 8 | PING=${PING:=ping} |
9 | PING6=${PING6:=ping6} | 9 | PING6=${PING6:=ping6} |
10 | MZ=${MZ:=mausezahn} | 10 | MZ=${MZ:=mausezahn} |
11 | ARPING=${ARPING:=arping} | ||
12 | TEAMD=${TEAMD:=teamd} | ||
11 | WAIT_TIME=${WAIT_TIME:=5} | 13 | WAIT_TIME=${WAIT_TIME:=5} |
12 | PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} | 14 | PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} |
13 | PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} | 15 | PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} |
14 | NETIF_TYPE=${NETIF_TYPE:=veth} | 16 | NETIF_TYPE=${NETIF_TYPE:=veth} |
15 | NETIF_CREATE=${NETIF_CREATE:=yes} | 17 | NETIF_CREATE=${NETIF_CREATE:=yes} |
16 | 18 | ||
17 | if [[ -f forwarding.config ]]; then | 19 | relative_path="${BASH_SOURCE%/*}" |
18 | source forwarding.config | 20 | if [[ "$relative_path" == "${BASH_SOURCE}" ]]; then |
21 | relative_path="." | ||
22 | fi | ||
23 | |||
24 | if [[ -f $relative_path/forwarding.config ]]; then | ||
25 | source "$relative_path/forwarding.config" | ||
19 | fi | 26 | fi |
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 | ||
40 | check_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 | ||
49 | check_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 | |||
39 | if [[ "$(id -u)" -ne 0 ]]; then | 58 | if [[ "$(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 |
46 | fi | 65 | fi |
47 | 66 | ||
48 | if [[ ! -x "$(command -v jq)" ]]; then | 67 | require_command() |
49 | echo "SKIP: jq not installed" | 68 | { |
50 | exit 1 | 69 | local cmd=$1; shift |
51 | fi | ||
52 | 70 | ||
53 | if [[ ! -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 |
56 | fi | 74 | fi |
75 | } | ||
76 | |||
77 | require_command jq | ||
78 | require_command $MZ | ||
57 | 79 | ||
58 | if [[ ! -v NUM_NETIFS ]]; then | 80 | if [[ ! -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 | ||
176 | check_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 | |||
154 | log_test() | 189 | log_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 | ||
223 | setup_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 | |||
188 | setup_wait() | 238 | setup_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 | ||
250 | lldpad_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 | |||
260 | lldpad_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 | |||
206 | pre_cleanup() | 271 | pre_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 | |||
290 | simple_if_init() | 378 | simple_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 | ||
308 | simple_if_fini() | 393 | simple_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 | ||
451 | team_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 | |||
466 | team_destroy() | ||
467 | { | ||
468 | local if_name=$1; shift | ||
469 | |||
470 | $TEAMD -t $if_name -k | ||
471 | } | ||
472 | |||
368 | master_name_get() | 473 | master_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 | ||
391 | mac_get() | 497 | mac_get() |
@@ -437,7 +543,9 @@ forwarding_restore() | |||
437 | 543 | ||
438 | tc_offload_check() | 544 | tc_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 | ||
461 | trap_uninstall() | 575 | trap_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 | ||
469 | slow_path_trap_install() | 583 | slow_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 | |||
670 | dscp_capture_install() | ||
671 | { | ||
672 | local dev=$1; shift | ||
673 | local base=$1; shift | ||
674 | |||
675 | __dscp_capture_add_del add $dev $base | ||
676 | } | ||
677 | |||
678 | dscp_capture_uninstall() | ||
679 | { | ||
680 | local dev=$1; shift | ||
681 | local base=$1; shift | ||
682 | |||
683 | __dscp_capture_add_del del $dev $base | ||
684 | } | ||
685 | |||
686 | dscp_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 | |||
540 | matchall_sink_create() | 698 | matchall_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 | ||
718 | multipath_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 | ||
563 | ping_test() | 764 | ping_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 | |||
774 | ping_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 | ||
577 | ping6_test() | 783 | ping6_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 | |||
793 | ping6_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 | |||
43 | ALL_TESTS=" | ||
44 | test_gretap | ||
45 | test_ip6gretap | ||
46 | " | ||
47 | |||
48 | NUM_NETIFS=6 | ||
49 | source lib.sh | ||
50 | source mirror_lib.sh | ||
51 | source mirror_gre_lib.sh | ||
52 | source mirror_gre_topo_lib.sh | ||
53 | |||
54 | setup_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 | |||
82 | cleanup() | ||
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 | |||
94 | test_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 | |||
100 | test_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 | |||
106 | test_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 | |||
117 | trap cleanup EXIT | ||
118 | |||
119 | setup_prepare | ||
120 | setup_wait | ||
121 | |||
122 | tcflags="skip_hw" | ||
123 | test_all | ||
124 | |||
125 | if ! tc_offload_check; then | ||
126 | echo "WARN: Could not test offloaded functionality" | ||
127 | else | ||
128 | tcflags="skip_sw" | ||
129 | test_all | ||
130 | fi | ||
131 | |||
132 | exit $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 | ||
75 | test_gretap() | 75 | test_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 | ||
80 | test_ip6gretap() | 81 | test_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 | ||
85 | test_gretap_stp() | 87 | test_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 | |||
40 | ALL_TESTS=" | ||
41 | test_gretap | ||
42 | test_ip6gretap | ||
43 | " | ||
44 | |||
45 | NUM_NETIFS=6 | ||
46 | source lib.sh | ||
47 | source mirror_lib.sh | ||
48 | source mirror_gre_lib.sh | ||
49 | source mirror_gre_topo_lib.sh | ||
50 | |||
51 | setup_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 | |||
77 | cleanup() | ||
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 | |||
88 | test_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 | |||
94 | test_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 | |||
100 | tests() | ||
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 | |||
111 | trap cleanup EXIT | ||
112 | |||
113 | setup_prepare | ||
114 | setup_wait | ||
115 | |||
116 | tcflags="skip_hw" | ||
117 | tests | ||
118 | |||
119 | if ! tc_offload_check; then | ||
120 | echo "WARN: Could not test offloaded functionality" | ||
121 | else | ||
122 | tcflags="skip_sw" | ||
123 | tests | ||
124 | fi | ||
125 | |||
126 | exit $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 | |||
47 | ALL_TESTS=" | ||
48 | test_mirror_gretap_first | ||
49 | test_mirror_gretap_second | ||
50 | " | ||
51 | |||
52 | NUM_NETIFS=6 | ||
53 | source lib.sh | ||
54 | source mirror_lib.sh | ||
55 | source mirror_gre_lib.sh | ||
56 | |||
57 | require_command $ARPING | ||
58 | |||
59 | vlan_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 | |||
71 | vlan_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 | |||
82 | h1_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 | |||
88 | h1_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 | |||
94 | h2_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 | |||
100 | h2_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 | |||
106 | h3_create() | ||
107 | { | ||
108 | simple_if_init $h3 192.0.2.130/28 | ||
109 | tc qdisc add dev $h3 clsact | ||
110 | } | ||
111 | |||
112 | h3_destroy() | ||
113 | { | ||
114 | tc qdisc del dev $h3 clsact | ||
115 | simple_if_fini $h3 192.0.2.130/28 | ||
116 | } | ||
117 | |||
118 | h4_create() | ||
119 | { | ||
120 | simple_if_init $h4 192.0.2.130/28 | ||
121 | tc qdisc add dev $h4 clsact | ||
122 | } | ||
123 | |||
124 | h4_destroy() | ||
125 | { | ||
126 | tc qdisc del dev $h4 clsact | ||
127 | simple_if_fini $h4 192.0.2.130/28 | ||
128 | } | ||
129 | |||
130 | switch_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 | |||
152 | switch_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 | |||
173 | setup_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 | |||
197 | cleanup() | ||
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 | |||
214 | test_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 | |||
247 | test_mirror_gretap_first() | ||
248 | { | ||
249 | test_lag_slave $h3 $swp3 $swp4 "mirror to gretap: LAG first slave" | ||
250 | } | ||
251 | |||
252 | test_mirror_gretap_second() | ||
253 | { | ||
254 | test_lag_slave $h4 $swp4 $swp3 "mirror to gretap: LAG second slave" | ||
255 | } | ||
256 | |||
257 | test_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 | |||
268 | trap cleanup EXIT | ||
269 | |||
270 | setup_prepare | ||
271 | setup_wait | ||
272 | |||
273 | tcflags="skip_hw" | ||
274 | test_all | ||
275 | |||
276 | if ! tc_offload_check; then | ||
277 | echo "WARN: Could not test offloaded functionality" | ||
278 | else | ||
279 | tcflags="skip_sw" | ||
280 | test_all | ||
281 | fi | ||
282 | |||
283 | exit $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 | |||
45 | ALL_TESTS=" | ||
46 | test_mirror_gretap_first | ||
47 | test_mirror_gretap_second | ||
48 | " | ||
49 | |||
50 | NUM_NETIFS=6 | ||
51 | source lib.sh | ||
52 | source mirror_lib.sh | ||
53 | source mirror_gre_lib.sh | ||
54 | |||
55 | require_command $ARPING | ||
56 | |||
57 | vlan_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 | |||
69 | vlan_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 | |||
80 | h1_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 | |||
86 | h1_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 | |||
92 | h2_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 | |||
98 | h2_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 | |||
104 | h3_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 | |||
111 | h3_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 | |||
121 | h3_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 | |||
130 | h3_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 | |||
139 | switch_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 | |||
156 | switch_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 | |||
173 | setup_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 | |||
196 | cleanup() | ||
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 | |||
212 | test_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 | |||
249 | test_mirror_gretap_first() | ||
250 | { | ||
251 | test_lag_slave $h3 $h4 "mirror to gretap: LAG first slave" | ||
252 | } | ||
253 | |||
254 | test_mirror_gretap_second() | ||
255 | { | ||
256 | test_lag_slave $h4 $h3 "mirror to gretap: LAG second slave" | ||
257 | } | ||
258 | |||
259 | test_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 | |||
270 | trap cleanup EXIT | ||
271 | |||
272 | setup_prepare | ||
273 | setup_wait | ||
274 | |||
275 | tcflags="skip_hw" | ||
276 | test_all | ||
277 | |||
278 | if ! tc_offload_check; then | ||
279 | echo "WARN: Could not test offloaded functionality" | ||
280 | else | ||
281 | tcflags="skip_sw" | ||
282 | test_all | ||
283 | fi | ||
284 | |||
285 | exit $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 | ||
3 | source mirror_lib.sh | 3 | source "$relative_path/mirror_lib.sh" |
4 | 4 | ||
5 | quick_test_span_gre_dir_ips() | 5 | quick_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 | ||
36 | source mirror_topo_lib.sh | 36 | source "$relative_path/mirror_topo_lib.sh" |
37 | 37 | ||
38 | mirror_gre_topo_h3_create() | 38 | mirror_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 | |||
28 | source mirror_gre_lib.sh | 28 | source mirror_gre_lib.sh |
29 | source mirror_gre_topo_lib.sh | 29 | source mirror_gre_topo_lib.sh |
30 | 30 | ||
31 | require_command $ARPING | ||
32 | |||
31 | setup_prepare() | 33 | setup_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 | ||
70 | test_vlan_match() | 81 | test_vlan_match() |
@@ -79,12 +90,14 @@ test_vlan_match() | |||
79 | 90 | ||
80 | test_gretap() | 91 | test_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 | ||
85 | test_ip6gretap() | 97 | test_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 | ||
90 | test_span_gre_forbidden_cpu() | 103 | test_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 | |||
4 | ALL_TESTS=" | ||
5 | ping_ipv4 | ||
6 | ping_ipv6 | ||
7 | " | ||
8 | NUM_NETIFS=4 | ||
9 | source lib.sh | ||
10 | |||
11 | h1_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 | |||
18 | h1_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 | |||
25 | h2_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 | |||
32 | h2_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 | |||
39 | router_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 | |||
52 | router_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 | |||
64 | setup_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 | |||
82 | cleanup() | ||
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 | |||
96 | ping_ipv4() | ||
97 | { | ||
98 | ping_test $h1 192.0.2.130 | ||
99 | } | ||
100 | |||
101 | ping_ipv6() | ||
102 | { | ||
103 | ping6_test $h1 2001:db8:2::2 | ||
104 | } | ||
105 | |||
106 | trap cleanup EXIT | ||
107 | |||
108 | setup_prepare | ||
109 | setup_wait | ||
110 | |||
111 | tests_run | ||
112 | |||
113 | exit $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 | |||
4 | ALL_TESTS=" | ||
5 | ping_ipv4 | ||
6 | ping_ipv6 | ||
7 | vlan | ||
8 | " | ||
9 | NUM_NETIFS=4 | ||
10 | source lib.sh | ||
11 | |||
12 | h1_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 | |||
20 | h1_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 | |||
28 | h2_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 | |||
35 | h2_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 | |||
42 | router_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 | |||
59 | router_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 | |||
71 | setup_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 | |||
89 | cleanup() | ||
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 | |||
103 | vlan() | ||
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 | |||
115 | ping_ipv4() | ||
116 | { | ||
117 | ping_test $h1 192.0.2.130 | ||
118 | } | ||
119 | |||
120 | ping_ipv6() | ||
121 | { | ||
122 | ping6_test $h1 2001:db8:2::2 | ||
123 | } | ||
124 | |||
125 | trap cleanup EXIT | ||
126 | |||
127 | setup_prepare | ||
128 | setup_wait | ||
129 | |||
130 | tests_run | ||
131 | |||
132 | exit $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 | |||
4 | ALL_TESTS="ping_ipv4" | ||
5 | NUM_NETIFS=6 | ||
6 | source lib.sh | ||
7 | |||
8 | h1_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 | |||
22 | h1_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 | |||
33 | h2_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 | |||
47 | h2_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 | |||
58 | h3_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 | |||
72 | h3_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 | |||
83 | router_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 | |||
95 | router_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 | |||
107 | setup_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 | |||
129 | cleanup() | ||
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 | |||
144 | bc_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 | |||
150 | bc_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 | |||
156 | bc_forwarding_restore() | ||
157 | { | ||
158 | sysctl_restore net.ipv4.conf.$rp1.bc_forwarding | ||
159 | sysctl_restore net.ipv4.conf.all.bc_forwarding | ||
160 | } | ||
161 | |||
162 | ping_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 | |||
177 | ping_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 | |||
226 | trap cleanup EXIT | ||
227 | |||
228 | setup_prepare | ||
229 | setup_wait | ||
230 | |||
231 | tests_run | ||
232 | |||
233 | exit $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 | ||
162 | multipath_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 | |||
201 | multipath4_test() | 162 | multipath4_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 | ||
4 | ALL_TESTS="unreachable_chain_test gact_goto_chain_test" | 4 | ALL_TESTS="unreachable_chain_test gact_goto_chain_test create_destroy_chain \ |
5 | template_filter_fits" | ||
5 | NUM_NETIFS=2 | 6 | NUM_NETIFS=2 |
6 | source tc_common.sh | 7 | source tc_common.sh |
7 | source lib.sh | 8 | source 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 | ||
84 | create_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 | |||
124 | template_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 | |||
83 | setup_prepare() | 165 | setup_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 | ||
188 | check_tc_chain_support | ||
189 | |||
106 | trap cleanup EXIT | 190 | trap cleanup EXIT |
107 | 191 | ||
108 | setup_prepare | 192 | setup_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 | ||
108 | check_tc_shblock_support | ||
109 | |||
108 | trap cleanup EXIT | 110 | trap cleanup EXIT |
109 | 111 | ||
110 | setup_prepare | 112 | setup_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 | |||
7 | setup_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 | |||
38 | cleanup() | ||
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 | |||
47 | test_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 | |||
61 | trap cleanup EXIT | ||
62 | |||
63 | setup_prepare | ||
64 | test_headroom ip6gretap gt6 | ||
65 | test_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 | #------------------------------------------------------------------- |
526 | kci_test_ipsec() | 526 | kci_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 | #------------------------------------------------------------------- | ||
626 | kci_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 | ||
694 | SA count=2 tx=3 | ||
695 | sa[0] tx ipaddr=0x00000000 00000000 00000000 00000000 | ||
696 | sa[0] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1 | ||
697 | sa[0] key=0x34333231 38373635 32313039 36353433 | ||
698 | sa[1] rx ipaddr=0x00000000 00000000 00000000 037ba8c0 | ||
699 | sa[1] spi=0x00000009 proto=0x32 salt=0x61626364 crypt=1 | ||
700 | sa[1] key=0x34333231 38373635 32313039 36353433 | ||
701 | EOF | ||
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 | |||
610 | kci_test_gretap() | 727 | kci_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 | |||
28 | FIXTURE(tls) | ||
29 | { | ||
30 | int fd, cfd; | ||
31 | bool notls; | ||
32 | }; | ||
33 | |||
34 | FIXTURE_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 | |||
94 | FIXTURE_TEARDOWN(tls) | ||
95 | { | ||
96 | close(self->fd); | ||
97 | close(self->cfd); | ||
98 | } | ||
99 | |||
100 | TEST_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 | |||
110 | TEST_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 | |||
131 | TEST_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 | |||
142 | TEST_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 | |||
154 | TEST_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 | |||
168 | TEST_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 | |||
187 | TEST_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 | |||
211 | TEST_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 | |||
248 | TEST_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 | |||
281 | TEST_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 | |||
295 | TEST_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 | |||
313 | TEST_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 | |||
335 | TEST_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 | |||
349 | TEST_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 | |||
367 | TEST_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 | |||
385 | TEST_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 | |||
414 | TEST_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 | |||
429 | TEST_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 | |||
445 | TEST_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 | |||
463 | TEST_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 | |||
473 | TEST_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 | |||
487 | TEST_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 | |||
505 | TEST_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 | |||
523 | TEST_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 | |||
539 | TEST_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 | |||
579 | TEST_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 | |||
647 | TEST_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 | |||
692 | TEST_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 | |||
109 | Run tdc.py -h to see the full list of available arguments. | 113 | Run tdc.py -h to see the full list of available arguments. |
110 | 114 | ||
111 | usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]] | 115 | usage: 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 | ||
115 | Linux TC unit tests | 119 | Linux 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 | ||
124 | selection: | 130 | selection: |
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 | ||
148 | netns: | 154 | netns: |
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 | ||
154 | valgrind: | 160 | valgrind: |
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 @@ | |||
1 | CONFIG_NET_SCHED=y | ||
2 | |||
3 | # | ||
4 | # Queueing/Scheduling | ||
5 | # | ||
6 | CONFIG_NET_SCH_PRIO=m | ||
7 | CONFIG_NET_SCH_INGRESS=m | ||
8 | |||
9 | # | ||
10 | # Classification | ||
11 | # | ||
12 | CONFIG_NET_CLS=y | ||
13 | CONFIG_NET_CLS_FW=m | ||
14 | CONFIG_NET_CLS_U32=m | ||
15 | CONFIG_CLS_U32_PERF=y | ||
16 | CONFIG_CLS_U32_MARK=y | ||
17 | CONFIG_NET_EMATCH=y | ||
18 | CONFIG_NET_EMATCH_STACK=32 | ||
19 | CONFIG_NET_EMATCH_CMP=m | ||
20 | CONFIG_NET_EMATCH_NBYTE=m | ||
21 | CONFIG_NET_EMATCH_U32=m | ||
22 | CONFIG_NET_EMATCH_META=m | ||
23 | CONFIG_NET_EMATCH_TEXT=m | ||
24 | CONFIG_NET_EMATCH_IPSET=m | ||
25 | CONFIG_NET_EMATCH_IPT=m | ||
26 | CONFIG_NET_CLS_ACT=y | ||
27 | CONFIG_NET_ACT_POLICE=m | ||
28 | CONFIG_NET_ACT_GACT=m | ||
29 | CONFIG_GACT_PROB=y | ||
30 | CONFIG_NET_ACT_MIRRED=m | ||
31 | CONFIG_NET_ACT_SAMPLE=m | ||
32 | CONFIG_NET_ACT_IPT=m | ||
33 | CONFIG_NET_ACT_NAT=m | ||
34 | CONFIG_NET_ACT_PEDIT=m | ||
35 | CONFIG_NET_ACT_SIMP=m | ||
36 | CONFIG_NET_ACT_SKBEDIT=m | ||
37 | CONFIG_NET_ACT_CSUM=m | ||
38 | CONFIG_NET_ACT_VLAN=m | ||
39 | CONFIG_NET_ACT_BPF=m | ||
40 | CONFIG_NET_ACT_CONNMARK=m | ||
41 | CONFIG_NET_ACT_SKBMOD=m | ||
42 | CONFIG_NET_ACT_IFE=m | ||
43 | CONFIG_NET_ACT_TUNNEL_KEY=m | ||
44 | CONFIG_NET_IFE_SKBMARK=m | ||
45 | CONFIG_NET_IFE_SKBPRIO=m | ||
46 | CONFIG_NET_IFE_SKBTCINDEX=m | ||
47 | CONFIG_NET_CLS_IND=y | ||
48 | CONFIG_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 | ] |