162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci# Copyright (C) 2017 Netronome Systems, Inc.
462306a36Sopenharmony_ci# Copyright (c) 2019 Mellanox Technologies. All rights reserved
562306a36Sopenharmony_ci#
662306a36Sopenharmony_ci# This software is licensed under the GNU General License Version 2,
762306a36Sopenharmony_ci# June 1991 as shown in the file COPYING in the top-level directory of this
862306a36Sopenharmony_ci# source tree.
962306a36Sopenharmony_ci#
1062306a36Sopenharmony_ci# THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
1162306a36Sopenharmony_ci# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
1262306a36Sopenharmony_ci# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1362306a36Sopenharmony_ci# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
1462306a36Sopenharmony_ci# OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
1562306a36Sopenharmony_ci# THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cifrom datetime import datetime
1862306a36Sopenharmony_ciimport argparse
1962306a36Sopenharmony_ciimport errno
2062306a36Sopenharmony_ciimport json
2162306a36Sopenharmony_ciimport os
2262306a36Sopenharmony_ciimport pprint
2362306a36Sopenharmony_ciimport random
2462306a36Sopenharmony_ciimport re
2562306a36Sopenharmony_ciimport stat
2662306a36Sopenharmony_ciimport string
2762306a36Sopenharmony_ciimport struct
2862306a36Sopenharmony_ciimport subprocess
2962306a36Sopenharmony_ciimport time
3062306a36Sopenharmony_ciimport traceback
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cilogfile = None
3362306a36Sopenharmony_cilog_level = 1
3462306a36Sopenharmony_ciskip_extack = False
3562306a36Sopenharmony_cibpf_test_dir = os.path.dirname(os.path.realpath(__file__))
3662306a36Sopenharmony_cipp = pprint.PrettyPrinter()
3762306a36Sopenharmony_cidevs = [] # devices we created for clean up
3862306a36Sopenharmony_cifiles = [] # files to be removed
3962306a36Sopenharmony_cinetns = [] # net namespaces to be removed
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cidef log_get_sec(level=0):
4262306a36Sopenharmony_ci    return "*" * (log_level + level)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cidef log_level_inc(add=1):
4562306a36Sopenharmony_ci    global log_level
4662306a36Sopenharmony_ci    log_level += add
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cidef log_level_dec(sub=1):
4962306a36Sopenharmony_ci    global log_level
5062306a36Sopenharmony_ci    log_level -= sub
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cidef log_level_set(level):
5362306a36Sopenharmony_ci    global log_level
5462306a36Sopenharmony_ci    log_level = level
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cidef log(header, data, level=None):
5762306a36Sopenharmony_ci    """
5862306a36Sopenharmony_ci    Output to an optional log.
5962306a36Sopenharmony_ci    """
6062306a36Sopenharmony_ci    if logfile is None:
6162306a36Sopenharmony_ci        return
6262306a36Sopenharmony_ci    if level is not None:
6362306a36Sopenharmony_ci        log_level_set(level)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci    if not isinstance(data, str):
6662306a36Sopenharmony_ci        data = pp.pformat(data)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci    if len(header):
6962306a36Sopenharmony_ci        logfile.write("\n" + log_get_sec() + " ")
7062306a36Sopenharmony_ci        logfile.write(header)
7162306a36Sopenharmony_ci    if len(header) and len(data.strip()):
7262306a36Sopenharmony_ci        logfile.write("\n")
7362306a36Sopenharmony_ci    logfile.write(data)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cidef skip(cond, msg):
7662306a36Sopenharmony_ci    if not cond:
7762306a36Sopenharmony_ci        return
7862306a36Sopenharmony_ci    print("SKIP: " + msg)
7962306a36Sopenharmony_ci    log("SKIP: " + msg, "", level=1)
8062306a36Sopenharmony_ci    os.sys.exit(0)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cidef fail(cond, msg):
8362306a36Sopenharmony_ci    if not cond:
8462306a36Sopenharmony_ci        return
8562306a36Sopenharmony_ci    print("FAIL: " + msg)
8662306a36Sopenharmony_ci    tb = "".join(traceback.extract_stack().format())
8762306a36Sopenharmony_ci    print(tb)
8862306a36Sopenharmony_ci    log("FAIL: " + msg, tb, level=1)
8962306a36Sopenharmony_ci    os.sys.exit(1)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cidef start_test(msg):
9262306a36Sopenharmony_ci    log(msg, "", level=1)
9362306a36Sopenharmony_ci    log_level_inc()
9462306a36Sopenharmony_ci    print(msg)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cidef cmd(cmd, shell=True, include_stderr=False, background=False, fail=True):
9762306a36Sopenharmony_ci    """
9862306a36Sopenharmony_ci    Run a command in subprocess and return tuple of (retval, stdout);
9962306a36Sopenharmony_ci    optionally return stderr as well as third value.
10062306a36Sopenharmony_ci    """
10162306a36Sopenharmony_ci    proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE,
10262306a36Sopenharmony_ci                            stderr=subprocess.PIPE)
10362306a36Sopenharmony_ci    if background:
10462306a36Sopenharmony_ci        msg = "%s START: %s" % (log_get_sec(1),
10562306a36Sopenharmony_ci                                datetime.now().strftime("%H:%M:%S.%f"))
10662306a36Sopenharmony_ci        log("BKG " + proc.args, msg)
10762306a36Sopenharmony_ci        return proc
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci    return cmd_result(proc, include_stderr=include_stderr, fail=fail)
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cidef cmd_result(proc, include_stderr=False, fail=False):
11262306a36Sopenharmony_ci    stdout, stderr = proc.communicate()
11362306a36Sopenharmony_ci    stdout = stdout.decode("utf-8")
11462306a36Sopenharmony_ci    stderr = stderr.decode("utf-8")
11562306a36Sopenharmony_ci    proc.stdout.close()
11662306a36Sopenharmony_ci    proc.stderr.close()
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci    stderr = "\n" + stderr
11962306a36Sopenharmony_ci    if stderr[-1] == "\n":
12062306a36Sopenharmony_ci        stderr = stderr[:-1]
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci    sec = log_get_sec(1)
12362306a36Sopenharmony_ci    log("CMD " + proc.args,
12462306a36Sopenharmony_ci        "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" %
12562306a36Sopenharmony_ci        (proc.returncode, sec, stdout, sec, stderr,
12662306a36Sopenharmony_ci         sec, datetime.now().strftime("%H:%M:%S.%f")))
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci    if proc.returncode != 0 and fail:
12962306a36Sopenharmony_ci        if len(stderr) > 0 and stderr[-1] == "\n":
13062306a36Sopenharmony_ci            stderr = stderr[:-1]
13162306a36Sopenharmony_ci        raise Exception("Command failed: %s\n%s" % (proc.args, stderr))
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci    if include_stderr:
13462306a36Sopenharmony_ci        return proc.returncode, stdout, stderr
13562306a36Sopenharmony_ci    else:
13662306a36Sopenharmony_ci        return proc.returncode, stdout
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cidef rm(f):
13962306a36Sopenharmony_ci    cmd("rm -f %s" % (f))
14062306a36Sopenharmony_ci    if f in files:
14162306a36Sopenharmony_ci        files.remove(f)
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cidef tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False):
14462306a36Sopenharmony_ci    params = ""
14562306a36Sopenharmony_ci    if JSON:
14662306a36Sopenharmony_ci        params += "%s " % (flags["json"])
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    if ns != "":
14962306a36Sopenharmony_ci        ns = "ip netns exec %s " % (ns)
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci    if include_stderr:
15262306a36Sopenharmony_ci        ret, stdout, stderr = cmd(ns + name + " " + params + args,
15362306a36Sopenharmony_ci                                  fail=fail, include_stderr=True)
15462306a36Sopenharmony_ci    else:
15562306a36Sopenharmony_ci        ret, stdout = cmd(ns + name + " " + params + args,
15662306a36Sopenharmony_ci                          fail=fail, include_stderr=False)
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci    if JSON and len(stdout.strip()) != 0:
15962306a36Sopenharmony_ci        out = json.loads(stdout)
16062306a36Sopenharmony_ci    else:
16162306a36Sopenharmony_ci        out = stdout
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci    if include_stderr:
16462306a36Sopenharmony_ci        return ret, out, stderr
16562306a36Sopenharmony_ci    else:
16662306a36Sopenharmony_ci        return ret, out
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cidef bpftool(args, JSON=True, ns="", fail=True, include_stderr=False):
16962306a36Sopenharmony_ci    return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns,
17062306a36Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cidef bpftool_prog_list(expected=None, ns=""):
17362306a36Sopenharmony_ci    _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
17462306a36Sopenharmony_ci    # Remove the base progs
17562306a36Sopenharmony_ci    for p in base_progs:
17662306a36Sopenharmony_ci        if p in progs:
17762306a36Sopenharmony_ci            progs.remove(p)
17862306a36Sopenharmony_ci    if expected is not None:
17962306a36Sopenharmony_ci        if len(progs) != expected:
18062306a36Sopenharmony_ci            fail(True, "%d BPF programs loaded, expected %d" %
18162306a36Sopenharmony_ci                 (len(progs), expected))
18262306a36Sopenharmony_ci    return progs
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cidef bpftool_map_list(expected=None, ns=""):
18562306a36Sopenharmony_ci    _, maps = bpftool("map show", JSON=True, ns=ns, fail=True)
18662306a36Sopenharmony_ci    # Remove the base maps
18762306a36Sopenharmony_ci    maps = [m for m in maps if m not in base_maps and m.get('name') and m.get('name') not in base_map_names]
18862306a36Sopenharmony_ci    if expected is not None:
18962306a36Sopenharmony_ci        if len(maps) != expected:
19062306a36Sopenharmony_ci            fail(True, "%d BPF maps loaded, expected %d" %
19162306a36Sopenharmony_ci                 (len(maps), expected))
19262306a36Sopenharmony_ci    return maps
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cidef bpftool_prog_list_wait(expected=0, n_retry=20):
19562306a36Sopenharmony_ci    for i in range(n_retry):
19662306a36Sopenharmony_ci        nprogs = len(bpftool_prog_list())
19762306a36Sopenharmony_ci        if nprogs == expected:
19862306a36Sopenharmony_ci            return
19962306a36Sopenharmony_ci        time.sleep(0.05)
20062306a36Sopenharmony_ci    raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cidef bpftool_map_list_wait(expected=0, n_retry=20):
20362306a36Sopenharmony_ci    for i in range(n_retry):
20462306a36Sopenharmony_ci        nmaps = len(bpftool_map_list())
20562306a36Sopenharmony_ci        if nmaps == expected:
20662306a36Sopenharmony_ci            return
20762306a36Sopenharmony_ci        time.sleep(0.05)
20862306a36Sopenharmony_ci    raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cidef bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None,
21162306a36Sopenharmony_ci                      fail=True, include_stderr=False):
21262306a36Sopenharmony_ci    args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name)
21362306a36Sopenharmony_ci    if prog_type is not None:
21462306a36Sopenharmony_ci        args += " type " + prog_type
21562306a36Sopenharmony_ci    if dev is not None:
21662306a36Sopenharmony_ci        args += " dev " + dev
21762306a36Sopenharmony_ci    if len(maps):
21862306a36Sopenharmony_ci        args += " map " + " map ".join(maps)
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci    res = bpftool(args, fail=fail, include_stderr=include_stderr)
22162306a36Sopenharmony_ci    if res[0] == 0:
22262306a36Sopenharmony_ci        files.append(file_name)
22362306a36Sopenharmony_ci    return res
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cidef ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False):
22662306a36Sopenharmony_ci    if force:
22762306a36Sopenharmony_ci        args = "-force " + args
22862306a36Sopenharmony_ci    return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns,
22962306a36Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cidef tc(args, JSON=True, ns="", fail=True, include_stderr=False):
23262306a36Sopenharmony_ci    return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns,
23362306a36Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cidef ethtool(dev, opt, args, fail=True):
23662306a36Sopenharmony_ci    return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cidef bpf_obj(name, sec=".text", path=bpf_test_dir,):
23962306a36Sopenharmony_ci    return "obj %s sec %s" % (os.path.join(path, name), sec)
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cidef bpf_pinned(name):
24262306a36Sopenharmony_ci    return "pinned %s" % (name)
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cidef bpf_bytecode(bytecode):
24562306a36Sopenharmony_ci    return "bytecode \"%s\"" % (bytecode)
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cidef mknetns(n_retry=10):
24862306a36Sopenharmony_ci    for i in range(n_retry):
24962306a36Sopenharmony_ci        name = ''.join([random.choice(string.ascii_letters) for i in range(8)])
25062306a36Sopenharmony_ci        ret, _ = ip("netns add %s" % (name), fail=False)
25162306a36Sopenharmony_ci        if ret == 0:
25262306a36Sopenharmony_ci            netns.append(name)
25362306a36Sopenharmony_ci            return name
25462306a36Sopenharmony_ci    return None
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cidef int2str(fmt, val):
25762306a36Sopenharmony_ci    ret = []
25862306a36Sopenharmony_ci    for b in struct.pack(fmt, val):
25962306a36Sopenharmony_ci        ret.append(int(b))
26062306a36Sopenharmony_ci    return " ".join(map(lambda x: str(x), ret))
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cidef str2int(strtab):
26362306a36Sopenharmony_ci    inttab = []
26462306a36Sopenharmony_ci    for i in strtab:
26562306a36Sopenharmony_ci        inttab.append(int(i, 16))
26662306a36Sopenharmony_ci    ba = bytearray(inttab)
26762306a36Sopenharmony_ci    if len(strtab) == 4:
26862306a36Sopenharmony_ci        fmt = "I"
26962306a36Sopenharmony_ci    elif len(strtab) == 8:
27062306a36Sopenharmony_ci        fmt = "Q"
27162306a36Sopenharmony_ci    else:
27262306a36Sopenharmony_ci        raise Exception("String array of len %d can't be unpacked to an int" %
27362306a36Sopenharmony_ci                        (len(strtab)))
27462306a36Sopenharmony_ci    return struct.unpack(fmt, ba)[0]
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciclass DebugfsDir:
27762306a36Sopenharmony_ci    """
27862306a36Sopenharmony_ci    Class for accessing DebugFS directories as a dictionary.
27962306a36Sopenharmony_ci    """
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci    def __init__(self, path):
28262306a36Sopenharmony_ci        self.path = path
28362306a36Sopenharmony_ci        self._dict = self._debugfs_dir_read(path)
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci    def __len__(self):
28662306a36Sopenharmony_ci        return len(self._dict.keys())
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci    def __getitem__(self, key):
28962306a36Sopenharmony_ci        if type(key) is int:
29062306a36Sopenharmony_ci            key = list(self._dict.keys())[key]
29162306a36Sopenharmony_ci        return self._dict[key]
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci    def __setitem__(self, key, value):
29462306a36Sopenharmony_ci        log("DebugFS set %s = %s" % (key, value), "")
29562306a36Sopenharmony_ci        log_level_inc()
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci        cmd("echo '%s' > %s/%s" % (value, self.path, key))
29862306a36Sopenharmony_ci        log_level_dec()
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci        _, out = cmd('cat %s/%s' % (self.path, key))
30162306a36Sopenharmony_ci        self._dict[key] = out.strip()
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci    def _debugfs_dir_read(self, path):
30462306a36Sopenharmony_ci        dfs = {}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci        log("DebugFS state for %s" % (path), "")
30762306a36Sopenharmony_ci        log_level_inc(add=2)
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci        _, out = cmd('ls ' + path)
31062306a36Sopenharmony_ci        for f in out.split():
31162306a36Sopenharmony_ci            if f == "ports":
31262306a36Sopenharmony_ci                continue
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci            p = os.path.join(path, f)
31562306a36Sopenharmony_ci            if not os.stat(p).st_mode & stat.S_IRUSR:
31662306a36Sopenharmony_ci                continue
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci            if os.path.isfile(p):
31962306a36Sopenharmony_ci                # We need to init trap_flow_action_cookie before read it
32062306a36Sopenharmony_ci                if f == "trap_flow_action_cookie":
32162306a36Sopenharmony_ci                    cmd('echo deadbeef > %s/%s' % (path, f))
32262306a36Sopenharmony_ci                _, out = cmd('cat %s/%s' % (path, f))
32362306a36Sopenharmony_ci                dfs[f] = out.strip()
32462306a36Sopenharmony_ci            elif os.path.isdir(p):
32562306a36Sopenharmony_ci                dfs[f] = DebugfsDir(p)
32662306a36Sopenharmony_ci            else:
32762306a36Sopenharmony_ci                raise Exception("%s is neither file nor directory" % (p))
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci        log_level_dec()
33062306a36Sopenharmony_ci        log("DebugFS state", dfs)
33162306a36Sopenharmony_ci        log_level_dec()
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci        return dfs
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciclass NetdevSimDev:
33662306a36Sopenharmony_ci    """
33762306a36Sopenharmony_ci    Class for netdevsim bus device and its attributes.
33862306a36Sopenharmony_ci    """
33962306a36Sopenharmony_ci    @staticmethod
34062306a36Sopenharmony_ci    def ctrl_write(path, val):
34162306a36Sopenharmony_ci        fullpath = os.path.join("/sys/bus/netdevsim/", path)
34262306a36Sopenharmony_ci        try:
34362306a36Sopenharmony_ci            with open(fullpath, "w") as f:
34462306a36Sopenharmony_ci                f.write(val)
34562306a36Sopenharmony_ci        except OSError as e:
34662306a36Sopenharmony_ci            log("WRITE %s: %r" % (fullpath, val), -e.errno)
34762306a36Sopenharmony_ci            raise e
34862306a36Sopenharmony_ci        log("WRITE %s: %r" % (fullpath, val), 0)
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci    def __init__(self, port_count=1):
35162306a36Sopenharmony_ci        addr = 0
35262306a36Sopenharmony_ci        while True:
35362306a36Sopenharmony_ci            try:
35462306a36Sopenharmony_ci                self.ctrl_write("new_device", "%u %u" % (addr, port_count))
35562306a36Sopenharmony_ci            except OSError as e:
35662306a36Sopenharmony_ci                if e.errno == errno.ENOSPC:
35762306a36Sopenharmony_ci                    addr += 1
35862306a36Sopenharmony_ci                    continue
35962306a36Sopenharmony_ci                raise e
36062306a36Sopenharmony_ci            break
36162306a36Sopenharmony_ci        self.addr = addr
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci        # As probe of netdevsim device might happen from a workqueue,
36462306a36Sopenharmony_ci        # so wait here until all netdevs appear.
36562306a36Sopenharmony_ci        self.wait_for_netdevs(port_count)
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci        ret, out = cmd("udevadm settle", fail=False)
36862306a36Sopenharmony_ci        if ret:
36962306a36Sopenharmony_ci            raise Exception("udevadm settle failed")
37062306a36Sopenharmony_ci        ifnames = self.get_ifnames()
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci        devs.append(self)
37362306a36Sopenharmony_ci        self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci        self.nsims = []
37662306a36Sopenharmony_ci        for port_index in range(port_count):
37762306a36Sopenharmony_ci            self.nsims.append(NetdevSim(self, port_index, ifnames[port_index]))
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci    def get_ifnames(self):
38062306a36Sopenharmony_ci        ifnames = []
38162306a36Sopenharmony_ci        listdir = os.listdir("/sys/bus/netdevsim/devices/netdevsim%u/net/" % self.addr)
38262306a36Sopenharmony_ci        for ifname in listdir:
38362306a36Sopenharmony_ci            ifnames.append(ifname)
38462306a36Sopenharmony_ci        ifnames.sort()
38562306a36Sopenharmony_ci        return ifnames
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci    def wait_for_netdevs(self, port_count):
38862306a36Sopenharmony_ci        timeout = 5
38962306a36Sopenharmony_ci        timeout_start = time.time()
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci        while True:
39262306a36Sopenharmony_ci            try:
39362306a36Sopenharmony_ci                ifnames = self.get_ifnames()
39462306a36Sopenharmony_ci            except FileNotFoundError as e:
39562306a36Sopenharmony_ci                ifnames = []
39662306a36Sopenharmony_ci            if len(ifnames) == port_count:
39762306a36Sopenharmony_ci                break
39862306a36Sopenharmony_ci            if time.time() < timeout_start + timeout:
39962306a36Sopenharmony_ci                continue
40062306a36Sopenharmony_ci            raise Exception("netdevices did not appear within timeout")
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci    def dfs_num_bound_progs(self):
40362306a36Sopenharmony_ci        path = os.path.join(self.dfs_dir, "bpf_bound_progs")
40462306a36Sopenharmony_ci        _, progs = cmd('ls %s' % (path))
40562306a36Sopenharmony_ci        return len(progs.split())
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci    def dfs_get_bound_progs(self, expected):
40862306a36Sopenharmony_ci        progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
40962306a36Sopenharmony_ci        if expected is not None:
41062306a36Sopenharmony_ci            if len(progs) != expected:
41162306a36Sopenharmony_ci                fail(True, "%d BPF programs bound, expected %d" %
41262306a36Sopenharmony_ci                     (len(progs), expected))
41362306a36Sopenharmony_ci        return progs
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci    def remove(self):
41662306a36Sopenharmony_ci        self.ctrl_write("del_device", "%u" % (self.addr, ))
41762306a36Sopenharmony_ci        devs.remove(self)
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci    def remove_nsim(self, nsim):
42062306a36Sopenharmony_ci        self.nsims.remove(nsim)
42162306a36Sopenharmony_ci        self.ctrl_write("devices/netdevsim%u/del_port" % (self.addr, ),
42262306a36Sopenharmony_ci                        "%u" % (nsim.port_index, ))
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ciclass NetdevSim:
42562306a36Sopenharmony_ci    """
42662306a36Sopenharmony_ci    Class for netdevsim netdevice and its attributes.
42762306a36Sopenharmony_ci    """
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci    def __init__(self, nsimdev, port_index, ifname):
43062306a36Sopenharmony_ci        # In case udev renamed the netdev to according to new schema,
43162306a36Sopenharmony_ci        # check if the name matches the port_index.
43262306a36Sopenharmony_ci        nsimnamere = re.compile("eni\d+np(\d+)")
43362306a36Sopenharmony_ci        match = nsimnamere.match(ifname)
43462306a36Sopenharmony_ci        if match and int(match.groups()[0]) != port_index + 1:
43562306a36Sopenharmony_ci            raise Exception("netdevice name mismatches the expected one")
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci        self.nsimdev = nsimdev
43862306a36Sopenharmony_ci        self.port_index = port_index
43962306a36Sopenharmony_ci        self.ns = ""
44062306a36Sopenharmony_ci        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
44162306a36Sopenharmony_ci        self.dfs_refresh()
44262306a36Sopenharmony_ci        _, [self.dev] = ip("link show dev %s" % ifname)
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci    def __getitem__(self, key):
44562306a36Sopenharmony_ci        return self.dev[key]
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci    def remove(self):
44862306a36Sopenharmony_ci        self.nsimdev.remove_nsim(self)
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci    def dfs_refresh(self):
45162306a36Sopenharmony_ci        self.dfs = DebugfsDir(self.dfs_dir)
45262306a36Sopenharmony_ci        return self.dfs
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci    def dfs_read(self, f):
45562306a36Sopenharmony_ci        path = os.path.join(self.dfs_dir, f)
45662306a36Sopenharmony_ci        _, data = cmd('cat %s' % (path))
45762306a36Sopenharmony_ci        return data.strip()
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci    def wait_for_flush(self, bound=0, total=0, n_retry=20):
46062306a36Sopenharmony_ci        for i in range(n_retry):
46162306a36Sopenharmony_ci            nbound = self.nsimdev.dfs_num_bound_progs()
46262306a36Sopenharmony_ci            nprogs = len(bpftool_prog_list())
46362306a36Sopenharmony_ci            if nbound == bound and nprogs == total:
46462306a36Sopenharmony_ci                return
46562306a36Sopenharmony_ci            time.sleep(0.05)
46662306a36Sopenharmony_ci        raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci    def set_ns(self, ns):
46962306a36Sopenharmony_ci        name = "1" if ns == "" else ns
47062306a36Sopenharmony_ci        ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
47162306a36Sopenharmony_ci        self.ns = ns
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci    def set_mtu(self, mtu, fail=True):
47462306a36Sopenharmony_ci        return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
47562306a36Sopenharmony_ci                  fail=fail)
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci    def set_xdp(self, bpf, mode, force=False, JSON=True, verbose=False,
47862306a36Sopenharmony_ci                fail=True, include_stderr=False):
47962306a36Sopenharmony_ci        if verbose:
48062306a36Sopenharmony_ci            bpf += " verbose"
48162306a36Sopenharmony_ci        return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf),
48262306a36Sopenharmony_ci                  force=force, JSON=JSON,
48362306a36Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci    def unset_xdp(self, mode, force=False, JSON=True,
48662306a36Sopenharmony_ci                  fail=True, include_stderr=False):
48762306a36Sopenharmony_ci        return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode),
48862306a36Sopenharmony_ci                  force=force, JSON=JSON,
48962306a36Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci    def ip_link_show(self, xdp):
49262306a36Sopenharmony_ci        _, link = ip("link show dev %s" % (self['ifname']))
49362306a36Sopenharmony_ci        if len(link) > 1:
49462306a36Sopenharmony_ci            raise Exception("Multiple objects on ip link show")
49562306a36Sopenharmony_ci        if len(link) < 1:
49662306a36Sopenharmony_ci            return {}
49762306a36Sopenharmony_ci        fail(xdp != "xdp" in link,
49862306a36Sopenharmony_ci             "XDP program not reporting in iplink (reported %s, expected %s)" %
49962306a36Sopenharmony_ci             ("xdp" in link, xdp))
50062306a36Sopenharmony_ci        return link[0]
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci    def tc_add_ingress(self):
50362306a36Sopenharmony_ci        tc("qdisc add dev %s ingress" % (self['ifname']))
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci    def tc_del_ingress(self):
50662306a36Sopenharmony_ci        tc("qdisc del dev %s ingress" % (self['ifname']))
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci    def tc_flush_filters(self, bound=0, total=0):
50962306a36Sopenharmony_ci        self.tc_del_ingress()
51062306a36Sopenharmony_ci        self.tc_add_ingress()
51162306a36Sopenharmony_ci        self.wait_for_flush(bound=bound, total=total)
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci    def tc_show_ingress(self, expected=None):
51462306a36Sopenharmony_ci        # No JSON support, oh well...
51562306a36Sopenharmony_ci        flags = ["skip_sw", "skip_hw", "in_hw"]
51662306a36Sopenharmony_ci        named = ["protocol", "pref", "chain", "handle", "id", "tag"]
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci        args = "-s filter show dev %s ingress" % (self['ifname'])
51962306a36Sopenharmony_ci        _, out = tc(args, JSON=False)
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci        filters = []
52262306a36Sopenharmony_ci        lines = out.split('\n')
52362306a36Sopenharmony_ci        for line in lines:
52462306a36Sopenharmony_ci            words = line.split()
52562306a36Sopenharmony_ci            if "handle" not in words:
52662306a36Sopenharmony_ci                continue
52762306a36Sopenharmony_ci            fltr = {}
52862306a36Sopenharmony_ci            for flag in flags:
52962306a36Sopenharmony_ci                fltr[flag] = flag in words
53062306a36Sopenharmony_ci            for name in named:
53162306a36Sopenharmony_ci                try:
53262306a36Sopenharmony_ci                    idx = words.index(name)
53362306a36Sopenharmony_ci                    fltr[name] = words[idx + 1]
53462306a36Sopenharmony_ci                except ValueError:
53562306a36Sopenharmony_ci                    pass
53662306a36Sopenharmony_ci            filters.append(fltr)
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci        if expected is not None:
53962306a36Sopenharmony_ci            fail(len(filters) != expected,
54062306a36Sopenharmony_ci                 "%d ingress filters loaded, expected %d" %
54162306a36Sopenharmony_ci                 (len(filters), expected))
54262306a36Sopenharmony_ci        return filters
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci    def cls_filter_op(self, op, qdisc="ingress", prio=None, handle=None,
54562306a36Sopenharmony_ci                      chain=None, cls="", params="",
54662306a36Sopenharmony_ci                      fail=True, include_stderr=False):
54762306a36Sopenharmony_ci        spec = ""
54862306a36Sopenharmony_ci        if prio is not None:
54962306a36Sopenharmony_ci            spec += " prio %d" % (prio)
55062306a36Sopenharmony_ci        if handle:
55162306a36Sopenharmony_ci            spec += " handle %s" % (handle)
55262306a36Sopenharmony_ci        if chain is not None:
55362306a36Sopenharmony_ci            spec += " chain %d" % (chain)
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci        return tc("filter {op} dev {dev} {qdisc} {spec} {cls} {params}"\
55662306a36Sopenharmony_ci                  .format(op=op, dev=self['ifname'], qdisc=qdisc, spec=spec,
55762306a36Sopenharmony_ci                          cls=cls, params=params),
55862306a36Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci    def cls_bpf_add_filter(self, bpf, op="add", prio=None, handle=None,
56162306a36Sopenharmony_ci                           chain=None, da=False, verbose=False,
56262306a36Sopenharmony_ci                           skip_sw=False, skip_hw=False,
56362306a36Sopenharmony_ci                           fail=True, include_stderr=False):
56462306a36Sopenharmony_ci        cls = "bpf " + bpf
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci        params = ""
56762306a36Sopenharmony_ci        if da:
56862306a36Sopenharmony_ci            params += " da"
56962306a36Sopenharmony_ci        if verbose:
57062306a36Sopenharmony_ci            params += " verbose"
57162306a36Sopenharmony_ci        if skip_sw:
57262306a36Sopenharmony_ci            params += " skip_sw"
57362306a36Sopenharmony_ci        if skip_hw:
57462306a36Sopenharmony_ci            params += " skip_hw"
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci        return self.cls_filter_op(op=op, prio=prio, handle=handle, cls=cls,
57762306a36Sopenharmony_ci                                  chain=chain, params=params,
57862306a36Sopenharmony_ci                                  fail=fail, include_stderr=include_stderr)
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci    def set_ethtool_tc_offloads(self, enable, fail=True):
58162306a36Sopenharmony_ci        args = "hw-tc-offload %s" % ("on" if enable else "off")
58262306a36Sopenharmony_ci        return ethtool(self, "-K", args, fail=fail)
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci################################################################################
58562306a36Sopenharmony_cidef clean_up():
58662306a36Sopenharmony_ci    global files, netns, devs
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci    for dev in devs:
58962306a36Sopenharmony_ci        dev.remove()
59062306a36Sopenharmony_ci    for f in files:
59162306a36Sopenharmony_ci        cmd("rm -f %s" % (f))
59262306a36Sopenharmony_ci    for ns in netns:
59362306a36Sopenharmony_ci        cmd("ip netns delete %s" % (ns))
59462306a36Sopenharmony_ci    files = []
59562306a36Sopenharmony_ci    netns = []
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cidef pin_prog(file_name, idx=0):
59862306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=(idx + 1))
59962306a36Sopenharmony_ci    prog = progs[idx]
60062306a36Sopenharmony_ci    bpftool("prog pin id %d %s" % (prog["id"], file_name))
60162306a36Sopenharmony_ci    files.append(file_name)
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci    return file_name, bpf_pinned(file_name)
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_cidef pin_map(file_name, idx=0, expected=1):
60662306a36Sopenharmony_ci    maps = bpftool_map_list(expected=expected)
60762306a36Sopenharmony_ci    m = maps[idx]
60862306a36Sopenharmony_ci    bpftool("map pin id %d %s" % (m["id"], file_name))
60962306a36Sopenharmony_ci    files.append(file_name)
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci    return file_name, bpf_pinned(file_name)
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cidef check_dev_info_removed(prog_file=None, map_file=None):
61462306a36Sopenharmony_ci    bpftool_prog_list(expected=0)
61562306a36Sopenharmony_ci    ret, err = bpftool("prog show pin %s" % (prog_file), fail=False)
61662306a36Sopenharmony_ci    fail(ret == 0, "Showing prog with removed device did not fail")
61762306a36Sopenharmony_ci    fail(err["error"].find("No such device") == -1,
61862306a36Sopenharmony_ci         "Showing prog with removed device expected ENODEV, error is %s" %
61962306a36Sopenharmony_ci         (err["error"]))
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci    bpftool_map_list(expected=0)
62262306a36Sopenharmony_ci    ret, err = bpftool("map show pin %s" % (map_file), fail=False)
62362306a36Sopenharmony_ci    fail(ret == 0, "Showing map with removed device did not fail")
62462306a36Sopenharmony_ci    fail(err["error"].find("No such device") == -1,
62562306a36Sopenharmony_ci         "Showing map with removed device expected ENODEV, error is %s" %
62662306a36Sopenharmony_ci         (err["error"]))
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cidef check_dev_info(other_ns, ns, prog_file=None, map_file=None, removed=False):
62962306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=1, ns=ns)
63062306a36Sopenharmony_ci    prog = progs[0]
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci    fail("dev" not in prog.keys(), "Device parameters not reported")
63362306a36Sopenharmony_ci    dev = prog["dev"]
63462306a36Sopenharmony_ci    fail("ifindex" not in dev.keys(), "Device parameters not reported")
63562306a36Sopenharmony_ci    fail("ns_dev" not in dev.keys(), "Device parameters not reported")
63662306a36Sopenharmony_ci    fail("ns_inode" not in dev.keys(), "Device parameters not reported")
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci    if not other_ns:
63962306a36Sopenharmony_ci        fail("ifname" not in dev.keys(), "Ifname not reported")
64062306a36Sopenharmony_ci        fail(dev["ifname"] != sim["ifname"],
64162306a36Sopenharmony_ci             "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
64262306a36Sopenharmony_ci    else:
64362306a36Sopenharmony_ci        fail("ifname" in dev.keys(), "Ifname is reported for other ns")
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci    maps = bpftool_map_list(expected=2, ns=ns)
64662306a36Sopenharmony_ci    for m in maps:
64762306a36Sopenharmony_ci        fail("dev" not in m.keys(), "Device parameters not reported")
64862306a36Sopenharmony_ci        fail(dev != m["dev"], "Map's device different than program's")
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cidef check_extack(output, reference, args):
65162306a36Sopenharmony_ci    if skip_extack:
65262306a36Sopenharmony_ci        return
65362306a36Sopenharmony_ci    lines = output.split("\n")
65462306a36Sopenharmony_ci    comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
65562306a36Sopenharmony_ci    fail(not comp, "Missing or incorrect netlink extack message")
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cidef check_extack_nsim(output, reference, args):
65862306a36Sopenharmony_ci    check_extack(output, "netdevsim: " + reference, args)
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cidef check_no_extack(res, needle):
66162306a36Sopenharmony_ci    fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
66262306a36Sopenharmony_ci         "Found '%s' in command output, leaky extack?" % (needle))
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_cidef check_verifier_log(output, reference):
66562306a36Sopenharmony_ci    lines = output.split("\n")
66662306a36Sopenharmony_ci    for l in reversed(lines):
66762306a36Sopenharmony_ci        if l == reference:
66862306a36Sopenharmony_ci            return
66962306a36Sopenharmony_ci    fail(True, "Missing or incorrect message from netdevsim in verifier log")
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_cidef check_multi_basic(two_xdps):
67262306a36Sopenharmony_ci    fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs")
67362306a36Sopenharmony_ci    fail("prog" in two_xdps, "Base program reported in multi program mode")
67462306a36Sopenharmony_ci    fail(len(two_xdps["attached"]) != 2,
67562306a36Sopenharmony_ci         "Wrong attached program count with two programs")
67662306a36Sopenharmony_ci    fail(two_xdps["attached"][0]["prog"]["id"] ==
67762306a36Sopenharmony_ci         two_xdps["attached"][1]["prog"]["id"],
67862306a36Sopenharmony_ci         "Offloaded and other programs have the same id")
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cidef test_spurios_extack(sim, obj, skip_hw, needle):
68162306a36Sopenharmony_ci    res = sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=skip_hw,
68262306a36Sopenharmony_ci                                 include_stderr=True)
68362306a36Sopenharmony_ci    check_no_extack(res, needle)
68462306a36Sopenharmony_ci    res = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
68562306a36Sopenharmony_ci                                 skip_hw=skip_hw, include_stderr=True)
68662306a36Sopenharmony_ci    check_no_extack(res, needle)
68762306a36Sopenharmony_ci    res = sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf",
68862306a36Sopenharmony_ci                            include_stderr=True)
68962306a36Sopenharmony_ci    check_no_extack(res, needle)
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cidef test_multi_prog(simdev, sim, obj, modename, modeid):
69262306a36Sopenharmony_ci    start_test("Test multi-attachment XDP - %s + offload..." %
69362306a36Sopenharmony_ci               (modename or "default", ))
69462306a36Sopenharmony_ci    sim.set_xdp(obj, "offload")
69562306a36Sopenharmony_ci    xdp = sim.ip_link_show(xdp=True)["xdp"]
69662306a36Sopenharmony_ci    offloaded = sim.dfs_read("bpf_offloaded_id")
69762306a36Sopenharmony_ci    fail("prog" not in xdp, "Base program not reported in single program mode")
69862306a36Sopenharmony_ci    fail(len(xdp["attached"]) != 1,
69962306a36Sopenharmony_ci         "Wrong attached program count with one program")
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci    sim.set_xdp(obj, modename)
70262306a36Sopenharmony_ci    two_xdps = sim.ip_link_show(xdp=True)["xdp"]
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
70562306a36Sopenharmony_ci         "Offload program not reported after other activated")
70662306a36Sopenharmony_ci    check_multi_basic(two_xdps)
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci    offloaded2 = sim.dfs_read("bpf_offloaded_id")
70962306a36Sopenharmony_ci    fail(offloaded != offloaded2,
71062306a36Sopenharmony_ci         "Offload ID changed after loading other program")
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci    start_test("Test multi-attachment XDP - replace...")
71362306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
71462306a36Sopenharmony_ci    fail(ret == 0, "Replaced one of programs without -force")
71562306a36Sopenharmony_ci    check_extack(err, "XDP program already attached.", args)
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci    start_test("Test multi-attachment XDP - remove without mode...")
71862306a36Sopenharmony_ci    ret, _, err = sim.unset_xdp("", force=True,
71962306a36Sopenharmony_ci                                fail=False, include_stderr=True)
72062306a36Sopenharmony_ci    fail(ret == 0, "Removed program without a mode flag")
72162306a36Sopenharmony_ci    check_extack(err, "More than one program loaded, unset mode is ambiguous.", args)
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci    sim.unset_xdp("offload")
72462306a36Sopenharmony_ci    xdp = sim.ip_link_show(xdp=True)["xdp"]
72562306a36Sopenharmony_ci    offloaded = sim.dfs_read("bpf_offloaded_id")
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci    fail(xdp["mode"] != modeid, "Bad mode reported after multiple programs")
72862306a36Sopenharmony_ci    fail("prog" not in xdp,
72962306a36Sopenharmony_ci         "Base program not reported after multi program mode")
73062306a36Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
73162306a36Sopenharmony_ci         "Offload program not reported after other activated")
73262306a36Sopenharmony_ci    fail(len(xdp["attached"]) != 1,
73362306a36Sopenharmony_ci         "Wrong attached program count with remaining programs")
73462306a36Sopenharmony_ci    fail(offloaded != "0", "Offload ID reported with only other program left")
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci    start_test("Test multi-attachment XDP - reattach...")
73762306a36Sopenharmony_ci    sim.set_xdp(obj, "offload")
73862306a36Sopenharmony_ci    two_xdps = sim.ip_link_show(xdp=True)["xdp"]
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
74162306a36Sopenharmony_ci         "Other program not reported after offload activated")
74262306a36Sopenharmony_ci    check_multi_basic(two_xdps)
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci    start_test("Test multi-attachment XDP - device remove...")
74562306a36Sopenharmony_ci    simdev.remove()
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci    simdev = NetdevSimDev()
74862306a36Sopenharmony_ci    sim, = simdev.nsims
74962306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
75062306a36Sopenharmony_ci    return [simdev, sim]
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci# Parse command line
75362306a36Sopenharmony_ciparser = argparse.ArgumentParser()
75462306a36Sopenharmony_ciparser.add_argument("--log", help="output verbose log to given file")
75562306a36Sopenharmony_ciargs = parser.parse_args()
75662306a36Sopenharmony_ciif args.log:
75762306a36Sopenharmony_ci    logfile = open(args.log, 'w+')
75862306a36Sopenharmony_ci    logfile.write("# -*-Org-*-")
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cilog("Prepare...", "", level=1)
76162306a36Sopenharmony_cilog_level_inc()
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci# Check permissions
76462306a36Sopenharmony_ciskip(os.getuid() != 0, "test must be run as root")
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci# Check tools
76762306a36Sopenharmony_ciret, progs = bpftool("prog", fail=False)
76862306a36Sopenharmony_ciskip(ret != 0, "bpftool not installed")
76962306a36Sopenharmony_cibase_progs = progs
77062306a36Sopenharmony_ci_, base_maps = bpftool("map")
77162306a36Sopenharmony_cibase_map_names = [
77262306a36Sopenharmony_ci    'pid_iter.rodata', # created on each bpftool invocation
77362306a36Sopenharmony_ci    'libbpf_det_bind', # created on each bpftool invocation
77462306a36Sopenharmony_ci]
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci# Check netdevsim
77762306a36Sopenharmony_ciif not os.path.isdir("/sys/bus/netdevsim/"):
77862306a36Sopenharmony_ci    ret, out = cmd("modprobe netdevsim", fail=False)
77962306a36Sopenharmony_ci    skip(ret != 0, "netdevsim module could not be loaded")
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci# Check debugfs
78262306a36Sopenharmony_ci_, out = cmd("mount")
78362306a36Sopenharmony_ciif out.find("/sys/kernel/debug type debugfs") == -1:
78462306a36Sopenharmony_ci    cmd("mount -t debugfs none /sys/kernel/debug")
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci# Check samples are compiled
78762306a36Sopenharmony_cisamples = ["sample_ret0.bpf.o", "sample_map_ret0.bpf.o"]
78862306a36Sopenharmony_cifor s in samples:
78962306a36Sopenharmony_ci    ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
79062306a36Sopenharmony_ci    skip(ret != 0, "sample %s/%s not found, please compile it" %
79162306a36Sopenharmony_ci         (bpf_test_dir, s))
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci# Check if iproute2 is built with libmnl (needed by extack support)
79462306a36Sopenharmony_ci_, _, err = cmd("tc qdisc delete dev lo handle 0",
79562306a36Sopenharmony_ci                fail=False, include_stderr=True)
79662306a36Sopenharmony_ciif err.find("Error: Failed to find qdisc with specified handle.") == -1:
79762306a36Sopenharmony_ci    print("Warning: no extack message in iproute2 output, libmnl missing?")
79862306a36Sopenharmony_ci    log("Warning: no extack message in iproute2 output, libmnl missing?", "")
79962306a36Sopenharmony_ci    skip_extack = True
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci# Check if net namespaces seem to work
80262306a36Sopenharmony_cins = mknetns()
80362306a36Sopenharmony_ciskip(ns is None, "Could not create a net namespace")
80462306a36Sopenharmony_cicmd("ip netns delete %s" % (ns))
80562306a36Sopenharmony_cinetns = []
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_citry:
80862306a36Sopenharmony_ci    obj = bpf_obj("sample_ret0.bpf.o")
80962306a36Sopenharmony_ci    bytecode = bpf_bytecode("1,6 0 0 4294967295,")
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci    start_test("Test destruction of generic XDP...")
81262306a36Sopenharmony_ci    simdev = NetdevSimDev()
81362306a36Sopenharmony_ci    sim, = simdev.nsims
81462306a36Sopenharmony_ci    sim.set_xdp(obj, "generic")
81562306a36Sopenharmony_ci    simdev.remove()
81662306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci    simdev = NetdevSimDev()
81962306a36Sopenharmony_ci    sim, = simdev.nsims
82062306a36Sopenharmony_ci    sim.tc_add_ingress()
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci    start_test("Test TC non-offloaded...")
82362306a36Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, skip_hw=True, fail=False)
82462306a36Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci    start_test("Test TC non-offloaded isn't getting bound...")
82762306a36Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
82862306a36Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
82962306a36Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci    sim.tc_flush_filters()
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci    start_test("Test TC offloads are off by default...")
83462306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
83562306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
83662306a36Sopenharmony_ci    fail(ret == 0, "TC filter loaded without enabling TC offloads")
83762306a36Sopenharmony_ci    check_extack(err, "TC offload is disabled on net device.", args)
83862306a36Sopenharmony_ci    sim.wait_for_flush()
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
84162306a36Sopenharmony_ci    sim.dfs["bpf_tc_non_bound_accept"] = "Y"
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci    start_test("Test TC offload by default...")
84462306a36Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
84562306a36Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
84662306a36Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
84762306a36Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
84862306a36Sopenharmony_ci    fltr = ingress[0]
84962306a36Sopenharmony_ci    fail(not fltr["in_hw"], "Filter not offloaded by default")
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci    sim.tc_flush_filters()
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci    start_test("Test TC cBPF bytcode tries offload by default...")
85462306a36Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False)
85562306a36Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
85662306a36Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
85762306a36Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
85862306a36Sopenharmony_ci    fltr = ingress[0]
85962306a36Sopenharmony_ci    fail(not fltr["in_hw"], "Bytecode not offloaded by default")
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci    sim.tc_flush_filters()
86262306a36Sopenharmony_ci    sim.dfs["bpf_tc_non_bound_accept"] = "N"
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci    start_test("Test TC cBPF unbound bytecode doesn't offload...")
86562306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(bytecode, skip_sw=True,
86662306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
86762306a36Sopenharmony_ci    fail(ret == 0, "TC bytecode loaded for offload")
86862306a36Sopenharmony_ci    check_extack_nsim(err, "netdevsim configured to reject unbound programs.",
86962306a36Sopenharmony_ci                      args)
87062306a36Sopenharmony_ci    sim.wait_for_flush()
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci    start_test("Test non-0 chain offload...")
87362306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, chain=1, prio=1, handle=1,
87462306a36Sopenharmony_ci                                         skip_sw=True,
87562306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
87662306a36Sopenharmony_ci    fail(ret == 0, "Offloaded a filter to chain other than 0")
87762306a36Sopenharmony_ci    check_extack(err, "Driver supports only offload of chain 0.", args)
87862306a36Sopenharmony_ci    sim.tc_flush_filters()
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci    start_test("Test TC replace...")
88162306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1)
88262306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1)
88362306a36Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_sw=True)
88662306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_sw=True)
88762306a36Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=True)
89062306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_hw=True)
89162306a36Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci    start_test("Test TC replace bad flags...")
89462306a36Sopenharmony_ci    for i in range(3):
89562306a36Sopenharmony_ci        for j in range(3):
89662306a36Sopenharmony_ci            ret, _ = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
89762306a36Sopenharmony_ci                                            skip_sw=(j == 1), skip_hw=(j == 2),
89862306a36Sopenharmony_ci                                            fail=False)
89962306a36Sopenharmony_ci            fail(bool(ret) != bool(j),
90062306a36Sopenharmony_ci                 "Software TC incorrect load in replace test, iteration %d" %
90162306a36Sopenharmony_ci                 (j))
90262306a36Sopenharmony_ci        sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci    start_test("Test spurious extack from the driver...")
90562306a36Sopenharmony_ci    test_spurios_extack(sim, obj, False, "netdevsim")
90662306a36Sopenharmony_ci    test_spurios_extack(sim, obj, True, "netdevsim")
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(False)
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci    test_spurios_extack(sim, obj, False, "TC offload is disabled")
91162306a36Sopenharmony_ci    test_spurios_extack(sim, obj, True, "TC offload is disabled")
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci    sim.tc_flush_filters()
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci    start_test("Test TC offloads failure...")
91862306a36Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 0
91962306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True,
92062306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
92162306a36Sopenharmony_ci    fail(ret == 0, "TC filter did not reject with TC offloads enabled")
92262306a36Sopenharmony_ci    check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
92362306a36Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 1
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci    start_test("Test TC offloads work...")
92662306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True,
92762306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
92862306a36Sopenharmony_ci    fail(ret != 0, "TC filter did not load with TC offloads enabled")
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci    start_test("Test TC offload basics...")
93162306a36Sopenharmony_ci    dfs = simdev.dfs_get_bound_progs(expected=1)
93262306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
93362306a36Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci    dprog = dfs[0]
93662306a36Sopenharmony_ci    prog = progs[0]
93762306a36Sopenharmony_ci    fltr = ingress[0]
93862306a36Sopenharmony_ci    fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter")
93962306a36Sopenharmony_ci    fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter")
94062306a36Sopenharmony_ci    fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back")
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci    start_test("Test TC offload is device-bound...")
94362306a36Sopenharmony_ci    fail(str(prog["id"]) != fltr["id"], "Program IDs don't match")
94462306a36Sopenharmony_ci    fail(prog["tag"] != fltr["tag"], "Program tags don't match")
94562306a36Sopenharmony_ci    fail(fltr["id"] != dprog["id"], "Program IDs don't match")
94662306a36Sopenharmony_ci    fail(dprog["state"] != "xlated", "Offloaded program state not translated")
94762306a36Sopenharmony_ci    fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci    start_test("Test disabling TC offloads is rejected while filters installed...")
95062306a36Sopenharmony_ci    ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
95162306a36Sopenharmony_ci    fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...")
95262306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci    start_test("Test qdisc removal frees things...")
95562306a36Sopenharmony_ci    sim.tc_flush_filters()
95662306a36Sopenharmony_ci    sim.tc_show_ingress(expected=0)
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci    start_test("Test disabling TC offloads is OK without filters...")
95962306a36Sopenharmony_ci    ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
96062306a36Sopenharmony_ci    fail(ret != 0,
96162306a36Sopenharmony_ci         "Driver refused to disable TC offloads without filters installed...")
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci    start_test("Test destroying device gets rid of TC filters...")
96662306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, skip_sw=True)
96762306a36Sopenharmony_ci    simdev.remove()
96862306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci    simdev = NetdevSimDev()
97162306a36Sopenharmony_ci    sim, = simdev.nsims
97262306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci    start_test("Test destroying device gets rid of XDP...")
97562306a36Sopenharmony_ci    sim.set_xdp(obj, "offload")
97662306a36Sopenharmony_ci    simdev.remove()
97762306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci    simdev = NetdevSimDev()
98062306a36Sopenharmony_ci    sim, = simdev.nsims
98162306a36Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci    start_test("Test XDP prog reporting...")
98462306a36Sopenharmony_ci    sim.set_xdp(obj, "drv")
98562306a36Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
98662306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
98762306a36Sopenharmony_ci    fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
98862306a36Sopenharmony_ci         "Loaded program has wrong ID")
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci    start_test("Test XDP prog replace without force...")
99162306a36Sopenharmony_ci    ret, _ = sim.set_xdp(obj, "drv", fail=False)
99262306a36Sopenharmony_ci    fail(ret == 0, "Replaced XDP program without -force")
99362306a36Sopenharmony_ci    sim.wait_for_flush(total=1)
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci    start_test("Test XDP prog replace with force...")
99662306a36Sopenharmony_ci    ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False)
99762306a36Sopenharmony_ci    fail(ret != 0, "Could not replace XDP program with -force")
99862306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
99962306a36Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
100062306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
100162306a36Sopenharmony_ci    fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
100262306a36Sopenharmony_ci         "Loaded program has wrong ID")
100362306a36Sopenharmony_ci    fail("dev" in progs[0].keys(),
100462306a36Sopenharmony_ci         "Device parameters reported for non-offloaded program")
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci    start_test("Test XDP prog replace with bad flags...")
100762306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "generic", force=True,
100862306a36Sopenharmony_ci                              fail=False, include_stderr=True)
100962306a36Sopenharmony_ci    fail(ret == 0, "Replaced XDP program with a program in different mode")
101062306a36Sopenharmony_ci    check_extack(err,
101162306a36Sopenharmony_ci                 "Native and generic XDP can't be active at the same time.",
101262306a36Sopenharmony_ci                 args)
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci    start_test("Test MTU restrictions...")
101562306a36Sopenharmony_ci    ret, _ = sim.set_mtu(9000, fail=False)
101662306a36Sopenharmony_ci    fail(ret == 0,
101762306a36Sopenharmony_ci         "Driver should refuse to increase MTU to 9000 with XDP loaded...")
101862306a36Sopenharmony_ci    sim.unset_xdp("drv")
101962306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
102062306a36Sopenharmony_ci    sim.set_mtu(9000)
102162306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "drv", fail=False, include_stderr=True)
102262306a36Sopenharmony_ci    fail(ret == 0, "Driver should refuse to load program with MTU of 9000...")
102362306a36Sopenharmony_ci    check_extack_nsim(err, "MTU too large w/ XDP enabled.", args)
102462306a36Sopenharmony_ci    sim.set_mtu(1500)
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci    sim.wait_for_flush()
102762306a36Sopenharmony_ci    start_test("Test non-offload XDP attaching to HW...")
102862306a36Sopenharmony_ci    bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/nooffload")
102962306a36Sopenharmony_ci    nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
103062306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(nooffload, "offload",
103162306a36Sopenharmony_ci                              fail=False, include_stderr=True)
103262306a36Sopenharmony_ci    fail(ret == 0, "attached non-offloaded XDP program to HW")
103362306a36Sopenharmony_ci    check_extack_nsim(err, "xdpoffload of non-bound program.", args)
103462306a36Sopenharmony_ci    rm("/sys/fs/bpf/nooffload")
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci    start_test("Test offload XDP attaching to drv...")
103762306a36Sopenharmony_ci    bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload",
103862306a36Sopenharmony_ci                      dev=sim['ifname'])
103962306a36Sopenharmony_ci    offload = bpf_pinned("/sys/fs/bpf/offload")
104062306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
104162306a36Sopenharmony_ci    fail(ret == 0, "attached offloaded XDP program to drv")
104262306a36Sopenharmony_ci    check_extack(err, "Using offloaded program without HW_MODE flag is not supported.", args)
104362306a36Sopenharmony_ci    rm("/sys/fs/bpf/offload")
104462306a36Sopenharmony_ci    sim.wait_for_flush()
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci    start_test("Test XDP load failure...")
104762306a36Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 0
104862306a36Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload",
104962306a36Sopenharmony_ci                                 dev=sim['ifname'], fail=False, include_stderr=True)
105062306a36Sopenharmony_ci    fail(ret == 0, "verifier should fail on load")
105162306a36Sopenharmony_ci    check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
105262306a36Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 1
105362306a36Sopenharmony_ci    sim.wait_for_flush()
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci    start_test("Test XDP offload...")
105662306a36Sopenharmony_ci    _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True)
105762306a36Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
105862306a36Sopenharmony_ci    link_xdp = ipl["xdp"]["prog"]
105962306a36Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
106062306a36Sopenharmony_ci    prog = progs[0]
106162306a36Sopenharmony_ci    fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID")
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci    start_test("Test XDP offload is device bound...")
106462306a36Sopenharmony_ci    dfs = simdev.dfs_get_bound_progs(expected=1)
106562306a36Sopenharmony_ci    dprog = dfs[0]
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci    fail(prog["id"] != link_xdp["id"], "Program IDs don't match")
106862306a36Sopenharmony_ci    fail(prog["tag"] != link_xdp["tag"], "Program tags don't match")
106962306a36Sopenharmony_ci    fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match")
107062306a36Sopenharmony_ci    fail(dprog["state"] != "xlated", "Offloaded program state not translated")
107162306a36Sopenharmony_ci    fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci    start_test("Test removing XDP program many times...")
107462306a36Sopenharmony_ci    sim.unset_xdp("offload")
107562306a36Sopenharmony_ci    sim.unset_xdp("offload")
107662306a36Sopenharmony_ci    sim.unset_xdp("drv")
107762306a36Sopenharmony_ci    sim.unset_xdp("drv")
107862306a36Sopenharmony_ci    sim.unset_xdp("")
107962306a36Sopenharmony_ci    sim.unset_xdp("")
108062306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci    start_test("Test attempt to use a program for a wrong device...")
108362306a36Sopenharmony_ci    simdev2 = NetdevSimDev()
108462306a36Sopenharmony_ci    sim2, = simdev2.nsims
108562306a36Sopenharmony_ci    sim2.set_xdp(obj, "offload")
108662306a36Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(pinned, "offload",
108962306a36Sopenharmony_ci                              fail=False, include_stderr=True)
109062306a36Sopenharmony_ci    fail(ret == 0, "Pinned program loaded for a different device accepted")
109162306a36Sopenharmony_ci    check_extack(err, "Program bound to different device.", args)
109262306a36Sopenharmony_ci    simdev2.remove()
109362306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(pinned, "offload",
109462306a36Sopenharmony_ci                              fail=False, include_stderr=True)
109562306a36Sopenharmony_ci    fail(ret == 0, "Pinned program loaded for a removed device accepted")
109662306a36Sopenharmony_ci    check_extack(err, "Program bound to different device.", args)
109762306a36Sopenharmony_ci    rm(pin_file)
109862306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "", 1)
110162306a36Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "drv", 1)
110262306a36Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "generic", 2)
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci    start_test("Test mixing of TC and XDP...")
110562306a36Sopenharmony_ci    sim.tc_add_ingress()
110662306a36Sopenharmony_ci    sim.set_xdp(obj, "offload")
110762306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
110862306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
110962306a36Sopenharmony_ci    fail(ret == 0, "Loading TC when XDP active should fail")
111062306a36Sopenharmony_ci    check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
111162306a36Sopenharmony_ci    sim.unset_xdp("offload")
111262306a36Sopenharmony_ci    sim.wait_for_flush()
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, skip_sw=True)
111562306a36Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
111662306a36Sopenharmony_ci    fail(ret == 0, "Loading XDP when TC active should fail")
111762306a36Sopenharmony_ci    check_extack_nsim(err, "TC program is already loaded.", args)
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci    start_test("Test binding TC from pinned...")
112062306a36Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
112162306a36Sopenharmony_ci    sim.tc_flush_filters(bound=1, total=1)
112262306a36Sopenharmony_ci    sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True)
112362306a36Sopenharmony_ci    sim.tc_flush_filters(bound=1, total=1)
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci    start_test("Test binding XDP from pinned...")
112662306a36Sopenharmony_ci    sim.set_xdp(obj, "offload")
112762306a36Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp2", idx=1)
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci    sim.set_xdp(pinned, "offload", force=True)
113062306a36Sopenharmony_ci    sim.unset_xdp("offload")
113162306a36Sopenharmony_ci    sim.set_xdp(pinned, "offload", force=True)
113262306a36Sopenharmony_ci    sim.unset_xdp("offload")
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci    start_test("Test offload of wrong type fails...")
113562306a36Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False)
113662306a36Sopenharmony_ci    fail(ret == 0, "Managed to attach XDP program to TC")
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci    start_test("Test asking for TC offload of two filters...")
113962306a36Sopenharmony_ci    sim.cls_bpf_add_filter(obj, da=True, skip_sw=True)
114062306a36Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True,
114162306a36Sopenharmony_ci                                         fail=False, include_stderr=True)
114262306a36Sopenharmony_ci    fail(ret == 0, "Managed to offload two TC filters at the same time")
114362306a36Sopenharmony_ci    check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci    sim.tc_flush_filters(bound=2, total=2)
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci    start_test("Test if netdev removal waits for translation...")
114862306a36Sopenharmony_ci    delay_msec = 500
114962306a36Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_delay"] = delay_msec
115062306a36Sopenharmony_ci    start = time.time()
115162306a36Sopenharmony_ci    cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \
115262306a36Sopenharmony_ci               (sim['ifname'], obj)
115362306a36Sopenharmony_ci    tc_proc = cmd(cmd_line, background=True, fail=False)
115462306a36Sopenharmony_ci    # Wait for the verifier to start
115562306a36Sopenharmony_ci    while simdev.dfs_num_bound_progs() <= 2:
115662306a36Sopenharmony_ci        pass
115762306a36Sopenharmony_ci    simdev.remove()
115862306a36Sopenharmony_ci    end = time.time()
115962306a36Sopenharmony_ci    ret, _ = cmd_result(tc_proc, fail=False)
116062306a36Sopenharmony_ci    time_diff = end - start
116162306a36Sopenharmony_ci    log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff))
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci    fail(ret == 0, "Managed to load TC filter on a unregistering device")
116462306a36Sopenharmony_ci    delay_sec = delay_msec * 0.001
116562306a36Sopenharmony_ci    fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
116662306a36Sopenharmony_ci         (time_diff, delay_sec))
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci    # Remove all pinned files and reinstantiate the netdev
116962306a36Sopenharmony_ci    clean_up()
117062306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci    simdev = NetdevSimDev()
117362306a36Sopenharmony_ci    sim, = simdev.nsims
117462306a36Sopenharmony_ci    map_obj = bpf_obj("sample_map_ret0.bpf.o")
117562306a36Sopenharmony_ci    start_test("Test loading program with maps...")
117662306a36Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci    start_test("Test bpftool bound info reporting (own ns)...")
117962306a36Sopenharmony_ci    check_dev_info(False, "")
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci    start_test("Test bpftool bound info reporting (other ns)...")
118262306a36Sopenharmony_ci    ns = mknetns()
118362306a36Sopenharmony_ci    sim.set_ns(ns)
118462306a36Sopenharmony_ci    check_dev_info(True, "")
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci    start_test("Test bpftool bound info reporting (remote ns)...")
118762306a36Sopenharmony_ci    check_dev_info(False, ns)
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci    start_test("Test bpftool bound info reporting (back to own ns)...")
119062306a36Sopenharmony_ci    sim.set_ns("")
119162306a36Sopenharmony_ci    check_dev_info(False, "")
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci    prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog")
119462306a36Sopenharmony_ci    map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2)
119562306a36Sopenharmony_ci    simdev.remove()
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci    start_test("Test bpftool bound info reporting (removed dev)...")
119862306a36Sopenharmony_ci    check_dev_info_removed(prog_file=prog_file, map_file=map_file)
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci    # Remove all pinned files and reinstantiate the netdev
120162306a36Sopenharmony_ci    clean_up()
120262306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci    simdev = NetdevSimDev()
120562306a36Sopenharmony_ci    sim, = simdev.nsims
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci    start_test("Test map update (no flags)...")
120862306a36Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
120962306a36Sopenharmony_ci    maps = bpftool_map_list(expected=2)
121062306a36Sopenharmony_ci    array = maps[0] if maps[0]["type"] == "array" else maps[1]
121162306a36Sopenharmony_ci    htab = maps[0] if maps[0]["type"] == "hash" else maps[1]
121262306a36Sopenharmony_ci    for m in maps:
121362306a36Sopenharmony_ci        for i in range(2):
121462306a36Sopenharmony_ci            bpftool("map update id %d key %s value %s" %
121562306a36Sopenharmony_ci                    (m["id"], int2str("I", i), int2str("Q", i * 3)))
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci    for m in maps:
121862306a36Sopenharmony_ci        ret, _ = bpftool("map update id %d key %s value %s" %
121962306a36Sopenharmony_ci                         (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
122062306a36Sopenharmony_ci                         fail=False)
122162306a36Sopenharmony_ci        fail(ret == 0, "added too many entries")
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci    start_test("Test map update (exists)...")
122462306a36Sopenharmony_ci    for m in maps:
122562306a36Sopenharmony_ci        for i in range(2):
122662306a36Sopenharmony_ci            bpftool("map update id %d key %s value %s exist" %
122762306a36Sopenharmony_ci                    (m["id"], int2str("I", i), int2str("Q", i * 3)))
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci    for m in maps:
123062306a36Sopenharmony_ci        ret, err = bpftool("map update id %d key %s value %s exist" %
123162306a36Sopenharmony_ci                           (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
123262306a36Sopenharmony_ci                           fail=False)
123362306a36Sopenharmony_ci        fail(ret == 0, "updated non-existing key")
123462306a36Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
123562306a36Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci    start_test("Test map update (noexist)...")
123862306a36Sopenharmony_ci    for m in maps:
123962306a36Sopenharmony_ci        for i in range(2):
124062306a36Sopenharmony_ci            ret, err = bpftool("map update id %d key %s value %s noexist" %
124162306a36Sopenharmony_ci                               (m["id"], int2str("I", i), int2str("Q", i * 3)),
124262306a36Sopenharmony_ci                               fail=False)
124362306a36Sopenharmony_ci        fail(ret == 0, "updated existing key")
124462306a36Sopenharmony_ci        fail(err["error"].find("File exists") == -1,
124562306a36Sopenharmony_ci             "expected EEXIST, error is '%s'" % (err["error"]))
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci    start_test("Test map dump...")
124862306a36Sopenharmony_ci    for m in maps:
124962306a36Sopenharmony_ci        _, entries = bpftool("map dump id %d" % (m["id"]))
125062306a36Sopenharmony_ci        for i in range(2):
125162306a36Sopenharmony_ci            key = str2int(entries[i]["key"])
125262306a36Sopenharmony_ci            fail(key != i, "expected key %d, got %d" % (key, i))
125362306a36Sopenharmony_ci            val = str2int(entries[i]["value"])
125462306a36Sopenharmony_ci            fail(val != i * 3, "expected value %d, got %d" % (val, i * 3))
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci    start_test("Test map getnext...")
125762306a36Sopenharmony_ci    for m in maps:
125862306a36Sopenharmony_ci        _, entry = bpftool("map getnext id %d" % (m["id"]))
125962306a36Sopenharmony_ci        key = str2int(entry["next_key"])
126062306a36Sopenharmony_ci        fail(key != 0, "next key %d, expected %d" % (key, 0))
126162306a36Sopenharmony_ci        _, entry = bpftool("map getnext id %d key %s" %
126262306a36Sopenharmony_ci                           (m["id"], int2str("I", 0)))
126362306a36Sopenharmony_ci        key = str2int(entry["next_key"])
126462306a36Sopenharmony_ci        fail(key != 1, "next key %d, expected %d" % (key, 1))
126562306a36Sopenharmony_ci        ret, err = bpftool("map getnext id %d key %s" %
126662306a36Sopenharmony_ci                           (m["id"], int2str("I", 1)), fail=False)
126762306a36Sopenharmony_ci        fail(ret == 0, "got next key past the end of map")
126862306a36Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
126962306a36Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci    start_test("Test map delete (htab)...")
127262306a36Sopenharmony_ci    for i in range(2):
127362306a36Sopenharmony_ci        bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i)))
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci    start_test("Test map delete (array)...")
127662306a36Sopenharmony_ci    for i in range(2):
127762306a36Sopenharmony_ci        ret, err = bpftool("map delete id %d key %s" %
127862306a36Sopenharmony_ci                           (htab["id"], int2str("I", i)), fail=False)
127962306a36Sopenharmony_ci        fail(ret == 0, "removed entry from an array")
128062306a36Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
128162306a36Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci    start_test("Test map remove...")
128462306a36Sopenharmony_ci    sim.unset_xdp("offload")
128562306a36Sopenharmony_ci    bpftool_map_list_wait(expected=0)
128662306a36Sopenharmony_ci    simdev.remove()
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci    simdev = NetdevSimDev()
128962306a36Sopenharmony_ci    sim, = simdev.nsims
129062306a36Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
129162306a36Sopenharmony_ci    simdev.remove()
129262306a36Sopenharmony_ci    bpftool_map_list_wait(expected=0)
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci    start_test("Test map creation fail path...")
129562306a36Sopenharmony_ci    simdev = NetdevSimDev()
129662306a36Sopenharmony_ci    sim, = simdev.nsims
129762306a36Sopenharmony_ci    sim.dfs["bpf_map_accept"] = "N"
129862306a36Sopenharmony_ci    ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False)
129962306a36Sopenharmony_ci    fail(ret == 0,
130062306a36Sopenharmony_ci         "netdevsim didn't refuse to create a map with offload disabled")
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci    simdev.remove()
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci    start_test("Test multi-dev ASIC program reuse...")
130562306a36Sopenharmony_ci    simdevA = NetdevSimDev()
130662306a36Sopenharmony_ci    simA, = simdevA.nsims
130762306a36Sopenharmony_ci    simdevB = NetdevSimDev(3)
130862306a36Sopenharmony_ci    simB1, simB2, simB3 = simdevB.nsims
130962306a36Sopenharmony_ci    sims = (simA, simB1, simB2, simB3)
131062306a36Sopenharmony_ci    simB = (simB1, simB2, simB3)
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci    bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA",
131362306a36Sopenharmony_ci                      dev=simA['ifname'])
131462306a36Sopenharmony_ci    progA = bpf_pinned("/sys/fs/bpf/nsimA")
131562306a36Sopenharmony_ci    bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB",
131662306a36Sopenharmony_ci                      dev=simB1['ifname'])
131762306a36Sopenharmony_ci    progB = bpf_pinned("/sys/fs/bpf/nsimB")
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci    simA.set_xdp(progA, "offload", JSON=False)
132062306a36Sopenharmony_ci    for d in simdevB.nsims:
132162306a36Sopenharmony_ci        d.set_xdp(progB, "offload", JSON=False)
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev replace...")
132462306a36Sopenharmony_ci    ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False)
132562306a36Sopenharmony_ci    fail(ret == 0, "cross-ASIC program allowed")
132662306a36Sopenharmony_ci    for d in simdevB.nsims:
132762306a36Sopenharmony_ci        ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False)
132862306a36Sopenharmony_ci        fail(ret == 0, "cross-ASIC program allowed")
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev install...")
133162306a36Sopenharmony_ci    for d in sims:
133262306a36Sopenharmony_ci        d.unset_xdp("offload")
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci    ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False,
133562306a36Sopenharmony_ci                               fail=False, include_stderr=True)
133662306a36Sopenharmony_ci    fail(ret == 0, "cross-ASIC program allowed")
133762306a36Sopenharmony_ci    check_extack(err, "Program bound to different device.", args)
133862306a36Sopenharmony_ci    for d in simdevB.nsims:
133962306a36Sopenharmony_ci        ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False,
134062306a36Sopenharmony_ci                                fail=False, include_stderr=True)
134162306a36Sopenharmony_ci        fail(ret == 0, "cross-ASIC program allowed")
134262306a36Sopenharmony_ci        check_extack(err, "Program bound to different device.", args)
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev map reuse...")
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci    mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
134762306a36Sopenharmony_ci    mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci    ret, _ = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
135062306a36Sopenharmony_ci                               dev=simB3['ifname'],
135162306a36Sopenharmony_ci                               maps=["idx 0 id %d" % (mapB)],
135262306a36Sopenharmony_ci                               fail=False)
135362306a36Sopenharmony_ci    fail(ret != 0, "couldn't reuse a map on the same ASIC")
135462306a36Sopenharmony_ci    rm("/sys/fs/bpf/nsimB_")
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA_",
135762306a36Sopenharmony_ci                                    dev=simA['ifname'],
135862306a36Sopenharmony_ci                                    maps=["idx 0 id %d" % (mapB)],
135962306a36Sopenharmony_ci                                    fail=False, include_stderr=True)
136062306a36Sopenharmony_ci    fail(ret == 0, "could reuse a map on a different ASIC")
136162306a36Sopenharmony_ci    fail(err.count("offload device mismatch between prog and map") == 0,
136262306a36Sopenharmony_ci         "error message missing for cross-ASIC map")
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_",
136562306a36Sopenharmony_ci                                    dev=simB1['ifname'],
136662306a36Sopenharmony_ci                                    maps=["idx 0 id %d" % (mapA)],
136762306a36Sopenharmony_ci                                    fail=False, include_stderr=True)
136862306a36Sopenharmony_ci    fail(ret == 0, "could reuse a map on a different ASIC")
136962306a36Sopenharmony_ci    fail(err.count("offload device mismatch between prog and map") == 0,
137062306a36Sopenharmony_ci         "error message missing for cross-ASIC map")
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction...")
137362306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=2)
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci    simdevA.remove()
137662306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
137962306a36Sopenharmony_ci    fail(ifnameB != simB1['ifname'], "program not bound to original device")
138062306a36Sopenharmony_ci    simB1.remove()
138162306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction - move...")
138462306a36Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
138562306a36Sopenharmony_ci    fail(ifnameB not in (simB2['ifname'], simB3['ifname']),
138662306a36Sopenharmony_ci         "program not bound to remaining devices")
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci    simB2.remove()
138962306a36Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
139062306a36Sopenharmony_ci    fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci    simB3.remove()
139362306a36Sopenharmony_ci    simdevB.remove()
139462306a36Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
139762306a36Sopenharmony_ci    ret, out = bpftool("prog show %s" % (progB), fail=False)
139862306a36Sopenharmony_ci    fail(ret == 0, "got information about orphaned program")
139962306a36Sopenharmony_ci    fail("error" not in out, "no error reported for get info on orphaned")
140062306a36Sopenharmony_ci    fail(out["error"] != "can't get prog info: No such device",
140162306a36Sopenharmony_ci         "wrong error for get info on orphaned")
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci    print("%s: OK" % (os.path.basename(__file__)))
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_cifinally:
140662306a36Sopenharmony_ci    log("Clean up...", "", level=1)
140762306a36Sopenharmony_ci    log_level_inc()
140862306a36Sopenharmony_ci    clean_up()
1409