# Copyright (C) 2017 Netronome Systems, Inc. # Copyright (c) 2019 Mellanox Technologies. All rights reserved # # This software is licensed under the GNU General License Version 2, # June 1991 as shown in the file COPYING in the top-level directory of this # source tree. # # THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" # WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME # THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
from datetime import datetime import argparse import errno import json import os import pprint import random import re import stat import string import struct import subprocess import time import traceback
from lib.py import NetdevSim, NetdevSimDev
logfile = None
log_level = 1
skip_extack = False
bpf_test_dir = os.path.dirname(os.path.realpath(__file__))
pp = pprint.PrettyPrinter()
devs = [] # devices we created for clean up
files = [] # files to be removed
netns = [] # net namespaces to be removed
def log_level_inc(add=1): global log_level
log_level += add
def log_level_dec(sub=1): global log_level
log_level -= sub
def log_level_set(level): global log_level
log_level = level
def log(header, data, level=None): """
Output to an optional log. """ if logfile isNone: return if level isnotNone:
log_level_set(level)
ifnot isinstance(data, str):
data = pp.pformat(data)
if len(header):
logfile.write("\n" + log_get_sec() + " ")
logfile.write(header) if len(header) and len(data.strip()):
logfile.write("\n")
logfile.write(data)
def bpftool_prog_list(expected=None, ns="", exclude_orphaned=True):
_, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) # Remove the base progs for p in base_progs: if p in progs:
progs.remove(p) if exclude_orphaned:
progs = [ p for p in progs ifnot p['orphaned'] ] if expected isnotNone: if len(progs) != expected:
fail(True, "%d BPF programs loaded, expected %d" %
(len(progs), expected)) return progs
def bpftool_map_list(expected=None, ns=""):
_, maps = bpftool("map show", JSON=True, ns=ns, fail=True) # Remove the base maps
maps = [m for m in maps if m notin base_maps and m.get('name') and m.get('name') notin base_map_names] if expected isnotNone: if len(maps) != expected:
fail(True, "%d BPF maps loaded, expected %d" %
(len(maps), expected)) return maps
def bpftool_prog_list_wait(expected=0, n_retry=20): for i in range(n_retry):
nprogs = len(bpftool_prog_list()) if nprogs == expected: return
time.sleep(0.05) raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
def bpftool_map_list_wait(expected=0, n_retry=20, ns=""):
nmaps = None for i in range(n_retry):
maps = bpftool_map_list(ns=ns)
nmaps = len(maps) if nmaps == expected: return maps
time.sleep(0.05) raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
def bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None,
fail=True, include_stderr=False, dev_bind=None):
args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name) if prog_type isnotNone:
args += " type " + prog_type if dev isnotNone:
args += " dev " + dev elif dev_bind isnotNone:
args += " xdpmeta_dev " + dev_bind if len(maps):
args += " map " + " map ".join(maps)
res = bpftool(args, fail=fail, include_stderr=include_stderr) if res[0] == 0:
files.append(file_name) return res
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 returnNone
def int2str(fmt, val):
ret = [] for b in struct.pack(fmt, val):
ret.append(int(b)) return" ".join(map(lambda x: str(x), ret))
def str2int(strtab):
inttab = [] for i in strtab:
inttab.append(int(i, 16))
ba = bytearray(inttab) if len(strtab) == 4:
fmt = "I" elif len(strtab) == 8:
fmt = "Q" else: raise Exception("String array of len %d can't be unpacked to an int" %
(len(strtab))) return struct.unpack(fmt, ba)[0]
class DebugfsDir: """ Classfor accessing DebugFS directories as a dictionary. """
log("DebugFS state for %s" % (path), "")
log_level_inc(add=2)
_, out = cmd('ls ' + path) for f in out.split(): if f == "ports": continue
p = os.path.join(path, f) ifnot os.stat(p).st_mode & stat.S_IRUSR: continue
if os.path.isfile(p): # We need to init trap_flow_action_cookie before read it if f == "trap_flow_action_cookie":
cmd('echo deadbeef > %s/%s' % (path, f))
_, out = cmd('cat %s/%s' % (path, f))
dfs[f] = out.strip() elif os.path.isdir(p):
dfs[f] = DebugfsDir(p) else: raise Exception("%s is neither file nor directory" % (p))
class BpfNetdevSimDev(NetdevSimDev): """ Classfor netdevsim bus device and its attributes. """ def __init__(self, port_count=1, ns=None):
super().__init__(port_count, ns=ns)
devs.append(self)
def wait_for_flush(self, bound=0, total=0, n_retry=20): for i in range(n_retry):
nbound = self.nsimdev.dfs_num_bound_progs()
nprogs = len(bpftool_prog_list()) if nbound == bound and nprogs == total: return
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))
def set_ns(self, ns):
name = ns if ns else"1"
ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
self.ns = ns
def set_mtu(self, mtu, fail=True): return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
fail=fail)
def set_xdp(self, bpf, mode, force=False, JSON=True, verbose=False,
fail=True, include_stderr=False): if verbose:
bpf += " verbose" return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf),
force=force, JSON=JSON,
fail=fail, include_stderr=include_stderr)
def ip_link_show(self, xdp):
_, link = ip("link show dev %s" % (self['ifname'])) if len(link) > 1: raise Exception("Multiple objects on ip link show") if len(link) < 1: return {}
fail(xdp != "xdp"in link, "XDP program not reporting in iplink (reported %s, expected %s)" %
("xdp"in link, xdp)) return link[0]
def tc_add_ingress(self):
tc("qdisc add dev %s ingress" % (self['ifname']))
def tc_del_ingress(self):
tc("qdisc del dev %s ingress" % (self['ifname']))
args = "-s filter show dev %s ingress" % (self['ifname'])
_, out = tc(args, JSON=False)
filters = []
lines = out.split('\n') for line in lines:
words = line.split() if"handle"notin words: continue
fltr = {} for flag in flags:
fltr[flag] = flag in words for name in named: try:
idx = words.index(name)
fltr[name] = words[idx + 1] except ValueError: pass
filters.append(fltr)
fail("dev"notin prog.keys(), "Device parameters not reported")
dev = prog["dev"]
fail("ifindex"notin dev.keys(), "Device parameters not reported")
fail("ns_dev"notin dev.keys(), "Device parameters not reported")
fail("ns_inode"notin dev.keys(), "Device parameters not reported")
ifnot other_ns:
fail("ifname"notin 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")
maps = bpftool_map_list_wait(expected=2, ns=ns) for m in maps:
fail("dev"notin m.keys(), "Device parameters not reported")
fail(dev != m["dev"], "Map's device different than program's")
def check_extack(output, reference, args): if skip_extack: return
lines = output.split("\n")
comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
fail(not comp, "Missing or incorrect netlink extack message")
def check_verifier_log(output, reference):
lines = output.split("\n") for l in reversed(lines): if l == reference: return
fail(True, "Missing or incorrect message from netdevsim in verifier log")
def check_multi_basic(two_xdps):
fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs")
fail("prog"in two_xdps, "Base program reported in multi program mode")
fail(len(two_xdps["attached"]) != 2, "Wrong attached program count with two programs")
fail(two_xdps["attached"][0]["prog"]["id"] ==
two_xdps["attached"][1]["prog"]["id"], "Offloaded and other programs have the same id")
fail(xdp["attached"][0] notin two_xdps["attached"], "Offload program not reported after other activated")
check_multi_basic(two_xdps)
offloaded2 = sim.dfs_read("bpf_offloaded_id")
fail(offloaded != offloaded2, "Offload ID changed after loading other program")
start_test("Test multi-attachment XDP - replace...")
ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
fail(ret == 0, "Replaced one of programs without -force")
check_extack(err, "XDP program already attached.", args)
start_test("Test multi-attachment XDP - remove without mode...")
ret, _, err = sim.unset_xdp("", force=True,
fail=False, include_stderr=True)
fail(ret == 0, "Removed program without a mode flag")
check_extack(err, "More than one program loaded, unset mode is ambiguous.", args)
fail(xdp["mode"] != modeid, "Bad mode reported after multiple programs")
fail("prog"notin xdp, "Base program not reported after multi program mode")
fail(xdp["attached"][0] notin two_xdps["attached"], "Offload program not reported after other activated")
fail(len(xdp["attached"]) != 1, "Wrong attached program count with remaining programs")
fail(offloaded != "0", "Offload ID reported with only other program left")
# Parse command line
parser = argparse.ArgumentParser()
parser.add_argument("--log", help="output verbose log to given file")
args = parser.parse_args() if args.log:
logfile = open(args.log, 'w+')
logfile.write("# -*-Org-*-")
log("Prepare...", "", level=1)
log_level_inc()
# Check permissions
skip(os.getuid() != 0, "test must be run as root")
# Check tools
ret, progs = bpftool("prog", fail=False)
skip(ret != 0, "bpftool not installed")
base_progs = progs
_, base_maps = bpftool("map")
base_map_names = [ 'pid_iter.rodata', # created on each bpftool invocation 'libbpf_det_bind', # created on each bpftool invocation 'libbpf_global',
]
# Check netdevsim ifnot os.path.isdir("/sys/bus/netdevsim/"):
ret, out = cmd("modprobe netdevsim", fail=False)
skip(ret != 0, "netdevsim module could not be loaded")
# Check debugfs
_, out = cmd("mount") if out.find("/sys/kernel/debug type debugfs") == -1:
cmd("mount -t debugfs none /sys/kernel/debug")
# Check samples are compiled
samples = ["sample_ret0.bpf.o", "sample_map_ret0.bpf.o"] for s in samples:
ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
skip(ret != 0, "sample %s/%s not found, please compile it" %
(bpf_test_dir, s))
# Check if iproute2 is built with libmnl (needed by extack support)
_, _, err = cmd("tc qdisc delete dev lo handle 0",
fail=False, include_stderr=True) if err.find("Error: Failed to find qdisc with specified handle.") == -1:
print("Warning: no extack message in iproute2 output, libmnl missing?")
log("Warning: no extack message in iproute2 output, libmnl missing?", "")
skip_extack = True
# Check if net namespaces seem to work
ns = mknetns()
skip(ns isNone, "Could not create a net namespace")
cmd("ip netns delete %s" % (ns))
netns = []
start_test("Test TC offloads are off by default...")
ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
fail=False, include_stderr=True)
fail(ret == 0, "TC filter loaded without enabling TC offloads")
check_extack(err, "TC offload is disabled on net device.", args)
sim.wait_for_flush()
dprog = dfs[0]
prog = progs[0]
fltr = ingress[0]
fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter")
fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter")
fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back")
start_test("Test TC offload is device-bound...")
fail(str(prog["id"]) != fltr["id"], "Program IDs don't match")
fail(prog["tag"] != fltr["tag"], "Program tags don't match")
fail(fltr["id"] != dprog["id"], "Program IDs don't match")
fail(dprog["state"] != "xlated", "Offloaded program state not translated")
fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
start_test("Test disabling TC offloads is rejected while filters installed...")
ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...")
sim.set_ethtool_tc_offloads(True)
start_test("Test disabling TC offloads is OK without filters...")
ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
fail(ret != 0, "Driver refused to disable TC offloads without filters installed...")
start_test("Test XDP prog reporting...")
sim.set_xdp(obj, "drv")
ipl = sim.ip_link_show(xdp=True)
progs = bpftool_prog_list(expected=1)
fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], "Loaded program has wrong ID")
start_test("Test XDP prog replace without force...")
ret, _ = sim.set_xdp(obj, "drv", fail=False)
fail(ret == 0, "Replaced XDP program without -force")
sim.wait_for_flush(total=1)
start_test("Test XDP prog replace with force...")
ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False)
fail(ret != 0, "Could not replace XDP program with -force")
bpftool_prog_list_wait(expected=1)
ipl = sim.ip_link_show(xdp=True)
progs = bpftool_prog_list(expected=1)
fail(ipl["xdp"]["prog"]["id"] != progs[0]["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...")
ret, _, err = sim.set_xdp(obj, "generic", force=True,
fail=False, include_stderr=True)
fail(ret == 0, "Replaced XDP program with a program in different mode")
check_extack(err, "Native and generic XDP can't be active at the same time.",
args)
start_test("Test MTU restrictions...")
ret, _ = sim.set_mtu(9000, fail=False)
fail(ret == 0, "Driver should refuse to increase MTU to 9000 with XDP loaded...")
sim.unset_xdp("drv")
bpftool_prog_list_wait(expected=0)
sim.set_mtu(9000)
ret, _, err = sim.set_xdp(obj, "drv", fail=False, include_stderr=True)
fail(ret == 0, "Driver should refuse to load program with MTU of 9000...")
check_extack_nsim(err, "MTU too large w/ XDP enabled.", args)
sim.set_mtu(1500)
sim.wait_for_flush()
start_test("Test non-offload XDP attaching to HW...")
bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/nooffload")
nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
ret, _, err = sim.set_xdp(nooffload, "offload",
fail=False, include_stderr=True)
fail(ret == 0, "attached non-offloaded XDP program to HW")
check_extack_nsim(err, "xdpoffload of non-bound program.", args)
rm("/sys/fs/bpf/nooffload")
start_test("Test offload XDP attaching to drv...")
bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload",
dev=sim['ifname'])
offload = bpf_pinned("/sys/fs/bpf/offload")
ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
fail(ret == 0, "attached offloaded XDP program to drv")
check_extack(err, "Using offloaded program without HW_MODE flag is not supported.", args)
rm("/sys/fs/bpf/offload")
sim.wait_for_flush()
bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/devbound",
dev_bind=sim['ifname'])
devbound = bpf_pinned("/sys/fs/bpf/devbound")
start_test("Test dev-bound program in generic mode...")
ret, _, err = sim.set_xdp(devbound, "generic", fail=False, include_stderr=True)
fail(ret == 0, "devbound program in generic mode allowed")
check_extack(err, "Can't attach device-bound programs in generic mode.", args)
rm("/sys/fs/bpf/devbound")
sim.wait_for_flush()
fail(prog["id"] != link_xdp["id"], "Program IDs don't match")
fail(prog["tag"] != link_xdp["tag"], "Program tags don't match")
fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match")
fail(dprog["state"] != "xlated", "Offloaded program state not translated")
fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
start_test("Test removing XDP program many times...")
sim.unset_xdp("offload")
sim.unset_xdp("offload")
sim.unset_xdp("drv")
sim.unset_xdp("drv")
sim.unset_xdp("")
sim.unset_xdp("")
bpftool_prog_list_wait(expected=0)
start_test("Test attempt to use a program for a wrong device...")
simdev2 = BpfNetdevSimDev()
sim2, = simdev2.nsims
sim2.set_xdp(obj, "offload")
pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
ret, _, err = sim.set_xdp(pinned, "offload",
fail=False, include_stderr=True)
fail(ret == 0, "Pinned program loaded for a different device accepted")
check_extack(err, "Program bound to different device.", args)
simdev2.remove()
ret, _, err = sim.set_xdp(pinned, "offload",
fail=False, include_stderr=True)
fail(ret == 0, "Pinned program loaded for a removed device accepted")
check_extack(err, "Program bound to different device.", args)
rm(pin_file)
bpftool_prog_list_wait(expected=0)
start_test("Test offload of wrong type fails...")
ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False)
fail(ret == 0, "Managed to attach XDP program to TC")
start_test("Test asking for TC offload of two filters...")
sim.cls_bpf_add_filter(obj, da=True, skip_sw=True)
ret, _, err = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True,
fail=False, include_stderr=True)
fail(ret == 0, "Managed to offload two TC filters at the same time")
check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
sim.tc_flush_filters(bound=2, total=2)
start_test("Test if netdev removal waits for translation...")
delay_msec = 500
sim.dfs["dev/bpf_bind_verifier_delay"] = delay_msec
start = time.time()
cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \
(sim['ifname'], obj)
tc_proc = cmd(cmd_line, background=True, fail=False) # Wait for the verifier to start while simdev.dfs_num_bound_progs() <= 2: pass
simdev.remove()
end = time.time()
ret, _ = cmd_result(tc_proc, fail=False)
time_diff = end - start
log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff))
fail(ret == 0, "Managed to load TC filter on a unregistering device")
delay_sec = delay_msec * 0.001
fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
(time_diff, delay_sec))
# Remove all pinned files and reinstantiate the netdev
clean_up()
bpftool_prog_list_wait(expected=0)
start_test("Test bpftool bound info reporting (removed dev)...")
check_dev_info_removed(prog_file=prog_file, map_file=map_file)
# Remove all pinned files and reinstantiate the netdev
clean_up()
bpftool_prog_list_wait(expected=0)
simdev = BpfNetdevSimDev()
sim, = simdev.nsims
start_test("Test map update (no flags)...")
sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
maps = bpftool_map_list_wait(expected=2)
array = maps[0] if maps[0]["type"] == "array"else maps[1]
htab = maps[0] if maps[0]["type"] == "hash"else maps[1] for m in maps: for i in range(2):
bpftool("map update id %d key %s value %s" %
(m["id"], int2str("I", i), int2str("Q", i * 3)))
for m in maps:
ret, _ = bpftool("map update id %d key %s value %s" %
(m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
fail=False)
fail(ret == 0, "added too many entries")
start_test("Test map update (exists)...") for m in maps: for i in range(2):
bpftool("map update id %d key %s value %s exist" %
(m["id"], int2str("I", i), int2str("Q", i * 3)))
for m in maps:
ret, err = bpftool("map update id %d key %s value %s exist" %
(m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
fail=False)
fail(ret == 0, "updated non-existing key")
fail(err["error"].find("No such file or directory") == -1, "expected ENOENT, error is '%s'" % (err["error"]))
start_test("Test map update (noexist)...") for m in maps: for i in range(2):
ret, err = bpftool("map update id %d key %s value %s noexist" %
(m["id"], int2str("I", i), int2str("Q", i * 3)),
fail=False)
fail(ret == 0, "updated existing key")
fail(err["error"].find("File exists") == -1, "expected EEXIST, error is '%s'" % (err["error"]))
start_test("Test map dump...") for m in maps:
_, entries = bpftool("map dump id %d" % (m["id"])) for i in range(2):
key = str2int(entries[i]["key"])
fail(key != i, "expected key %d, got %d" % (key, i))
val = str2int(entries[i]["value"])
fail(val != i * 3, "expected value %d, got %d" % (val, i * 3))
start_test("Test map getnext...") for m in maps:
_, entry = bpftool("map getnext id %d" % (m["id"]))
key = str2int(entry["next_key"])
fail(key != 0, "next key %d, expected %d" % (key, 0))
_, entry = bpftool("map getnext id %d key %s" %
(m["id"], int2str("I", 0)))
key = str2int(entry["next_key"])
fail(key != 1, "next key %d, expected %d" % (key, 1))
ret, err = bpftool("map getnext id %d key %s" %
(m["id"], int2str("I", 1)), fail=False)
fail(ret == 0, "got next key past the end of map")
fail(err["error"].find("No such file or directory") == -1, "expected ENOENT, error is '%s'" % (err["error"]))
start_test("Test map delete (htab)...") for i in range(2):
bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i)))
start_test("Test map delete (array)...") for i in range(2):
ret, err = bpftool("map delete id %d key %s" %
(htab["id"], int2str("I", i)), fail=False)
fail(ret == 0, "removed entry from an array")
fail(err["error"].find("No such file or directory") == -1, "expected ENOENT, error is '%s'" % (err["error"]))
mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
ret, _ = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
dev=simB3['ifname'],
maps=["idx 0 id %d" % (mapB)],
fail=False)
fail(ret != 0, "couldn't reuse a map on the same ASIC")
rm("/sys/fs/bpf/nsimB_")
ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA_",
dev=simA['ifname'],
maps=["idx 0 id %d" % (mapB)],
fail=False, include_stderr=True)
fail(ret == 0, "could reuse a map on a different ASIC")
fail(err.count("offload device mismatch between prog and map") == 0, "error message missing for cross-ASIC map")
ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
dev=simB1['ifname'],
maps=["idx 0 id %d" % (mapA)],
fail=False, include_stderr=True)
fail(ret == 0, "could reuse a map on a different ASIC")
fail(err.count("offload device mismatch between prog and map") == 0, "error message missing for cross-ASIC map")
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
fail(ifnameB != simB1['ifname'], "program not bound to original device")
simB1.remove()
bpftool_prog_list_wait(expected=1)
start_test("Test multi-dev ASIC cross-dev destruction - move...")
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
fail(ifnameB notin (simB2['ifname'], simB3['ifname']), "program not bound to remaining devices")
simB2.remove()
ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
ret, out = bpftool("prog show %s" % (progB), fail=False)
fail(ret != 0, "couldn't get information about orphaned program")
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.