mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-18 18:46:53 +07:00
selftests/bpf: test device info reporting for bound progs
Check if bound programs report correct device info. Test in local namespace, in remote one, back to the local ns, remove the device and check that information is cleared. Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
522622104e
commit
752d7b4501
@ -18,6 +18,8 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import pprint
|
import pprint
|
||||||
|
import random
|
||||||
|
import string
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ bpf_test_dir = os.path.dirname(os.path.realpath(__file__))
|
|||||||
pp = pprint.PrettyPrinter()
|
pp = pprint.PrettyPrinter()
|
||||||
devs = [] # devices we created for clean up
|
devs = [] # devices we created for clean up
|
||||||
files = [] # files to be removed
|
files = [] # files to be removed
|
||||||
|
netns = [] # net namespaces to be removed
|
||||||
|
|
||||||
def log_get_sec(level=0):
|
def log_get_sec(level=0):
|
||||||
return "*" * (log_level + level)
|
return "*" * (log_level + level)
|
||||||
@ -128,22 +131,25 @@ def rm(f):
|
|||||||
if f in files:
|
if f in files:
|
||||||
files.remove(f)
|
files.remove(f)
|
||||||
|
|
||||||
def tool(name, args, flags, JSON=True, fail=True):
|
def tool(name, args, flags, JSON=True, ns="", fail=True):
|
||||||
params = ""
|
params = ""
|
||||||
if JSON:
|
if JSON:
|
||||||
params += "%s " % (flags["json"])
|
params += "%s " % (flags["json"])
|
||||||
|
|
||||||
ret, out = cmd(name + " " + params + args, fail=fail)
|
if ns != "":
|
||||||
|
ns = "ip netns exec %s " % (ns)
|
||||||
|
|
||||||
|
ret, out = cmd(ns + name + " " + params + args, fail=fail)
|
||||||
if JSON and len(out.strip()) != 0:
|
if JSON and len(out.strip()) != 0:
|
||||||
return ret, json.loads(out)
|
return ret, json.loads(out)
|
||||||
else:
|
else:
|
||||||
return ret, out
|
return ret, out
|
||||||
|
|
||||||
def bpftool(args, JSON=True, fail=True):
|
def bpftool(args, JSON=True, ns="", fail=True):
|
||||||
return tool("bpftool", args, {"json":"-p"}, JSON=JSON, fail=fail)
|
return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
|
||||||
|
|
||||||
def bpftool_prog_list(expected=None):
|
def bpftool_prog_list(expected=None, ns=""):
|
||||||
_, progs = bpftool("prog show", JSON=True, fail=True)
|
_, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
|
||||||
if expected is not None:
|
if expected is not None:
|
||||||
if len(progs) != expected:
|
if len(progs) != expected:
|
||||||
fail(True, "%d BPF programs loaded, expected %d" %
|
fail(True, "%d BPF programs loaded, expected %d" %
|
||||||
@ -158,13 +164,13 @@ def bpftool_prog_list_wait(expected=0, n_retry=20):
|
|||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
|
raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
|
||||||
|
|
||||||
def ip(args, force=False, JSON=True, fail=True):
|
def ip(args, force=False, JSON=True, ns="", fail=True):
|
||||||
if force:
|
if force:
|
||||||
args = "-force " + args
|
args = "-force " + args
|
||||||
return tool("ip", args, {"json":"-j"}, JSON=JSON, fail=fail)
|
return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns, fail=fail)
|
||||||
|
|
||||||
def tc(args, JSON=True, fail=True):
|
def tc(args, JSON=True, ns="", fail=True):
|
||||||
return tool("tc", args, {"json":"-p"}, JSON=JSON, fail=fail)
|
return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
|
||||||
|
|
||||||
def ethtool(dev, opt, args, fail=True):
|
def ethtool(dev, opt, args, fail=True):
|
||||||
return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
|
return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
|
||||||
@ -178,6 +184,15 @@ def bpf_pinned(name):
|
|||||||
def bpf_bytecode(bytecode):
|
def bpf_bytecode(bytecode):
|
||||||
return "bytecode \"%s\"" % (bytecode)
|
return "bytecode \"%s\"" % (bytecode)
|
||||||
|
|
||||||
|
def mknetns(n_retry=10):
|
||||||
|
for i in range(n_retry):
|
||||||
|
name = ''.join([random.choice(string.ascii_letters) for i in range(8)])
|
||||||
|
ret, _ = ip("netns add %s" % (name), fail=False)
|
||||||
|
if ret == 0:
|
||||||
|
netns.append(name)
|
||||||
|
return name
|
||||||
|
return None
|
||||||
|
|
||||||
class DebugfsDir:
|
class DebugfsDir:
|
||||||
"""
|
"""
|
||||||
Class for accessing DebugFS directories as a dictionary.
|
Class for accessing DebugFS directories as a dictionary.
|
||||||
@ -237,6 +252,8 @@ class NetdevSim:
|
|||||||
self.dev = self._netdevsim_create()
|
self.dev = self._netdevsim_create()
|
||||||
devs.append(self)
|
devs.append(self)
|
||||||
|
|
||||||
|
self.ns = ""
|
||||||
|
|
||||||
self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
|
self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
|
||||||
self.dfs_refresh()
|
self.dfs_refresh()
|
||||||
|
|
||||||
@ -257,7 +274,7 @@ class NetdevSim:
|
|||||||
|
|
||||||
def remove(self):
|
def remove(self):
|
||||||
devs.remove(self)
|
devs.remove(self)
|
||||||
ip("link del dev %s" % (self.dev["ifname"]))
|
ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
|
||||||
|
|
||||||
def dfs_refresh(self):
|
def dfs_refresh(self):
|
||||||
self.dfs = DebugfsDir(self.dfs_dir)
|
self.dfs = DebugfsDir(self.dfs_dir)
|
||||||
@ -285,6 +302,11 @@ class NetdevSim:
|
|||||||
time.sleep(0.05)
|
time.sleep(0.05)
|
||||||
raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
|
raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
|
||||||
|
|
||||||
|
def set_ns(self, ns):
|
||||||
|
name = "1" if ns == "" else ns
|
||||||
|
ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
|
||||||
|
self.ns = ns
|
||||||
|
|
||||||
def set_mtu(self, mtu, fail=True):
|
def set_mtu(self, mtu, fail=True):
|
||||||
return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
|
return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
|
||||||
fail=fail)
|
fail=fail)
|
||||||
@ -372,6 +394,8 @@ def clean_up():
|
|||||||
dev.remove()
|
dev.remove()
|
||||||
for f in files:
|
for f in files:
|
||||||
cmd("rm -f %s" % (f))
|
cmd("rm -f %s" % (f))
|
||||||
|
for ns in netns:
|
||||||
|
cmd("ip netns delete %s" % (ns))
|
||||||
|
|
||||||
def pin_prog(file_name, idx=0):
|
def pin_prog(file_name, idx=0):
|
||||||
progs = bpftool_prog_list(expected=(idx + 1))
|
progs = bpftool_prog_list(expected=(idx + 1))
|
||||||
@ -381,6 +405,35 @@ def pin_prog(file_name, idx=0):
|
|||||||
|
|
||||||
return file_name, bpf_pinned(file_name)
|
return file_name, bpf_pinned(file_name)
|
||||||
|
|
||||||
|
def check_dev_info(other_ns, ns, pin_file=None, removed=False):
|
||||||
|
if removed:
|
||||||
|
bpftool_prog_list(expected=0)
|
||||||
|
ret, err = bpftool("prog show pin %s" % (pin_file), fail=False)
|
||||||
|
fail(ret == 0, "Showing prog with removed device did not fail")
|
||||||
|
fail(err["error"].find("No such device") == -1,
|
||||||
|
"Showing prog with removed device expected ENODEV, error is %s" %
|
||||||
|
(err["error"]))
|
||||||
|
return
|
||||||
|
progs = bpftool_prog_list(expected=int(not removed), ns=ns)
|
||||||
|
prog = progs[0]
|
||||||
|
|
||||||
|
fail("dev" not in prog.keys(), "Device parameters not reported")
|
||||||
|
dev = prog["dev"]
|
||||||
|
fail("ifindex" not in dev.keys(), "Device parameters not reported")
|
||||||
|
fail("ns_dev" not in dev.keys(), "Device parameters not reported")
|
||||||
|
fail("ns_inode" not in dev.keys(), "Device parameters not reported")
|
||||||
|
|
||||||
|
if not removed and not other_ns:
|
||||||
|
fail("ifname" not in dev.keys(), "Ifname not reported")
|
||||||
|
fail(dev["ifname"] != sim["ifname"],
|
||||||
|
"Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
|
||||||
|
else:
|
||||||
|
fail("ifname" in dev.keys(), "Ifname is reported for other ns")
|
||||||
|
if removed:
|
||||||
|
fail(dev["ifindex"] != 0, "Device perameters not zero on removed")
|
||||||
|
fail(dev["ns_dev"] != 0, "Device perameters not zero on removed")
|
||||||
|
fail(dev["ns_inode"] != 0, "Device perameters not zero on removed")
|
||||||
|
|
||||||
# Parse command line
|
# Parse command line
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--log", help="output verbose log to given file")
|
parser.add_argument("--log", help="output verbose log to given file")
|
||||||
@ -417,6 +470,12 @@ for s in samples:
|
|||||||
skip(ret != 0, "sample %s/%s not found, please compile it" %
|
skip(ret != 0, "sample %s/%s not found, please compile it" %
|
||||||
(bpf_test_dir, s))
|
(bpf_test_dir, s))
|
||||||
|
|
||||||
|
# Check if net namespaces seem to work
|
||||||
|
ns = mknetns()
|
||||||
|
skip(ns is None, "Could not create a net namespace")
|
||||||
|
cmd("ip netns delete %s" % (ns))
|
||||||
|
netns = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = bpf_obj("sample_ret0.o")
|
obj = bpf_obj("sample_ret0.o")
|
||||||
bytecode = bpf_bytecode("1,6 0 0 4294967295,")
|
bytecode = bpf_bytecode("1,6 0 0 4294967295,")
|
||||||
@ -549,6 +608,8 @@ try:
|
|||||||
progs = bpftool_prog_list(expected=1)
|
progs = bpftool_prog_list(expected=1)
|
||||||
fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
|
fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
|
||||||
"Loaded program has wrong ID")
|
"Loaded program has wrong ID")
|
||||||
|
fail("dev" in progs[0].keys(),
|
||||||
|
"Device parameters reported for non-offloaded program")
|
||||||
|
|
||||||
start_test("Test XDP prog replace with bad flags...")
|
start_test("Test XDP prog replace with bad flags...")
|
||||||
ret, _ = sim.set_xdp(obj, "offload", force=True, fail=False)
|
ret, _ = sim.set_xdp(obj, "offload", force=True, fail=False)
|
||||||
@ -673,6 +734,35 @@ try:
|
|||||||
fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
|
fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
|
||||||
(time_diff, delay_sec))
|
(time_diff, delay_sec))
|
||||||
|
|
||||||
|
# Remove all pinned files and reinstantiate the netdev
|
||||||
|
clean_up()
|
||||||
|
bpftool_prog_list_wait(expected=0)
|
||||||
|
|
||||||
|
sim = NetdevSim()
|
||||||
|
sim.set_ethtool_tc_offloads(True)
|
||||||
|
sim.set_xdp(obj, "offload")
|
||||||
|
|
||||||
|
start_test("Test bpftool bound info reporting (own ns)...")
|
||||||
|
check_dev_info(False, "")
|
||||||
|
|
||||||
|
start_test("Test bpftool bound info reporting (other ns)...")
|
||||||
|
ns = mknetns()
|
||||||
|
sim.set_ns(ns)
|
||||||
|
check_dev_info(True, "")
|
||||||
|
|
||||||
|
start_test("Test bpftool bound info reporting (remote ns)...")
|
||||||
|
check_dev_info(False, ns)
|
||||||
|
|
||||||
|
start_test("Test bpftool bound info reporting (back to own ns)...")
|
||||||
|
sim.set_ns("")
|
||||||
|
check_dev_info(False, "")
|
||||||
|
|
||||||
|
pin_file, _ = pin_prog("/sys/fs/bpf/tmp")
|
||||||
|
sim.remove()
|
||||||
|
|
||||||
|
start_test("Test bpftool bound info reporting (removed dev)...")
|
||||||
|
check_dev_info(True, "", pin_file=pin_file, removed=True)
|
||||||
|
|
||||||
print("%s: OK" % (os.path.basename(__file__)))
|
print("%s: OK" % (os.path.basename(__file__)))
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
Loading…
Reference in New Issue
Block a user