aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2018-01-17 22:13:31 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2018-01-18 16:54:26 -0500
commit7fedbb7c5a7c4bda418bc1056c06c81db36e4299 (patch)
treeff8d1f47eff09b3e16909b731c0aa5bee854698a /tools
parent395cacb5f1a0a290f1ae9ca4692c400d2b57a705 (diff)
selftest/bpf: extend the offload test with map checks
Check map device information is reported correctly, and perform basic map operations. Check device destruction gets rid of the maps and map allocation failure path by telling netdevsim to reject map offload via DebugFS. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/bpf/Makefile3
-rw-r--r--tools/testing/selftests/bpf/sample_map_ret0.c34
-rwxr-xr-xtools/testing/selftests/bpf/test_offload.py206
3 files changed, 218 insertions, 25 deletions
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index a8aa7e251c8e..3a44b655d852 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -19,7 +19,8 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
19TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 19TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
20 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 20 test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \
21 sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ 21 sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \
22 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o 22 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
23 sample_map_ret0.o
23 24
24TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \ 25TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \
25 test_offload.py 26 test_offload.py
diff --git a/tools/testing/selftests/bpf/sample_map_ret0.c b/tools/testing/selftests/bpf/sample_map_ret0.c
new file mode 100644
index 000000000000..0756303676ac
--- /dev/null
+++ b/tools/testing/selftests/bpf/sample_map_ret0.c
@@ -0,0 +1,34 @@
1/* SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) */
2#include <linux/bpf.h>
3#include "bpf_helpers.h"
4
5struct bpf_map_def SEC("maps") htab = {
6 .type = BPF_MAP_TYPE_HASH,
7 .key_size = sizeof(__u32),
8 .value_size = sizeof(long),
9 .max_entries = 2,
10};
11
12struct bpf_map_def SEC("maps") array = {
13 .type = BPF_MAP_TYPE_ARRAY,
14 .key_size = sizeof(__u32),
15 .value_size = sizeof(long),
16 .max_entries = 2,
17};
18
19/* Sample program which should always load for testing control paths. */
20SEC(".text") int func()
21{
22 __u64 key64 = 0;
23 __u32 key = 0;
24 long *value;
25
26 value = bpf_map_lookup_elem(&htab, &key);
27 if (!value)
28 return 1;
29 value = bpf_map_lookup_elem(&array, &key64);
30 if (!value)
31 return 1;
32
33 return 0;
34}
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index e3c750f17cb8..833b9c1ec450 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -20,6 +20,7 @@ import os
20import pprint 20import pprint
21import random 21import random
22import string 22import string
23import struct
23import subprocess 24import subprocess
24import time 25import time
25 26
@@ -156,6 +157,14 @@ def bpftool_prog_list(expected=None, ns=""):
156 (len(progs), expected)) 157 (len(progs), expected))
157 return progs 158 return progs
158 159
160def bpftool_map_list(expected=None, ns=""):
161 _, maps = bpftool("map show", JSON=True, ns=ns, fail=True)
162 if expected is not None:
163 if len(maps) != expected:
164 fail(True, "%d BPF maps loaded, expected %d" %
165 (len(maps), expected))
166 return maps
167
159def bpftool_prog_list_wait(expected=0, n_retry=20): 168def bpftool_prog_list_wait(expected=0, n_retry=20):
160 for i in range(n_retry): 169 for i in range(n_retry):
161 nprogs = len(bpftool_prog_list()) 170 nprogs = len(bpftool_prog_list())
@@ -164,6 +173,14 @@ def bpftool_prog_list_wait(expected=0, n_retry=20):
164 time.sleep(0.05) 173 time.sleep(0.05)
165 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs)) 174 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
166 175
176def bpftool_map_list_wait(expected=0, n_retry=20):
177 for i in range(n_retry):
178 nmaps = len(bpftool_map_list())
179 if nmaps == expected:
180 return
181 time.sleep(0.05)
182 raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
183
167def ip(args, force=False, JSON=True, ns="", fail=True): 184def ip(args, force=False, JSON=True, ns="", fail=True):
168 if force: 185 if force:
169 args = "-force " + args 186 args = "-force " + args
@@ -193,6 +210,26 @@ def mknetns(n_retry=10):
193 return name 210 return name
194 return None 211 return None
195 212
213def int2str(fmt, val):
214 ret = []
215 for b in struct.pack(fmt, val):
216 ret.append(int(b))
217 return " ".join(map(lambda x: str(x), ret))
218
219def str2int(strtab):
220 inttab = []
221 for i in strtab:
222 inttab.append(int(i, 16))
223 ba = bytearray(inttab)
224 if len(strtab) == 4:
225 fmt = "I"
226 elif len(strtab) == 8:
227 fmt = "Q"
228 else:
229 raise Exception("String array of len %d can't be unpacked to an int" %
230 (len(strtab)))
231 return struct.unpack(fmt, ba)[0]
232
196class DebugfsDir: 233class DebugfsDir:
197 """ 234 """
198 Class for accessing DebugFS directories as a dictionary. 235 Class for accessing DebugFS directories as a dictionary.
@@ -311,13 +348,13 @@ class NetdevSim:
311 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu), 348 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
312 fail=fail) 349 fail=fail)
313 350
314 def set_xdp(self, bpf, mode, force=False, fail=True): 351 def set_xdp(self, bpf, mode, force=False, JSON=True, fail=True):
315 return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf), 352 return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf),
316 force=force, fail=fail) 353 force=force, JSON=JSON, fail=fail)
317 354
318 def unset_xdp(self, mode, force=False, fail=True): 355 def unset_xdp(self, mode, force=False, JSON=True, fail=True):
319 return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode), 356 return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode),
320 force=force, fail=fail) 357 force=force, JSON=JSON, fail=fail)
321 358
322 def ip_link_show(self, xdp): 359 def ip_link_show(self, xdp):
323 _, link = ip("link show dev %s" % (self['ifname'])) 360 _, link = ip("link show dev %s" % (self['ifname']))
@@ -390,12 +427,16 @@ class NetdevSim:
390 427
391################################################################################ 428################################################################################
392def clean_up(): 429def clean_up():
430 global files, netns, devs
431
393 for dev in devs: 432 for dev in devs:
394 dev.remove() 433 dev.remove()
395 for f in files: 434 for f in files:
396 cmd("rm -f %s" % (f)) 435 cmd("rm -f %s" % (f))
397 for ns in netns: 436 for ns in netns:
398 cmd("ip netns delete %s" % (ns)) 437 cmd("ip netns delete %s" % (ns))
438 files = []
439 netns = []
399 440
400def pin_prog(file_name, idx=0): 441def pin_prog(file_name, idx=0):
401 progs = bpftool_prog_list(expected=(idx + 1)) 442 progs = bpftool_prog_list(expected=(idx + 1))
@@ -405,16 +446,31 @@ def pin_prog(file_name, idx=0):
405 446
406 return file_name, bpf_pinned(file_name) 447 return file_name, bpf_pinned(file_name)
407 448
408def check_dev_info(other_ns, ns, pin_file=None, removed=False): 449def pin_map(file_name, idx=0, expected=1):
409 if removed: 450 maps = bpftool_map_list(expected=expected)
410 bpftool_prog_list(expected=0) 451 m = maps[idx]
411 ret, err = bpftool("prog show pin %s" % (pin_file), fail=False) 452 bpftool("map pin id %d %s" % (m["id"], file_name))
412 fail(ret == 0, "Showing prog with removed device did not fail") 453 files.append(file_name)
413 fail(err["error"].find("No such device") == -1, 454
414 "Showing prog with removed device expected ENODEV, error is %s" % 455 return file_name, bpf_pinned(file_name)
415 (err["error"])) 456
416 return 457def check_dev_info_removed(prog_file=None, map_file=None):
417 progs = bpftool_prog_list(expected=int(not removed), ns=ns) 458 bpftool_prog_list(expected=0)
459 ret, err = bpftool("prog show pin %s" % (prog_file), fail=False)
460 fail(ret == 0, "Showing prog with removed device did not fail")
461 fail(err["error"].find("No such device") == -1,
462 "Showing prog with removed device expected ENODEV, error is %s" %
463 (err["error"]))
464
465 bpftool_map_list(expected=0)
466 ret, err = bpftool("map show pin %s" % (map_file), fail=False)
467 fail(ret == 0, "Showing map with removed device did not fail")
468 fail(err["error"].find("No such device") == -1,
469 "Showing map with removed device expected ENODEV, error is %s" %
470 (err["error"]))
471
472def check_dev_info(other_ns, ns, prog_file=None, map_file=None, removed=False):
473 progs = bpftool_prog_list(expected=1, ns=ns)
418 prog = progs[0] 474 prog = progs[0]
419 475
420 fail("dev" not in prog.keys(), "Device parameters not reported") 476 fail("dev" not in prog.keys(), "Device parameters not reported")
@@ -423,16 +479,17 @@ def check_dev_info(other_ns, ns, pin_file=None, removed=False):
423 fail("ns_dev" not in dev.keys(), "Device parameters not reported") 479 fail("ns_dev" not in dev.keys(), "Device parameters not reported")
424 fail("ns_inode" not in dev.keys(), "Device parameters not reported") 480 fail("ns_inode" not in dev.keys(), "Device parameters not reported")
425 481
426 if not removed and not other_ns: 482 if not other_ns:
427 fail("ifname" not in dev.keys(), "Ifname not reported") 483 fail("ifname" not in dev.keys(), "Ifname not reported")
428 fail(dev["ifname"] != sim["ifname"], 484 fail(dev["ifname"] != sim["ifname"],
429 "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"])) 485 "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
430 else: 486 else:
431 fail("ifname" in dev.keys(), "Ifname is reported for other ns") 487 fail("ifname" in dev.keys(), "Ifname is reported for other ns")
432 if removed: 488
433 fail(dev["ifindex"] != 0, "Device perameters not zero on removed") 489 maps = bpftool_map_list(expected=2, ns=ns)
434 fail(dev["ns_dev"] != 0, "Device perameters not zero on removed") 490 for m in maps:
435 fail(dev["ns_inode"] != 0, "Device perameters not zero on removed") 491 fail("dev" not in m.keys(), "Device parameters not reported")
492 fail(dev != m["dev"], "Map's device different than program's")
436 493
437# Parse command line 494# Parse command line
438parser = argparse.ArgumentParser() 495parser = argparse.ArgumentParser()
@@ -464,7 +521,7 @@ if out.find("/sys/kernel/debug type debugfs") == -1:
464 cmd("mount -t debugfs none /sys/kernel/debug") 521 cmd("mount -t debugfs none /sys/kernel/debug")
465 522
466# Check samples are compiled 523# Check samples are compiled
467samples = ["sample_ret0.o"] 524samples = ["sample_ret0.o", "sample_map_ret0.o"]
468for s in samples: 525for s in samples:
469 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False) 526 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
470 skip(ret != 0, "sample %s/%s not found, please compile it" % 527 skip(ret != 0, "sample %s/%s not found, please compile it" %
@@ -739,8 +796,9 @@ try:
739 bpftool_prog_list_wait(expected=0) 796 bpftool_prog_list_wait(expected=0)
740 797
741 sim = NetdevSim() 798 sim = NetdevSim()
742 sim.set_ethtool_tc_offloads(True) 799 map_obj = bpf_obj("sample_map_ret0.o")
743 sim.set_xdp(obj, "offload") 800 start_test("Test loading program with maps...")
801 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
744 802
745 start_test("Test bpftool bound info reporting (own ns)...") 803 start_test("Test bpftool bound info reporting (own ns)...")
746 check_dev_info(False, "") 804 check_dev_info(False, "")
@@ -757,11 +815,111 @@ try:
757 sim.set_ns("") 815 sim.set_ns("")
758 check_dev_info(False, "") 816 check_dev_info(False, "")
759 817
760 pin_file, _ = pin_prog("/sys/fs/bpf/tmp") 818 prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog")
819 map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2)
761 sim.remove() 820 sim.remove()
762 821
763 start_test("Test bpftool bound info reporting (removed dev)...") 822 start_test("Test bpftool bound info reporting (removed dev)...")
764 check_dev_info(True, "", pin_file=pin_file, removed=True) 823 check_dev_info_removed(prog_file=prog_file, map_file=map_file)
824
825 # Remove all pinned files and reinstantiate the netdev
826 clean_up()
827 bpftool_prog_list_wait(expected=0)
828
829 sim = NetdevSim()
830
831 start_test("Test map update (no flags)...")
832 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
833 maps = bpftool_map_list(expected=2)
834 array = maps[0] if maps[0]["type"] == "array" else maps[1]
835 htab = maps[0] if maps[0]["type"] == "hash" else maps[1]
836 for m in maps:
837 for i in range(2):
838 bpftool("map update id %d key %s value %s" %
839 (m["id"], int2str("I", i), int2str("Q", i * 3)))
840
841 for m in maps:
842 ret, _ = bpftool("map update id %d key %s value %s" %
843 (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
844 fail=False)
845 fail(ret == 0, "added too many entries")
846
847 start_test("Test map update (exists)...")
848 for m in maps:
849 for i in range(2):
850 bpftool("map update id %d key %s value %s exist" %
851 (m["id"], int2str("I", i), int2str("Q", i * 3)))
852
853 for m in maps:
854 ret, err = bpftool("map update id %d key %s value %s exist" %
855 (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
856 fail=False)
857 fail(ret == 0, "updated non-existing key")
858 fail(err["error"].find("No such file or directory") == -1,
859 "expected ENOENT, error is '%s'" % (err["error"]))
860
861 start_test("Test map update (noexist)...")
862 for m in maps:
863 for i in range(2):
864 ret, err = bpftool("map update id %d key %s value %s noexist" %
865 (m["id"], int2str("I", i), int2str("Q", i * 3)),
866 fail=False)
867 fail(ret == 0, "updated existing key")
868 fail(err["error"].find("File exists") == -1,
869 "expected EEXIST, error is '%s'" % (err["error"]))
870
871 start_test("Test map dump...")
872 for m in maps:
873 _, entries = bpftool("map dump id %d" % (m["id"]))
874 for i in range(2):
875 key = str2int(entries[i]["key"])
876 fail(key != i, "expected key %d, got %d" % (key, i))
877 val = str2int(entries[i]["value"])
878 fail(val != i * 3, "expected value %d, got %d" % (val, i * 3))
879
880 start_test("Test map getnext...")
881 for m in maps:
882 _, entry = bpftool("map getnext id %d" % (m["id"]))
883 key = str2int(entry["next_key"])
884 fail(key != 0, "next key %d, expected %d" % (key, 0))
885 _, entry = bpftool("map getnext id %d key %s" %
886 (m["id"], int2str("I", 0)))
887 key = str2int(entry["next_key"])
888 fail(key != 1, "next key %d, expected %d" % (key, 1))
889 ret, err = bpftool("map getnext id %d key %s" %
890 (m["id"], int2str("I", 1)), fail=False)
891 fail(ret == 0, "got next key past the end of map")
892 fail(err["error"].find("No such file or directory") == -1,
893 "expected ENOENT, error is '%s'" % (err["error"]))
894
895 start_test("Test map delete (htab)...")
896 for i in range(2):
897 bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i)))
898
899 start_test("Test map delete (array)...")
900 for i in range(2):
901 ret, err = bpftool("map delete id %d key %s" %
902 (htab["id"], int2str("I", i)), fail=False)
903 fail(ret == 0, "removed entry from an array")
904 fail(err["error"].find("No such file or directory") == -1,
905 "expected ENOENT, error is '%s'" % (err["error"]))
906
907 start_test("Test map remove...")
908 sim.unset_xdp("offload")
909 bpftool_map_list_wait(expected=0)
910 sim.remove()
911
912 sim = NetdevSim()
913 sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
914 sim.remove()
915 bpftool_map_list_wait(expected=0)
916
917 start_test("Test map creation fail path...")
918 sim = NetdevSim()
919 sim.dfs["bpf_map_accept"] = "N"
920 ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False)
921 fail(ret == 0,
922 "netdevsim didn't refuse to create a map with offload disabled")
765 923
766 print("%s: OK" % (os.path.basename(__file__))) 924 print("%s: OK" % (os.path.basename(__file__)))
767 925