1c25ce589SFinn Behrens#!/usr/bin/env python3 2417ec264SJakub Kicinski 3417ec264SJakub Kicinski# Copyright (C) 2017 Netronome Systems, Inc. 4e05b2d14SJiri Pirko# Copyright (c) 2019 Mellanox Technologies. All rights reserved 5417ec264SJakub Kicinski# 6417ec264SJakub Kicinski# This software is licensed under the GNU General License Version 2, 7417ec264SJakub Kicinski# June 1991 as shown in the file COPYING in the top-level directory of this 8417ec264SJakub Kicinski# source tree. 9417ec264SJakub Kicinski# 10417ec264SJakub Kicinski# THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 11417ec264SJakub Kicinski# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 12417ec264SJakub Kicinski# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13417ec264SJakub Kicinski# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 14417ec264SJakub Kicinski# OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 15417ec264SJakub Kicinski# THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16417ec264SJakub Kicinski 17417ec264SJakub Kicinskifrom datetime import datetime 18417ec264SJakub Kicinskiimport argparse 19e05b2d14SJiri Pirkoimport errno 20417ec264SJakub Kicinskiimport json 21417ec264SJakub Kicinskiimport os 22417ec264SJakub Kicinskiimport pprint 23752d7b45SJakub Kicinskiimport random 24e05b2d14SJiri Pirkoimport re 258101e069SJakub Kicinskiimport stat 26752d7b45SJakub Kicinskiimport string 277fedbb7cSJakub Kicinskiimport struct 28417ec264SJakub Kicinskiimport subprocess 29417ec264SJakub Kicinskiimport time 30d7f35638SJakub Kicinskiimport traceback 31417ec264SJakub Kicinski 32417ec264SJakub Kicinskilogfile = None 33417ec264SJakub Kicinskilog_level = 1 34caf95228SQuentin Monnetskip_extack = False 35417ec264SJakub Kicinskibpf_test_dir = os.path.dirname(os.path.realpath(__file__)) 36417ec264SJakub Kicinskipp = pprint.PrettyPrinter() 37417ec264SJakub Kicinskidevs = [] # devices we created for clean up 38417ec264SJakub Kicinskifiles = [] # files to be removed 39752d7b45SJakub Kicinskinetns = [] # net namespaces to be removed 40417ec264SJakub Kicinski 41417ec264SJakub Kicinskidef log_get_sec(level=0): 42417ec264SJakub Kicinski return "*" * (log_level + level) 43417ec264SJakub Kicinski 44417ec264SJakub Kicinskidef log_level_inc(add=1): 45417ec264SJakub Kicinski global log_level 46417ec264SJakub Kicinski log_level += add 47417ec264SJakub Kicinski 48417ec264SJakub Kicinskidef log_level_dec(sub=1): 49417ec264SJakub Kicinski global log_level 50417ec264SJakub Kicinski log_level -= sub 51417ec264SJakub Kicinski 52417ec264SJakub Kicinskidef log_level_set(level): 53417ec264SJakub Kicinski global log_level 54417ec264SJakub Kicinski log_level = level 55417ec264SJakub Kicinski 56417ec264SJakub Kicinskidef log(header, data, level=None): 57417ec264SJakub Kicinski """ 58417ec264SJakub Kicinski Output to an optional log. 59417ec264SJakub Kicinski """ 60417ec264SJakub Kicinski if logfile is None: 61417ec264SJakub Kicinski return 62417ec264SJakub Kicinski if level is not None: 63417ec264SJakub Kicinski log_level_set(level) 64417ec264SJakub Kicinski 65417ec264SJakub Kicinski if not isinstance(data, str): 66417ec264SJakub Kicinski data = pp.pformat(data) 67417ec264SJakub Kicinski 68417ec264SJakub Kicinski if len(header): 69417ec264SJakub Kicinski logfile.write("\n" + log_get_sec() + " ") 70417ec264SJakub Kicinski logfile.write(header) 71417ec264SJakub Kicinski if len(header) and len(data.strip()): 72417ec264SJakub Kicinski logfile.write("\n") 73417ec264SJakub Kicinski logfile.write(data) 74417ec264SJakub Kicinski 75417ec264SJakub Kicinskidef skip(cond, msg): 76417ec264SJakub Kicinski if not cond: 77417ec264SJakub Kicinski return 78417ec264SJakub Kicinski print("SKIP: " + msg) 79417ec264SJakub Kicinski log("SKIP: " + msg, "", level=1) 80417ec264SJakub Kicinski os.sys.exit(0) 81417ec264SJakub Kicinski 82417ec264SJakub Kicinskidef fail(cond, msg): 83417ec264SJakub Kicinski if not cond: 84417ec264SJakub Kicinski return 85417ec264SJakub Kicinski print("FAIL: " + msg) 86d7f35638SJakub Kicinski tb = "".join(traceback.extract_stack().format()) 87d7f35638SJakub Kicinski print(tb) 88d7f35638SJakub Kicinski log("FAIL: " + msg, tb, level=1) 89417ec264SJakub Kicinski os.sys.exit(1) 90417ec264SJakub Kicinski 91417ec264SJakub Kicinskidef start_test(msg): 92417ec264SJakub Kicinski log(msg, "", level=1) 93417ec264SJakub Kicinski log_level_inc() 94417ec264SJakub Kicinski print(msg) 95417ec264SJakub Kicinski 96417ec264SJakub Kicinskidef cmd(cmd, shell=True, include_stderr=False, background=False, fail=True): 97417ec264SJakub Kicinski """ 98417ec264SJakub Kicinski Run a command in subprocess and return tuple of (retval, stdout); 99417ec264SJakub Kicinski optionally return stderr as well as third value. 100417ec264SJakub Kicinski """ 101417ec264SJakub Kicinski proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE, 102417ec264SJakub Kicinski stderr=subprocess.PIPE) 103417ec264SJakub Kicinski if background: 104417ec264SJakub Kicinski msg = "%s START: %s" % (log_get_sec(1), 105417ec264SJakub Kicinski datetime.now().strftime("%H:%M:%S.%f")) 106417ec264SJakub Kicinski log("BKG " + proc.args, msg) 107417ec264SJakub Kicinski return proc 108417ec264SJakub Kicinski 109417ec264SJakub Kicinski return cmd_result(proc, include_stderr=include_stderr, fail=fail) 110417ec264SJakub Kicinski 111417ec264SJakub Kicinskidef cmd_result(proc, include_stderr=False, fail=False): 112417ec264SJakub Kicinski stdout, stderr = proc.communicate() 113417ec264SJakub Kicinski stdout = stdout.decode("utf-8") 114417ec264SJakub Kicinski stderr = stderr.decode("utf-8") 115417ec264SJakub Kicinski proc.stdout.close() 116417ec264SJakub Kicinski proc.stderr.close() 117417ec264SJakub Kicinski 118417ec264SJakub Kicinski stderr = "\n" + stderr 119417ec264SJakub Kicinski if stderr[-1] == "\n": 120417ec264SJakub Kicinski stderr = stderr[:-1] 121417ec264SJakub Kicinski 122417ec264SJakub Kicinski sec = log_get_sec(1) 123417ec264SJakub Kicinski log("CMD " + proc.args, 124417ec264SJakub Kicinski "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" % 125417ec264SJakub Kicinski (proc.returncode, sec, stdout, sec, stderr, 126417ec264SJakub Kicinski sec, datetime.now().strftime("%H:%M:%S.%f"))) 127417ec264SJakub Kicinski 128417ec264SJakub Kicinski if proc.returncode != 0 and fail: 129417ec264SJakub Kicinski if len(stderr) > 0 and stderr[-1] == "\n": 130417ec264SJakub Kicinski stderr = stderr[:-1] 131417ec264SJakub Kicinski raise Exception("Command failed: %s\n%s" % (proc.args, stderr)) 132417ec264SJakub Kicinski 133417ec264SJakub Kicinski if include_stderr: 134417ec264SJakub Kicinski return proc.returncode, stdout, stderr 135417ec264SJakub Kicinski else: 136417ec264SJakub Kicinski return proc.returncode, stdout 137417ec264SJakub Kicinski 138417ec264SJakub Kicinskidef rm(f): 139417ec264SJakub Kicinski cmd("rm -f %s" % (f)) 140417ec264SJakub Kicinski if f in files: 141417ec264SJakub Kicinski files.remove(f) 142417ec264SJakub Kicinski 143caf95228SQuentin Monnetdef tool(name, args, flags, JSON=True, ns="", fail=True, include_stderr=False): 144417ec264SJakub Kicinski params = "" 145417ec264SJakub Kicinski if JSON: 146417ec264SJakub Kicinski params += "%s " % (flags["json"]) 147417ec264SJakub Kicinski 148752d7b45SJakub Kicinski if ns != "": 149752d7b45SJakub Kicinski ns = "ip netns exec %s " % (ns) 150752d7b45SJakub Kicinski 151caf95228SQuentin Monnet if include_stderr: 152caf95228SQuentin Monnet ret, stdout, stderr = cmd(ns + name + " " + params + args, 153caf95228SQuentin Monnet fail=fail, include_stderr=True) 154caf95228SQuentin Monnet else: 155caf95228SQuentin Monnet ret, stdout = cmd(ns + name + " " + params + args, 156caf95228SQuentin Monnet fail=fail, include_stderr=False) 157caf95228SQuentin Monnet 158caf95228SQuentin Monnet if JSON and len(stdout.strip()) != 0: 159caf95228SQuentin Monnet out = json.loads(stdout) 160caf95228SQuentin Monnet else: 161caf95228SQuentin Monnet out = stdout 162caf95228SQuentin Monnet 163caf95228SQuentin Monnet if include_stderr: 164caf95228SQuentin Monnet return ret, out, stderr 165417ec264SJakub Kicinski else: 166417ec264SJakub Kicinski return ret, out 167417ec264SJakub Kicinski 1687736b6edSJakub Kicinskidef bpftool(args, JSON=True, ns="", fail=True, include_stderr=False): 1697736b6edSJakub Kicinski return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, 1707736b6edSJakub Kicinski fail=fail, include_stderr=include_stderr) 171417ec264SJakub Kicinski 172752d7b45SJakub Kicinskidef bpftool_prog_list(expected=None, ns=""): 173752d7b45SJakub Kicinski _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) 17447cf52a2SJakub Kicinski # Remove the base progs 17547cf52a2SJakub Kicinski for p in base_progs: 17647cf52a2SJakub Kicinski if p in progs: 17747cf52a2SJakub Kicinski progs.remove(p) 178417ec264SJakub Kicinski if expected is not None: 179417ec264SJakub Kicinski if len(progs) != expected: 180417ec264SJakub Kicinski fail(True, "%d BPF programs loaded, expected %d" % 181417ec264SJakub Kicinski (len(progs), expected)) 182417ec264SJakub Kicinski return progs 183417ec264SJakub Kicinski 1847fedbb7cSJakub Kicinskidef bpftool_map_list(expected=None, ns=""): 1857fedbb7cSJakub Kicinski _, maps = bpftool("map show", JSON=True, ns=ns, fail=True) 18647cf52a2SJakub Kicinski # Remove the base maps 187891663acSYauheni Kaliuta 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] 1887fedbb7cSJakub Kicinski if expected is not None: 1897fedbb7cSJakub Kicinski if len(maps) != expected: 1907fedbb7cSJakub Kicinski fail(True, "%d BPF maps loaded, expected %d" % 1917fedbb7cSJakub Kicinski (len(maps), expected)) 1927fedbb7cSJakub Kicinski return maps 1937fedbb7cSJakub Kicinski 194417ec264SJakub Kicinskidef bpftool_prog_list_wait(expected=0, n_retry=20): 195417ec264SJakub Kicinski for i in range(n_retry): 196417ec264SJakub Kicinski nprogs = len(bpftool_prog_list()) 197417ec264SJakub Kicinski if nprogs == expected: 198417ec264SJakub Kicinski return 199417ec264SJakub Kicinski time.sleep(0.05) 200417ec264SJakub Kicinski raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs)) 201417ec264SJakub Kicinski 2027fedbb7cSJakub Kicinskidef bpftool_map_list_wait(expected=0, n_retry=20): 2037fedbb7cSJakub Kicinski for i in range(n_retry): 2047fedbb7cSJakub Kicinski nmaps = len(bpftool_map_list()) 2057fedbb7cSJakub Kicinski if nmaps == expected: 2067fedbb7cSJakub Kicinski return 2077fedbb7cSJakub Kicinski time.sleep(0.05) 2087fedbb7cSJakub Kicinski raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected, nmaps)) 2097fedbb7cSJakub Kicinski 2107736b6edSJakub Kicinskidef bpftool_prog_load(sample, file_name, maps=[], prog_type="xdp", dev=None, 2117736b6edSJakub Kicinski fail=True, include_stderr=False): 2127736b6edSJakub Kicinski args = "prog load %s %s" % (os.path.join(bpf_test_dir, sample), file_name) 2137736b6edSJakub Kicinski if prog_type is not None: 2147736b6edSJakub Kicinski args += " type " + prog_type 2157736b6edSJakub Kicinski if dev is not None: 2167736b6edSJakub Kicinski args += " dev " + dev 2177736b6edSJakub Kicinski if len(maps): 2187736b6edSJakub Kicinski args += " map " + " map ".join(maps) 2197736b6edSJakub Kicinski 2207736b6edSJakub Kicinski res = bpftool(args, fail=fail, include_stderr=include_stderr) 2217736b6edSJakub Kicinski if res[0] == 0: 2227736b6edSJakub Kicinski files.append(file_name) 2237736b6edSJakub Kicinski return res 2247736b6edSJakub Kicinski 225caf95228SQuentin Monnetdef ip(args, force=False, JSON=True, ns="", fail=True, include_stderr=False): 226417ec264SJakub Kicinski if force: 227417ec264SJakub Kicinski args = "-force " + args 228caf95228SQuentin Monnet return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns, 229caf95228SQuentin Monnet fail=fail, include_stderr=include_stderr) 230417ec264SJakub Kicinski 231caf95228SQuentin Monnetdef tc(args, JSON=True, ns="", fail=True, include_stderr=False): 232caf95228SQuentin Monnet return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns, 233caf95228SQuentin Monnet fail=fail, include_stderr=include_stderr) 234417ec264SJakub Kicinski 235417ec264SJakub Kicinskidef ethtool(dev, opt, args, fail=True): 236417ec264SJakub Kicinski return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail) 237417ec264SJakub Kicinski 238417ec264SJakub Kicinskidef bpf_obj(name, sec=".text", path=bpf_test_dir,): 239417ec264SJakub Kicinski return "obj %s sec %s" % (os.path.join(path, name), sec) 240417ec264SJakub Kicinski 241417ec264SJakub Kicinskidef bpf_pinned(name): 242417ec264SJakub Kicinski return "pinned %s" % (name) 243417ec264SJakub Kicinski 244417ec264SJakub Kicinskidef bpf_bytecode(bytecode): 245417ec264SJakub Kicinski return "bytecode \"%s\"" % (bytecode) 246417ec264SJakub Kicinski 247752d7b45SJakub Kicinskidef mknetns(n_retry=10): 248752d7b45SJakub Kicinski for i in range(n_retry): 249752d7b45SJakub Kicinski name = ''.join([random.choice(string.ascii_letters) for i in range(8)]) 250752d7b45SJakub Kicinski ret, _ = ip("netns add %s" % (name), fail=False) 251752d7b45SJakub Kicinski if ret == 0: 252752d7b45SJakub Kicinski netns.append(name) 253752d7b45SJakub Kicinski return name 254752d7b45SJakub Kicinski return None 255752d7b45SJakub Kicinski 2567fedbb7cSJakub Kicinskidef int2str(fmt, val): 2577fedbb7cSJakub Kicinski ret = [] 2587fedbb7cSJakub Kicinski for b in struct.pack(fmt, val): 2597fedbb7cSJakub Kicinski ret.append(int(b)) 2607fedbb7cSJakub Kicinski return " ".join(map(lambda x: str(x), ret)) 2617fedbb7cSJakub Kicinski 2627fedbb7cSJakub Kicinskidef str2int(strtab): 2637fedbb7cSJakub Kicinski inttab = [] 2647fedbb7cSJakub Kicinski for i in strtab: 2657fedbb7cSJakub Kicinski inttab.append(int(i, 16)) 2667fedbb7cSJakub Kicinski ba = bytearray(inttab) 2677fedbb7cSJakub Kicinski if len(strtab) == 4: 2687fedbb7cSJakub Kicinski fmt = "I" 2697fedbb7cSJakub Kicinski elif len(strtab) == 8: 2707fedbb7cSJakub Kicinski fmt = "Q" 2717fedbb7cSJakub Kicinski else: 2727fedbb7cSJakub Kicinski raise Exception("String array of len %d can't be unpacked to an int" % 2737fedbb7cSJakub Kicinski (len(strtab))) 2747fedbb7cSJakub Kicinski return struct.unpack(fmt, ba)[0] 2757fedbb7cSJakub Kicinski 276417ec264SJakub Kicinskiclass DebugfsDir: 277417ec264SJakub Kicinski """ 278417ec264SJakub Kicinski Class for accessing DebugFS directories as a dictionary. 279417ec264SJakub Kicinski """ 280417ec264SJakub Kicinski 281417ec264SJakub Kicinski def __init__(self, path): 282417ec264SJakub Kicinski self.path = path 283417ec264SJakub Kicinski self._dict = self._debugfs_dir_read(path) 284417ec264SJakub Kicinski 285417ec264SJakub Kicinski def __len__(self): 286417ec264SJakub Kicinski return len(self._dict.keys()) 287417ec264SJakub Kicinski 288417ec264SJakub Kicinski def __getitem__(self, key): 289417ec264SJakub Kicinski if type(key) is int: 290417ec264SJakub Kicinski key = list(self._dict.keys())[key] 291417ec264SJakub Kicinski return self._dict[key] 292417ec264SJakub Kicinski 293417ec264SJakub Kicinski def __setitem__(self, key, value): 294417ec264SJakub Kicinski log("DebugFS set %s = %s" % (key, value), "") 295417ec264SJakub Kicinski log_level_inc() 296417ec264SJakub Kicinski 297417ec264SJakub Kicinski cmd("echo '%s' > %s/%s" % (value, self.path, key)) 298417ec264SJakub Kicinski log_level_dec() 299417ec264SJakub Kicinski 300417ec264SJakub Kicinski _, out = cmd('cat %s/%s' % (self.path, key)) 301417ec264SJakub Kicinski self._dict[key] = out.strip() 302417ec264SJakub Kicinski 303417ec264SJakub Kicinski def _debugfs_dir_read(self, path): 304417ec264SJakub Kicinski dfs = {} 305417ec264SJakub Kicinski 306417ec264SJakub Kicinski log("DebugFS state for %s" % (path), "") 307417ec264SJakub Kicinski log_level_inc(add=2) 308417ec264SJakub Kicinski 309417ec264SJakub Kicinski _, out = cmd('ls ' + path) 310417ec264SJakub Kicinski for f in out.split(): 311ab1d0cc0SJiri Pirko if f == "ports": 312ab1d0cc0SJiri Pirko continue 3138101e069SJakub Kicinski 314417ec264SJakub Kicinski p = os.path.join(path, f) 31556c1291eSDaniel Borkmann if not os.stat(p).st_mode & stat.S_IRUSR: 31656c1291eSDaniel Borkmann continue 31756c1291eSDaniel Borkmann 31856c1291eSDaniel Borkmann if os.path.isfile(p): 3194bbca662SHangbin Liu # We need to init trap_flow_action_cookie before read it 3204bbca662SHangbin Liu if f == "trap_flow_action_cookie": 3214bbca662SHangbin Liu cmd('echo deadbeef > %s/%s' % (path, f)) 322417ec264SJakub Kicinski _, out = cmd('cat %s/%s' % (path, f)) 323417ec264SJakub Kicinski dfs[f] = out.strip() 324417ec264SJakub Kicinski elif os.path.isdir(p): 325417ec264SJakub Kicinski dfs[f] = DebugfsDir(p) 326417ec264SJakub Kicinski else: 327417ec264SJakub Kicinski raise Exception("%s is neither file nor directory" % (p)) 328417ec264SJakub Kicinski 329417ec264SJakub Kicinski log_level_dec() 330417ec264SJakub Kicinski log("DebugFS state", dfs) 331417ec264SJakub Kicinski log_level_dec() 332417ec264SJakub Kicinski 333417ec264SJakub Kicinski return dfs 334417ec264SJakub Kicinski 335e05b2d14SJiri Pirkoclass NetdevSimDev: 336e05b2d14SJiri Pirko """ 337e05b2d14SJiri Pirko Class for netdevsim bus device and its attributes. 338e05b2d14SJiri Pirko """ 339acceca8dSJakub Kicinski @staticmethod 340acceca8dSJakub Kicinski def ctrl_write(path, val): 341acceca8dSJakub Kicinski fullpath = os.path.join("/sys/bus/netdevsim/", path) 342acceca8dSJakub Kicinski try: 343acceca8dSJakub Kicinski with open(fullpath, "w") as f: 344acceca8dSJakub Kicinski f.write(val) 345acceca8dSJakub Kicinski except OSError as e: 346acceca8dSJakub Kicinski log("WRITE %s: %r" % (fullpath, val), -e.errno) 347acceca8dSJakub Kicinski raise e 348acceca8dSJakub Kicinski log("WRITE %s: %r" % (fullpath, val), 0) 349e05b2d14SJiri Pirko 350e05b2d14SJiri Pirko def __init__(self, port_count=1): 351e05b2d14SJiri Pirko addr = 0 352e05b2d14SJiri Pirko while True: 353e05b2d14SJiri Pirko try: 354acceca8dSJakub Kicinski self.ctrl_write("new_device", "%u %u" % (addr, port_count)) 355e05b2d14SJiri Pirko except OSError as e: 356e05b2d14SJiri Pirko if e.errno == errno.ENOSPC: 357e05b2d14SJiri Pirko addr += 1 358e05b2d14SJiri Pirko continue 359e05b2d14SJiri Pirko raise e 360e05b2d14SJiri Pirko break 361e05b2d14SJiri Pirko self.addr = addr 362e05b2d14SJiri Pirko 363e05b2d14SJiri Pirko # As probe of netdevsim device might happen from a workqueue, 364e05b2d14SJiri Pirko # so wait here until all netdevs appear. 365e05b2d14SJiri Pirko self.wait_for_netdevs(port_count) 366e05b2d14SJiri Pirko 367e05b2d14SJiri Pirko ret, out = cmd("udevadm settle", fail=False) 368e05b2d14SJiri Pirko if ret: 369e05b2d14SJiri Pirko raise Exception("udevadm settle failed") 370e05b2d14SJiri Pirko ifnames = self.get_ifnames() 371e05b2d14SJiri Pirko 372e05b2d14SJiri Pirko devs.append(self) 373e05b2d14SJiri Pirko self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr 374e05b2d14SJiri Pirko 375e05b2d14SJiri Pirko self.nsims = [] 376e05b2d14SJiri Pirko for port_index in range(port_count): 377e05b2d14SJiri Pirko self.nsims.append(NetdevSim(self, port_index, ifnames[port_index])) 378e05b2d14SJiri Pirko 379e05b2d14SJiri Pirko def get_ifnames(self): 380e05b2d14SJiri Pirko ifnames = [] 381e05b2d14SJiri Pirko listdir = os.listdir("/sys/bus/netdevsim/devices/netdevsim%u/net/" % self.addr) 382e05b2d14SJiri Pirko for ifname in listdir: 383e05b2d14SJiri Pirko ifnames.append(ifname) 384e05b2d14SJiri Pirko ifnames.sort() 385e05b2d14SJiri Pirko return ifnames 386e05b2d14SJiri Pirko 387e05b2d14SJiri Pirko def wait_for_netdevs(self, port_count): 388e05b2d14SJiri Pirko timeout = 5 389e05b2d14SJiri Pirko timeout_start = time.time() 390e05b2d14SJiri Pirko 391e05b2d14SJiri Pirko while True: 392e05b2d14SJiri Pirko try: 393e05b2d14SJiri Pirko ifnames = self.get_ifnames() 394e05b2d14SJiri Pirko except FileNotFoundError as e: 395e05b2d14SJiri Pirko ifnames = [] 396e05b2d14SJiri Pirko if len(ifnames) == port_count: 397e05b2d14SJiri Pirko break 398e05b2d14SJiri Pirko if time.time() < timeout_start + timeout: 399e05b2d14SJiri Pirko continue 400e05b2d14SJiri Pirko raise Exception("netdevices did not appear within timeout") 401e05b2d14SJiri Pirko 402e05b2d14SJiri Pirko def dfs_num_bound_progs(self): 403e05b2d14SJiri Pirko path = os.path.join(self.dfs_dir, "bpf_bound_progs") 404e05b2d14SJiri Pirko _, progs = cmd('ls %s' % (path)) 405e05b2d14SJiri Pirko return len(progs.split()) 406e05b2d14SJiri Pirko 407e05b2d14SJiri Pirko def dfs_get_bound_progs(self, expected): 408e05b2d14SJiri Pirko progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) 409e05b2d14SJiri Pirko if expected is not None: 410e05b2d14SJiri Pirko if len(progs) != expected: 411e05b2d14SJiri Pirko fail(True, "%d BPF programs bound, expected %d" % 412e05b2d14SJiri Pirko (len(progs), expected)) 413e05b2d14SJiri Pirko return progs 414e05b2d14SJiri Pirko 415e05b2d14SJiri Pirko def remove(self): 416acceca8dSJakub Kicinski self.ctrl_write("del_device", "%u" % (self.addr, )) 417e05b2d14SJiri Pirko devs.remove(self) 418e05b2d14SJiri Pirko 419e05b2d14SJiri Pirko def remove_nsim(self, nsim): 420e05b2d14SJiri Pirko self.nsims.remove(nsim) 421acceca8dSJakub Kicinski self.ctrl_write("devices/netdevsim%u/del_port" % (self.addr, ), 422acceca8dSJakub Kicinski "%u" % (nsim.port_index, )) 423e05b2d14SJiri Pirko 424417ec264SJakub Kicinskiclass NetdevSim: 425417ec264SJakub Kicinski """ 426417ec264SJakub Kicinski Class for netdevsim netdevice and its attributes. 427417ec264SJakub Kicinski """ 428417ec264SJakub Kicinski 429e05b2d14SJiri Pirko def __init__(self, nsimdev, port_index, ifname): 430e05b2d14SJiri Pirko # In case udev renamed the netdev to according to new schema, 431e05b2d14SJiri Pirko # check if the name matches the port_index. 432e05b2d14SJiri Pirko nsimnamere = re.compile("eni\d+np(\d+)") 433e05b2d14SJiri Pirko match = nsimnamere.match(ifname) 434e05b2d14SJiri Pirko if match and int(match.groups()[0]) != port_index + 1: 435e05b2d14SJiri Pirko raise Exception("netdevice name mismatches the expected one") 4367736b6edSJakub Kicinski 437e05b2d14SJiri Pirko self.nsimdev = nsimdev 438e05b2d14SJiri Pirko self.port_index = port_index 439752d7b45SJakub Kicinski self.ns = "" 440e05b2d14SJiri Pirko self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index) 441417ec264SJakub Kicinski self.dfs_refresh() 442e05b2d14SJiri Pirko _, [self.dev] = ip("link show dev %s" % ifname) 443417ec264SJakub Kicinski 444417ec264SJakub Kicinski def __getitem__(self, key): 445417ec264SJakub Kicinski return self.dev[key] 446417ec264SJakub Kicinski 447417ec264SJakub Kicinski def remove(self): 448e05b2d14SJiri Pirko self.nsimdev.remove_nsim(self) 449417ec264SJakub Kicinski 450417ec264SJakub Kicinski def dfs_refresh(self): 451417ec264SJakub Kicinski self.dfs = DebugfsDir(self.dfs_dir) 452417ec264SJakub Kicinski return self.dfs 453417ec264SJakub Kicinski 45499dadb6eSJakub Kicinski def dfs_read(self, f): 45599dadb6eSJakub Kicinski path = os.path.join(self.dfs_dir, f) 45699dadb6eSJakub Kicinski _, data = cmd('cat %s' % (path)) 45799dadb6eSJakub Kicinski return data.strip() 45899dadb6eSJakub Kicinski 459417ec264SJakub Kicinski def wait_for_flush(self, bound=0, total=0, n_retry=20): 460417ec264SJakub Kicinski for i in range(n_retry): 461e05b2d14SJiri Pirko nbound = self.nsimdev.dfs_num_bound_progs() 462417ec264SJakub Kicinski nprogs = len(bpftool_prog_list()) 463417ec264SJakub Kicinski if nbound == bound and nprogs == total: 464417ec264SJakub Kicinski return 465417ec264SJakub Kicinski time.sleep(0.05) 466417ec264SJakub Kicinski raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs)) 467417ec264SJakub Kicinski 468752d7b45SJakub Kicinski def set_ns(self, ns): 469752d7b45SJakub Kicinski name = "1" if ns == "" else ns 470752d7b45SJakub Kicinski ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns) 471752d7b45SJakub Kicinski self.ns = ns 472752d7b45SJakub Kicinski 473417ec264SJakub Kicinski def set_mtu(self, mtu, fail=True): 474417ec264SJakub Kicinski return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu), 475417ec264SJakub Kicinski fail=fail) 476417ec264SJakub Kicinski 4779045bdc8SQuentin Monnet def set_xdp(self, bpf, mode, force=False, JSON=True, verbose=False, 478caf95228SQuentin Monnet fail=True, include_stderr=False): 4799045bdc8SQuentin Monnet if verbose: 4809045bdc8SQuentin Monnet bpf += " verbose" 481417ec264SJakub Kicinski return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf), 482caf95228SQuentin Monnet force=force, JSON=JSON, 483caf95228SQuentin Monnet fail=fail, include_stderr=include_stderr) 484417ec264SJakub Kicinski 485caf95228SQuentin Monnet def unset_xdp(self, mode, force=False, JSON=True, 486caf95228SQuentin Monnet fail=True, include_stderr=False): 487417ec264SJakub Kicinski return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode), 488caf95228SQuentin Monnet force=force, JSON=JSON, 489caf95228SQuentin Monnet fail=fail, include_stderr=include_stderr) 490417ec264SJakub Kicinski 491417ec264SJakub Kicinski def ip_link_show(self, xdp): 492417ec264SJakub Kicinski _, link = ip("link show dev %s" % (self['ifname'])) 493417ec264SJakub Kicinski if len(link) > 1: 494417ec264SJakub Kicinski raise Exception("Multiple objects on ip link show") 495417ec264SJakub Kicinski if len(link) < 1: 496417ec264SJakub Kicinski return {} 497417ec264SJakub Kicinski fail(xdp != "xdp" in link, 498417ec264SJakub Kicinski "XDP program not reporting in iplink (reported %s, expected %s)" % 499417ec264SJakub Kicinski ("xdp" in link, xdp)) 500417ec264SJakub Kicinski return link[0] 501417ec264SJakub Kicinski 502417ec264SJakub Kicinski def tc_add_ingress(self): 503417ec264SJakub Kicinski tc("qdisc add dev %s ingress" % (self['ifname'])) 504417ec264SJakub Kicinski 505417ec264SJakub Kicinski def tc_del_ingress(self): 506417ec264SJakub Kicinski tc("qdisc del dev %s ingress" % (self['ifname'])) 507417ec264SJakub Kicinski 508417ec264SJakub Kicinski def tc_flush_filters(self, bound=0, total=0): 509417ec264SJakub Kicinski self.tc_del_ingress() 510417ec264SJakub Kicinski self.tc_add_ingress() 511417ec264SJakub Kicinski self.wait_for_flush(bound=bound, total=total) 512417ec264SJakub Kicinski 513417ec264SJakub Kicinski def tc_show_ingress(self, expected=None): 514417ec264SJakub Kicinski # No JSON support, oh well... 515417ec264SJakub Kicinski flags = ["skip_sw", "skip_hw", "in_hw"] 516417ec264SJakub Kicinski named = ["protocol", "pref", "chain", "handle", "id", "tag"] 517417ec264SJakub Kicinski 518417ec264SJakub Kicinski args = "-s filter show dev %s ingress" % (self['ifname']) 519417ec264SJakub Kicinski _, out = tc(args, JSON=False) 520417ec264SJakub Kicinski 521417ec264SJakub Kicinski filters = [] 522417ec264SJakub Kicinski lines = out.split('\n') 523417ec264SJakub Kicinski for line in lines: 524417ec264SJakub Kicinski words = line.split() 525417ec264SJakub Kicinski if "handle" not in words: 526417ec264SJakub Kicinski continue 527417ec264SJakub Kicinski fltr = {} 528417ec264SJakub Kicinski for flag in flags: 529417ec264SJakub Kicinski fltr[flag] = flag in words 530417ec264SJakub Kicinski for name in named: 531417ec264SJakub Kicinski try: 532417ec264SJakub Kicinski idx = words.index(name) 533417ec264SJakub Kicinski fltr[name] = words[idx + 1] 534417ec264SJakub Kicinski except ValueError: 535417ec264SJakub Kicinski pass 536417ec264SJakub Kicinski filters.append(fltr) 537417ec264SJakub Kicinski 538417ec264SJakub Kicinski if expected is not None: 539417ec264SJakub Kicinski fail(len(filters) != expected, 540417ec264SJakub Kicinski "%d ingress filters loaded, expected %d" % 541417ec264SJakub Kicinski (len(filters), expected)) 542417ec264SJakub Kicinski return filters 543417ec264SJakub Kicinski 5446d2d58f1SJakub Kicinski def cls_filter_op(self, op, qdisc="ingress", prio=None, handle=None, 545baf6a07eSJakub Kicinski chain=None, cls="", params="", 5466d2d58f1SJakub Kicinski fail=True, include_stderr=False): 5476d2d58f1SJakub Kicinski spec = "" 5486d2d58f1SJakub Kicinski if prio is not None: 5496d2d58f1SJakub Kicinski spec += " prio %d" % (prio) 5506d2d58f1SJakub Kicinski if handle: 5516d2d58f1SJakub Kicinski spec += " handle %s" % (handle) 552baf6a07eSJakub Kicinski if chain is not None: 553baf6a07eSJakub Kicinski spec += " chain %d" % (chain) 5546d2d58f1SJakub Kicinski 5556d2d58f1SJakub Kicinski return tc("filter {op} dev {dev} {qdisc} {spec} {cls} {params}"\ 5566d2d58f1SJakub Kicinski .format(op=op, dev=self['ifname'], qdisc=qdisc, spec=spec, 5576d2d58f1SJakub Kicinski cls=cls, params=params), 5586d2d58f1SJakub Kicinski fail=fail, include_stderr=include_stderr) 5596d2d58f1SJakub Kicinski 5606d2d58f1SJakub Kicinski def cls_bpf_add_filter(self, bpf, op="add", prio=None, handle=None, 561baf6a07eSJakub Kicinski chain=None, da=False, verbose=False, 5626d2d58f1SJakub Kicinski skip_sw=False, skip_hw=False, 5636d2d58f1SJakub Kicinski fail=True, include_stderr=False): 5646d2d58f1SJakub Kicinski cls = "bpf " + bpf 5656d2d58f1SJakub Kicinski 566417ec264SJakub Kicinski params = "" 567417ec264SJakub Kicinski if da: 568417ec264SJakub Kicinski params += " da" 5699045bdc8SQuentin Monnet if verbose: 5709045bdc8SQuentin Monnet params += " verbose" 571417ec264SJakub Kicinski if skip_sw: 572417ec264SJakub Kicinski params += " skip_sw" 573417ec264SJakub Kicinski if skip_hw: 574417ec264SJakub Kicinski params += " skip_hw" 5756d2d58f1SJakub Kicinski 5766d2d58f1SJakub Kicinski return self.cls_filter_op(op=op, prio=prio, handle=handle, cls=cls, 577baf6a07eSJakub Kicinski chain=chain, params=params, 578caf95228SQuentin Monnet fail=fail, include_stderr=include_stderr) 579417ec264SJakub Kicinski 580417ec264SJakub Kicinski def set_ethtool_tc_offloads(self, enable, fail=True): 581417ec264SJakub Kicinski args = "hw-tc-offload %s" % ("on" if enable else "off") 582417ec264SJakub Kicinski return ethtool(self, "-K", args, fail=fail) 583417ec264SJakub Kicinski 584417ec264SJakub Kicinski################################################################################ 585417ec264SJakub Kicinskidef clean_up(): 5867fedbb7cSJakub Kicinski global files, netns, devs 5877fedbb7cSJakub Kicinski 588417ec264SJakub Kicinski for dev in devs: 589417ec264SJakub Kicinski dev.remove() 590417ec264SJakub Kicinski for f in files: 591417ec264SJakub Kicinski cmd("rm -f %s" % (f)) 592752d7b45SJakub Kicinski for ns in netns: 593752d7b45SJakub Kicinski cmd("ip netns delete %s" % (ns)) 5947fedbb7cSJakub Kicinski files = [] 5957fedbb7cSJakub Kicinski netns = [] 596417ec264SJakub Kicinski 597417ec264SJakub Kicinskidef pin_prog(file_name, idx=0): 598417ec264SJakub Kicinski progs = bpftool_prog_list(expected=(idx + 1)) 599417ec264SJakub Kicinski prog = progs[idx] 600417ec264SJakub Kicinski bpftool("prog pin id %d %s" % (prog["id"], file_name)) 601417ec264SJakub Kicinski files.append(file_name) 602417ec264SJakub Kicinski 603417ec264SJakub Kicinski return file_name, bpf_pinned(file_name) 604417ec264SJakub Kicinski 6057fedbb7cSJakub Kicinskidef pin_map(file_name, idx=0, expected=1): 6067fedbb7cSJakub Kicinski maps = bpftool_map_list(expected=expected) 6077fedbb7cSJakub Kicinski m = maps[idx] 6087fedbb7cSJakub Kicinski bpftool("map pin id %d %s" % (m["id"], file_name)) 6097fedbb7cSJakub Kicinski files.append(file_name) 6107fedbb7cSJakub Kicinski 6117fedbb7cSJakub Kicinski return file_name, bpf_pinned(file_name) 6127fedbb7cSJakub Kicinski 6137fedbb7cSJakub Kicinskidef check_dev_info_removed(prog_file=None, map_file=None): 614752d7b45SJakub Kicinski bpftool_prog_list(expected=0) 6157fedbb7cSJakub Kicinski ret, err = bpftool("prog show pin %s" % (prog_file), fail=False) 616752d7b45SJakub Kicinski fail(ret == 0, "Showing prog with removed device did not fail") 617752d7b45SJakub Kicinski fail(err["error"].find("No such device") == -1, 618752d7b45SJakub Kicinski "Showing prog with removed device expected ENODEV, error is %s" % 619752d7b45SJakub Kicinski (err["error"])) 6207fedbb7cSJakub Kicinski 6217fedbb7cSJakub Kicinski bpftool_map_list(expected=0) 6227fedbb7cSJakub Kicinski ret, err = bpftool("map show pin %s" % (map_file), fail=False) 6237fedbb7cSJakub Kicinski fail(ret == 0, "Showing map with removed device did not fail") 6247fedbb7cSJakub Kicinski fail(err["error"].find("No such device") == -1, 6257fedbb7cSJakub Kicinski "Showing map with removed device expected ENODEV, error is %s" % 6267fedbb7cSJakub Kicinski (err["error"])) 6277fedbb7cSJakub Kicinski 6287fedbb7cSJakub Kicinskidef check_dev_info(other_ns, ns, prog_file=None, map_file=None, removed=False): 6297fedbb7cSJakub Kicinski progs = bpftool_prog_list(expected=1, ns=ns) 630752d7b45SJakub Kicinski prog = progs[0] 631752d7b45SJakub Kicinski 632752d7b45SJakub Kicinski fail("dev" not in prog.keys(), "Device parameters not reported") 633752d7b45SJakub Kicinski dev = prog["dev"] 634752d7b45SJakub Kicinski fail("ifindex" not in dev.keys(), "Device parameters not reported") 635752d7b45SJakub Kicinski fail("ns_dev" not in dev.keys(), "Device parameters not reported") 636752d7b45SJakub Kicinski fail("ns_inode" not in dev.keys(), "Device parameters not reported") 637752d7b45SJakub Kicinski 6387fedbb7cSJakub Kicinski if not other_ns: 639752d7b45SJakub Kicinski fail("ifname" not in dev.keys(), "Ifname not reported") 640752d7b45SJakub Kicinski fail(dev["ifname"] != sim["ifname"], 641752d7b45SJakub Kicinski "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"])) 642752d7b45SJakub Kicinski else: 643752d7b45SJakub Kicinski fail("ifname" in dev.keys(), "Ifname is reported for other ns") 6447fedbb7cSJakub Kicinski 6457fedbb7cSJakub Kicinski maps = bpftool_map_list(expected=2, ns=ns) 6467fedbb7cSJakub Kicinski for m in maps: 6477fedbb7cSJakub Kicinski fail("dev" not in m.keys(), "Device parameters not reported") 6487fedbb7cSJakub Kicinski fail(dev != m["dev"], "Map's device different than program's") 649752d7b45SJakub Kicinski 650caf95228SQuentin Monnetdef check_extack(output, reference, args): 651caf95228SQuentin Monnet if skip_extack: 652caf95228SQuentin Monnet return 653caf95228SQuentin Monnet lines = output.split("\n") 654219f860dSJakub Kicinski comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference 655caf95228SQuentin Monnet fail(not comp, "Missing or incorrect netlink extack message") 656caf95228SQuentin Monnet 657caf95228SQuentin Monnetdef check_extack_nsim(output, reference, args): 658219f860dSJakub Kicinski check_extack(output, "netdevsim: " + reference, args) 659caf95228SQuentin Monnet 6602fb89a38SJakub Kicinskidef check_no_extack(res, needle): 6612fb89a38SJakub Kicinski fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"), 6622fb89a38SJakub Kicinski "Found '%s' in command output, leaky extack?" % (needle)) 6632fb89a38SJakub Kicinski 6649045bdc8SQuentin Monnetdef check_verifier_log(output, reference): 6659045bdc8SQuentin Monnet lines = output.split("\n") 6669045bdc8SQuentin Monnet for l in reversed(lines): 6679045bdc8SQuentin Monnet if l == reference: 6689045bdc8SQuentin Monnet return 6699045bdc8SQuentin Monnet fail(True, "Missing or incorrect message from netdevsim in verifier log") 6709045bdc8SQuentin Monnet 67142a40e84SJakub Kicinskidef check_multi_basic(two_xdps): 67242a40e84SJakub Kicinski fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs") 67342a40e84SJakub Kicinski fail("prog" in two_xdps, "Base program reported in multi program mode") 67442a40e84SJakub Kicinski fail(len(two_xdps["attached"]) != 2, 67542a40e84SJakub Kicinski "Wrong attached program count with two programs") 67642a40e84SJakub Kicinski fail(two_xdps["attached"][0]["prog"]["id"] == 67742a40e84SJakub Kicinski two_xdps["attached"][1]["prog"]["id"], 67842a40e84SJakub Kicinski "Offloaded and other programs have the same id") 67942a40e84SJakub Kicinski 6802fb89a38SJakub Kicinskidef test_spurios_extack(sim, obj, skip_hw, needle): 6812fb89a38SJakub Kicinski res = sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=skip_hw, 6822fb89a38SJakub Kicinski include_stderr=True) 6832fb89a38SJakub Kicinski check_no_extack(res, needle) 6842fb89a38SJakub Kicinski res = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, 6852fb89a38SJakub Kicinski skip_hw=skip_hw, include_stderr=True) 6862fb89a38SJakub Kicinski check_no_extack(res, needle) 6872fb89a38SJakub Kicinski res = sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf", 6882fb89a38SJakub Kicinski include_stderr=True) 6892fb89a38SJakub Kicinski check_no_extack(res, needle) 6902fb89a38SJakub Kicinski 691e05b2d14SJiri Pirkodef test_multi_prog(simdev, sim, obj, modename, modeid): 69206ea9e63SJakub Kicinski start_test("Test multi-attachment XDP - %s + offload..." % 69306ea9e63SJakub Kicinski (modename or "default", )) 69406ea9e63SJakub Kicinski sim.set_xdp(obj, "offload") 69506ea9e63SJakub Kicinski xdp = sim.ip_link_show(xdp=True)["xdp"] 69606ea9e63SJakub Kicinski offloaded = sim.dfs_read("bpf_offloaded_id") 69706ea9e63SJakub Kicinski fail("prog" not in xdp, "Base program not reported in single program mode") 69806ea9e63SJakub Kicinski fail(len(xdp["attached"]) != 1, 69906ea9e63SJakub Kicinski "Wrong attached program count with one program") 70006ea9e63SJakub Kicinski 70106ea9e63SJakub Kicinski sim.set_xdp(obj, modename) 70206ea9e63SJakub Kicinski two_xdps = sim.ip_link_show(xdp=True)["xdp"] 70306ea9e63SJakub Kicinski 70406ea9e63SJakub Kicinski fail(xdp["attached"][0] not in two_xdps["attached"], 70506ea9e63SJakub Kicinski "Offload program not reported after other activated") 70642a40e84SJakub Kicinski check_multi_basic(two_xdps) 70742a40e84SJakub Kicinski 70842a40e84SJakub Kicinski offloaded2 = sim.dfs_read("bpf_offloaded_id") 70906ea9e63SJakub Kicinski fail(offloaded != offloaded2, 71006ea9e63SJakub Kicinski "Offload ID changed after loading other program") 71106ea9e63SJakub Kicinski 71206ea9e63SJakub Kicinski start_test("Test multi-attachment XDP - replace...") 71306ea9e63SJakub Kicinski ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True) 71406ea9e63SJakub Kicinski fail(ret == 0, "Replaced one of programs without -force") 71506ea9e63SJakub Kicinski check_extack(err, "XDP program already attached.", args) 71606ea9e63SJakub Kicinski 7170b5b6e74SToke Høiland-Jørgensen start_test("Test multi-attachment XDP - remove without mode...") 7180b5b6e74SToke Høiland-Jørgensen ret, _, err = sim.unset_xdp("", force=True, 71906ea9e63SJakub Kicinski fail=False, include_stderr=True) 7200b5b6e74SToke Høiland-Jørgensen fail(ret == 0, "Removed program without a mode flag") 7210b5b6e74SToke Høiland-Jørgensen check_extack(err, "More than one program loaded, unset mode is ambiguous.", args) 72206ea9e63SJakub Kicinski 72306ea9e63SJakub Kicinski sim.unset_xdp("offload") 72406ea9e63SJakub Kicinski xdp = sim.ip_link_show(xdp=True)["xdp"] 72506ea9e63SJakub Kicinski offloaded = sim.dfs_read("bpf_offloaded_id") 72606ea9e63SJakub Kicinski 72706ea9e63SJakub Kicinski fail(xdp["mode"] != modeid, "Bad mode reported after multiple programs") 72806ea9e63SJakub Kicinski fail("prog" not in xdp, 72906ea9e63SJakub Kicinski "Base program not reported after multi program mode") 73006ea9e63SJakub Kicinski fail(xdp["attached"][0] not in two_xdps["attached"], 73106ea9e63SJakub Kicinski "Offload program not reported after other activated") 73206ea9e63SJakub Kicinski fail(len(xdp["attached"]) != 1, 73306ea9e63SJakub Kicinski "Wrong attached program count with remaining programs") 73406ea9e63SJakub Kicinski fail(offloaded != "0", "Offload ID reported with only other program left") 73506ea9e63SJakub Kicinski 73642a40e84SJakub Kicinski start_test("Test multi-attachment XDP - reattach...") 73706ea9e63SJakub Kicinski sim.set_xdp(obj, "offload") 73842a40e84SJakub Kicinski two_xdps = sim.ip_link_show(xdp=True)["xdp"] 73942a40e84SJakub Kicinski 74042a40e84SJakub Kicinski fail(xdp["attached"][0] not in two_xdps["attached"], 74142a40e84SJakub Kicinski "Other program not reported after offload activated") 74242a40e84SJakub Kicinski check_multi_basic(two_xdps) 74342a40e84SJakub Kicinski 74442a40e84SJakub Kicinski start_test("Test multi-attachment XDP - device remove...") 745e05b2d14SJiri Pirko simdev.remove() 74606ea9e63SJakub Kicinski 747e05b2d14SJiri Pirko simdev = NetdevSimDev() 748e05b2d14SJiri Pirko sim, = simdev.nsims 74906ea9e63SJakub Kicinski sim.set_ethtool_tc_offloads(True) 750e05b2d14SJiri Pirko return [simdev, sim] 7512fb89a38SJakub Kicinski 752417ec264SJakub Kicinski# Parse command line 753417ec264SJakub Kicinskiparser = argparse.ArgumentParser() 754417ec264SJakub Kicinskiparser.add_argument("--log", help="output verbose log to given file") 755417ec264SJakub Kicinskiargs = parser.parse_args() 756417ec264SJakub Kicinskiif args.log: 757417ec264SJakub Kicinski logfile = open(args.log, 'w+') 758417ec264SJakub Kicinski logfile.write("# -*-Org-*-") 759417ec264SJakub Kicinski 760417ec264SJakub Kicinskilog("Prepare...", "", level=1) 761417ec264SJakub Kicinskilog_level_inc() 762417ec264SJakub Kicinski 763417ec264SJakub Kicinski# Check permissions 764417ec264SJakub Kicinskiskip(os.getuid() != 0, "test must be run as root") 765417ec264SJakub Kicinski 766417ec264SJakub Kicinski# Check tools 767417ec264SJakub Kicinskiret, progs = bpftool("prog", fail=False) 768417ec264SJakub Kicinskiskip(ret != 0, "bpftool not installed") 76947cf52a2SJakub Kicinskibase_progs = progs 77047cf52a2SJakub Kicinski_, base_maps = bpftool("map") 7718158cad1SToke Høiland-Jørgensenbase_map_names = [ 772e60db051SStanislav Fomichev 'pid_iter.rodata', # created on each bpftool invocation 773e60db051SStanislav Fomichev 'libbpf_det_bind', # created on each bpftool invocation 7748158cad1SToke Høiland-Jørgensen] 775417ec264SJakub Kicinski 776417ec264SJakub Kicinski# Check netdevsim 777e60db051SStanislav Fomichevif not os.path.isdir("/sys/bus/netdevsim/"): 778417ec264SJakub Kicinski ret, out = cmd("modprobe netdevsim", fail=False) 779417ec264SJakub Kicinski skip(ret != 0, "netdevsim module could not be loaded") 780417ec264SJakub Kicinski 781417ec264SJakub Kicinski# Check debugfs 782417ec264SJakub Kicinski_, out = cmd("mount") 783417ec264SJakub Kicinskiif out.find("/sys/kernel/debug type debugfs") == -1: 784417ec264SJakub Kicinski cmd("mount -t debugfs none /sys/kernel/debug") 785417ec264SJakub Kicinski 786417ec264SJakub Kicinski# Check samples are compiled 787afef88e6SDaniel Müllersamples = ["sample_ret0.bpf.o", "sample_map_ret0.bpf.o"] 788417ec264SJakub Kicinskifor s in samples: 789417ec264SJakub Kicinski ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False) 790417ec264SJakub Kicinski skip(ret != 0, "sample %s/%s not found, please compile it" % 791417ec264SJakub Kicinski (bpf_test_dir, s)) 792417ec264SJakub Kicinski 793caf95228SQuentin Monnet# Check if iproute2 is built with libmnl (needed by extack support) 794caf95228SQuentin Monnet_, _, err = cmd("tc qdisc delete dev lo handle 0", 795caf95228SQuentin Monnet fail=False, include_stderr=True) 796caf95228SQuentin Monnetif err.find("Error: Failed to find qdisc with specified handle.") == -1: 797caf95228SQuentin Monnet print("Warning: no extack message in iproute2 output, libmnl missing?") 798caf95228SQuentin Monnet log("Warning: no extack message in iproute2 output, libmnl missing?", "") 799caf95228SQuentin Monnet skip_extack = True 800caf95228SQuentin Monnet 801752d7b45SJakub Kicinski# Check if net namespaces seem to work 802752d7b45SJakub Kicinskins = mknetns() 803752d7b45SJakub Kicinskiskip(ns is None, "Could not create a net namespace") 804752d7b45SJakub Kicinskicmd("ip netns delete %s" % (ns)) 805752d7b45SJakub Kicinskinetns = [] 806752d7b45SJakub Kicinski 807417ec264SJakub Kicinskitry: 808afef88e6SDaniel Müller obj = bpf_obj("sample_ret0.bpf.o") 809417ec264SJakub Kicinski bytecode = bpf_bytecode("1,6 0 0 4294967295,") 810417ec264SJakub Kicinski 811417ec264SJakub Kicinski start_test("Test destruction of generic XDP...") 812e05b2d14SJiri Pirko simdev = NetdevSimDev() 813e05b2d14SJiri Pirko sim, = simdev.nsims 814417ec264SJakub Kicinski sim.set_xdp(obj, "generic") 815e05b2d14SJiri Pirko simdev.remove() 816417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 817417ec264SJakub Kicinski 818e05b2d14SJiri Pirko simdev = NetdevSimDev() 819e05b2d14SJiri Pirko sim, = simdev.nsims 820417ec264SJakub Kicinski sim.tc_add_ingress() 821417ec264SJakub Kicinski 822417ec264SJakub Kicinski start_test("Test TC non-offloaded...") 823417ec264SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(obj, skip_hw=True, fail=False) 824417ec264SJakub Kicinski fail(ret != 0, "Software TC filter did not load") 825417ec264SJakub Kicinski 826417ec264SJakub Kicinski start_test("Test TC non-offloaded isn't getting bound...") 827417ec264SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(obj, fail=False) 828417ec264SJakub Kicinski fail(ret != 0, "Software TC filter did not load") 829e05b2d14SJiri Pirko simdev.dfs_get_bound_progs(expected=0) 830417ec264SJakub Kicinski 831417ec264SJakub Kicinski sim.tc_flush_filters() 832417ec264SJakub Kicinski 833417ec264SJakub Kicinski start_test("Test TC offloads are off by default...") 834caf95228SQuentin Monnet ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True, 835caf95228SQuentin Monnet fail=False, include_stderr=True) 836417ec264SJakub Kicinski fail(ret == 0, "TC filter loaded without enabling TC offloads") 837219f860dSJakub Kicinski check_extack(err, "TC offload is disabled on net device.", args) 838417ec264SJakub Kicinski sim.wait_for_flush() 839417ec264SJakub Kicinski 840417ec264SJakub Kicinski sim.set_ethtool_tc_offloads(True) 841417ec264SJakub Kicinski sim.dfs["bpf_tc_non_bound_accept"] = "Y" 842417ec264SJakub Kicinski 843417ec264SJakub Kicinski start_test("Test TC offload by default...") 844417ec264SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(obj, fail=False) 845417ec264SJakub Kicinski fail(ret != 0, "Software TC filter did not load") 846e05b2d14SJiri Pirko simdev.dfs_get_bound_progs(expected=0) 847417ec264SJakub Kicinski ingress = sim.tc_show_ingress(expected=1) 848417ec264SJakub Kicinski fltr = ingress[0] 849417ec264SJakub Kicinski fail(not fltr["in_hw"], "Filter not offloaded by default") 850417ec264SJakub Kicinski 851417ec264SJakub Kicinski sim.tc_flush_filters() 852417ec264SJakub Kicinski 853417ec264SJakub Kicinski start_test("Test TC cBPF bytcode tries offload by default...") 854417ec264SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False) 855417ec264SJakub Kicinski fail(ret != 0, "Software TC filter did not load") 856e05b2d14SJiri Pirko simdev.dfs_get_bound_progs(expected=0) 857417ec264SJakub Kicinski ingress = sim.tc_show_ingress(expected=1) 858417ec264SJakub Kicinski fltr = ingress[0] 859417ec264SJakub Kicinski fail(not fltr["in_hw"], "Bytecode not offloaded by default") 860417ec264SJakub Kicinski 861417ec264SJakub Kicinski sim.tc_flush_filters() 862417ec264SJakub Kicinski sim.dfs["bpf_tc_non_bound_accept"] = "N" 863417ec264SJakub Kicinski 864417ec264SJakub Kicinski start_test("Test TC cBPF unbound bytecode doesn't offload...") 865caf95228SQuentin Monnet ret, _, err = sim.cls_bpf_add_filter(bytecode, skip_sw=True, 866caf95228SQuentin Monnet fail=False, include_stderr=True) 867417ec264SJakub Kicinski fail(ret == 0, "TC bytecode loaded for offload") 868caf95228SQuentin Monnet check_extack_nsim(err, "netdevsim configured to reject unbound programs.", 869caf95228SQuentin Monnet args) 870417ec264SJakub Kicinski sim.wait_for_flush() 871417ec264SJakub Kicinski 872baf6a07eSJakub Kicinski start_test("Test non-0 chain offload...") 873baf6a07eSJakub Kicinski ret, _, err = sim.cls_bpf_add_filter(obj, chain=1, prio=1, handle=1, 874baf6a07eSJakub Kicinski skip_sw=True, 875baf6a07eSJakub Kicinski fail=False, include_stderr=True) 876baf6a07eSJakub Kicinski fail(ret == 0, "Offloaded a filter to chain other than 0") 877219f860dSJakub Kicinski check_extack(err, "Driver supports only offload of chain 0.", args) 878baf6a07eSJakub Kicinski sim.tc_flush_filters() 879baf6a07eSJakub Kicinski 8806d2d58f1SJakub Kicinski start_test("Test TC replace...") 8816d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, prio=1, handle=1) 8826d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1) 8836d2d58f1SJakub Kicinski sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf") 8846d2d58f1SJakub Kicinski 8856d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_sw=True) 8866d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_sw=True) 8876d2d58f1SJakub Kicinski sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf") 8886d2d58f1SJakub Kicinski 8896d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=True) 8906d2d58f1SJakub Kicinski sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, skip_hw=True) 8916d2d58f1SJakub Kicinski sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf") 8926d2d58f1SJakub Kicinski 8936d2d58f1SJakub Kicinski start_test("Test TC replace bad flags...") 8946d2d58f1SJakub Kicinski for i in range(3): 8956d2d58f1SJakub Kicinski for j in range(3): 8966d2d58f1SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(obj, op="replace", prio=1, handle=1, 8976d2d58f1SJakub Kicinski skip_sw=(j == 1), skip_hw=(j == 2), 8986d2d58f1SJakub Kicinski fail=False) 8996d2d58f1SJakub Kicinski fail(bool(ret) != bool(j), 9006d2d58f1SJakub Kicinski "Software TC incorrect load in replace test, iteration %d" % 9016d2d58f1SJakub Kicinski (j)) 9026d2d58f1SJakub Kicinski sim.cls_filter_op(op="delete", prio=1, handle=1, cls="bpf") 9036d2d58f1SJakub Kicinski 9042fb89a38SJakub Kicinski start_test("Test spurious extack from the driver...") 9052fb89a38SJakub Kicinski test_spurios_extack(sim, obj, False, "netdevsim") 9062fb89a38SJakub Kicinski test_spurios_extack(sim, obj, True, "netdevsim") 9072fb89a38SJakub Kicinski 9082fb89a38SJakub Kicinski sim.set_ethtool_tc_offloads(False) 9092fb89a38SJakub Kicinski 9102fb89a38SJakub Kicinski test_spurios_extack(sim, obj, False, "TC offload is disabled") 9112fb89a38SJakub Kicinski test_spurios_extack(sim, obj, True, "TC offload is disabled") 9122fb89a38SJakub Kicinski 9132fb89a38SJakub Kicinski sim.set_ethtool_tc_offloads(True) 9142fb89a38SJakub Kicinski 9156d2d58f1SJakub Kicinski sim.tc_flush_filters() 9166d2d58f1SJakub Kicinski 917d8b5e76aSToke Høiland-Jørgensen start_test("Test TC offloads failure...") 918d8b5e76aSToke Høiland-Jørgensen sim.dfs["dev/bpf_bind_verifier_accept"] = 0 919d8b5e76aSToke Høiland-Jørgensen ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True, 920d8b5e76aSToke Høiland-Jørgensen fail=False, include_stderr=True) 921d8b5e76aSToke Høiland-Jørgensen fail(ret == 0, "TC filter did not reject with TC offloads enabled") 922d8b5e76aSToke Høiland-Jørgensen check_verifier_log(err, "[netdevsim] Hello from netdevsim!") 923d8b5e76aSToke Høiland-Jørgensen sim.dfs["dev/bpf_bind_verifier_accept"] = 1 924d8b5e76aSToke Høiland-Jørgensen 925417ec264SJakub Kicinski start_test("Test TC offloads work...") 9269045bdc8SQuentin Monnet ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True, 9279045bdc8SQuentin Monnet fail=False, include_stderr=True) 928417ec264SJakub Kicinski fail(ret != 0, "TC filter did not load with TC offloads enabled") 929417ec264SJakub Kicinski 930417ec264SJakub Kicinski start_test("Test TC offload basics...") 931e05b2d14SJiri Pirko dfs = simdev.dfs_get_bound_progs(expected=1) 932417ec264SJakub Kicinski progs = bpftool_prog_list(expected=1) 933417ec264SJakub Kicinski ingress = sim.tc_show_ingress(expected=1) 934417ec264SJakub Kicinski 935417ec264SJakub Kicinski dprog = dfs[0] 936417ec264SJakub Kicinski prog = progs[0] 937417ec264SJakub Kicinski fltr = ingress[0] 938417ec264SJakub Kicinski fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter") 939417ec264SJakub Kicinski fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter") 940417ec264SJakub Kicinski fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back") 941417ec264SJakub Kicinski 942417ec264SJakub Kicinski start_test("Test TC offload is device-bound...") 943417ec264SJakub Kicinski fail(str(prog["id"]) != fltr["id"], "Program IDs don't match") 944417ec264SJakub Kicinski fail(prog["tag"] != fltr["tag"], "Program tags don't match") 945417ec264SJakub Kicinski fail(fltr["id"] != dprog["id"], "Program IDs don't match") 946417ec264SJakub Kicinski fail(dprog["state"] != "xlated", "Offloaded program state not translated") 947417ec264SJakub Kicinski fail(dprog["loaded"] != "Y", "Offloaded program is not loaded") 948417ec264SJakub Kicinski 949417ec264SJakub Kicinski start_test("Test disabling TC offloads is rejected while filters installed...") 950417ec264SJakub Kicinski ret, _ = sim.set_ethtool_tc_offloads(False, fail=False) 951417ec264SJakub Kicinski fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...") 952766e62b7SToke Høiland-Jørgensen sim.set_ethtool_tc_offloads(True) 953417ec264SJakub Kicinski 954417ec264SJakub Kicinski start_test("Test qdisc removal frees things...") 955417ec264SJakub Kicinski sim.tc_flush_filters() 956417ec264SJakub Kicinski sim.tc_show_ingress(expected=0) 957417ec264SJakub Kicinski 958417ec264SJakub Kicinski start_test("Test disabling TC offloads is OK without filters...") 959417ec264SJakub Kicinski ret, _ = sim.set_ethtool_tc_offloads(False, fail=False) 960417ec264SJakub Kicinski fail(ret != 0, 961417ec264SJakub Kicinski "Driver refused to disable TC offloads without filters installed...") 962417ec264SJakub Kicinski 963417ec264SJakub Kicinski sim.set_ethtool_tc_offloads(True) 964417ec264SJakub Kicinski 965417ec264SJakub Kicinski start_test("Test destroying device gets rid of TC filters...") 966417ec264SJakub Kicinski sim.cls_bpf_add_filter(obj, skip_sw=True) 967e05b2d14SJiri Pirko simdev.remove() 968417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 969417ec264SJakub Kicinski 970e05b2d14SJiri Pirko simdev = NetdevSimDev() 971e05b2d14SJiri Pirko sim, = simdev.nsims 972417ec264SJakub Kicinski sim.set_ethtool_tc_offloads(True) 973417ec264SJakub Kicinski 974417ec264SJakub Kicinski start_test("Test destroying device gets rid of XDP...") 975417ec264SJakub Kicinski sim.set_xdp(obj, "offload") 976e05b2d14SJiri Pirko simdev.remove() 977417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 978417ec264SJakub Kicinski 979e05b2d14SJiri Pirko simdev = NetdevSimDev() 980e05b2d14SJiri Pirko sim, = simdev.nsims 981417ec264SJakub Kicinski sim.set_ethtool_tc_offloads(True) 982417ec264SJakub Kicinski 983417ec264SJakub Kicinski start_test("Test XDP prog reporting...") 984417ec264SJakub Kicinski sim.set_xdp(obj, "drv") 985417ec264SJakub Kicinski ipl = sim.ip_link_show(xdp=True) 986417ec264SJakub Kicinski progs = bpftool_prog_list(expected=1) 987417ec264SJakub Kicinski fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], 988417ec264SJakub Kicinski "Loaded program has wrong ID") 989417ec264SJakub Kicinski 990417ec264SJakub Kicinski start_test("Test XDP prog replace without force...") 991417ec264SJakub Kicinski ret, _ = sim.set_xdp(obj, "drv", fail=False) 992417ec264SJakub Kicinski fail(ret == 0, "Replaced XDP program without -force") 993417ec264SJakub Kicinski sim.wait_for_flush(total=1) 994417ec264SJakub Kicinski 995417ec264SJakub Kicinski start_test("Test XDP prog replace with force...") 996417ec264SJakub Kicinski ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False) 997417ec264SJakub Kicinski fail(ret != 0, "Could not replace XDP program with -force") 998417ec264SJakub Kicinski bpftool_prog_list_wait(expected=1) 999417ec264SJakub Kicinski ipl = sim.ip_link_show(xdp=True) 1000417ec264SJakub Kicinski progs = bpftool_prog_list(expected=1) 1001417ec264SJakub Kicinski fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], 1002417ec264SJakub Kicinski "Loaded program has wrong ID") 1003752d7b45SJakub Kicinski fail("dev" in progs[0].keys(), 1004752d7b45SJakub Kicinski "Device parameters reported for non-offloaded program") 1005417ec264SJakub Kicinski 1006417ec264SJakub Kicinski start_test("Test XDP prog replace with bad flags...") 100799dadb6eSJakub Kicinski ret, _, err = sim.set_xdp(obj, "generic", force=True, 100899dadb6eSJakub Kicinski fail=False, include_stderr=True) 100999dadb6eSJakub Kicinski fail(ret == 0, "Replaced XDP program with a program in different mode") 101052158f00SJakub Kicinski check_extack(err, 1011852c2ee3SToke Høiland-Jørgensen "Native and generic XDP can't be active at the same time.", 101252158f00SJakub Kicinski args) 1013417ec264SJakub Kicinski 1014417ec264SJakub Kicinski start_test("Test MTU restrictions...") 1015417ec264SJakub Kicinski ret, _ = sim.set_mtu(9000, fail=False) 1016417ec264SJakub Kicinski fail(ret == 0, 1017417ec264SJakub Kicinski "Driver should refuse to increase MTU to 9000 with XDP loaded...") 1018417ec264SJakub Kicinski sim.unset_xdp("drv") 1019417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 1020417ec264SJakub Kicinski sim.set_mtu(9000) 1021caf95228SQuentin Monnet ret, _, err = sim.set_xdp(obj, "drv", fail=False, include_stderr=True) 1022417ec264SJakub Kicinski fail(ret == 0, "Driver should refuse to load program with MTU of 9000...") 1023caf95228SQuentin Monnet check_extack_nsim(err, "MTU too large w/ XDP enabled.", args) 1024417ec264SJakub Kicinski sim.set_mtu(1500) 1025417ec264SJakub Kicinski 1026417ec264SJakub Kicinski sim.wait_for_flush() 10277736b6edSJakub Kicinski start_test("Test non-offload XDP attaching to HW...") 1028afef88e6SDaniel Müller bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/nooffload") 10297736b6edSJakub Kicinski nooffload = bpf_pinned("/sys/fs/bpf/nooffload") 10307736b6edSJakub Kicinski ret, _, err = sim.set_xdp(nooffload, "offload", 10317736b6edSJakub Kicinski fail=False, include_stderr=True) 10327736b6edSJakub Kicinski fail(ret == 0, "attached non-offloaded XDP program to HW") 10337736b6edSJakub Kicinski check_extack_nsim(err, "xdpoffload of non-bound program.", args) 10347736b6edSJakub Kicinski rm("/sys/fs/bpf/nooffload") 10357736b6edSJakub Kicinski 10367736b6edSJakub Kicinski start_test("Test offload XDP attaching to drv...") 1037afef88e6SDaniel Müller bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload", 10387736b6edSJakub Kicinski dev=sim['ifname']) 10397736b6edSJakub Kicinski offload = bpf_pinned("/sys/fs/bpf/offload") 10407736b6edSJakub Kicinski ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True) 10417736b6edSJakub Kicinski fail(ret == 0, "attached offloaded XDP program to drv") 1042*40535704SStanislav Fomichev check_extack(err, "Using offloaded program without HW_MODE flag is not supported.", args) 10437736b6edSJakub Kicinski rm("/sys/fs/bpf/offload") 10447736b6edSJakub Kicinski sim.wait_for_flush() 10457736b6edSJakub Kicinski 1046d8b5e76aSToke Høiland-Jørgensen start_test("Test XDP load failure...") 1047d8b5e76aSToke Høiland-Jørgensen sim.dfs["dev/bpf_bind_verifier_accept"] = 0 1048afef88e6SDaniel Müller ret, _, err = bpftool_prog_load("sample_ret0.bpf.o", "/sys/fs/bpf/offload", 1049d8b5e76aSToke Høiland-Jørgensen dev=sim['ifname'], fail=False, include_stderr=True) 1050d8b5e76aSToke Høiland-Jørgensen fail(ret == 0, "verifier should fail on load") 1051d8b5e76aSToke Høiland-Jørgensen check_verifier_log(err, "[netdevsim] Hello from netdevsim!") 1052d8b5e76aSToke Høiland-Jørgensen sim.dfs["dev/bpf_bind_verifier_accept"] = 1 1053d8b5e76aSToke Høiland-Jørgensen sim.wait_for_flush() 1054d8b5e76aSToke Høiland-Jørgensen 1055417ec264SJakub Kicinski start_test("Test XDP offload...") 10569045bdc8SQuentin Monnet _, _, err = sim.set_xdp(obj, "offload", verbose=True, include_stderr=True) 1057417ec264SJakub Kicinski ipl = sim.ip_link_show(xdp=True) 1058417ec264SJakub Kicinski link_xdp = ipl["xdp"]["prog"] 1059417ec264SJakub Kicinski progs = bpftool_prog_list(expected=1) 1060417ec264SJakub Kicinski prog = progs[0] 1061417ec264SJakub Kicinski fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID") 1062417ec264SJakub Kicinski 1063417ec264SJakub Kicinski start_test("Test XDP offload is device bound...") 1064e05b2d14SJiri Pirko dfs = simdev.dfs_get_bound_progs(expected=1) 1065417ec264SJakub Kicinski dprog = dfs[0] 1066417ec264SJakub Kicinski 1067417ec264SJakub Kicinski fail(prog["id"] != link_xdp["id"], "Program IDs don't match") 1068417ec264SJakub Kicinski fail(prog["tag"] != link_xdp["tag"], "Program tags don't match") 1069417ec264SJakub Kicinski fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match") 1070417ec264SJakub Kicinski fail(dprog["state"] != "xlated", "Offloaded program state not translated") 1071417ec264SJakub Kicinski fail(dprog["loaded"] != "Y", "Offloaded program is not loaded") 1072417ec264SJakub Kicinski 1073417ec264SJakub Kicinski start_test("Test removing XDP program many times...") 1074417ec264SJakub Kicinski sim.unset_xdp("offload") 1075417ec264SJakub Kicinski sim.unset_xdp("offload") 1076417ec264SJakub Kicinski sim.unset_xdp("drv") 1077417ec264SJakub Kicinski sim.unset_xdp("drv") 1078417ec264SJakub Kicinski sim.unset_xdp("") 1079417ec264SJakub Kicinski sim.unset_xdp("") 1080417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 1081417ec264SJakub Kicinski 1082417ec264SJakub Kicinski start_test("Test attempt to use a program for a wrong device...") 1083e05b2d14SJiri Pirko simdev2 = NetdevSimDev() 1084e05b2d14SJiri Pirko sim2, = simdev2.nsims 1085417ec264SJakub Kicinski sim2.set_xdp(obj, "offload") 1086417ec264SJakub Kicinski pin_file, pinned = pin_prog("/sys/fs/bpf/tmp") 1087417ec264SJakub Kicinski 1088caf95228SQuentin Monnet ret, _, err = sim.set_xdp(pinned, "offload", 1089caf95228SQuentin Monnet fail=False, include_stderr=True) 1090417ec264SJakub Kicinski fail(ret == 0, "Pinned program loaded for a different device accepted") 1091*40535704SStanislav Fomichev check_extack(err, "Program bound to different device.", args) 1092e05b2d14SJiri Pirko simdev2.remove() 1093caf95228SQuentin Monnet ret, _, err = sim.set_xdp(pinned, "offload", 1094caf95228SQuentin Monnet fail=False, include_stderr=True) 1095417ec264SJakub Kicinski fail(ret == 0, "Pinned program loaded for a removed device accepted") 1096*40535704SStanislav Fomichev check_extack(err, "Program bound to different device.", args) 1097417ec264SJakub Kicinski rm(pin_file) 1098417ec264SJakub Kicinski bpftool_prog_list_wait(expected=0) 1099417ec264SJakub Kicinski 1100e05b2d14SJiri Pirko simdev, sim = test_multi_prog(simdev, sim, obj, "", 1) 1101e05b2d14SJiri Pirko simdev, sim = test_multi_prog(simdev, sim, obj, "drv", 1) 1102e05b2d14SJiri Pirko simdev, sim = test_multi_prog(simdev, sim, obj, "generic", 2) 110399dadb6eSJakub Kicinski 1104417ec264SJakub Kicinski start_test("Test mixing of TC and XDP...") 1105417ec264SJakub Kicinski sim.tc_add_ingress() 1106417ec264SJakub Kicinski sim.set_xdp(obj, "offload") 1107caf95228SQuentin Monnet ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True, 1108caf95228SQuentin Monnet fail=False, include_stderr=True) 1109417ec264SJakub Kicinski fail(ret == 0, "Loading TC when XDP active should fail") 1110caf95228SQuentin Monnet check_extack_nsim(err, "driver and netdev offload states mismatch.", args) 1111417ec264SJakub Kicinski sim.unset_xdp("offload") 1112417ec264SJakub Kicinski sim.wait_for_flush() 1113417ec264SJakub Kicinski 1114417ec264SJakub Kicinski sim.cls_bpf_add_filter(obj, skip_sw=True) 1115caf95228SQuentin Monnet ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True) 1116417ec264SJakub Kicinski fail(ret == 0, "Loading XDP when TC active should fail") 1117caf95228SQuentin Monnet check_extack_nsim(err, "TC program is already loaded.", args) 1118417ec264SJakub Kicinski 1119417ec264SJakub Kicinski start_test("Test binding TC from pinned...") 1120417ec264SJakub Kicinski pin_file, pinned = pin_prog("/sys/fs/bpf/tmp") 1121417ec264SJakub Kicinski sim.tc_flush_filters(bound=1, total=1) 1122417ec264SJakub Kicinski sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True) 1123417ec264SJakub Kicinski sim.tc_flush_filters(bound=1, total=1) 1124417ec264SJakub Kicinski 1125417ec264SJakub Kicinski start_test("Test binding XDP from pinned...") 1126417ec264SJakub Kicinski sim.set_xdp(obj, "offload") 1127417ec264SJakub Kicinski pin_file, pinned = pin_prog("/sys/fs/bpf/tmp2", idx=1) 1128417ec264SJakub Kicinski 1129417ec264SJakub Kicinski sim.set_xdp(pinned, "offload", force=True) 1130417ec264SJakub Kicinski sim.unset_xdp("offload") 1131417ec264SJakub Kicinski sim.set_xdp(pinned, "offload", force=True) 1132417ec264SJakub Kicinski sim.unset_xdp("offload") 1133417ec264SJakub Kicinski 1134417ec264SJakub Kicinski start_test("Test offload of wrong type fails...") 1135417ec264SJakub Kicinski ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False) 1136417ec264SJakub Kicinski fail(ret == 0, "Managed to attach XDP program to TC") 1137417ec264SJakub Kicinski 1138417ec264SJakub Kicinski start_test("Test asking for TC offload of two filters...") 1139417ec264SJakub Kicinski sim.cls_bpf_add_filter(obj, da=True, skip_sw=True) 1140caf95228SQuentin Monnet ret, _, err = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True, 1141caf95228SQuentin Monnet fail=False, include_stderr=True) 1142fba961abSDavid S. Miller fail(ret == 0, "Managed to offload two TC filters at the same time") 1143caf95228SQuentin Monnet check_extack_nsim(err, "driver and netdev offload states mismatch.", args) 1144417ec264SJakub Kicinski 1145417ec264SJakub Kicinski sim.tc_flush_filters(bound=2, total=2) 1146417ec264SJakub Kicinski 1147417ec264SJakub Kicinski start_test("Test if netdev removal waits for translation...") 1148417ec264SJakub Kicinski delay_msec = 500 1149d514f41eSJiri Pirko sim.dfs["dev/bpf_bind_verifier_delay"] = delay_msec 1150417ec264SJakub Kicinski start = time.time() 1151417ec264SJakub Kicinski cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \ 1152417ec264SJakub Kicinski (sim['ifname'], obj) 1153417ec264SJakub Kicinski tc_proc = cmd(cmd_line, background=True, fail=False) 1154417ec264SJakub Kicinski # Wait for the verifier to start 1155e05b2d14SJiri Pirko while simdev.dfs_num_bound_progs() <= 2: 1156417ec264SJakub Kicinski pass 1157e05b2d14SJiri Pirko simdev.remove() 1158417ec264SJakub Kicinski end = time.time() 1159417ec264SJakub Kicinski ret, _ = cmd_result(tc_proc, fail=False) 1160417ec264SJakub Kicinski time_diff = end - start 1161417ec264SJakub Kicinski log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff)) 1162417ec264SJakub Kicinski 1163417ec264SJakub Kicinski fail(ret == 0, "Managed to load TC filter on a unregistering device") 1164417ec264SJakub Kicinski delay_sec = delay_msec * 0.001 1165417ec264SJakub Kicinski fail(time_diff < delay_sec, "Removal process took %s, expected %s" % 1166417ec264SJakub Kicinski (time_diff, delay_sec)) 1167417ec264SJakub Kicinski 1168752d7b45SJakub Kicinski # Remove all pinned files and reinstantiate the netdev 1169752d7b45SJakub Kicinski clean_up() 1170752d7b45SJakub Kicinski bpftool_prog_list_wait(expected=0) 1171752d7b45SJakub Kicinski 1172e05b2d14SJiri Pirko simdev = NetdevSimDev() 1173e05b2d14SJiri Pirko sim, = simdev.nsims 1174afef88e6SDaniel Müller map_obj = bpf_obj("sample_map_ret0.bpf.o") 11757fedbb7cSJakub Kicinski start_test("Test loading program with maps...") 11767fedbb7cSJakub Kicinski sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON 1177752d7b45SJakub Kicinski 1178752d7b45SJakub Kicinski start_test("Test bpftool bound info reporting (own ns)...") 1179752d7b45SJakub Kicinski check_dev_info(False, "") 1180752d7b45SJakub Kicinski 1181752d7b45SJakub Kicinski start_test("Test bpftool bound info reporting (other ns)...") 1182752d7b45SJakub Kicinski ns = mknetns() 1183752d7b45SJakub Kicinski sim.set_ns(ns) 1184752d7b45SJakub Kicinski check_dev_info(True, "") 1185752d7b45SJakub Kicinski 1186752d7b45SJakub Kicinski start_test("Test bpftool bound info reporting (remote ns)...") 1187752d7b45SJakub Kicinski check_dev_info(False, ns) 1188752d7b45SJakub Kicinski 1189752d7b45SJakub Kicinski start_test("Test bpftool bound info reporting (back to own ns)...") 1190752d7b45SJakub Kicinski sim.set_ns("") 1191752d7b45SJakub Kicinski check_dev_info(False, "") 1192752d7b45SJakub Kicinski 11937fedbb7cSJakub Kicinski prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog") 11947fedbb7cSJakub Kicinski map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2) 1195e05b2d14SJiri Pirko simdev.remove() 1196752d7b45SJakub Kicinski 1197752d7b45SJakub Kicinski start_test("Test bpftool bound info reporting (removed dev)...") 11987fedbb7cSJakub Kicinski check_dev_info_removed(prog_file=prog_file, map_file=map_file) 11997fedbb7cSJakub Kicinski 12007fedbb7cSJakub Kicinski # Remove all pinned files and reinstantiate the netdev 12017fedbb7cSJakub Kicinski clean_up() 12027fedbb7cSJakub Kicinski bpftool_prog_list_wait(expected=0) 12037fedbb7cSJakub Kicinski 1204e05b2d14SJiri Pirko simdev = NetdevSimDev() 1205e05b2d14SJiri Pirko sim, = simdev.nsims 12067fedbb7cSJakub Kicinski 12077fedbb7cSJakub Kicinski start_test("Test map update (no flags)...") 12087fedbb7cSJakub Kicinski sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON 12097fedbb7cSJakub Kicinski maps = bpftool_map_list(expected=2) 12107fedbb7cSJakub Kicinski array = maps[0] if maps[0]["type"] == "array" else maps[1] 12117fedbb7cSJakub Kicinski htab = maps[0] if maps[0]["type"] == "hash" else maps[1] 12127fedbb7cSJakub Kicinski for m in maps: 12137fedbb7cSJakub Kicinski for i in range(2): 12147fedbb7cSJakub Kicinski bpftool("map update id %d key %s value %s" % 12157fedbb7cSJakub Kicinski (m["id"], int2str("I", i), int2str("Q", i * 3))) 12167fedbb7cSJakub Kicinski 12177fedbb7cSJakub Kicinski for m in maps: 12187fedbb7cSJakub Kicinski ret, _ = bpftool("map update id %d key %s value %s" % 12197fedbb7cSJakub Kicinski (m["id"], int2str("I", 3), int2str("Q", 3 * 3)), 12207fedbb7cSJakub Kicinski fail=False) 12217fedbb7cSJakub Kicinski fail(ret == 0, "added too many entries") 12227fedbb7cSJakub Kicinski 12237fedbb7cSJakub Kicinski start_test("Test map update (exists)...") 12247fedbb7cSJakub Kicinski for m in maps: 12257fedbb7cSJakub Kicinski for i in range(2): 12267fedbb7cSJakub Kicinski bpftool("map update id %d key %s value %s exist" % 12277fedbb7cSJakub Kicinski (m["id"], int2str("I", i), int2str("Q", i * 3))) 12287fedbb7cSJakub Kicinski 12297fedbb7cSJakub Kicinski for m in maps: 12307fedbb7cSJakub Kicinski ret, err = bpftool("map update id %d key %s value %s exist" % 12317fedbb7cSJakub Kicinski (m["id"], int2str("I", 3), int2str("Q", 3 * 3)), 12327fedbb7cSJakub Kicinski fail=False) 12337fedbb7cSJakub Kicinski fail(ret == 0, "updated non-existing key") 12347fedbb7cSJakub Kicinski fail(err["error"].find("No such file or directory") == -1, 12357fedbb7cSJakub Kicinski "expected ENOENT, error is '%s'" % (err["error"])) 12367fedbb7cSJakub Kicinski 12377fedbb7cSJakub Kicinski start_test("Test map update (noexist)...") 12387fedbb7cSJakub Kicinski for m in maps: 12397fedbb7cSJakub Kicinski for i in range(2): 12407fedbb7cSJakub Kicinski ret, err = bpftool("map update id %d key %s value %s noexist" % 12417fedbb7cSJakub Kicinski (m["id"], int2str("I", i), int2str("Q", i * 3)), 12427fedbb7cSJakub Kicinski fail=False) 12437fedbb7cSJakub Kicinski fail(ret == 0, "updated existing key") 12447fedbb7cSJakub Kicinski fail(err["error"].find("File exists") == -1, 12457fedbb7cSJakub Kicinski "expected EEXIST, error is '%s'" % (err["error"])) 12467fedbb7cSJakub Kicinski 12477fedbb7cSJakub Kicinski start_test("Test map dump...") 12487fedbb7cSJakub Kicinski for m in maps: 12497fedbb7cSJakub Kicinski _, entries = bpftool("map dump id %d" % (m["id"])) 12507fedbb7cSJakub Kicinski for i in range(2): 12517fedbb7cSJakub Kicinski key = str2int(entries[i]["key"]) 12527fedbb7cSJakub Kicinski fail(key != i, "expected key %d, got %d" % (key, i)) 12537fedbb7cSJakub Kicinski val = str2int(entries[i]["value"]) 12547fedbb7cSJakub Kicinski fail(val != i * 3, "expected value %d, got %d" % (val, i * 3)) 12557fedbb7cSJakub Kicinski 12567fedbb7cSJakub Kicinski start_test("Test map getnext...") 12577fedbb7cSJakub Kicinski for m in maps: 12587fedbb7cSJakub Kicinski _, entry = bpftool("map getnext id %d" % (m["id"])) 12597fedbb7cSJakub Kicinski key = str2int(entry["next_key"]) 12607fedbb7cSJakub Kicinski fail(key != 0, "next key %d, expected %d" % (key, 0)) 12617fedbb7cSJakub Kicinski _, entry = bpftool("map getnext id %d key %s" % 12627fedbb7cSJakub Kicinski (m["id"], int2str("I", 0))) 12637fedbb7cSJakub Kicinski key = str2int(entry["next_key"]) 12647fedbb7cSJakub Kicinski fail(key != 1, "next key %d, expected %d" % (key, 1)) 12657fedbb7cSJakub Kicinski ret, err = bpftool("map getnext id %d key %s" % 12667fedbb7cSJakub Kicinski (m["id"], int2str("I", 1)), fail=False) 12677fedbb7cSJakub Kicinski fail(ret == 0, "got next key past the end of map") 12687fedbb7cSJakub Kicinski fail(err["error"].find("No such file or directory") == -1, 12697fedbb7cSJakub Kicinski "expected ENOENT, error is '%s'" % (err["error"])) 12707fedbb7cSJakub Kicinski 12717fedbb7cSJakub Kicinski start_test("Test map delete (htab)...") 12727fedbb7cSJakub Kicinski for i in range(2): 12737fedbb7cSJakub Kicinski bpftool("map delete id %d key %s" % (htab["id"], int2str("I", i))) 12747fedbb7cSJakub Kicinski 12757fedbb7cSJakub Kicinski start_test("Test map delete (array)...") 12767fedbb7cSJakub Kicinski for i in range(2): 12777fedbb7cSJakub Kicinski ret, err = bpftool("map delete id %d key %s" % 12787fedbb7cSJakub Kicinski (htab["id"], int2str("I", i)), fail=False) 12797fedbb7cSJakub Kicinski fail(ret == 0, "removed entry from an array") 12807fedbb7cSJakub Kicinski fail(err["error"].find("No such file or directory") == -1, 12817fedbb7cSJakub Kicinski "expected ENOENT, error is '%s'" % (err["error"])) 12827fedbb7cSJakub Kicinski 12837fedbb7cSJakub Kicinski start_test("Test map remove...") 12847fedbb7cSJakub Kicinski sim.unset_xdp("offload") 12857fedbb7cSJakub Kicinski bpftool_map_list_wait(expected=0) 1286e05b2d14SJiri Pirko simdev.remove() 12877fedbb7cSJakub Kicinski 1288e05b2d14SJiri Pirko simdev = NetdevSimDev() 1289e05b2d14SJiri Pirko sim, = simdev.nsims 12907fedbb7cSJakub Kicinski sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON 1291e05b2d14SJiri Pirko simdev.remove() 12927fedbb7cSJakub Kicinski bpftool_map_list_wait(expected=0) 12937fedbb7cSJakub Kicinski 12947fedbb7cSJakub Kicinski start_test("Test map creation fail path...") 1295e05b2d14SJiri Pirko simdev = NetdevSimDev() 1296e05b2d14SJiri Pirko sim, = simdev.nsims 12977fedbb7cSJakub Kicinski sim.dfs["bpf_map_accept"] = "N" 12987fedbb7cSJakub Kicinski ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False) 12997fedbb7cSJakub Kicinski fail(ret == 0, 13007fedbb7cSJakub Kicinski "netdevsim didn't refuse to create a map with offload disabled") 1301752d7b45SJakub Kicinski 1302e05b2d14SJiri Pirko simdev.remove() 13037736b6edSJakub Kicinski 13047736b6edSJakub Kicinski start_test("Test multi-dev ASIC program reuse...") 1305e05b2d14SJiri Pirko simdevA = NetdevSimDev() 1306e05b2d14SJiri Pirko simA, = simdevA.nsims 1307e05b2d14SJiri Pirko simdevB = NetdevSimDev(3) 1308e05b2d14SJiri Pirko simB1, simB2, simB3 = simdevB.nsims 13097736b6edSJakub Kicinski sims = (simA, simB1, simB2, simB3) 13107736b6edSJakub Kicinski simB = (simB1, simB2, simB3) 13117736b6edSJakub Kicinski 1312afef88e6SDaniel Müller bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA", 13137736b6edSJakub Kicinski dev=simA['ifname']) 13147736b6edSJakub Kicinski progA = bpf_pinned("/sys/fs/bpf/nsimA") 1315afef88e6SDaniel Müller bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB", 13167736b6edSJakub Kicinski dev=simB1['ifname']) 13177736b6edSJakub Kicinski progB = bpf_pinned("/sys/fs/bpf/nsimB") 13187736b6edSJakub Kicinski 13197736b6edSJakub Kicinski simA.set_xdp(progA, "offload", JSON=False) 1320e05b2d14SJiri Pirko for d in simdevB.nsims: 13217736b6edSJakub Kicinski d.set_xdp(progB, "offload", JSON=False) 13227736b6edSJakub Kicinski 13237736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev replace...") 13247736b6edSJakub Kicinski ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False) 13257736b6edSJakub Kicinski fail(ret == 0, "cross-ASIC program allowed") 1326e05b2d14SJiri Pirko for d in simdevB.nsims: 13277736b6edSJakub Kicinski ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False) 13287736b6edSJakub Kicinski fail(ret == 0, "cross-ASIC program allowed") 13297736b6edSJakub Kicinski 13307736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev install...") 13317736b6edSJakub Kicinski for d in sims: 13327736b6edSJakub Kicinski d.unset_xdp("offload") 13337736b6edSJakub Kicinski 13347736b6edSJakub Kicinski ret, _, err = simA.set_xdp(progB, "offload", force=True, JSON=False, 13357736b6edSJakub Kicinski fail=False, include_stderr=True) 13367736b6edSJakub Kicinski fail(ret == 0, "cross-ASIC program allowed") 1337*40535704SStanislav Fomichev check_extack(err, "Program bound to different device.", args) 1338e05b2d14SJiri Pirko for d in simdevB.nsims: 13397736b6edSJakub Kicinski ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False, 13407736b6edSJakub Kicinski fail=False, include_stderr=True) 13417736b6edSJakub Kicinski fail(ret == 0, "cross-ASIC program allowed") 1342*40535704SStanislav Fomichev check_extack(err, "Program bound to different device.", args) 13437736b6edSJakub Kicinski 13447736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev map reuse...") 13457736b6edSJakub Kicinski 13467736b6edSJakub Kicinski mapA = bpftool("prog show %s" % (progA))[1]["map_ids"][0] 13477736b6edSJakub Kicinski mapB = bpftool("prog show %s" % (progB))[1]["map_ids"][0] 13487736b6edSJakub Kicinski 1349afef88e6SDaniel Müller ret, _ = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_", 13507736b6edSJakub Kicinski dev=simB3['ifname'], 13517736b6edSJakub Kicinski maps=["idx 0 id %d" % (mapB)], 13527736b6edSJakub Kicinski fail=False) 13537736b6edSJakub Kicinski fail(ret != 0, "couldn't reuse a map on the same ASIC") 13547736b6edSJakub Kicinski rm("/sys/fs/bpf/nsimB_") 13557736b6edSJakub Kicinski 1356afef88e6SDaniel Müller ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimA_", 13577736b6edSJakub Kicinski dev=simA['ifname'], 13587736b6edSJakub Kicinski maps=["idx 0 id %d" % (mapB)], 13597736b6edSJakub Kicinski fail=False, include_stderr=True) 13607736b6edSJakub Kicinski fail(ret == 0, "could reuse a map on a different ASIC") 13617736b6edSJakub Kicinski fail(err.count("offload device mismatch between prog and map") == 0, 13627736b6edSJakub Kicinski "error message missing for cross-ASIC map") 13637736b6edSJakub Kicinski 1364afef88e6SDaniel Müller ret, _, err = bpftool_prog_load("sample_map_ret0.bpf.o", "/sys/fs/bpf/nsimB_", 13657736b6edSJakub Kicinski dev=simB1['ifname'], 13667736b6edSJakub Kicinski maps=["idx 0 id %d" % (mapA)], 13677736b6edSJakub Kicinski fail=False, include_stderr=True) 13687736b6edSJakub Kicinski fail(ret == 0, "could reuse a map on a different ASIC") 13697736b6edSJakub Kicinski fail(err.count("offload device mismatch between prog and map") == 0, 13707736b6edSJakub Kicinski "error message missing for cross-ASIC map") 13717736b6edSJakub Kicinski 13727736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev destruction...") 13737736b6edSJakub Kicinski bpftool_prog_list_wait(expected=2) 13747736b6edSJakub Kicinski 1375e05b2d14SJiri Pirko simdevA.remove() 13767736b6edSJakub Kicinski bpftool_prog_list_wait(expected=1) 13777736b6edSJakub Kicinski 13787736b6edSJakub Kicinski ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] 13791c6d6e02SMasanari Iida fail(ifnameB != simB1['ifname'], "program not bound to original device") 13807736b6edSJakub Kicinski simB1.remove() 13817736b6edSJakub Kicinski bpftool_prog_list_wait(expected=1) 13827736b6edSJakub Kicinski 13837736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev destruction - move...") 13847736b6edSJakub Kicinski ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] 13857736b6edSJakub Kicinski fail(ifnameB not in (simB2['ifname'], simB3['ifname']), 13867736b6edSJakub Kicinski "program not bound to remaining devices") 13877736b6edSJakub Kicinski 13887736b6edSJakub Kicinski simB2.remove() 13897736b6edSJakub Kicinski ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] 13907736b6edSJakub Kicinski fail(ifnameB != simB3['ifname'], "program not bound to remaining device") 13917736b6edSJakub Kicinski 13927736b6edSJakub Kicinski simB3.remove() 1393e05b2d14SJiri Pirko simdevB.remove() 13947736b6edSJakub Kicinski bpftool_prog_list_wait(expected=0) 13957736b6edSJakub Kicinski 13967736b6edSJakub Kicinski start_test("Test multi-dev ASIC cross-dev destruction - orphaned...") 13977736b6edSJakub Kicinski ret, out = bpftool("prog show %s" % (progB), fail=False) 13987736b6edSJakub Kicinski fail(ret == 0, "got information about orphaned program") 13997736b6edSJakub Kicinski fail("error" not in out, "no error reported for get info on orphaned") 14007736b6edSJakub Kicinski fail(out["error"] != "can't get prog info: No such device", 14017736b6edSJakub Kicinski "wrong error for get info on orphaned") 14027736b6edSJakub Kicinski 1403417ec264SJakub Kicinski print("%s: OK" % (os.path.basename(__file__))) 1404417ec264SJakub Kicinski 1405417ec264SJakub Kicinskifinally: 1406417ec264SJakub Kicinski log("Clean up...", "", level=1) 1407417ec264SJakub Kicinski log_level_inc() 1408417ec264SJakub Kicinski clean_up() 1409