| .. | .. |
|---|
| 1 | 1 | #!/usr/bin/env python3 |
|---|
| 2 | 2 | |
|---|
| 3 | 3 | # Copyright (C) 2017 Netronome Systems, Inc. |
|---|
| 4 | +# Copyright (c) 2019 Mellanox Technologies. All rights reserved |
|---|
| 4 | 5 | # |
|---|
| 5 | 6 | # This software is licensed under the GNU General License Version 2, |
|---|
| 6 | 7 | # June 1991 as shown in the file COPYING in the top-level directory of this |
|---|
| .. | .. |
|---|
| 15 | 16 | |
|---|
| 16 | 17 | from datetime import datetime |
|---|
| 17 | 18 | import argparse |
|---|
| 19 | +import errno |
|---|
| 18 | 20 | import json |
|---|
| 19 | 21 | import os |
|---|
| 20 | 22 | import pprint |
|---|
| 21 | 23 | import random |
|---|
| 24 | +import re |
|---|
| 25 | +import stat |
|---|
| 22 | 26 | import string |
|---|
| 23 | 27 | import struct |
|---|
| 24 | 28 | import subprocess |
|---|
| 25 | 29 | import time |
|---|
| 30 | +import traceback |
|---|
| 26 | 31 | |
|---|
| 27 | 32 | logfile = None |
|---|
| 28 | 33 | log_level = 1 |
|---|
| .. | .. |
|---|
| 78 | 83 | if not cond: |
|---|
| 79 | 84 | return |
|---|
| 80 | 85 | print("FAIL: " + msg) |
|---|
| 81 | | - log("FAIL: " + msg, "", level=1) |
|---|
| 86 | + tb = "".join(traceback.extract_stack().format()) |
|---|
| 87 | + print(tb) |
|---|
| 88 | + log("FAIL: " + msg, tb, level=1) |
|---|
| 82 | 89 | os.sys.exit(1) |
|---|
| 83 | 90 | |
|---|
| 84 | 91 | def start_test(msg): |
|---|
| .. | .. |
|---|
| 177 | 184 | def bpftool_map_list(expected=None, ns=""): |
|---|
| 178 | 185 | _, maps = bpftool("map show", JSON=True, ns=ns, fail=True) |
|---|
| 179 | 186 | # Remove the base maps |
|---|
| 180 | | - for m in base_maps: |
|---|
| 181 | | - if m in maps: |
|---|
| 182 | | - maps.remove(m) |
|---|
| 187 | + maps = [m for m in maps if m not in base_maps and m.get('name') not in base_map_names] |
|---|
| 183 | 188 | if expected is not None: |
|---|
| 184 | 189 | if len(maps) != expected: |
|---|
| 185 | 190 | fail(True, "%d BPF maps loaded, expected %d" % |
|---|
| .. | .. |
|---|
| 303 | 308 | |
|---|
| 304 | 309 | _, out = cmd('ls ' + path) |
|---|
| 305 | 310 | for f in out.split(): |
|---|
| 311 | + if f == "ports": |
|---|
| 312 | + continue |
|---|
| 313 | + |
|---|
| 306 | 314 | p = os.path.join(path, f) |
|---|
| 315 | + if not os.stat(p).st_mode & stat.S_IRUSR: |
|---|
| 316 | + continue |
|---|
| 317 | + |
|---|
| 307 | 318 | if os.path.isfile(p): |
|---|
| 319 | + # We need to init trap_flow_action_cookie before read it |
|---|
| 320 | + if f == "trap_flow_action_cookie": |
|---|
| 321 | + cmd('echo deadbeef > %s/%s' % (path, f)) |
|---|
| 308 | 322 | _, out = cmd('cat %s/%s' % (path, f)) |
|---|
| 309 | 323 | dfs[f] = out.strip() |
|---|
| 310 | 324 | elif os.path.isdir(p): |
|---|
| .. | .. |
|---|
| 318 | 332 | |
|---|
| 319 | 333 | return dfs |
|---|
| 320 | 334 | |
|---|
| 335 | +class NetdevSimDev: |
|---|
| 336 | + """ |
|---|
| 337 | + Class for netdevsim bus device and its attributes. |
|---|
| 338 | + """ |
|---|
| 339 | + @staticmethod |
|---|
| 340 | + def ctrl_write(path, val): |
|---|
| 341 | + fullpath = os.path.join("/sys/bus/netdevsim/", path) |
|---|
| 342 | + try: |
|---|
| 343 | + with open(fullpath, "w") as f: |
|---|
| 344 | + f.write(val) |
|---|
| 345 | + except OSError as e: |
|---|
| 346 | + log("WRITE %s: %r" % (fullpath, val), -e.errno) |
|---|
| 347 | + raise e |
|---|
| 348 | + log("WRITE %s: %r" % (fullpath, val), 0) |
|---|
| 349 | + |
|---|
| 350 | + def __init__(self, port_count=1): |
|---|
| 351 | + addr = 0 |
|---|
| 352 | + while True: |
|---|
| 353 | + try: |
|---|
| 354 | + self.ctrl_write("new_device", "%u %u" % (addr, port_count)) |
|---|
| 355 | + except OSError as e: |
|---|
| 356 | + if e.errno == errno.ENOSPC: |
|---|
| 357 | + addr += 1 |
|---|
| 358 | + continue |
|---|
| 359 | + raise e |
|---|
| 360 | + break |
|---|
| 361 | + self.addr = addr |
|---|
| 362 | + |
|---|
| 363 | + # As probe of netdevsim device might happen from a workqueue, |
|---|
| 364 | + # so wait here until all netdevs appear. |
|---|
| 365 | + self.wait_for_netdevs(port_count) |
|---|
| 366 | + |
|---|
| 367 | + ret, out = cmd("udevadm settle", fail=False) |
|---|
| 368 | + if ret: |
|---|
| 369 | + raise Exception("udevadm settle failed") |
|---|
| 370 | + ifnames = self.get_ifnames() |
|---|
| 371 | + |
|---|
| 372 | + devs.append(self) |
|---|
| 373 | + self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr |
|---|
| 374 | + |
|---|
| 375 | + self.nsims = [] |
|---|
| 376 | + for port_index in range(port_count): |
|---|
| 377 | + self.nsims.append(NetdevSim(self, port_index, ifnames[port_index])) |
|---|
| 378 | + |
|---|
| 379 | + def get_ifnames(self): |
|---|
| 380 | + ifnames = [] |
|---|
| 381 | + listdir = os.listdir("/sys/bus/netdevsim/devices/netdevsim%u/net/" % self.addr) |
|---|
| 382 | + for ifname in listdir: |
|---|
| 383 | + ifnames.append(ifname) |
|---|
| 384 | + ifnames.sort() |
|---|
| 385 | + return ifnames |
|---|
| 386 | + |
|---|
| 387 | + def wait_for_netdevs(self, port_count): |
|---|
| 388 | + timeout = 5 |
|---|
| 389 | + timeout_start = time.time() |
|---|
| 390 | + |
|---|
| 391 | + while True: |
|---|
| 392 | + try: |
|---|
| 393 | + ifnames = self.get_ifnames() |
|---|
| 394 | + except FileNotFoundError as e: |
|---|
| 395 | + ifnames = [] |
|---|
| 396 | + if len(ifnames) == port_count: |
|---|
| 397 | + break |
|---|
| 398 | + if time.time() < timeout_start + timeout: |
|---|
| 399 | + continue |
|---|
| 400 | + raise Exception("netdevices did not appear within timeout") |
|---|
| 401 | + |
|---|
| 402 | + def dfs_num_bound_progs(self): |
|---|
| 403 | + path = os.path.join(self.dfs_dir, "bpf_bound_progs") |
|---|
| 404 | + _, progs = cmd('ls %s' % (path)) |
|---|
| 405 | + return len(progs.split()) |
|---|
| 406 | + |
|---|
| 407 | + def dfs_get_bound_progs(self, expected): |
|---|
| 408 | + progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) |
|---|
| 409 | + if expected is not None: |
|---|
| 410 | + if len(progs) != expected: |
|---|
| 411 | + fail(True, "%d BPF programs bound, expected %d" % |
|---|
| 412 | + (len(progs), expected)) |
|---|
| 413 | + return progs |
|---|
| 414 | + |
|---|
| 415 | + def remove(self): |
|---|
| 416 | + self.ctrl_write("del_device", "%u" % (self.addr, )) |
|---|
| 417 | + devs.remove(self) |
|---|
| 418 | + |
|---|
| 419 | + def remove_nsim(self, nsim): |
|---|
| 420 | + self.nsims.remove(nsim) |
|---|
| 421 | + self.ctrl_write("devices/netdevsim%u/del_port" % (self.addr, ), |
|---|
| 422 | + "%u" % (nsim.port_index, )) |
|---|
| 423 | + |
|---|
| 321 | 424 | class NetdevSim: |
|---|
| 322 | 425 | """ |
|---|
| 323 | 426 | Class for netdevsim netdevice and its attributes. |
|---|
| 324 | 427 | """ |
|---|
| 325 | 428 | |
|---|
| 326 | | - def __init__(self, link=None): |
|---|
| 327 | | - self.link = link |
|---|
| 429 | + def __init__(self, nsimdev, port_index, ifname): |
|---|
| 430 | + # In case udev renamed the netdev to according to new schema, |
|---|
| 431 | + # check if the name matches the port_index. |
|---|
| 432 | + nsimnamere = re.compile("eni\d+np(\d+)") |
|---|
| 433 | + match = nsimnamere.match(ifname) |
|---|
| 434 | + if match and int(match.groups()[0]) != port_index + 1: |
|---|
| 435 | + raise Exception("netdevice name mismatches the expected one") |
|---|
| 328 | 436 | |
|---|
| 329 | | - self.dev = self._netdevsim_create() |
|---|
| 330 | | - devs.append(self) |
|---|
| 331 | | - |
|---|
| 437 | + self.nsimdev = nsimdev |
|---|
| 438 | + self.port_index = port_index |
|---|
| 332 | 439 | self.ns = "" |
|---|
| 333 | | - |
|---|
| 334 | | - self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) |
|---|
| 335 | | - self.sdev_dir = self.dfs_dir + '/sdev/' |
|---|
| 440 | + self.dfs_dir = "%s/ports/%u/" % (nsimdev.dfs_dir, port_index) |
|---|
| 336 | 441 | self.dfs_refresh() |
|---|
| 442 | + _, [self.dev] = ip("link show dev %s" % ifname) |
|---|
| 337 | 443 | |
|---|
| 338 | 444 | def __getitem__(self, key): |
|---|
| 339 | 445 | return self.dev[key] |
|---|
| 340 | 446 | |
|---|
| 341 | | - def _netdevsim_create(self): |
|---|
| 342 | | - link = "" if self.link is None else "link " + self.link.dev['ifname'] |
|---|
| 343 | | - _, old = ip("link show") |
|---|
| 344 | | - ip("link add sim%d {link} type netdevsim".format(link=link)) |
|---|
| 345 | | - _, new = ip("link show") |
|---|
| 346 | | - |
|---|
| 347 | | - for dev in new: |
|---|
| 348 | | - f = filter(lambda x: x["ifname"] == dev["ifname"], old) |
|---|
| 349 | | - if len(list(f)) == 0: |
|---|
| 350 | | - return dev |
|---|
| 351 | | - |
|---|
| 352 | | - raise Exception("failed to create netdevsim device") |
|---|
| 353 | | - |
|---|
| 354 | 447 | def remove(self): |
|---|
| 355 | | - devs.remove(self) |
|---|
| 356 | | - ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns) |
|---|
| 448 | + self.nsimdev.remove_nsim(self) |
|---|
| 357 | 449 | |
|---|
| 358 | 450 | def dfs_refresh(self): |
|---|
| 359 | 451 | self.dfs = DebugfsDir(self.dfs_dir) |
|---|
| .. | .. |
|---|
| 364 | 456 | _, data = cmd('cat %s' % (path)) |
|---|
| 365 | 457 | return data.strip() |
|---|
| 366 | 458 | |
|---|
| 367 | | - def dfs_num_bound_progs(self): |
|---|
| 368 | | - path = os.path.join(self.sdev_dir, "bpf_bound_progs") |
|---|
| 369 | | - _, progs = cmd('ls %s' % (path)) |
|---|
| 370 | | - return len(progs.split()) |
|---|
| 371 | | - |
|---|
| 372 | | - def dfs_get_bound_progs(self, expected): |
|---|
| 373 | | - progs = DebugfsDir(os.path.join(self.sdev_dir, "bpf_bound_progs")) |
|---|
| 374 | | - if expected is not None: |
|---|
| 375 | | - if len(progs) != expected: |
|---|
| 376 | | - fail(True, "%d BPF programs bound, expected %d" % |
|---|
| 377 | | - (len(progs), expected)) |
|---|
| 378 | | - return progs |
|---|
| 379 | | - |
|---|
| 380 | 459 | def wait_for_flush(self, bound=0, total=0, n_retry=20): |
|---|
| 381 | 460 | for i in range(n_retry): |
|---|
| 382 | | - nbound = self.dfs_num_bound_progs() |
|---|
| 461 | + nbound = self.nsimdev.dfs_num_bound_progs() |
|---|
| 383 | 462 | nprogs = len(bpftool_prog_list()) |
|---|
| 384 | 463 | if nbound == bound and nprogs == total: |
|---|
| 385 | 464 | return |
|---|
| .. | .. |
|---|
| 589 | 668 | return |
|---|
| 590 | 669 | fail(True, "Missing or incorrect message from netdevsim in verifier log") |
|---|
| 591 | 670 | |
|---|
| 671 | +def check_multi_basic(two_xdps): |
|---|
| 672 | + fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs") |
|---|
| 673 | + fail("prog" in two_xdps, "Base program reported in multi program mode") |
|---|
| 674 | + fail(len(two_xdps["attached"]) != 2, |
|---|
| 675 | + "Wrong attached program count with two programs") |
|---|
| 676 | + fail(two_xdps["attached"][0]["prog"]["id"] == |
|---|
| 677 | + two_xdps["attached"][1]["prog"]["id"], |
|---|
| 678 | + "Offloaded and other programs have the same id") |
|---|
| 679 | + |
|---|
| 592 | 680 | def test_spurios_extack(sim, obj, skip_hw, needle): |
|---|
| 593 | 681 | res = sim.cls_bpf_add_filter(obj, prio=1, handle=1, skip_hw=skip_hw, |
|---|
| 594 | 682 | include_stderr=True) |
|---|
| .. | .. |
|---|
| 600 | 688 | include_stderr=True) |
|---|
| 601 | 689 | check_no_extack(res, needle) |
|---|
| 602 | 690 | |
|---|
| 691 | +def test_multi_prog(simdev, sim, obj, modename, modeid): |
|---|
| 692 | + start_test("Test multi-attachment XDP - %s + offload..." % |
|---|
| 693 | + (modename or "default", )) |
|---|
| 694 | + sim.set_xdp(obj, "offload") |
|---|
| 695 | + xdp = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 696 | + offloaded = sim.dfs_read("bpf_offloaded_id") |
|---|
| 697 | + fail("prog" not in xdp, "Base program not reported in single program mode") |
|---|
| 698 | + fail(len(xdp["attached"]) != 1, |
|---|
| 699 | + "Wrong attached program count with one program") |
|---|
| 700 | + |
|---|
| 701 | + sim.set_xdp(obj, modename) |
|---|
| 702 | + two_xdps = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 703 | + |
|---|
| 704 | + fail(xdp["attached"][0] not in two_xdps["attached"], |
|---|
| 705 | + "Offload program not reported after other activated") |
|---|
| 706 | + check_multi_basic(two_xdps) |
|---|
| 707 | + |
|---|
| 708 | + offloaded2 = sim.dfs_read("bpf_offloaded_id") |
|---|
| 709 | + fail(offloaded != offloaded2, |
|---|
| 710 | + "Offload ID changed after loading other program") |
|---|
| 711 | + |
|---|
| 712 | + start_test("Test multi-attachment XDP - replace...") |
|---|
| 713 | + ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True) |
|---|
| 714 | + fail(ret == 0, "Replaced one of programs without -force") |
|---|
| 715 | + check_extack(err, "XDP program already attached.", args) |
|---|
| 716 | + |
|---|
| 717 | + start_test("Test multi-attachment XDP - remove without mode...") |
|---|
| 718 | + ret, _, err = sim.unset_xdp("", force=True, |
|---|
| 719 | + fail=False, include_stderr=True) |
|---|
| 720 | + fail(ret == 0, "Removed program without a mode flag") |
|---|
| 721 | + check_extack(err, "More than one program loaded, unset mode is ambiguous.", args) |
|---|
| 722 | + |
|---|
| 723 | + sim.unset_xdp("offload") |
|---|
| 724 | + xdp = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 725 | + offloaded = sim.dfs_read("bpf_offloaded_id") |
|---|
| 726 | + |
|---|
| 727 | + fail(xdp["mode"] != modeid, "Bad mode reported after multiple programs") |
|---|
| 728 | + fail("prog" not in xdp, |
|---|
| 729 | + "Base program not reported after multi program mode") |
|---|
| 730 | + fail(xdp["attached"][0] not in two_xdps["attached"], |
|---|
| 731 | + "Offload program not reported after other activated") |
|---|
| 732 | + fail(len(xdp["attached"]) != 1, |
|---|
| 733 | + "Wrong attached program count with remaining programs") |
|---|
| 734 | + fail(offloaded != "0", "Offload ID reported with only other program left") |
|---|
| 735 | + |
|---|
| 736 | + start_test("Test multi-attachment XDP - reattach...") |
|---|
| 737 | + sim.set_xdp(obj, "offload") |
|---|
| 738 | + two_xdps = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 739 | + |
|---|
| 740 | + fail(xdp["attached"][0] not in two_xdps["attached"], |
|---|
| 741 | + "Other program not reported after offload activated") |
|---|
| 742 | + check_multi_basic(two_xdps) |
|---|
| 743 | + |
|---|
| 744 | + start_test("Test multi-attachment XDP - device remove...") |
|---|
| 745 | + simdev.remove() |
|---|
| 746 | + |
|---|
| 747 | + simdev = NetdevSimDev() |
|---|
| 748 | + sim, = simdev.nsims |
|---|
| 749 | + sim.set_ethtool_tc_offloads(True) |
|---|
| 750 | + return [simdev, sim] |
|---|
| 603 | 751 | |
|---|
| 604 | 752 | # Parse command line |
|---|
| 605 | 753 | parser = argparse.ArgumentParser() |
|---|
| .. | .. |
|---|
| 620 | 768 | skip(ret != 0, "bpftool not installed") |
|---|
| 621 | 769 | base_progs = progs |
|---|
| 622 | 770 | _, base_maps = bpftool("map") |
|---|
| 771 | +base_map_names = [ |
|---|
| 772 | + 'pid_iter.rodata' # created on each bpftool invocation |
|---|
| 773 | +] |
|---|
| 623 | 774 | |
|---|
| 624 | 775 | # Check netdevsim |
|---|
| 625 | 776 | ret, out = cmd("modprobe netdevsim", fail=False) |
|---|
| .. | .. |
|---|
| 656 | 807 | bytecode = bpf_bytecode("1,6 0 0 4294967295,") |
|---|
| 657 | 808 | |
|---|
| 658 | 809 | start_test("Test destruction of generic XDP...") |
|---|
| 659 | | - sim = NetdevSim() |
|---|
| 810 | + simdev = NetdevSimDev() |
|---|
| 811 | + sim, = simdev.nsims |
|---|
| 660 | 812 | sim.set_xdp(obj, "generic") |
|---|
| 661 | | - sim.remove() |
|---|
| 813 | + simdev.remove() |
|---|
| 662 | 814 | bpftool_prog_list_wait(expected=0) |
|---|
| 663 | 815 | |
|---|
| 664 | | - sim = NetdevSim() |
|---|
| 816 | + simdev = NetdevSimDev() |
|---|
| 817 | + sim, = simdev.nsims |
|---|
| 665 | 818 | sim.tc_add_ingress() |
|---|
| 666 | 819 | |
|---|
| 667 | 820 | start_test("Test TC non-offloaded...") |
|---|
| .. | .. |
|---|
| 671 | 824 | start_test("Test TC non-offloaded isn't getting bound...") |
|---|
| 672 | 825 | ret, _ = sim.cls_bpf_add_filter(obj, fail=False) |
|---|
| 673 | 826 | fail(ret != 0, "Software TC filter did not load") |
|---|
| 674 | | - sim.dfs_get_bound_progs(expected=0) |
|---|
| 827 | + simdev.dfs_get_bound_progs(expected=0) |
|---|
| 675 | 828 | |
|---|
| 676 | 829 | sim.tc_flush_filters() |
|---|
| 677 | 830 | |
|---|
| .. | .. |
|---|
| 688 | 841 | start_test("Test TC offload by default...") |
|---|
| 689 | 842 | ret, _ = sim.cls_bpf_add_filter(obj, fail=False) |
|---|
| 690 | 843 | fail(ret != 0, "Software TC filter did not load") |
|---|
| 691 | | - sim.dfs_get_bound_progs(expected=0) |
|---|
| 844 | + simdev.dfs_get_bound_progs(expected=0) |
|---|
| 692 | 845 | ingress = sim.tc_show_ingress(expected=1) |
|---|
| 693 | 846 | fltr = ingress[0] |
|---|
| 694 | 847 | fail(not fltr["in_hw"], "Filter not offloaded by default") |
|---|
| .. | .. |
|---|
| 698 | 851 | start_test("Test TC cBPF bytcode tries offload by default...") |
|---|
| 699 | 852 | ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False) |
|---|
| 700 | 853 | fail(ret != 0, "Software TC filter did not load") |
|---|
| 701 | | - sim.dfs_get_bound_progs(expected=0) |
|---|
| 854 | + simdev.dfs_get_bound_progs(expected=0) |
|---|
| 702 | 855 | ingress = sim.tc_show_ingress(expected=1) |
|---|
| 703 | 856 | fltr = ingress[0] |
|---|
| 704 | 857 | fail(not fltr["in_hw"], "Bytecode not offloaded by default") |
|---|
| .. | .. |
|---|
| 759 | 912 | |
|---|
| 760 | 913 | sim.tc_flush_filters() |
|---|
| 761 | 914 | |
|---|
| 915 | + start_test("Test TC offloads failure...") |
|---|
| 916 | + sim.dfs["dev/bpf_bind_verifier_accept"] = 0 |
|---|
| 917 | + ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True, |
|---|
| 918 | + fail=False, include_stderr=True) |
|---|
| 919 | + fail(ret == 0, "TC filter did not reject with TC offloads enabled") |
|---|
| 920 | + check_verifier_log(err, "[netdevsim] Hello from netdevsim!") |
|---|
| 921 | + sim.dfs["dev/bpf_bind_verifier_accept"] = 1 |
|---|
| 922 | + |
|---|
| 762 | 923 | start_test("Test TC offloads work...") |
|---|
| 763 | 924 | ret, _, err = sim.cls_bpf_add_filter(obj, verbose=True, skip_sw=True, |
|---|
| 764 | 925 | fail=False, include_stderr=True) |
|---|
| 765 | 926 | fail(ret != 0, "TC filter did not load with TC offloads enabled") |
|---|
| 766 | | - check_verifier_log(err, "[netdevsim] Hello from netdevsim!") |
|---|
| 767 | 927 | |
|---|
| 768 | 928 | start_test("Test TC offload basics...") |
|---|
| 769 | | - dfs = sim.dfs_get_bound_progs(expected=1) |
|---|
| 929 | + dfs = simdev.dfs_get_bound_progs(expected=1) |
|---|
| 770 | 930 | progs = bpftool_prog_list(expected=1) |
|---|
| 771 | 931 | ingress = sim.tc_show_ingress(expected=1) |
|---|
| 772 | 932 | |
|---|
| .. | .. |
|---|
| 802 | 962 | |
|---|
| 803 | 963 | start_test("Test destroying device gets rid of TC filters...") |
|---|
| 804 | 964 | sim.cls_bpf_add_filter(obj, skip_sw=True) |
|---|
| 805 | | - sim.remove() |
|---|
| 965 | + simdev.remove() |
|---|
| 806 | 966 | bpftool_prog_list_wait(expected=0) |
|---|
| 807 | 967 | |
|---|
| 808 | | - sim = NetdevSim() |
|---|
| 968 | + simdev = NetdevSimDev() |
|---|
| 969 | + sim, = simdev.nsims |
|---|
| 809 | 970 | sim.set_ethtool_tc_offloads(True) |
|---|
| 810 | 971 | |
|---|
| 811 | 972 | start_test("Test destroying device gets rid of XDP...") |
|---|
| 812 | 973 | sim.set_xdp(obj, "offload") |
|---|
| 813 | | - sim.remove() |
|---|
| 974 | + simdev.remove() |
|---|
| 814 | 975 | bpftool_prog_list_wait(expected=0) |
|---|
| 815 | 976 | |
|---|
| 816 | | - sim = NetdevSim() |
|---|
| 977 | + simdev = NetdevSimDev() |
|---|
| 978 | + sim, = simdev.nsims |
|---|
| 817 | 979 | sim.set_ethtool_tc_offloads(True) |
|---|
| 818 | 980 | |
|---|
| 819 | 981 | start_test("Test XDP prog reporting...") |
|---|
| .. | .. |
|---|
| 843 | 1005 | ret, _, err = sim.set_xdp(obj, "generic", force=True, |
|---|
| 844 | 1006 | fail=False, include_stderr=True) |
|---|
| 845 | 1007 | fail(ret == 0, "Replaced XDP program with a program in different mode") |
|---|
| 846 | | - fail(err.count("File exists") != 1, "Replaced driver XDP with generic") |
|---|
| 847 | | - ret, _, err = sim.set_xdp(obj, "", force=True, |
|---|
| 848 | | - fail=False, include_stderr=True) |
|---|
| 849 | | - fail(ret == 0, "Replaced XDP program with a program in different mode") |
|---|
| 850 | | - check_extack(err, "program loaded with different flags.", args) |
|---|
| 851 | | - |
|---|
| 852 | | - start_test("Test XDP prog remove with bad flags...") |
|---|
| 853 | | - ret, _, err = sim.unset_xdp("", force=True, |
|---|
| 854 | | - fail=False, include_stderr=True) |
|---|
| 855 | | - fail(ret == 0, "Removed program with a bad mode") |
|---|
| 856 | | - check_extack(err, "program loaded with different flags.", args) |
|---|
| 1008 | + check_extack(err, |
|---|
| 1009 | + "Native and generic XDP can't be active at the same time.", |
|---|
| 1010 | + args) |
|---|
| 857 | 1011 | |
|---|
| 858 | 1012 | start_test("Test MTU restrictions...") |
|---|
| 859 | 1013 | ret, _ = sim.set_mtu(9000, fail=False) |
|---|
| .. | .. |
|---|
| 883 | 1037 | offload = bpf_pinned("/sys/fs/bpf/offload") |
|---|
| 884 | 1038 | ret, _, err = sim.set_xdp(offload, "drv", fail=False, include_stderr=True) |
|---|
| 885 | 1039 | fail(ret == 0, "attached offloaded XDP program to drv") |
|---|
| 886 | | - check_extack(err, "using device-bound program without HW_MODE flag is not supported.", args) |
|---|
| 1040 | + check_extack(err, "Using device-bound program without HW_MODE flag is not supported.", args) |
|---|
| 887 | 1041 | rm("/sys/fs/bpf/offload") |
|---|
| 1042 | + sim.wait_for_flush() |
|---|
| 1043 | + |
|---|
| 1044 | + start_test("Test XDP load failure...") |
|---|
| 1045 | + sim.dfs["dev/bpf_bind_verifier_accept"] = 0 |
|---|
| 1046 | + ret, _, err = bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload", |
|---|
| 1047 | + dev=sim['ifname'], fail=False, include_stderr=True) |
|---|
| 1048 | + fail(ret == 0, "verifier should fail on load") |
|---|
| 1049 | + check_verifier_log(err, "[netdevsim] Hello from netdevsim!") |
|---|
| 1050 | + sim.dfs["dev/bpf_bind_verifier_accept"] = 1 |
|---|
| 888 | 1051 | sim.wait_for_flush() |
|---|
| 889 | 1052 | |
|---|
| 890 | 1053 | start_test("Test XDP offload...") |
|---|
| .. | .. |
|---|
| 894 | 1057 | progs = bpftool_prog_list(expected=1) |
|---|
| 895 | 1058 | prog = progs[0] |
|---|
| 896 | 1059 | fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID") |
|---|
| 897 | | - check_verifier_log(err, "[netdevsim] Hello from netdevsim!") |
|---|
| 898 | 1060 | |
|---|
| 899 | 1061 | start_test("Test XDP offload is device bound...") |
|---|
| 900 | | - dfs = sim.dfs_get_bound_progs(expected=1) |
|---|
| 1062 | + dfs = simdev.dfs_get_bound_progs(expected=1) |
|---|
| 901 | 1063 | dprog = dfs[0] |
|---|
| 902 | 1064 | |
|---|
| 903 | 1065 | fail(prog["id"] != link_xdp["id"], "Program IDs don't match") |
|---|
| .. | .. |
|---|
| 916 | 1078 | bpftool_prog_list_wait(expected=0) |
|---|
| 917 | 1079 | |
|---|
| 918 | 1080 | start_test("Test attempt to use a program for a wrong device...") |
|---|
| 919 | | - sim2 = NetdevSim() |
|---|
| 1081 | + simdev2 = NetdevSimDev() |
|---|
| 1082 | + sim2, = simdev2.nsims |
|---|
| 920 | 1083 | sim2.set_xdp(obj, "offload") |
|---|
| 921 | 1084 | pin_file, pinned = pin_prog("/sys/fs/bpf/tmp") |
|---|
| 922 | 1085 | |
|---|
| .. | .. |
|---|
| 924 | 1087 | fail=False, include_stderr=True) |
|---|
| 925 | 1088 | fail(ret == 0, "Pinned program loaded for a different device accepted") |
|---|
| 926 | 1089 | check_extack_nsim(err, "program bound to different dev.", args) |
|---|
| 927 | | - sim2.remove() |
|---|
| 1090 | + simdev2.remove() |
|---|
| 928 | 1091 | ret, _, err = sim.set_xdp(pinned, "offload", |
|---|
| 929 | 1092 | fail=False, include_stderr=True) |
|---|
| 930 | 1093 | fail(ret == 0, "Pinned program loaded for a removed device accepted") |
|---|
| .. | .. |
|---|
| 932 | 1095 | rm(pin_file) |
|---|
| 933 | 1096 | bpftool_prog_list_wait(expected=0) |
|---|
| 934 | 1097 | |
|---|
| 935 | | - start_test("Test multi-attachment XDP - attach...") |
|---|
| 936 | | - sim.set_xdp(obj, "offload") |
|---|
| 937 | | - xdp = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 938 | | - offloaded = sim.dfs_read("bpf_offloaded_id") |
|---|
| 939 | | - fail("prog" not in xdp, "Base program not reported in single program mode") |
|---|
| 940 | | - fail(len(ipl["xdp"]["attached"]) != 1, |
|---|
| 941 | | - "Wrong attached program count with one program") |
|---|
| 942 | | - |
|---|
| 943 | | - sim.set_xdp(obj, "") |
|---|
| 944 | | - two_xdps = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 945 | | - offloaded2 = sim.dfs_read("bpf_offloaded_id") |
|---|
| 946 | | - |
|---|
| 947 | | - fail(two_xdps["mode"] != 4, "Bad mode reported with multiple programs") |
|---|
| 948 | | - fail("prog" in two_xdps, "Base program reported in multi program mode") |
|---|
| 949 | | - fail(xdp["attached"][0] not in two_xdps["attached"], |
|---|
| 950 | | - "Offload program not reported after driver activated") |
|---|
| 951 | | - fail(len(two_xdps["attached"]) != 2, |
|---|
| 952 | | - "Wrong attached program count with two programs") |
|---|
| 953 | | - fail(two_xdps["attached"][0]["prog"]["id"] == |
|---|
| 954 | | - two_xdps["attached"][1]["prog"]["id"], |
|---|
| 955 | | - "offloaded and drv programs have the same id") |
|---|
| 956 | | - fail(offloaded != offloaded2, |
|---|
| 957 | | - "offload ID changed after loading driver program") |
|---|
| 958 | | - |
|---|
| 959 | | - start_test("Test multi-attachment XDP - replace...") |
|---|
| 960 | | - ret, _, err = sim.set_xdp(obj, "offload", fail=False, include_stderr=True) |
|---|
| 961 | | - fail(err.count("busy") != 1, "Replaced one of programs without -force") |
|---|
| 962 | | - |
|---|
| 963 | | - start_test("Test multi-attachment XDP - detach...") |
|---|
| 964 | | - ret, _, err = sim.unset_xdp("drv", force=True, |
|---|
| 965 | | - fail=False, include_stderr=True) |
|---|
| 966 | | - fail(ret == 0, "Removed program with a bad mode") |
|---|
| 967 | | - check_extack(err, "program loaded with different flags.", args) |
|---|
| 968 | | - |
|---|
| 969 | | - sim.unset_xdp("offload") |
|---|
| 970 | | - xdp = sim.ip_link_show(xdp=True)["xdp"] |
|---|
| 971 | | - offloaded = sim.dfs_read("bpf_offloaded_id") |
|---|
| 972 | | - |
|---|
| 973 | | - fail(xdp["mode"] != 1, "Bad mode reported after multiple programs") |
|---|
| 974 | | - fail("prog" not in xdp, |
|---|
| 975 | | - "Base program not reported after multi program mode") |
|---|
| 976 | | - fail(xdp["attached"][0] not in two_xdps["attached"], |
|---|
| 977 | | - "Offload program not reported after driver activated") |
|---|
| 978 | | - fail(len(ipl["xdp"]["attached"]) != 1, |
|---|
| 979 | | - "Wrong attached program count with remaining programs") |
|---|
| 980 | | - fail(offloaded != "0", "offload ID reported with only driver program left") |
|---|
| 981 | | - |
|---|
| 982 | | - start_test("Test multi-attachment XDP - device remove...") |
|---|
| 983 | | - sim.set_xdp(obj, "offload") |
|---|
| 984 | | - sim.remove() |
|---|
| 985 | | - |
|---|
| 986 | | - sim = NetdevSim() |
|---|
| 987 | | - sim.set_ethtool_tc_offloads(True) |
|---|
| 1098 | + simdev, sim = test_multi_prog(simdev, sim, obj, "", 1) |
|---|
| 1099 | + simdev, sim = test_multi_prog(simdev, sim, obj, "drv", 1) |
|---|
| 1100 | + simdev, sim = test_multi_prog(simdev, sim, obj, "generic", 2) |
|---|
| 988 | 1101 | |
|---|
| 989 | 1102 | start_test("Test mixing of TC and XDP...") |
|---|
| 990 | 1103 | sim.tc_add_ingress() |
|---|
| .. | .. |
|---|
| 1031 | 1144 | |
|---|
| 1032 | 1145 | start_test("Test if netdev removal waits for translation...") |
|---|
| 1033 | 1146 | delay_msec = 500 |
|---|
| 1034 | | - sim.dfs["bpf_bind_verifier_delay"] = delay_msec |
|---|
| 1147 | + sim.dfs["dev/bpf_bind_verifier_delay"] = delay_msec |
|---|
| 1035 | 1148 | start = time.time() |
|---|
| 1036 | 1149 | cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \ |
|---|
| 1037 | 1150 | (sim['ifname'], obj) |
|---|
| 1038 | 1151 | tc_proc = cmd(cmd_line, background=True, fail=False) |
|---|
| 1039 | 1152 | # Wait for the verifier to start |
|---|
| 1040 | | - while sim.dfs_num_bound_progs() <= 2: |
|---|
| 1153 | + while simdev.dfs_num_bound_progs() <= 2: |
|---|
| 1041 | 1154 | pass |
|---|
| 1042 | | - sim.remove() |
|---|
| 1155 | + simdev.remove() |
|---|
| 1043 | 1156 | end = time.time() |
|---|
| 1044 | 1157 | ret, _ = cmd_result(tc_proc, fail=False) |
|---|
| 1045 | 1158 | time_diff = end - start |
|---|
| .. | .. |
|---|
| 1054 | 1167 | clean_up() |
|---|
| 1055 | 1168 | bpftool_prog_list_wait(expected=0) |
|---|
| 1056 | 1169 | |
|---|
| 1057 | | - sim = NetdevSim() |
|---|
| 1170 | + simdev = NetdevSimDev() |
|---|
| 1171 | + sim, = simdev.nsims |
|---|
| 1058 | 1172 | map_obj = bpf_obj("sample_map_ret0.o") |
|---|
| 1059 | 1173 | start_test("Test loading program with maps...") |
|---|
| 1060 | 1174 | sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON |
|---|
| .. | .. |
|---|
| 1076 | 1190 | |
|---|
| 1077 | 1191 | prog_file, _ = pin_prog("/sys/fs/bpf/tmp_prog") |
|---|
| 1078 | 1192 | map_file, _ = pin_map("/sys/fs/bpf/tmp_map", idx=1, expected=2) |
|---|
| 1079 | | - sim.remove() |
|---|
| 1193 | + simdev.remove() |
|---|
| 1080 | 1194 | |
|---|
| 1081 | 1195 | start_test("Test bpftool bound info reporting (removed dev)...") |
|---|
| 1082 | 1196 | check_dev_info_removed(prog_file=prog_file, map_file=map_file) |
|---|
| .. | .. |
|---|
| 1085 | 1199 | clean_up() |
|---|
| 1086 | 1200 | bpftool_prog_list_wait(expected=0) |
|---|
| 1087 | 1201 | |
|---|
| 1088 | | - sim = NetdevSim() |
|---|
| 1202 | + simdev = NetdevSimDev() |
|---|
| 1203 | + sim, = simdev.nsims |
|---|
| 1089 | 1204 | |
|---|
| 1090 | 1205 | start_test("Test map update (no flags)...") |
|---|
| 1091 | 1206 | sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON |
|---|
| .. | .. |
|---|
| 1166 | 1281 | start_test("Test map remove...") |
|---|
| 1167 | 1282 | sim.unset_xdp("offload") |
|---|
| 1168 | 1283 | bpftool_map_list_wait(expected=0) |
|---|
| 1169 | | - sim.remove() |
|---|
| 1284 | + simdev.remove() |
|---|
| 1170 | 1285 | |
|---|
| 1171 | | - sim = NetdevSim() |
|---|
| 1286 | + simdev = NetdevSimDev() |
|---|
| 1287 | + sim, = simdev.nsims |
|---|
| 1172 | 1288 | sim.set_xdp(map_obj, "offload", JSON=False) # map fixup msg breaks JSON |
|---|
| 1173 | | - sim.remove() |
|---|
| 1289 | + simdev.remove() |
|---|
| 1174 | 1290 | bpftool_map_list_wait(expected=0) |
|---|
| 1175 | 1291 | |
|---|
| 1176 | 1292 | start_test("Test map creation fail path...") |
|---|
| 1177 | | - sim = NetdevSim() |
|---|
| 1293 | + simdev = NetdevSimDev() |
|---|
| 1294 | + sim, = simdev.nsims |
|---|
| 1178 | 1295 | sim.dfs["bpf_map_accept"] = "N" |
|---|
| 1179 | 1296 | ret, _ = sim.set_xdp(map_obj, "offload", JSON=False, fail=False) |
|---|
| 1180 | 1297 | fail(ret == 0, |
|---|
| 1181 | 1298 | "netdevsim didn't refuse to create a map with offload disabled") |
|---|
| 1182 | 1299 | |
|---|
| 1183 | | - sim.remove() |
|---|
| 1300 | + simdev.remove() |
|---|
| 1184 | 1301 | |
|---|
| 1185 | 1302 | start_test("Test multi-dev ASIC program reuse...") |
|---|
| 1186 | | - simA = NetdevSim() |
|---|
| 1187 | | - simB1 = NetdevSim() |
|---|
| 1188 | | - simB2 = NetdevSim(link=simB1) |
|---|
| 1189 | | - simB3 = NetdevSim(link=simB1) |
|---|
| 1303 | + simdevA = NetdevSimDev() |
|---|
| 1304 | + simA, = simdevA.nsims |
|---|
| 1305 | + simdevB = NetdevSimDev(3) |
|---|
| 1306 | + simB1, simB2, simB3 = simdevB.nsims |
|---|
| 1190 | 1307 | sims = (simA, simB1, simB2, simB3) |
|---|
| 1191 | 1308 | simB = (simB1, simB2, simB3) |
|---|
| 1192 | 1309 | |
|---|
| .. | .. |
|---|
| 1198 | 1315 | progB = bpf_pinned("/sys/fs/bpf/nsimB") |
|---|
| 1199 | 1316 | |
|---|
| 1200 | 1317 | simA.set_xdp(progA, "offload", JSON=False) |
|---|
| 1201 | | - for d in simB: |
|---|
| 1318 | + for d in simdevB.nsims: |
|---|
| 1202 | 1319 | d.set_xdp(progB, "offload", JSON=False) |
|---|
| 1203 | 1320 | |
|---|
| 1204 | 1321 | start_test("Test multi-dev ASIC cross-dev replace...") |
|---|
| 1205 | 1322 | ret, _ = simA.set_xdp(progB, "offload", force=True, JSON=False, fail=False) |
|---|
| 1206 | 1323 | fail(ret == 0, "cross-ASIC program allowed") |
|---|
| 1207 | | - for d in simB: |
|---|
| 1324 | + for d in simdevB.nsims: |
|---|
| 1208 | 1325 | ret, _ = d.set_xdp(progA, "offload", force=True, JSON=False, fail=False) |
|---|
| 1209 | 1326 | fail(ret == 0, "cross-ASIC program allowed") |
|---|
| 1210 | 1327 | |
|---|
| .. | .. |
|---|
| 1216 | 1333 | fail=False, include_stderr=True) |
|---|
| 1217 | 1334 | fail(ret == 0, "cross-ASIC program allowed") |
|---|
| 1218 | 1335 | check_extack_nsim(err, "program bound to different dev.", args) |
|---|
| 1219 | | - for d in simB: |
|---|
| 1336 | + for d in simdevB.nsims: |
|---|
| 1220 | 1337 | ret, _, err = d.set_xdp(progA, "offload", force=True, JSON=False, |
|---|
| 1221 | 1338 | fail=False, include_stderr=True) |
|---|
| 1222 | 1339 | fail(ret == 0, "cross-ASIC program allowed") |
|---|
| .. | .. |
|---|
| 1253 | 1370 | start_test("Test multi-dev ASIC cross-dev destruction...") |
|---|
| 1254 | 1371 | bpftool_prog_list_wait(expected=2) |
|---|
| 1255 | 1372 | |
|---|
| 1256 | | - simA.remove() |
|---|
| 1373 | + simdevA.remove() |
|---|
| 1257 | 1374 | bpftool_prog_list_wait(expected=1) |
|---|
| 1258 | 1375 | |
|---|
| 1259 | 1376 | ifnameB = bpftool("prog show %s" % (progB))[1]["dev"]["ifname"] |
|---|
| 1260 | | - fail(ifnameB != simB1['ifname'], "program not bound to originial device") |
|---|
| 1377 | + fail(ifnameB != simB1['ifname'], "program not bound to original device") |
|---|
| 1261 | 1378 | simB1.remove() |
|---|
| 1262 | 1379 | bpftool_prog_list_wait(expected=1) |
|---|
| 1263 | 1380 | |
|---|
| .. | .. |
|---|
| 1271 | 1388 | fail(ifnameB != simB3['ifname'], "program not bound to remaining device") |
|---|
| 1272 | 1389 | |
|---|
| 1273 | 1390 | simB3.remove() |
|---|
| 1391 | + simdevB.remove() |
|---|
| 1274 | 1392 | bpftool_prog_list_wait(expected=0) |
|---|
| 1275 | 1393 | |
|---|
| 1276 | 1394 | start_test("Test multi-dev ASIC cross-dev destruction - orphaned...") |
|---|