18c2ecf20Sopenharmony_ci#!/usr/bin/env python3
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci# Copyright (C) 2017 Netronome Systems, Inc.
48c2ecf20Sopenharmony_ci# Copyright (c) 2019 Mellanox Technologies. All rights reserved
58c2ecf20Sopenharmony_ci#
68c2ecf20Sopenharmony_ci# This software is licensed under the GNU General License Version 2,
78c2ecf20Sopenharmony_ci# June 1991 as shown in the file COPYING in the top-level directory of this
88c2ecf20Sopenharmony_ci# source tree.
98c2ecf20Sopenharmony_ci#
108c2ecf20Sopenharmony_ci# THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
118c2ecf20Sopenharmony_ci# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
128c2ecf20Sopenharmony_ci# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
138c2ecf20Sopenharmony_ci# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
148c2ecf20Sopenharmony_ci# OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
158c2ecf20Sopenharmony_ci# THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cifrom datetime import datetime
188c2ecf20Sopenharmony_ciimport argparse
198c2ecf20Sopenharmony_ciimport errno
208c2ecf20Sopenharmony_ciimport json
218c2ecf20Sopenharmony_ciimport os
228c2ecf20Sopenharmony_ciimport pprint
238c2ecf20Sopenharmony_ciimport random
248c2ecf20Sopenharmony_ciimport re
258c2ecf20Sopenharmony_ciimport stat
268c2ecf20Sopenharmony_ciimport string
278c2ecf20Sopenharmony_ciimport struct
288c2ecf20Sopenharmony_ciimport subprocess
298c2ecf20Sopenharmony_ciimport time
308c2ecf20Sopenharmony_ciimport traceback
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cilogfile = None
338c2ecf20Sopenharmony_cilog_level = 1
348c2ecf20Sopenharmony_ciskip_extack = False
358c2ecf20Sopenharmony_cibpf_test_dir = os.path.dirname(os.path.realpath(__file__))
368c2ecf20Sopenharmony_cipp = pprint.PrettyPrinter()
378c2ecf20Sopenharmony_cidevs = [] # devices we created for clean up
388c2ecf20Sopenharmony_cifiles = [] # files to be removed
398c2ecf20Sopenharmony_cinetns = [] # net namespaces to be removed
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cidef log_get_sec(level=0):
428c2ecf20Sopenharmony_ci    return "*" * (log_level + level)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cidef log_level_inc(add=1):
458c2ecf20Sopenharmony_ci    global log_level
468c2ecf20Sopenharmony_ci    log_level += add
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cidef log_level_dec(sub=1):
498c2ecf20Sopenharmony_ci    global log_level
508c2ecf20Sopenharmony_ci    log_level -= sub
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cidef log_level_set(level):
538c2ecf20Sopenharmony_ci    global log_level
548c2ecf20Sopenharmony_ci    log_level = level
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cidef log(header, data, level=None):
578c2ecf20Sopenharmony_ci    """
588c2ecf20Sopenharmony_ci    Output to an optional log.
598c2ecf20Sopenharmony_ci    """
608c2ecf20Sopenharmony_ci    if logfile is None:
618c2ecf20Sopenharmony_ci        return
628c2ecf20Sopenharmony_ci    if level is not None:
638c2ecf20Sopenharmony_ci        log_level_set(level)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci    if not isinstance(data, str):
668c2ecf20Sopenharmony_ci        data = pp.pformat(data)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci    if len(header):
698c2ecf20Sopenharmony_ci        logfile.write("\n" + log_get_sec() + " ")
708c2ecf20Sopenharmony_ci        logfile.write(header)
718c2ecf20Sopenharmony_ci    if len(header) and len(data.strip()):
728c2ecf20Sopenharmony_ci        logfile.write("\n")
738c2ecf20Sopenharmony_ci    logfile.write(data)
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cidef skip(cond, msg):
768c2ecf20Sopenharmony_ci    if not cond:
778c2ecf20Sopenharmony_ci        return
788c2ecf20Sopenharmony_ci    print("SKIP: " + msg)
798c2ecf20Sopenharmony_ci    log("SKIP: " + msg, "", level=1)
808c2ecf20Sopenharmony_ci    os.sys.exit(0)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cidef fail(cond, msg):
838c2ecf20Sopenharmony_ci    if not cond:
848c2ecf20Sopenharmony_ci        return
858c2ecf20Sopenharmony_ci    print("FAIL: " + msg)
868c2ecf20Sopenharmony_ci    tb = "".join(traceback.extract_stack().format())
878c2ecf20Sopenharmony_ci    print(tb)
888c2ecf20Sopenharmony_ci    log("FAIL: " + msg, tb, level=1)
898c2ecf20Sopenharmony_ci    os.sys.exit(1)
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cidef start_test(msg):
928c2ecf20Sopenharmony_ci    log(msg, "", level=1)
938c2ecf20Sopenharmony_ci    log_level_inc()
948c2ecf20Sopenharmony_ci    print(msg)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cidef cmd(cmd, shell=True, include_stderr=False, background=False, fail=True):
978c2ecf20Sopenharmony_ci    """
988c2ecf20Sopenharmony_ci    Run a command in subprocess and return tuple of (retval, stdout);
998c2ecf20Sopenharmony_ci    optionally return stderr as well as third value.
1008c2ecf20Sopenharmony_ci    """
1018c2ecf20Sopenharmony_ci    proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE,
1028c2ecf20Sopenharmony_ci                            stderr=subprocess.PIPE)
1038c2ecf20Sopenharmony_ci    if background:
1048c2ecf20Sopenharmony_ci        msg = "%s START: %s" % (log_get_sec(1),
1058c2ecf20Sopenharmony_ci                                datetime.now().strftime("%H:%M:%S.%f"))
1068c2ecf20Sopenharmony_ci        log("BKG " + proc.args, msg)
1078c2ecf20Sopenharmony_ci        return proc
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci    return cmd_result(proc, include_stderr=include_stderr, fail=fail)
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cidef cmd_result(proc, include_stderr=False, fail=False):
1128c2ecf20Sopenharmony_ci    stdout, stderr = proc.communicate()
1138c2ecf20Sopenharmony_ci    stdout = stdout.decode("utf-8")
1148c2ecf20Sopenharmony_ci    stderr = stderr.decode("utf-8")
1158c2ecf20Sopenharmony_ci    proc.stdout.close()
1168c2ecf20Sopenharmony_ci    proc.stderr.close()
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci    stderr = "\n" + stderr
1198c2ecf20Sopenharmony_ci    if stderr[-1] == "\n":
1208c2ecf20Sopenharmony_ci        stderr = stderr[:-1]
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci    sec = log_get_sec(1)
1238c2ecf20Sopenharmony_ci    log("CMD " + proc.args,
1248c2ecf20Sopenharmony_ci        "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" %
1258c2ecf20Sopenharmony_ci        (proc.returncode, sec, stdout, sec, stderr,
1268c2ecf20Sopenharmony_ci         sec, datetime.now().strftime("%H:%M:%S.%f")))
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci    if proc.returncode != 0 and fail:
1298c2ecf20Sopenharmony_ci        if len(stderr) > 0 and stderr[-1] == "\n":
1308c2ecf20Sopenharmony_ci            stderr = stderr[:-1]
1318c2ecf20Sopenharmony_ci        raise Exception("Command failed: %s\n%s" % (proc.args, stderr))
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci    if include_stderr:
1348c2ecf20Sopenharmony_ci        return proc.returncode, stdout, stderr
1358c2ecf20Sopenharmony_ci    else:
1368c2ecf20Sopenharmony_ci        return proc.returncode, stdout
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cidef rm(f):
1398c2ecf20Sopenharmony_ci    cmd("rm -f %s" % (f))
1408c2ecf20Sopenharmony_ci    if f in files:
1418c2ecf20Sopenharmony_ci        files.remove(f)
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cidef tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False):
1448c2ecf20Sopenharmony_ci    params = ""
1458c2ecf20Sopenharmony_ci    if JSON:
1468c2ecf20Sopenharmony_ci        params += "%s " % (flags["json"])
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci    if ns != "":
1498c2ecf20Sopenharmony_ci        ns = "ip netns exec %s " % (ns)
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci    if include_stderr:
1528c2ecf20Sopenharmony_ci        ret, stdout, stderr = cmd(ns + name + " " + params + args,
1538c2ecf20Sopenharmony_ci                                  fail=fail, include_stderr=True)
1548c2ecf20Sopenharmony_ci    else:
1558c2ecf20Sopenharmony_ci        ret, stdout = cmd(ns + name + " " + params + args,
1568c2ecf20Sopenharmony_ci                          fail=fail, include_stderr=False)
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci    if JSON and len(stdout.strip()) != 0:
1598c2ecf20Sopenharmony_ci        out = json.loads(stdout)
1608c2ecf20Sopenharmony_ci    else:
1618c2ecf20Sopenharmony_ci        out = stdout
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci    if include_stderr:
1648c2ecf20Sopenharmony_ci        return ret, out, stderr
1658c2ecf20Sopenharmony_ci    else:
1668c2ecf20Sopenharmony_ci        return ret, out
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cidef bpftool(args, JSON=True, ns="", fail=True, include_stderr=False):
1698c2ecf20Sopenharmony_ci    return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns,
1708c2ecf20Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cidef bpftool_prog_list(expected=None, ns=""):
1738c2ecf20Sopenharmony_ci    _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
1748c2ecf20Sopenharmony_ci    # Remove the base progs
1758c2ecf20Sopenharmony_ci    for p in base_progs:
1768c2ecf20Sopenharmony_ci        if p in progs:
1778c2ecf20Sopenharmony_ci            progs.remove(p)
1788c2ecf20Sopenharmony_ci    if expected is not None:
1798c2ecf20Sopenharmony_ci        if len(progs) != expected:
1808c2ecf20Sopenharmony_ci            fail(True, "%d BPF programs loaded, expected %d" %
1818c2ecf20Sopenharmony_ci                 (len(progs), expected))
1828c2ecf20Sopenharmony_ci    return progs
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cidef bpftool_map_list(expected=None, ns=""):
1858c2ecf20Sopenharmony_ci    _, maps = bpftool("map show", JSON=True, ns=ns, fail=True)
1868c2ecf20Sopenharmony_ci    # Remove the base maps
1878c2ecf20Sopenharmony_ci    maps = [m for m in maps if m not in base_maps and m.get('name') not in base_map_names]
1888c2ecf20Sopenharmony_ci    if expected is not None:
1898c2ecf20Sopenharmony_ci        if len(maps) != expected:
1908c2ecf20Sopenharmony_ci            fail(True, "%d BPF maps loaded, expected %d" %
1918c2ecf20Sopenharmony_ci                 (len(maps), expected))
1928c2ecf20Sopenharmony_ci    return maps
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cidef bpftool_prog_list_wait(expected=0, n_retry=20):
1958c2ecf20Sopenharmony_ci    for i in range(n_retry):
1968c2ecf20Sopenharmony_ci        nprogs = len(bpftool_prog_list())
1978c2ecf20Sopenharmony_ci        if nprogs == expected:
1988c2ecf20Sopenharmony_ci            return
1998c2ecf20Sopenharmony_ci        time.sleep(0.05)
2008c2ecf20Sopenharmony_ci    raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cidef bpftool_map_list_wait(expected=0, n_retry=20):
2038c2ecf20Sopenharmony_ci    for i in range(n_retry):
2048c2ecf20Sopenharmony_ci        nmaps = len(bpftool_map_list())
2058c2ecf20Sopenharmony_ci        if nmaps == expected:
2068c2ecf20Sopenharmony_ci            return
2078c2ecf20Sopenharmony_ci        time.sleep(0.05)
2088c2ecf20Sopenharmony_ci    raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps))
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cidef bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None,
2118c2ecf20Sopenharmony_ci                      fail=True, include_stderr=False):
2128c2ecf20Sopenharmony_ci    args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name)
2138c2ecf20Sopenharmony_ci    if prog_type is not None:
2148c2ecf20Sopenharmony_ci        args += " type " + prog_type
2158c2ecf20Sopenharmony_ci    if dev is not None:
2168c2ecf20Sopenharmony_ci        args += " dev " + dev
2178c2ecf20Sopenharmony_ci    if len(maps):
2188c2ecf20Sopenharmony_ci        args += " map " + " map ".join(maps)
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci    res = bpftool(args, fail=fail, include_stderr=include_stderr)
2218c2ecf20Sopenharmony_ci    if res[0] == 0:
2228c2ecf20Sopenharmony_ci        files.append(file_name)
2238c2ecf20Sopenharmony_ci    return res
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cidef ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False):
2268c2ecf20Sopenharmony_ci    if force:
2278c2ecf20Sopenharmony_ci        args = "-force " + args
2288c2ecf20Sopenharmony_ci    return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns,
2298c2ecf20Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cidef tc(args, JSON=True, ns="", fail=True, include_stderr=False):
2328c2ecf20Sopenharmony_ci    return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns,
2338c2ecf20Sopenharmony_ci                fail=fail, include_stderr=include_stderr)
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cidef ethtool(dev, opt, args, fail=True):
2368c2ecf20Sopenharmony_ci    return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cidef bpf_obj(name, sec=".text", path=bpf_test_dir,):
2398c2ecf20Sopenharmony_ci    return "obj %s sec %s" % (os.path.join(path, name), sec)
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cidef bpf_pinned(name):
2428c2ecf20Sopenharmony_ci    return "pinned %s" % (name)
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cidef bpf_bytecode(bytecode):
2458c2ecf20Sopenharmony_ci    return "bytecode \"%s\"" % (bytecode)
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cidef mknetns(n_retry=10):
2488c2ecf20Sopenharmony_ci    for i in range(n_retry):
2498c2ecf20Sopenharmony_ci        name = ''.join([random.choice(string.ascii_letters) for i in range(8)])
2508c2ecf20Sopenharmony_ci        ret, _ = ip("netns add %s" % (name), fail=False)
2518c2ecf20Sopenharmony_ci        if ret == 0:
2528c2ecf20Sopenharmony_ci            netns.append(name)
2538c2ecf20Sopenharmony_ci            return name
2548c2ecf20Sopenharmony_ci    return None
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cidef int2str(fmt, val):
2578c2ecf20Sopenharmony_ci    ret = []
2588c2ecf20Sopenharmony_ci    for b in struct.pack(fmt, val):
2598c2ecf20Sopenharmony_ci        ret.append(int(b))
2608c2ecf20Sopenharmony_ci    return " ".join(map(lambda x: str(x), ret))
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cidef str2int(strtab):
2638c2ecf20Sopenharmony_ci    inttab = []
2648c2ecf20Sopenharmony_ci    for i in strtab:
2658c2ecf20Sopenharmony_ci        inttab.append(int(i, 16))
2668c2ecf20Sopenharmony_ci    ba = bytearray(inttab)
2678c2ecf20Sopenharmony_ci    if len(strtab) == 4:
2688c2ecf20Sopenharmony_ci        fmt = "I"
2698c2ecf20Sopenharmony_ci    elif len(strtab) == 8:
2708c2ecf20Sopenharmony_ci        fmt = "Q"
2718c2ecf20Sopenharmony_ci    else:
2728c2ecf20Sopenharmony_ci        raise Exception("String array of len %d can't be unpacked to an int" %
2738c2ecf20Sopenharmony_ci                        (len(strtab)))
2748c2ecf20Sopenharmony_ci    return struct.unpack(fmt, ba)[0]
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciclass DebugfsDir:
2778c2ecf20Sopenharmony_ci    """
2788c2ecf20Sopenharmony_ci    Class for accessing DebugFS directories as a dictionary.
2798c2ecf20Sopenharmony_ci    """
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci    def __init__(self, path):
2828c2ecf20Sopenharmony_ci        self.path = path
2838c2ecf20Sopenharmony_ci        self._dict = self._debugfs_dir_read(path)
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci    def __len__(self):
2868c2ecf20Sopenharmony_ci        return len(self._dict.keys())
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci    def __getitem__(self, key):
2898c2ecf20Sopenharmony_ci        if type(key) is int:
2908c2ecf20Sopenharmony_ci            key = list(self._dict.keys())[key]
2918c2ecf20Sopenharmony_ci        return self._dict[key]
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci    def __setitem__(self, key, value):
2948c2ecf20Sopenharmony_ci        log("DebugFS set %s = %s" % (key, value), "")
2958c2ecf20Sopenharmony_ci        log_level_inc()
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci        cmd("echo '%s' > %s/%s" % (value, self.path, key))
2988c2ecf20Sopenharmony_ci        log_level_dec()
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci        _, out = cmd('cat %s/%s' % (self.path, key))
3018c2ecf20Sopenharmony_ci        self._dict[key] = out.strip()
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci    def _debugfs_dir_read(self, path):
3048c2ecf20Sopenharmony_ci        dfs = {}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci        log("DebugFS state for %s" % (path), "")
3078c2ecf20Sopenharmony_ci        log_level_inc(add=2)
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci        _, out = cmd('ls ' + path)
3108c2ecf20Sopenharmony_ci        for f in out.split():
3118c2ecf20Sopenharmony_ci            if f == "ports":
3128c2ecf20Sopenharmony_ci                continue
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci            p = os.path.join(path, f)
3158c2ecf20Sopenharmony_ci            if not os.stat(p).st_mode & stat.S_IRUSR:
3168c2ecf20Sopenharmony_ci                continue
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci            if os.path.isfile(p):
3198c2ecf20Sopenharmony_ci                # We need to init trap_flow_action_cookie before read it
3208c2ecf20Sopenharmony_ci                if f == "trap_flow_action_cookie":
3218c2ecf20Sopenharmony_ci                    cmd('echo deadbeef > %s/%s' % (path, f))
3228c2ecf20Sopenharmony_ci                _, out = cmd('cat %s/%s' % (path, f))
3238c2ecf20Sopenharmony_ci                dfs[f] = out.strip()
3248c2ecf20Sopenharmony_ci            elif os.path.isdir(p):
3258c2ecf20Sopenharmony_ci                dfs[f] = DebugfsDir(p)
3268c2ecf20Sopenharmony_ci            else:
3278c2ecf20Sopenharmony_ci                raise Exception("%s is neither file nor directory" % (p))
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci        log_level_dec()
3308c2ecf20Sopenharmony_ci        log("DebugFS state", dfs)
3318c2ecf20Sopenharmony_ci        log_level_dec()
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci        return dfs
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ciclass NetdevSimDev:
3368c2ecf20Sopenharmony_ci    """
3378c2ecf20Sopenharmony_ci    Class for netdevsim bus device and its attributes.
3388c2ecf20Sopenharmony_ci    """
3398c2ecf20Sopenharmony_ci    @staticmethod
3408c2ecf20Sopenharmony_ci    def ctrl_write(path, val):
3418c2ecf20Sopenharmony_ci        fullpath = os.path.join("/sys/bus/netdevsim/", path)
3428c2ecf20Sopenharmony_ci        try:
3438c2ecf20Sopenharmony_ci            with open(fullpath, "w") as f:
3448c2ecf20Sopenharmony_ci                f.write(val)
3458c2ecf20Sopenharmony_ci        except OSError as e:
3468c2ecf20Sopenharmony_ci            log("WRITE %s: %r" % (fullpath, val), -e.errno)
3478c2ecf20Sopenharmony_ci            raise e
3488c2ecf20Sopenharmony_ci        log("WRITE %s: %r" % (fullpath, val), 0)
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci    def __init__(self, port_count=1):
3518c2ecf20Sopenharmony_ci        addr = 0
3528c2ecf20Sopenharmony_ci        while True:
3538c2ecf20Sopenharmony_ci            try:
3548c2ecf20Sopenharmony_ci                self.ctrl_write("new_device", "%u %u" % (addr, port_count))
3558c2ecf20Sopenharmony_ci            except OSError as e:
3568c2ecf20Sopenharmony_ci                if e.errno == errno.ENOSPC:
3578c2ecf20Sopenharmony_ci                    addr += 1
3588c2ecf20Sopenharmony_ci                    continue
3598c2ecf20Sopenharmony_ci                raise e
3608c2ecf20Sopenharmony_ci            break
3618c2ecf20Sopenharmony_ci        self.addr = addr
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci        # As probe of netdevsim device might happen from a workqueue,
3648c2ecf20Sopenharmony_ci        # so wait here until all netdevs appear.
3658c2ecf20Sopenharmony_ci        self.wait_for_netdevs(port_count)
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci        ret, out = cmd("udevadm settle", fail=False)
3688c2ecf20Sopenharmony_ci        if ret:
3698c2ecf20Sopenharmony_ci            raise Exception("udevadm settle failed")
3708c2ecf20Sopenharmony_ci        ifnames = self.get_ifnames()
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci        devs.append(self)
3738c2ecf20Sopenharmony_ci        self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci        self.nsims = []
3768c2ecf20Sopenharmony_ci        for port_index in range(port_count):
3778c2ecf20Sopenharmony_ci            self.nsims.append(NetdevSim(self, port_index, ifnames[port_index]))
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci    def get_ifnames(self):
3808c2ecf20Sopenharmony_ci        ifnames = []
3818c2ecf20Sopenharmony_ci        listdir = os.listdir("/sys/bus/netdevsim/devices/netdevsim%u/net/" % self.addr)
3828c2ecf20Sopenharmony_ci        for ifname in listdir:
3838c2ecf20Sopenharmony_ci            ifnames.append(ifname)
3848c2ecf20Sopenharmony_ci        ifnames.sort()
3858c2ecf20Sopenharmony_ci        return ifnames
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci    def wait_for_netdevs(self, port_count):
3888c2ecf20Sopenharmony_ci        timeout = 5
3898c2ecf20Sopenharmony_ci        timeout_start = time.time()
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci        while True:
3928c2ecf20Sopenharmony_ci            try:
3938c2ecf20Sopenharmony_ci                ifnames = self.get_ifnames()
3948c2ecf20Sopenharmony_ci            except FileNotFoundError as e:
3958c2ecf20Sopenharmony_ci                ifnames = []
3968c2ecf20Sopenharmony_ci            if len(ifnames) == port_count:
3978c2ecf20Sopenharmony_ci                break
3988c2ecf20Sopenharmony_ci            if time.time() < timeout_start + timeout:
3998c2ecf20Sopenharmony_ci                continue
4008c2ecf20Sopenharmony_ci            raise Exception("netdevices did not appear within timeout")
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci    def dfs_num_bound_progs(self):
4038c2ecf20Sopenharmony_ci        path = os.path.join(self.dfs_dir, "bpf_bound_progs")
4048c2ecf20Sopenharmony_ci        _, progs = cmd('ls %s' % (path))
4058c2ecf20Sopenharmony_ci        return len(progs.split())
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci    def dfs_get_bound_progs(self, expected):
4088c2ecf20Sopenharmony_ci        progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs"))
4098c2ecf20Sopenharmony_ci        if expected is not None:
4108c2ecf20Sopenharmony_ci            if len(progs) != expected:
4118c2ecf20Sopenharmony_ci                fail(True, "%d BPF programs bound, expected %d" %
4128c2ecf20Sopenharmony_ci                     (len(progs), expected))
4138c2ecf20Sopenharmony_ci        return progs
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci    def remove(self):
4168c2ecf20Sopenharmony_ci        self.ctrl_write("del_device", "%u" % (self.addr, ))
4178c2ecf20Sopenharmony_ci        devs.remove(self)
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci    def remove_nsim(self, nsim):
4208c2ecf20Sopenharmony_ci        self.nsims.remove(nsim)
4218c2ecf20Sopenharmony_ci        self.ctrl_write("devices/netdevsim%u/del_port" % (self.addr, ),
4228c2ecf20Sopenharmony_ci                        "%u" % (nsim.port_index, ))
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ciclass NetdevSim:
4258c2ecf20Sopenharmony_ci    """
4268c2ecf20Sopenharmony_ci    Class for netdevsim netdevice and its attributes.
4278c2ecf20Sopenharmony_ci    """
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci    def __init__(self, nsimdev, port_index, ifname):
4308c2ecf20Sopenharmony_ci        # In case udev renamed the netdev to according to new schema,
4318c2ecf20Sopenharmony_ci        # check if the name matches the port_index.
4328c2ecf20Sopenharmony_ci        nsimnamere = re.compile("eni\d+np(\d+)")
4338c2ecf20Sopenharmony_ci        match = nsimnamere.match(ifname)
4348c2ecf20Sopenharmony_ci        if match and int(match.groups()[0]) != port_index + 1:
4358c2ecf20Sopenharmony_ci            raise Exception("netdevice name mismatches the expected one")
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci        self.nsimdev = nsimdev
4388c2ecf20Sopenharmony_ci        self.port_index = port_index
4398c2ecf20Sopenharmony_ci        self.ns = ""
4408c2ecf20Sopenharmony_ci        self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index)
4418c2ecf20Sopenharmony_ci        self.dfs_refresh()
4428c2ecf20Sopenharmony_ci        _, [self.dev] = ip("link show dev %s" % ifname)
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci    def __getitem__(self, key):
4458c2ecf20Sopenharmony_ci        return self.dev[key]
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci    def remove(self):
4488c2ecf20Sopenharmony_ci        self.nsimdev.remove_nsim(self)
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci    def dfs_refresh(self):
4518c2ecf20Sopenharmony_ci        self.dfs = DebugfsDir(self.dfs_dir)
4528c2ecf20Sopenharmony_ci        return self.dfs
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci    def dfs_read(self, f):
4558c2ecf20Sopenharmony_ci        path = os.path.join(self.dfs_dir, f)
4568c2ecf20Sopenharmony_ci        _, data = cmd('cat %s' % (path))
4578c2ecf20Sopenharmony_ci        return data.strip()
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci    def wait_for_flush(self, bound=0, total=0, n_retry=20):
4608c2ecf20Sopenharmony_ci        for i in range(n_retry):
4618c2ecf20Sopenharmony_ci            nbound = self.nsimdev.dfs_num_bound_progs()
4628c2ecf20Sopenharmony_ci            nprogs = len(bpftool_prog_list())
4638c2ecf20Sopenharmony_ci            if nbound == bound and nprogs == total:
4648c2ecf20Sopenharmony_ci                return
4658c2ecf20Sopenharmony_ci            time.sleep(0.05)
4668c2ecf20Sopenharmony_ci        raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci    def set_ns(self, ns):
4698c2ecf20Sopenharmony_ci        name = "1" if ns == "" else ns
4708c2ecf20Sopenharmony_ci        ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
4718c2ecf20Sopenharmony_ci        self.ns = ns
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci    def set_mtu(self, mtu, fail=True):
4748c2ecf20Sopenharmony_ci        return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
4758c2ecf20Sopenharmony_ci                  fail=fail)
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci    def set_xdp(self, bpf, mode, force=False, JSON=True, verbose=False,
4788c2ecf20Sopenharmony_ci                fail=True, include_stderr=False):
4798c2ecf20Sopenharmony_ci        if verbose:
4808c2ecf20Sopenharmony_ci            bpf += " verbose"
4818c2ecf20Sopenharmony_ci        return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf),
4828c2ecf20Sopenharmony_ci                  force=force, JSON=JSON,
4838c2ecf20Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci    def unset_xdp(self, mode, force=False, JSON=True,
4868c2ecf20Sopenharmony_ci                  fail=True, include_stderr=False):
4878c2ecf20Sopenharmony_ci        return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode),
4888c2ecf20Sopenharmony_ci                  force=force, JSON=JSON,
4898c2ecf20Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci    def ip_link_show(self, xdp):
4928c2ecf20Sopenharmony_ci        _, link = ip("link show dev %s" % (self['ifname']))
4938c2ecf20Sopenharmony_ci        if len(link) > 1:
4948c2ecf20Sopenharmony_ci            raise Exception("Multiple objects on ip link show")
4958c2ecf20Sopenharmony_ci        if len(link) < 1:
4968c2ecf20Sopenharmony_ci            return {}
4978c2ecf20Sopenharmony_ci        fail(xdp != "xdp" in link,
4988c2ecf20Sopenharmony_ci             "XDP program not reporting in iplink (reported %s, expected %s)" %
4998c2ecf20Sopenharmony_ci             ("xdp" in link, xdp))
5008c2ecf20Sopenharmony_ci        return link[0]
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci    def tc_add_ingress(self):
5038c2ecf20Sopenharmony_ci        tc("qdisc add dev %s ingress" % (self['ifname']))
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci    def tc_del_ingress(self):
5068c2ecf20Sopenharmony_ci        tc("qdisc del dev %s ingress" % (self['ifname']))
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci    def tc_flush_filters(self, bound=0, total=0):
5098c2ecf20Sopenharmony_ci        self.tc_del_ingress()
5108c2ecf20Sopenharmony_ci        self.tc_add_ingress()
5118c2ecf20Sopenharmony_ci        self.wait_for_flush(bound=bound, total=total)
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci    def tc_show_ingress(self, expected=None):
5148c2ecf20Sopenharmony_ci        # No JSON support, oh well...
5158c2ecf20Sopenharmony_ci        flags = ["skip_sw", "skip_hw", "in_hw"]
5168c2ecf20Sopenharmony_ci        named = ["protocol", "pref", "chain", "handle", "id", "tag"]
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci        args = "-s filter show dev %s ingress" % (self['ifname'])
5198c2ecf20Sopenharmony_ci        _, out = tc(args, JSON=False)
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci        filters = []
5228c2ecf20Sopenharmony_ci        lines = out.split('\n')
5238c2ecf20Sopenharmony_ci        for line in lines:
5248c2ecf20Sopenharmony_ci            words = line.split()
5258c2ecf20Sopenharmony_ci            if "handle" not in words:
5268c2ecf20Sopenharmony_ci                continue
5278c2ecf20Sopenharmony_ci            fltr = {}
5288c2ecf20Sopenharmony_ci            for flag in flags:
5298c2ecf20Sopenharmony_ci                fltr[flag] = flag in words
5308c2ecf20Sopenharmony_ci            for name in named:
5318c2ecf20Sopenharmony_ci                try:
5328c2ecf20Sopenharmony_ci                    idx = words.index(name)
5338c2ecf20Sopenharmony_ci                    fltr[name] = words[idx + 1]
5348c2ecf20Sopenharmony_ci                except ValueError:
5358c2ecf20Sopenharmony_ci                    pass
5368c2ecf20Sopenharmony_ci            filters.append(fltr)
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci        if expected is not None:
5398c2ecf20Sopenharmony_ci            fail(len(filters) != expected,
5408c2ecf20Sopenharmony_ci                 "%d ingress filters loaded, expected %d" %
5418c2ecf20Sopenharmony_ci                 (len(filters), expected))
5428c2ecf20Sopenharmony_ci        return filters
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci    def cls_filter_op(self, op, qdisc="ingress", prio=None, handle=None,
5458c2ecf20Sopenharmony_ci                      chain=None, cls="", params="",
5468c2ecf20Sopenharmony_ci                      fail=True, include_stderr=False):
5478c2ecf20Sopenharmony_ci        spec = ""
5488c2ecf20Sopenharmony_ci        if prio is not None:
5498c2ecf20Sopenharmony_ci            spec += " prio %d" % (prio)
5508c2ecf20Sopenharmony_ci        if handle:
5518c2ecf20Sopenharmony_ci            spec += " handle %s" % (handle)
5528c2ecf20Sopenharmony_ci        if chain is not None:
5538c2ecf20Sopenharmony_ci            spec += " chain %d" % (chain)
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci        return tc("filter {op} dev {dev} {qdisc} {spec} {cls} {params}"\
5568c2ecf20Sopenharmony_ci                  .format(op=op, dev=self['ifname'], qdisc=qdisc, spec=spec,
5578c2ecf20Sopenharmony_ci                          cls=cls, params=params),
5588c2ecf20Sopenharmony_ci                  fail=fail, include_stderr=include_stderr)
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci    def cls_bpf_add_filter(self, bpf, op="add", prio=None, handle=None,
5618c2ecf20Sopenharmony_ci                           chain=None, da=False, verbose=False,
5628c2ecf20Sopenharmony_ci                           skip_sw=False, skip_hw=False,
5638c2ecf20Sopenharmony_ci                           fail=True, include_stderr=False):
5648c2ecf20Sopenharmony_ci        cls = "bpf " + bpf
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci        params = ""
5678c2ecf20Sopenharmony_ci        if da:
5688c2ecf20Sopenharmony_ci            params += " da"
5698c2ecf20Sopenharmony_ci        if verbose:
5708c2ecf20Sopenharmony_ci            params += " verbose"
5718c2ecf20Sopenharmony_ci        if skip_sw:
5728c2ecf20Sopenharmony_ci            params += " skip_sw"
5738c2ecf20Sopenharmony_ci        if skip_hw:
5748c2ecf20Sopenharmony_ci            params += " skip_hw"
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci        return self.cls_filter_op(op=op, prio=prio, handle=handle, cls=cls,
5778c2ecf20Sopenharmony_ci                                  chain=chain, params=params,
5788c2ecf20Sopenharmony_ci                                  fail=fail, include_stderr=include_stderr)
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci    def set_ethtool_tc_offloads(self, enable, fail=True):
5818c2ecf20Sopenharmony_ci        args = "hw-tc-offload %s" % ("on" if enable else "off")
5828c2ecf20Sopenharmony_ci        return ethtool(self, "-K", args, fail=fail)
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci################################################################################
5858c2ecf20Sopenharmony_cidef clean_up():
5868c2ecf20Sopenharmony_ci    global files, netns, devs
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci    for dev in devs:
5898c2ecf20Sopenharmony_ci        dev.remove()
5908c2ecf20Sopenharmony_ci    for f in files:
5918c2ecf20Sopenharmony_ci        cmd("rm -f %s" % (f))
5928c2ecf20Sopenharmony_ci    for ns in netns:
5938c2ecf20Sopenharmony_ci        cmd("ip netns delete %s" % (ns))
5948c2ecf20Sopenharmony_ci    files = []
5958c2ecf20Sopenharmony_ci    netns = []
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cidef pin_prog(file_name, idx=0):
5988c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=(idx + 1))
5998c2ecf20Sopenharmony_ci    prog = progs[idx]
6008c2ecf20Sopenharmony_ci    bpftool("prog pin id %d %s" % (prog["id"], file_name))
6018c2ecf20Sopenharmony_ci    files.append(file_name)
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci    return file_name, bpf_pinned(file_name)
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cidef pin_map(file_name, idx=0, expected=1):
6068c2ecf20Sopenharmony_ci    maps = bpftool_map_list(expected=expected)
6078c2ecf20Sopenharmony_ci    m = maps[idx]
6088c2ecf20Sopenharmony_ci    bpftool("map pin id %d %s" % (m["id"], file_name))
6098c2ecf20Sopenharmony_ci    files.append(file_name)
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci    return file_name, bpf_pinned(file_name)
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cidef check_dev_info_removed(prog_file=None, map_file=None):
6148c2ecf20Sopenharmony_ci    bpftool_prog_list(expected=0)
6158c2ecf20Sopenharmony_ci    ret, err = bpftool("prog show pin %s" % (prog_file), fail=False)
6168c2ecf20Sopenharmony_ci    fail(ret == 0, "Showing prog with removed device did not fail")
6178c2ecf20Sopenharmony_ci    fail(err["error"].find("No such device") == -1,
6188c2ecf20Sopenharmony_ci         "Showing prog with removed device expected ENODEV, error is %s" %
6198c2ecf20Sopenharmony_ci         (err["error"]))
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci    bpftool_map_list(expected=0)
6228c2ecf20Sopenharmony_ci    ret, err = bpftool("map show pin %s" % (map_file), fail=False)
6238c2ecf20Sopenharmony_ci    fail(ret == 0, "Showing map with removed device did not fail")
6248c2ecf20Sopenharmony_ci    fail(err["error"].find("No such device") == -1,
6258c2ecf20Sopenharmony_ci         "Showing map with removed device expected ENODEV, error is %s" %
6268c2ecf20Sopenharmony_ci         (err["error"]))
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cidef check_dev_info(other_ns, ns, prog_file=None, map_file=None, removed=False):
6298c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=1, ns=ns)
6308c2ecf20Sopenharmony_ci    prog = progs[0]
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci    fail("dev" not in prog.keys(), "Device parameters not reported")
6338c2ecf20Sopenharmony_ci    dev = prog["dev"]
6348c2ecf20Sopenharmony_ci    fail("ifindex" not in dev.keys(), "Device parameters not reported")
6358c2ecf20Sopenharmony_ci    fail("ns_dev" not in dev.keys(), "Device parameters not reported")
6368c2ecf20Sopenharmony_ci    fail("ns_inode" not in dev.keys(), "Device parameters not reported")
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci    if not other_ns:
6398c2ecf20Sopenharmony_ci        fail("ifname" not in dev.keys(), "Ifname not reported")
6408c2ecf20Sopenharmony_ci        fail(dev["ifname"] != sim["ifname"],
6418c2ecf20Sopenharmony_ci             "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
6428c2ecf20Sopenharmony_ci    else:
6438c2ecf20Sopenharmony_ci        fail("ifname" in dev.keys(), "Ifname is reported for other ns")
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci    maps = bpftool_map_list(expected=2, ns=ns)
6468c2ecf20Sopenharmony_ci    for m in maps:
6478c2ecf20Sopenharmony_ci        fail("dev" not in m.keys(), "Device parameters not reported")
6488c2ecf20Sopenharmony_ci        fail(dev != m["dev"], "Map's device different than program's")
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cidef check_extack(output, reference, args):
6518c2ecf20Sopenharmony_ci    if skip_extack:
6528c2ecf20Sopenharmony_ci        return
6538c2ecf20Sopenharmony_ci    lines = output.split("\n")
6548c2ecf20Sopenharmony_ci    comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
6558c2ecf20Sopenharmony_ci    fail(not comp, "Missing or incorrect netlink extack message")
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cidef check_extack_nsim(output, reference, args):
6588c2ecf20Sopenharmony_ci    check_extack(output, "netdevsim: " + reference, args)
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cidef check_no_extack(res, needle):
6618c2ecf20Sopenharmony_ci    fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
6628c2ecf20Sopenharmony_ci         "Found '%s' in command output, leaky extack?" % (needle))
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_cidef check_verifier_log(output, reference):
6658c2ecf20Sopenharmony_ci    lines = output.split("\n")
6668c2ecf20Sopenharmony_ci    for l in reversed(lines):
6678c2ecf20Sopenharmony_ci        if l == reference:
6688c2ecf20Sopenharmony_ci            return
6698c2ecf20Sopenharmony_ci    fail(True, "Missing or incorrect message from netdevsim in verifier log")
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cidef check_multi_basic(two_xdps):
6728c2ecf20Sopenharmony_ci    fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs")
6738c2ecf20Sopenharmony_ci    fail("prog" in two_xdps, "Base program reported in multi program mode")
6748c2ecf20Sopenharmony_ci    fail(len(two_xdps["attached"]) != 2,
6758c2ecf20Sopenharmony_ci         "Wrong attached program count with two programs")
6768c2ecf20Sopenharmony_ci    fail(two_xdps["attached"][0]["prog"]["id"] ==
6778c2ecf20Sopenharmony_ci         two_xdps["attached"][1]["prog"]["id"],
6788c2ecf20Sopenharmony_ci         "Offloaded and other programs have the same id")
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_cidef test_spurios_extack(sim, obj, skip_hw, needle):
6818c2ecf20Sopenharmony_ci    res = sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=skip_hw,
6828c2ecf20Sopenharmony_ci                                 include_stderr=True)
6838c2ecf20Sopenharmony_ci    check_no_extack(res, needle)
6848c2ecf20Sopenharmony_ci    res = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
6858c2ecf20Sopenharmony_ci                                 skip_hw=skip_hw, include_stderr=True)
6868c2ecf20Sopenharmony_ci    check_no_extack(res, needle)
6878c2ecf20Sopenharmony_ci    res = sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf",
6888c2ecf20Sopenharmony_ci                            include_stderr=True)
6898c2ecf20Sopenharmony_ci    check_no_extack(res, needle)
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cidef test_multi_prog(simdev, sim, obj, modename, modeid):
6928c2ecf20Sopenharmony_ci    start_test("Test multi-attachment XDP - %s + offload..." %
6938c2ecf20Sopenharmony_ci               (modename or "default", ))
6948c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "offload")
6958c2ecf20Sopenharmony_ci    xdp = sim.ip_link_show(xdp=True)["xdp"]
6968c2ecf20Sopenharmony_ci    offloaded = sim.dfs_read("bpf_offloaded_id")
6978c2ecf20Sopenharmony_ci    fail("prog" not in xdp, "Base program not reported in single program mode")
6988c2ecf20Sopenharmony_ci    fail(len(xdp["attached"]) != 1,
6998c2ecf20Sopenharmony_ci         "Wrong attached program count with one program")
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci    sim.set_xdp(obj, modename)
7028c2ecf20Sopenharmony_ci    two_xdps = sim.ip_link_show(xdp=True)["xdp"]
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
7058c2ecf20Sopenharmony_ci         "Offload program not reported after other activated")
7068c2ecf20Sopenharmony_ci    check_multi_basic(two_xdps)
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci    offloaded2 = sim.dfs_read("bpf_offloaded_id")
7098c2ecf20Sopenharmony_ci    fail(offloaded != offloaded2,
7108c2ecf20Sopenharmony_ci         "Offload ID changed after loading other program")
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci    start_test("Test multi-attachment XDP - replace...")
7138c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
7148c2ecf20Sopenharmony_ci    fail(ret == 0, "Replaced one of programs without -force")
7158c2ecf20Sopenharmony_ci    check_extack(err, "XDP program already attached.", args)
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci    start_test("Test multi-attachment XDP - remove without mode...")
7188c2ecf20Sopenharmony_ci    ret, _, err = sim.unset_xdp("", force=True,
7198c2ecf20Sopenharmony_ci                                fail=False, include_stderr=True)
7208c2ecf20Sopenharmony_ci    fail(ret == 0, "Removed program without a mode flag")
7218c2ecf20Sopenharmony_ci    check_extack(err, "More than one program loaded, unset mode is ambiguous.", args)
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
7248c2ecf20Sopenharmony_ci    xdp = sim.ip_link_show(xdp=True)["xdp"]
7258c2ecf20Sopenharmony_ci    offloaded = sim.dfs_read("bpf_offloaded_id")
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci    fail(xdp["mode"] != modeid, "Bad mode reported after multiple programs")
7288c2ecf20Sopenharmony_ci    fail("prog" not in xdp,
7298c2ecf20Sopenharmony_ci         "Base program not reported after multi program mode")
7308c2ecf20Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
7318c2ecf20Sopenharmony_ci         "Offload program not reported after other activated")
7328c2ecf20Sopenharmony_ci    fail(len(xdp["attached"]) != 1,
7338c2ecf20Sopenharmony_ci         "Wrong attached program count with remaining programs")
7348c2ecf20Sopenharmony_ci    fail(offloaded != "0", "Offload ID reported with only other program left")
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci    start_test("Test multi-attachment XDP - reattach...")
7378c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "offload")
7388c2ecf20Sopenharmony_ci    two_xdps = sim.ip_link_show(xdp=True)["xdp"]
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci    fail(xdp["attached"][0] not in two_xdps["attached"],
7418c2ecf20Sopenharmony_ci         "Other program not reported after offload activated")
7428c2ecf20Sopenharmony_ci    check_multi_basic(two_xdps)
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci    start_test("Test multi-attachment XDP - device remove...")
7458c2ecf20Sopenharmony_ci    simdev.remove()
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
7488c2ecf20Sopenharmony_ci    sim, = simdev.nsims
7498c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
7508c2ecf20Sopenharmony_ci    return [simdev, sim]
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci# Parse command line
7538c2ecf20Sopenharmony_ciparser = argparse.ArgumentParser()
7548c2ecf20Sopenharmony_ciparser.add_argument("--log", help="output verbose log to given file")
7558c2ecf20Sopenharmony_ciargs = parser.parse_args()
7568c2ecf20Sopenharmony_ciif args.log:
7578c2ecf20Sopenharmony_ci    logfile = open(args.log, 'w+')
7588c2ecf20Sopenharmony_ci    logfile.write("# -*-Org-*-")
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cilog("Prepare...", "", level=1)
7618c2ecf20Sopenharmony_cilog_level_inc()
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci# Check permissions
7648c2ecf20Sopenharmony_ciskip(os.getuid() != 0, "test must be run as root")
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci# Check tools
7678c2ecf20Sopenharmony_ciret, progs = bpftool("prog", fail=False)
7688c2ecf20Sopenharmony_ciskip(ret != 0, "bpftool not installed")
7698c2ecf20Sopenharmony_cibase_progs = progs
7708c2ecf20Sopenharmony_ci_, base_maps = bpftool("map")
7718c2ecf20Sopenharmony_cibase_map_names = [
7728c2ecf20Sopenharmony_ci    'pid_iter.rodata' # created on each bpftool invocation
7738c2ecf20Sopenharmony_ci]
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci# Check netdevsim
7768c2ecf20Sopenharmony_ciret, out = cmd("modprobe netdevsim", fail=False)
7778c2ecf20Sopenharmony_ciskip(ret != 0, "netdevsim module could not be loaded")
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci# Check debugfs
7808c2ecf20Sopenharmony_ci_, out = cmd("mount")
7818c2ecf20Sopenharmony_ciif out.find("/sys/kernel/debug type debugfs") == -1:
7828c2ecf20Sopenharmony_ci    cmd("mount -t debugfs none /sys/kernel/debug")
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci# Check samples are compiled
7858c2ecf20Sopenharmony_cisamples = ["sample_ret0.o", "sample_map_ret0.o"]
7868c2ecf20Sopenharmony_cifor s in samples:
7878c2ecf20Sopenharmony_ci    ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False)
7888c2ecf20Sopenharmony_ci    skip(ret != 0, "sample %s/%s not found, please compile it" %
7898c2ecf20Sopenharmony_ci         (bpf_test_dir, s))
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci# Check if iproute2 is built with libmnl (needed by extack support)
7928c2ecf20Sopenharmony_ci_, _, err = cmd("tc qdisc delete dev lo handle 0",
7938c2ecf20Sopenharmony_ci                fail=False, include_stderr=True)
7948c2ecf20Sopenharmony_ciif err.find("Error: Failed to find qdisc with specified handle.") == -1:
7958c2ecf20Sopenharmony_ci    print("Warning: no extack message in iproute2 output, libmnl missing?")
7968c2ecf20Sopenharmony_ci    log("Warning: no extack message in iproute2 output, libmnl missing?", "")
7978c2ecf20Sopenharmony_ci    skip_extack = True
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci# Check if net namespaces seem to work
8008c2ecf20Sopenharmony_cins = mknetns()
8018c2ecf20Sopenharmony_ciskip(ns is None, "Could not create a net namespace")
8028c2ecf20Sopenharmony_cicmd("ip netns delete %s" % (ns))
8038c2ecf20Sopenharmony_cinetns = []
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_citry:
8068c2ecf20Sopenharmony_ci    obj = bpf_obj("sample_ret0.o")
8078c2ecf20Sopenharmony_ci    bytecode = bpf_bytecode("1,6 0 0 4294967295,")
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci    start_test("Test destruction of generic XDP...")
8108c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
8118c2ecf20Sopenharmony_ci    sim, = simdev.nsims
8128c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "generic")
8138c2ecf20Sopenharmony_ci    simdev.remove()
8148c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
8178c2ecf20Sopenharmony_ci    sim, = simdev.nsims
8188c2ecf20Sopenharmony_ci    sim.tc_add_ingress()
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci    start_test("Test TC non-offloaded...")
8218c2ecf20Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, skip_hw=True, fail=False)
8228c2ecf20Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci    start_test("Test TC non-offloaded isn't getting bound...")
8258c2ecf20Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
8268c2ecf20Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
8278c2ecf20Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci    start_test("Test TC offloads are off by default...")
8328c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
8338c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
8348c2ecf20Sopenharmony_ci    fail(ret == 0, "TC filter loaded without enabling TC offloads")
8358c2ecf20Sopenharmony_ci    check_extack(err, "TC offload is disabled on net device.", args)
8368c2ecf20Sopenharmony_ci    sim.wait_for_flush()
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
8398c2ecf20Sopenharmony_ci    sim.dfs["bpf_tc_non_bound_accept"] = "Y"
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci    start_test("Test TC offload by default...")
8428c2ecf20Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(obj, fail=False)
8438c2ecf20Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
8448c2ecf20Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
8458c2ecf20Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
8468c2ecf20Sopenharmony_ci    fltr = ingress[0]
8478c2ecf20Sopenharmony_ci    fail(not fltr["in_hw"], "Filter not offloaded by default")
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci    start_test("Test TC cBPF bytcode tries offload by default...")
8528c2ecf20Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False)
8538c2ecf20Sopenharmony_ci    fail(ret != 0, "Software TC filter did not load")
8548c2ecf20Sopenharmony_ci    simdev.dfs_get_bound_progs(expected=0)
8558c2ecf20Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
8568c2ecf20Sopenharmony_ci    fltr = ingress[0]
8578c2ecf20Sopenharmony_ci    fail(not fltr["in_hw"], "Bytecode not offloaded by default")
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
8608c2ecf20Sopenharmony_ci    sim.dfs["bpf_tc_non_bound_accept"] = "N"
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci    start_test("Test TC cBPF unbound bytecode doesn't offload...")
8638c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(bytecode, skip_sw=True,
8648c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
8658c2ecf20Sopenharmony_ci    fail(ret == 0, "TC bytecode loaded for offload")
8668c2ecf20Sopenharmony_ci    check_extack_nsim(err, "netdevsim configured to reject unbound programs.",
8678c2ecf20Sopenharmony_ci                      args)
8688c2ecf20Sopenharmony_ci    sim.wait_for_flush()
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci    start_test("Test non-0 chain offload...")
8718c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, chain=1, prio=1, handle=1,
8728c2ecf20Sopenharmony_ci                                         skip_sw=True,
8738c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
8748c2ecf20Sopenharmony_ci    fail(ret == 0, "Offloaded a filter to chain other than 0")
8758c2ecf20Sopenharmony_ci    check_extack(err, "Driver supports only offload of chain 0.", args)
8768c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci    start_test("Test TC replace...")
8798c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1)
8808c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1)
8818c2ecf20Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_sw=True)
8848c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_sw=True)
8858c2ecf20Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=True)
8888c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_hw=True)
8898c2ecf20Sopenharmony_ci    sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci    start_test("Test TC replace bad flags...")
8928c2ecf20Sopenharmony_ci    for i in range(3):
8938c2ecf20Sopenharmony_ci        for j in range(3):
8948c2ecf20Sopenharmony_ci            ret, _ = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1,
8958c2ecf20Sopenharmony_ci                                            skip_sw=(j == 1), skip_hw=(j == 2),
8968c2ecf20Sopenharmony_ci                                            fail=False)
8978c2ecf20Sopenharmony_ci            fail(bool(ret) != bool(j),
8988c2ecf20Sopenharmony_ci                 "Software TC incorrect load in replace test, iteration %d" %
8998c2ecf20Sopenharmony_ci                 (j))
9008c2ecf20Sopenharmony_ci        sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf")
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci    start_test("Test spurious extack from the driver...")
9038c2ecf20Sopenharmony_ci    test_spurios_extack(sim, obj, False, "netdevsim")
9048c2ecf20Sopenharmony_ci    test_spurios_extack(sim, obj, True, "netdevsim")
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(False)
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci    test_spurios_extack(sim, obj, False, "TC offload is disabled")
9098c2ecf20Sopenharmony_ci    test_spurios_extack(sim, obj, True, "TC offload is disabled")
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci    start_test("Test TC offloads failure...")
9168c2ecf20Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 0
9178c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True,
9188c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
9198c2ecf20Sopenharmony_ci    fail(ret == 0, "TC filter did not reject with TC offloads enabled")
9208c2ecf20Sopenharmony_ci    check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
9218c2ecf20Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 1
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci    start_test("Test TC offloads work...")
9248c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True,
9258c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
9268c2ecf20Sopenharmony_ci    fail(ret != 0, "TC filter did not load with TC offloads enabled")
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci    start_test("Test TC offload basics...")
9298c2ecf20Sopenharmony_ci    dfs = simdev.dfs_get_bound_progs(expected=1)
9308c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
9318c2ecf20Sopenharmony_ci    ingress = sim.tc_show_ingress(expected=1)
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci    dprog = dfs[0]
9348c2ecf20Sopenharmony_ci    prog = progs[0]
9358c2ecf20Sopenharmony_ci    fltr = ingress[0]
9368c2ecf20Sopenharmony_ci    fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter")
9378c2ecf20Sopenharmony_ci    fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter")
9388c2ecf20Sopenharmony_ci    fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back")
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci    start_test("Test TC offload is device-bound...")
9418c2ecf20Sopenharmony_ci    fail(str(prog["id"]) != fltr["id"], "Program IDs don't match")
9428c2ecf20Sopenharmony_ci    fail(prog["tag"] != fltr["tag"], "Program tags don't match")
9438c2ecf20Sopenharmony_ci    fail(fltr["id"] != dprog["id"], "Program IDs don't match")
9448c2ecf20Sopenharmony_ci    fail(dprog["state"] != "xlated", "Offloaded program state not translated")
9458c2ecf20Sopenharmony_ci    fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci    start_test("Test disabling TC offloads is rejected while filters installed...")
9488c2ecf20Sopenharmony_ci    ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
9498c2ecf20Sopenharmony_ci    fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...")
9508c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci    start_test("Test qdisc removal frees things...")
9538c2ecf20Sopenharmony_ci    sim.tc_flush_filters()
9548c2ecf20Sopenharmony_ci    sim.tc_show_ingress(expected=0)
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci    start_test("Test disabling TC offloads is OK without filters...")
9578c2ecf20Sopenharmony_ci    ret, _ = sim.set_ethtool_tc_offloads(False, fail=False)
9588c2ecf20Sopenharmony_ci    fail(ret != 0,
9598c2ecf20Sopenharmony_ci         "Driver refused to disable TC offloads without filters installed...")
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci    start_test("Test destroying device gets rid of TC filters...")
9648c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, skip_sw=True)
9658c2ecf20Sopenharmony_ci    simdev.remove()
9668c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
9698c2ecf20Sopenharmony_ci    sim, = simdev.nsims
9708c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci    start_test("Test destroying device gets rid of XDP...")
9738c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "offload")
9748c2ecf20Sopenharmony_ci    simdev.remove()
9758c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
9788c2ecf20Sopenharmony_ci    sim, = simdev.nsims
9798c2ecf20Sopenharmony_ci    sim.set_ethtool_tc_offloads(True)
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci    start_test("Test XDP prog reporting...")
9828c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "drv")
9838c2ecf20Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
9848c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
9858c2ecf20Sopenharmony_ci    fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
9868c2ecf20Sopenharmony_ci         "Loaded program has wrong ID")
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci    start_test("Test XDP prog replace without force...")
9898c2ecf20Sopenharmony_ci    ret, _ = sim.set_xdp(obj, "drv", fail=False)
9908c2ecf20Sopenharmony_ci    fail(ret == 0, "Replaced XDP program without -force")
9918c2ecf20Sopenharmony_ci    sim.wait_for_flush(total=1)
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci    start_test("Test XDP prog replace with force...")
9948c2ecf20Sopenharmony_ci    ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False)
9958c2ecf20Sopenharmony_ci    fail(ret != 0, "Could not replace XDP program with -force")
9968c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
9978c2ecf20Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
9988c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
9998c2ecf20Sopenharmony_ci    fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
10008c2ecf20Sopenharmony_ci         "Loaded program has wrong ID")
10018c2ecf20Sopenharmony_ci    fail("dev" in progs[0].keys(),
10028c2ecf20Sopenharmony_ci         "Device parameters reported for non-offloaded program")
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci    start_test("Test XDP prog replace with bad flags...")
10058c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "generic", force=True,
10068c2ecf20Sopenharmony_ci                              fail=False, include_stderr=True)
10078c2ecf20Sopenharmony_ci    fail(ret == 0, "Replaced XDP program with a program in different mode")
10088c2ecf20Sopenharmony_ci    check_extack(err,
10098c2ecf20Sopenharmony_ci                 "Native and generic XDP can't be active at the same time.",
10108c2ecf20Sopenharmony_ci                 args)
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci    start_test("Test MTU restrictions...")
10138c2ecf20Sopenharmony_ci    ret, _ = sim.set_mtu(9000, fail=False)
10148c2ecf20Sopenharmony_ci    fail(ret == 0,
10158c2ecf20Sopenharmony_ci         "Driver should refuse to increase MTU to 9000 with XDP loaded...")
10168c2ecf20Sopenharmony_ci    sim.unset_xdp("drv")
10178c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
10188c2ecf20Sopenharmony_ci    sim.set_mtu(9000)
10198c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "drv", fail=False, include_stderr=True)
10208c2ecf20Sopenharmony_ci    fail(ret == 0, "Driver should refuse to load program with MTU of 9000...")
10218c2ecf20Sopenharmony_ci    check_extack_nsim(err, "MTU too large w/ XDP enabled.", args)
10228c2ecf20Sopenharmony_ci    sim.set_mtu(1500)
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci    sim.wait_for_flush()
10258c2ecf20Sopenharmony_ci    start_test("Test non-offload XDP attaching to HW...")
10268c2ecf20Sopenharmony_ci    bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload")
10278c2ecf20Sopenharmony_ci    nooffload = bpf_pinned("/sys/fs/bpf/nooffload")
10288c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(nooffload, "offload",
10298c2ecf20Sopenharmony_ci                              fail=False, include_stderr=True)
10308c2ecf20Sopenharmony_ci    fail(ret == 0, "attached non-offloaded XDP program to HW")
10318c2ecf20Sopenharmony_ci    check_extack_nsim(err, "xdpoffload of non-bound program.", args)
10328c2ecf20Sopenharmony_ci    rm("/sys/fs/bpf/nooffload")
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci    start_test("Test offload XDP attaching to drv...")
10358c2ecf20Sopenharmony_ci    bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",
10368c2ecf20Sopenharmony_ci                      dev=sim['ifname'])
10378c2ecf20Sopenharmony_ci    offload = bpf_pinned("/sys/fs/bpf/offload")
10388c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True)
10398c2ecf20Sopenharmony_ci    fail(ret == 0, "attached offloaded XDP program to drv")
10408c2ecf20Sopenharmony_ci    check_extack(err, "Using device-bound program without HW_MODE flag is not supported.", args)
10418c2ecf20Sopenharmony_ci    rm("/sys/fs/bpf/offload")
10428c2ecf20Sopenharmony_ci    sim.wait_for_flush()
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci    start_test("Test XDP load failure...")
10458c2ecf20Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 0
10468c2ecf20Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",
10478c2ecf20Sopenharmony_ci                                 dev=sim['ifname'], fail=False, include_stderr=True)
10488c2ecf20Sopenharmony_ci    fail(ret == 0, "verifier should fail on load")
10498c2ecf20Sopenharmony_ci    check_verifier_log(err, "[netdevsim] Hello from netdevsim!")
10508c2ecf20Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_accept"] = 1
10518c2ecf20Sopenharmony_ci    sim.wait_for_flush()
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci    start_test("Test XDP offload...")
10548c2ecf20Sopenharmony_ci    _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True)
10558c2ecf20Sopenharmony_ci    ipl = sim.ip_link_show(xdp=True)
10568c2ecf20Sopenharmony_ci    link_xdp = ipl["xdp"]["prog"]
10578c2ecf20Sopenharmony_ci    progs = bpftool_prog_list(expected=1)
10588c2ecf20Sopenharmony_ci    prog = progs[0]
10598c2ecf20Sopenharmony_ci    fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID")
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci    start_test("Test XDP offload is device bound...")
10628c2ecf20Sopenharmony_ci    dfs = simdev.dfs_get_bound_progs(expected=1)
10638c2ecf20Sopenharmony_ci    dprog = dfs[0]
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci    fail(prog["id"] != link_xdp["id"], "Program IDs don't match")
10668c2ecf20Sopenharmony_ci    fail(prog["tag"] != link_xdp["tag"], "Program tags don't match")
10678c2ecf20Sopenharmony_ci    fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match")
10688c2ecf20Sopenharmony_ci    fail(dprog["state"] != "xlated", "Offloaded program state not translated")
10698c2ecf20Sopenharmony_ci    fail(dprog["loaded"] != "Y", "Offloaded program is not loaded")
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci    start_test("Test removing XDP program many times...")
10728c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
10738c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
10748c2ecf20Sopenharmony_ci    sim.unset_xdp("drv")
10758c2ecf20Sopenharmony_ci    sim.unset_xdp("drv")
10768c2ecf20Sopenharmony_ci    sim.unset_xdp("")
10778c2ecf20Sopenharmony_ci    sim.unset_xdp("")
10788c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci    start_test("Test attempt to use a program for a wrong device...")
10818c2ecf20Sopenharmony_ci    simdev2 = NetdevSimDev()
10828c2ecf20Sopenharmony_ci    sim2, = simdev2.nsims
10838c2ecf20Sopenharmony_ci    sim2.set_xdp(obj, "offload")
10848c2ecf20Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(pinned, "offload",
10878c2ecf20Sopenharmony_ci                              fail=False, include_stderr=True)
10888c2ecf20Sopenharmony_ci    fail(ret == 0, "Pinned program loaded for a different device accepted")
10898c2ecf20Sopenharmony_ci    check_extack_nsim(err, "program bound to different dev.", args)
10908c2ecf20Sopenharmony_ci    simdev2.remove()
10918c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(pinned, "offload",
10928c2ecf20Sopenharmony_ci                              fail=False, include_stderr=True)
10938c2ecf20Sopenharmony_ci    fail(ret == 0, "Pinned program loaded for a removed device accepted")
10948c2ecf20Sopenharmony_ci    check_extack_nsim(err, "xdpoffload of non-bound program.", args)
10958c2ecf20Sopenharmony_ci    rm(pin_file)
10968c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "", 1)
10998c2ecf20Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "drv", 1)
11008c2ecf20Sopenharmony_ci    simdev, sim = test_multi_prog(simdev, sim, obj, "generic", 2)
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci    start_test("Test mixing of TC and XDP...")
11038c2ecf20Sopenharmony_ci    sim.tc_add_ingress()
11048c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "offload")
11058c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
11068c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
11078c2ecf20Sopenharmony_ci    fail(ret == 0, "Loading TC when XDP active should fail")
11088c2ecf20Sopenharmony_ci    check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
11098c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
11108c2ecf20Sopenharmony_ci    sim.wait_for_flush()
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, skip_sw=True)
11138c2ecf20Sopenharmony_ci    ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True)
11148c2ecf20Sopenharmony_ci    fail(ret == 0, "Loading XDP when TC active should fail")
11158c2ecf20Sopenharmony_ci    check_extack_nsim(err, "TC program is already loaded.", args)
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci    start_test("Test binding TC from pinned...")
11188c2ecf20Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp")
11198c2ecf20Sopenharmony_ci    sim.tc_flush_filters(bound=1, total=1)
11208c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True)
11218c2ecf20Sopenharmony_ci    sim.tc_flush_filters(bound=1, total=1)
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci    start_test("Test binding XDP from pinned...")
11248c2ecf20Sopenharmony_ci    sim.set_xdp(obj, "offload")
11258c2ecf20Sopenharmony_ci    pin_file, pinned = pin_prog("/sys/fs/bpf/tmp2", idx=1)
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_ci    sim.set_xdp(pinned, "offload", force=True)
11288c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
11298c2ecf20Sopenharmony_ci    sim.set_xdp(pinned, "offload", force=True)
11308c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci    start_test("Test offload of wrong type fails...")
11338c2ecf20Sopenharmony_ci    ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False)
11348c2ecf20Sopenharmony_ci    fail(ret == 0, "Managed to attach XDP program to TC")
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci    start_test("Test asking for TC offload of two filters...")
11378c2ecf20Sopenharmony_ci    sim.cls_bpf_add_filter(obj, da=True, skip_sw=True)
11388c2ecf20Sopenharmony_ci    ret, _, err = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True,
11398c2ecf20Sopenharmony_ci                                         fail=False, include_stderr=True)
11408c2ecf20Sopenharmony_ci    fail(ret == 0, "Managed to offload two TC filters at the same time")
11418c2ecf20Sopenharmony_ci    check_extack_nsim(err, "driver and netdev offload states mismatch.", args)
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci    sim.tc_flush_filters(bound=2, total=2)
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci    start_test("Test if netdev removal waits for translation...")
11468c2ecf20Sopenharmony_ci    delay_msec = 500
11478c2ecf20Sopenharmony_ci    sim.dfs["dev/bpf_bind_verifier_delay"] = delay_msec
11488c2ecf20Sopenharmony_ci    start = time.time()
11498c2ecf20Sopenharmony_ci    cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \
11508c2ecf20Sopenharmony_ci               (sim['ifname'], obj)
11518c2ecf20Sopenharmony_ci    tc_proc = cmd(cmd_line, background=True, fail=False)
11528c2ecf20Sopenharmony_ci    # Wait for the verifier to start
11538c2ecf20Sopenharmony_ci    while simdev.dfs_num_bound_progs() <= 2:
11548c2ecf20Sopenharmony_ci        pass
11558c2ecf20Sopenharmony_ci    simdev.remove()
11568c2ecf20Sopenharmony_ci    end = time.time()
11578c2ecf20Sopenharmony_ci    ret, _ = cmd_result(tc_proc, fail=False)
11588c2ecf20Sopenharmony_ci    time_diff = end - start
11598c2ecf20Sopenharmony_ci    log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff))
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci    fail(ret == 0, "Managed to load TC filter on a unregistering device")
11628c2ecf20Sopenharmony_ci    delay_sec = delay_msec * 0.001
11638c2ecf20Sopenharmony_ci    fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
11648c2ecf20Sopenharmony_ci         (time_diff, delay_sec))
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci    # Remove all pinned files and reinstantiate the netdev
11678c2ecf20Sopenharmony_ci    clean_up()
11688c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
11718c2ecf20Sopenharmony_ci    sim, = simdev.nsims
11728c2ecf20Sopenharmony_ci    map_obj = bpf_obj("sample_map_ret0.o")
11738c2ecf20Sopenharmony_ci    start_test("Test loading program with maps...")
11748c2ecf20Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci    start_test("Test bpftool bound info reporting (own ns)...")
11778c2ecf20Sopenharmony_ci    check_dev_info(False, "")
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci    start_test("Test bpftool bound info reporting (other ns)...")
11808c2ecf20Sopenharmony_ci    ns = mknetns()
11818c2ecf20Sopenharmony_ci    sim.set_ns(ns)
11828c2ecf20Sopenharmony_ci    check_dev_info(True, "")
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci    start_test("Test bpftool bound info reporting (remote ns)...")
11858c2ecf20Sopenharmony_ci    check_dev_info(False, ns)
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci    start_test("Test bpftool bound info reporting (back to own ns)...")
11888c2ecf20Sopenharmony_ci    sim.set_ns("")
11898c2ecf20Sopenharmony_ci    check_dev_info(False, "")
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci    prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog")
11928c2ecf20Sopenharmony_ci    map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2)
11938c2ecf20Sopenharmony_ci    simdev.remove()
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci    start_test("Test bpftool bound info reporting (removed dev)...")
11968c2ecf20Sopenharmony_ci    check_dev_info_removed(prog_file=prog_file, map_file=map_file)
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci    # Remove all pinned files and reinstantiate the netdev
11998c2ecf20Sopenharmony_ci    clean_up()
12008c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
12038c2ecf20Sopenharmony_ci    sim, = simdev.nsims
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci    start_test("Test map update (no flags)...")
12068c2ecf20Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
12078c2ecf20Sopenharmony_ci    maps = bpftool_map_list(expected=2)
12088c2ecf20Sopenharmony_ci    array = maps[0] if maps[0]["type"] == "array" else maps[1]
12098c2ecf20Sopenharmony_ci    htab = maps[0] if maps[0]["type"] == "hash" else maps[1]
12108c2ecf20Sopenharmony_ci    for m in maps:
12118c2ecf20Sopenharmony_ci        for i in range(2):
12128c2ecf20Sopenharmony_ci            bpftool("map update id %d key %s value %s" %
12138c2ecf20Sopenharmony_ci                    (m["id"], int2str("I", i), int2str("Q", i * 3)))
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci    for m in maps:
12168c2ecf20Sopenharmony_ci        ret, _ = bpftool("map update id %d key %s value %s" %
12178c2ecf20Sopenharmony_ci                         (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
12188c2ecf20Sopenharmony_ci                         fail=False)
12198c2ecf20Sopenharmony_ci        fail(ret == 0, "added too many entries")
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci    start_test("Test map update (exists)...")
12228c2ecf20Sopenharmony_ci    for m in maps:
12238c2ecf20Sopenharmony_ci        for i in range(2):
12248c2ecf20Sopenharmony_ci            bpftool("map update id %d key %s value %s exist" %
12258c2ecf20Sopenharmony_ci                    (m["id"], int2str("I", i), int2str("Q", i * 3)))
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci    for m in maps:
12288c2ecf20Sopenharmony_ci        ret, err = bpftool("map update id %d key %s value %s exist" %
12298c2ecf20Sopenharmony_ci                           (m["id"], int2str("I", 3), int2str("Q", 3 * 3)),
12308c2ecf20Sopenharmony_ci                           fail=False)
12318c2ecf20Sopenharmony_ci        fail(ret == 0, "updated non-existing key")
12328c2ecf20Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
12338c2ecf20Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci    start_test("Test map update (noexist)...")
12368c2ecf20Sopenharmony_ci    for m in maps:
12378c2ecf20Sopenharmony_ci        for i in range(2):
12388c2ecf20Sopenharmony_ci            ret, err = bpftool("map update id %d key %s value %s noexist" %
12398c2ecf20Sopenharmony_ci                               (m["id"], int2str("I", i), int2str("Q", i * 3)),
12408c2ecf20Sopenharmony_ci                               fail=False)
12418c2ecf20Sopenharmony_ci        fail(ret == 0, "updated existing key")
12428c2ecf20Sopenharmony_ci        fail(err["error"].find("File exists") == -1,
12438c2ecf20Sopenharmony_ci             "expected EEXIST, error is '%s'" % (err["error"]))
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci    start_test("Test map dump...")
12468c2ecf20Sopenharmony_ci    for m in maps:
12478c2ecf20Sopenharmony_ci        _, entries = bpftool("map dump id %d" % (m["id"]))
12488c2ecf20Sopenharmony_ci        for i in range(2):
12498c2ecf20Sopenharmony_ci            key = str2int(entries[i]["key"])
12508c2ecf20Sopenharmony_ci            fail(key != i, "expected key %d, got %d" % (key, i))
12518c2ecf20Sopenharmony_ci            val = str2int(entries[i]["value"])
12528c2ecf20Sopenharmony_ci            fail(val != i * 3, "expected value %d, got %d" % (val, i * 3))
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci    start_test("Test map getnext...")
12558c2ecf20Sopenharmony_ci    for m in maps:
12568c2ecf20Sopenharmony_ci        _, entry = bpftool("map getnext id %d" % (m["id"]))
12578c2ecf20Sopenharmony_ci        key = str2int(entry["next_key"])
12588c2ecf20Sopenharmony_ci        fail(key != 0, "next key %d, expected %d" % (key, 0))
12598c2ecf20Sopenharmony_ci        _, entry = bpftool("map getnext id %d key %s" %
12608c2ecf20Sopenharmony_ci                           (m["id"], int2str("I", 0)))
12618c2ecf20Sopenharmony_ci        key = str2int(entry["next_key"])
12628c2ecf20Sopenharmony_ci        fail(key != 1, "next key %d, expected %d" % (key, 1))
12638c2ecf20Sopenharmony_ci        ret, err = bpftool("map getnext id %d key %s" %
12648c2ecf20Sopenharmony_ci                           (m["id"], int2str("I", 1)), fail=False)
12658c2ecf20Sopenharmony_ci        fail(ret == 0, "got next key past the end of map")
12668c2ecf20Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
12678c2ecf20Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci    start_test("Test map delete (htab)...")
12708c2ecf20Sopenharmony_ci    for i in range(2):
12718c2ecf20Sopenharmony_ci        bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i)))
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_ci    start_test("Test map delete (array)...")
12748c2ecf20Sopenharmony_ci    for i in range(2):
12758c2ecf20Sopenharmony_ci        ret, err = bpftool("map delete id %d key %s" %
12768c2ecf20Sopenharmony_ci                           (htab["id"], int2str("I", i)), fail=False)
12778c2ecf20Sopenharmony_ci        fail(ret == 0, "removed entry from an array")
12788c2ecf20Sopenharmony_ci        fail(err["error"].find("No such file or directory") == -1,
12798c2ecf20Sopenharmony_ci             "expected ENOENT, error is '%s'" % (err["error"]))
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci    start_test("Test map remove...")
12828c2ecf20Sopenharmony_ci    sim.unset_xdp("offload")
12838c2ecf20Sopenharmony_ci    bpftool_map_list_wait(expected=0)
12848c2ecf20Sopenharmony_ci    simdev.remove()
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
12878c2ecf20Sopenharmony_ci    sim, = simdev.nsims
12888c2ecf20Sopenharmony_ci    sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON
12898c2ecf20Sopenharmony_ci    simdev.remove()
12908c2ecf20Sopenharmony_ci    bpftool_map_list_wait(expected=0)
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci    start_test("Test map creation fail path...")
12938c2ecf20Sopenharmony_ci    simdev = NetdevSimDev()
12948c2ecf20Sopenharmony_ci    sim, = simdev.nsims
12958c2ecf20Sopenharmony_ci    sim.dfs["bpf_map_accept"] = "N"
12968c2ecf20Sopenharmony_ci    ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False)
12978c2ecf20Sopenharmony_ci    fail(ret == 0,
12988c2ecf20Sopenharmony_ci         "netdevsim didn't refuse to create a map with offload disabled")
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci    simdev.remove()
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC program reuse...")
13038c2ecf20Sopenharmony_ci    simdevA = NetdevSimDev()
13048c2ecf20Sopenharmony_ci    simA, = simdevA.nsims
13058c2ecf20Sopenharmony_ci    simdevB = NetdevSimDev(3)
13068c2ecf20Sopenharmony_ci    simB1, simB2, simB3 = simdevB.nsims
13078c2ecf20Sopenharmony_ci    sims = (simA, simB1, simB2, simB3)
13088c2ecf20Sopenharmony_ci    simB = (simB1, simB2, simB3)
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci    bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA",
13118c2ecf20Sopenharmony_ci                      dev=simA['ifname'])
13128c2ecf20Sopenharmony_ci    progA = bpf_pinned("/sys/fs/bpf/nsimA")
13138c2ecf20Sopenharmony_ci    bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB",
13148c2ecf20Sopenharmony_ci                      dev=simB1['ifname'])
13158c2ecf20Sopenharmony_ci    progB = bpf_pinned("/sys/fs/bpf/nsimB")
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci    simA.set_xdp(progA, "offload", JSON=False)
13188c2ecf20Sopenharmony_ci    for d in simdevB.nsims:
13198c2ecf20Sopenharmony_ci        d.set_xdp(progB, "offload", JSON=False)
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev replace...")
13228c2ecf20Sopenharmony_ci    ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False)
13238c2ecf20Sopenharmony_ci    fail(ret == 0, "cross-ASIC program allowed")
13248c2ecf20Sopenharmony_ci    for d in simdevB.nsims:
13258c2ecf20Sopenharmony_ci        ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False)
13268c2ecf20Sopenharmony_ci        fail(ret == 0, "cross-ASIC program allowed")
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev install...")
13298c2ecf20Sopenharmony_ci    for d in sims:
13308c2ecf20Sopenharmony_ci        d.unset_xdp("offload")
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci    ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False,
13338c2ecf20Sopenharmony_ci                               fail=False, include_stderr=True)
13348c2ecf20Sopenharmony_ci    fail(ret == 0, "cross-ASIC program allowed")
13358c2ecf20Sopenharmony_ci    check_extack_nsim(err, "program bound to different dev.", args)
13368c2ecf20Sopenharmony_ci    for d in simdevB.nsims:
13378c2ecf20Sopenharmony_ci        ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False,
13388c2ecf20Sopenharmony_ci                                fail=False, include_stderr=True)
13398c2ecf20Sopenharmony_ci        fail(ret == 0, "cross-ASIC program allowed")
13408c2ecf20Sopenharmony_ci        check_extack_nsim(err, "program bound to different dev.", args)
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev map reuse...")
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci    mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0]
13458c2ecf20Sopenharmony_ci    mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0]
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci    ret, _ = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
13488c2ecf20Sopenharmony_ci                               dev=simB3['ifname'],
13498c2ecf20Sopenharmony_ci                               maps=["idx 0 id %d" % (mapB)],
13508c2ecf20Sopenharmony_ci                               fail=False)
13518c2ecf20Sopenharmony_ci    fail(ret != 0, "couldn't reuse a map on the same ASIC")
13528c2ecf20Sopenharmony_ci    rm("/sys/fs/bpf/nsimB_")
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_",
13558c2ecf20Sopenharmony_ci                                    dev=simA['ifname'],
13568c2ecf20Sopenharmony_ci                                    maps=["idx 0 id %d" % (mapB)],
13578c2ecf20Sopenharmony_ci                                    fail=False, include_stderr=True)
13588c2ecf20Sopenharmony_ci    fail(ret == 0, "could reuse a map on a different ASIC")
13598c2ecf20Sopenharmony_ci    fail(err.count("offload device mismatch between prog and map") == 0,
13608c2ecf20Sopenharmony_ci         "error message missing for cross-ASIC map")
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci    ret, _, err = bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
13638c2ecf20Sopenharmony_ci                                    dev=simB1['ifname'],
13648c2ecf20Sopenharmony_ci                                    maps=["idx 0 id %d" % (mapA)],
13658c2ecf20Sopenharmony_ci                                    fail=False, include_stderr=True)
13668c2ecf20Sopenharmony_ci    fail(ret == 0, "could reuse a map on a different ASIC")
13678c2ecf20Sopenharmony_ci    fail(err.count("offload device mismatch between prog and map") == 0,
13688c2ecf20Sopenharmony_ci         "error message missing for cross-ASIC map")
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction...")
13718c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=2)
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci    simdevA.remove()
13748c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
13778c2ecf20Sopenharmony_ci    fail(ifnameB != simB1['ifname'], "program not bound to original device")
13788c2ecf20Sopenharmony_ci    simB1.remove()
13798c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=1)
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction - move...")
13828c2ecf20Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
13838c2ecf20Sopenharmony_ci    fail(ifnameB not in (simB2['ifname'], simB3['ifname']),
13848c2ecf20Sopenharmony_ci         "program not bound to remaining devices")
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci    simB2.remove()
13878c2ecf20Sopenharmony_ci    ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"]
13888c2ecf20Sopenharmony_ci    fail(ifnameB != simB3['ifname'], "program not bound to remaining device")
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_ci    simB3.remove()
13918c2ecf20Sopenharmony_ci    simdevB.remove()
13928c2ecf20Sopenharmony_ci    bpftool_prog_list_wait(expected=0)
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci    start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
13958c2ecf20Sopenharmony_ci    ret, out = bpftool("prog show %s" % (progB), fail=False)
13968c2ecf20Sopenharmony_ci    fail(ret == 0, "got information about orphaned program")
13978c2ecf20Sopenharmony_ci    fail("error" not in out, "no error reported for get info on orphaned")
13988c2ecf20Sopenharmony_ci    fail(out["error"] != "can't get prog info: No such device",
13998c2ecf20Sopenharmony_ci         "wrong error for get info on orphaned")
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci    print("%s: OK" % (os.path.basename(__file__)))
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_cifinally:
14048c2ecf20Sopenharmony_ci    log("Clean up...", "", level=1)
14058c2ecf20Sopenharmony_ci    log_level_inc()
14068c2ecf20Sopenharmony_ci    clean_up()
1407