1#!/usr/bin/python3 2 3# Copyright (C) 2017 Netronome Systems, Inc. 4# 5# This software is licensed under the GNU General License Version 2, 6# June 1991 as shown in the file COPYING in the top-level directory of this 7# source tree. 8# 9# THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" 10# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 11# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 12# FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 13# OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 14# THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 15 16from datetime import datetime 17import argparse 18import json 19import os 20import pprint 21import random 22import string 23import subprocess 24import time 25 26logfile = None 27log_level = 1 28bpf_test_dir = os.path.dirname(os.path.realpath(__file__)) 29pp = pprint.PrettyPrinter() 30devs = [] # devices we created for clean up 31files = [] # files to be removed 32netns = [] # net namespaces to be removed 33 34def log_get_sec(level=0): 35 return "*" * (log_level + level) 36 37def log_level_inc(add=1): 38 global log_level 39 log_level += add 40 41def log_level_dec(sub=1): 42 global log_level 43 log_level -= sub 44 45def log_level_set(level): 46 global log_level 47 log_level = level 48 49def log(header, data, level=None): 50 """ 51 Output to an optional log. 52 """ 53 if logfile is None: 54 return 55 if level is not None: 56 log_level_set(level) 57 58 if not isinstance(data, str): 59 data = pp.pformat(data) 60 61 if len(header): 62 logfile.write("\n" + log_get_sec() + " ") 63 logfile.write(header) 64 if len(header) and len(data.strip()): 65 logfile.write("\n") 66 logfile.write(data) 67 68def skip(cond, msg): 69 if not cond: 70 return 71 print("SKIP: " + msg) 72 log("SKIP: " + msg, "", level=1) 73 os.sys.exit(0) 74 75def fail(cond, msg): 76 if not cond: 77 return 78 print("FAIL: " + msg) 79 log("FAIL: " + msg, "", level=1) 80 os.sys.exit(1) 81 82def start_test(msg): 83 log(msg, "", level=1) 84 log_level_inc() 85 print(msg) 86 87def cmd(cmd, shell=True, include_stderr=False, background=False, fail=True): 88 """ 89 Run a command in subprocess and return tuple of (retval, stdout); 90 optionally return stderr as well as third value. 91 """ 92 proc = subprocess.Popen(cmd, shell=shell, stdout=subprocess.PIPE, 93 stderr=subprocess.PIPE) 94 if background: 95 msg = "%s START: %s" % (log_get_sec(1), 96 datetime.now().strftime("%H:%M:%S.%f")) 97 log("BKG " + proc.args, msg) 98 return proc 99 100 return cmd_result(proc, include_stderr=include_stderr, fail=fail) 101 102def cmd_result(proc, include_stderr=False, fail=False): 103 stdout, stderr = proc.communicate() 104 stdout = stdout.decode("utf-8") 105 stderr = stderr.decode("utf-8") 106 proc.stdout.close() 107 proc.stderr.close() 108 109 stderr = "\n" + stderr 110 if stderr[-1] == "\n": 111 stderr = stderr[:-1] 112 113 sec = log_get_sec(1) 114 log("CMD " + proc.args, 115 "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" % 116 (proc.returncode, sec, stdout, sec, stderr, 117 sec, datetime.now().strftime("%H:%M:%S.%f"))) 118 119 if proc.returncode != 0 and fail: 120 if len(stderr) > 0 and stderr[-1] == "\n": 121 stderr = stderr[:-1] 122 raise Exception("Command failed: %s\n%s" % (proc.args, stderr)) 123 124 if include_stderr: 125 return proc.returncode, stdout, stderr 126 else: 127 return proc.returncode, stdout 128 129def rm(f): 130 cmd("rm -f %s" % (f)) 131 if f in files: 132 files.remove(f) 133 134def tool(name, args, flags, JSON=True, ns="", fail=True): 135 params = "" 136 if JSON: 137 params += "%s " % (flags["json"]) 138 139 if ns != "": 140 ns = "ip netns exec %s " % (ns) 141 142 ret, out = cmd(ns + name + " " + params + args, fail=fail) 143 if JSON and len(out.strip()) != 0: 144 return ret, json.loads(out) 145 else: 146 return ret, out 147 148def bpftool(args, JSON=True, ns="", fail=True): 149 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail) 150 151def bpftool_prog_list(expected=None, ns=""): 152 _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) 153 if expected is not None: 154 if len(progs) != expected: 155 fail(True, "%d BPF programs loaded, expected %d" % 156 (len(progs), expected)) 157 return progs 158 159def bpftool_prog_list_wait(expected=0, n_retry=20): 160 for i in range(n_retry): 161 nprogs = len(bpftool_prog_list()) 162 if nprogs == expected: 163 return 164 time.sleep(0.05) 165 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs)) 166 167def ip(args, force=False, JSON=True, ns="", fail=True): 168 if force: 169 args = "-force " + args 170 return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns, fail=fail) 171 172def tc(args, JSON=True, ns="", fail=True): 173 return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail) 174 175def ethtool(dev, opt, args, fail=True): 176 return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail) 177 178def bpf_obj(name, sec=".text", path=bpf_test_dir,): 179 return "obj %s sec %s" % (os.path.join(path, name), sec) 180 181def bpf_pinned(name): 182 return "pinned %s" % (name) 183 184def bpf_bytecode(bytecode): 185 return "bytecode \"%s\"" % (bytecode) 186 187def mknetns(n_retry=10): 188 for i in range(n_retry): 189 name = ''.join([random.choice(string.ascii_letters) for i in range(8)]) 190 ret, _ = ip("netns add %s" % (name), fail=False) 191 if ret == 0: 192 netns.append(name) 193 return name 194 return None 195 196class DebugfsDir: 197 """ 198 Class for accessing DebugFS directories as a dictionary. 199 """ 200 201 def __init__(self, path): 202 self.path = path 203 self._dict = self._debugfs_dir_read(path) 204 205 def __len__(self): 206 return len(self._dict.keys()) 207 208 def __getitem__(self, key): 209 if type(key) is int: 210 key = list(self._dict.keys())[key] 211 return self._dict[key] 212 213 def __setitem__(self, key, value): 214 log("DebugFS set %s = %s" % (key, value), "") 215 log_level_inc() 216 217 cmd("echo '%s' > %s/%s" % (value, self.path, key)) 218 log_level_dec() 219 220 _, out = cmd('cat %s/%s' % (self.path, key)) 221 self._dict[key] = out.strip() 222 223 def _debugfs_dir_read(self, path): 224 dfs = {} 225 226 log("DebugFS state for %s" % (path), "") 227 log_level_inc(add=2) 228 229 _, out = cmd('ls ' + path) 230 for f in out.split(): 231 p = os.path.join(path, f) 232 if os.path.isfile(p): 233 _, out = cmd('cat %s/%s' % (path, f)) 234 dfs[f] = out.strip() 235 elif os.path.isdir(p): 236 dfs[f] = DebugfsDir(p) 237 else: 238 raise Exception("%s is neither file nor directory" % (p)) 239 240 log_level_dec() 241 log("DebugFS state", dfs) 242 log_level_dec() 243 244 return dfs 245 246class NetdevSim: 247 """ 248 Class for netdevsim netdevice and its attributes. 249 """ 250 251 def __init__(self): 252 self.dev = self._netdevsim_create() 253 devs.append(self) 254 255 self.ns = "" 256 257 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) 258 self.dfs_refresh() 259 260 def __getitem__(self, key): 261 return self.dev[key] 262 263 def _netdevsim_create(self): 264 _, old = ip("link show") 265 ip("link add sim%d type netdevsim") 266 _, new = ip("link show") 267 268 for dev in new: 269 f = filter(lambda x: x["ifname"] == dev["ifname"], old) 270 if len(list(f)) == 0: 271 return dev 272 273 raise Exception("failed to create netdevsim device") 274 275 def remove(self): 276 devs.remove(self) 277 ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns) 278 279 def dfs_refresh(self): 280 self.dfs = DebugfsDir(self.dfs_dir) 281 return self.dfs 282 283 def dfs_num_bound_progs(self): 284 path = os.path.join(self.dfs_dir, "bpf_bound_progs") 285 _, progs = cmd('ls %s' % (path)) 286 return len(progs.split()) 287 288 def dfs_get_bound_progs(self, expected): 289 progs = DebugfsDir(os.path.join(self.dfs_dir, "bpf_bound_progs")) 290 if expected is not None: 291 if len(progs) != expected: 292 fail(True, "%d BPF programs bound, expected %d" % 293 (len(progs), expected)) 294 return progs 295 296 def wait_for_flush(self, bound=0, total=0, n_retry=20): 297 for i in range(n_retry): 298 nbound = self.dfs_num_bound_progs() 299 nprogs = len(bpftool_prog_list()) 300 if nbound == bound and nprogs == total: 301 return 302 time.sleep(0.05) 303 raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs)) 304 305 def set_ns(self, ns): 306 name = "1" if ns == "" else ns 307 ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns) 308 self.ns = ns 309 310 def set_mtu(self, mtu, fail=True): 311 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu), 312 fail=fail) 313 314 def set_xdp(self, bpf, mode, force=False, fail=True): 315 return ip("link set dev %s xdp%s %s" % (self.dev["ifname"], mode, bpf), 316 force=force, fail=fail) 317 318 def unset_xdp(self, mode, force=False, fail=True): 319 return ip("link set dev %s xdp%s off" % (self.dev["ifname"], mode), 320 force=force, fail=fail) 321 322 def ip_link_show(self, xdp): 323 _, link = ip("link show dev %s" % (self['ifname'])) 324 if len(link) > 1: 325 raise Exception("Multiple objects on ip link show") 326 if len(link) < 1: 327 return {} 328 fail(xdp != "xdp" in link, 329 "XDP program not reporting in iplink (reported %s, expected %s)" % 330 ("xdp" in link, xdp)) 331 return link[0] 332 333 def tc_add_ingress(self): 334 tc("qdisc add dev %s ingress" % (self['ifname'])) 335 336 def tc_del_ingress(self): 337 tc("qdisc del dev %s ingress" % (self['ifname'])) 338 339 def tc_flush_filters(self, bound=0, total=0): 340 self.tc_del_ingress() 341 self.tc_add_ingress() 342 self.wait_for_flush(bound=bound, total=total) 343 344 def tc_show_ingress(self, expected=None): 345 # No JSON support, oh well... 346 flags = ["skip_sw", "skip_hw", "in_hw"] 347 named = ["protocol", "pref", "chain", "handle", "id", "tag"] 348 349 args = "-s filter show dev %s ingress" % (self['ifname']) 350 _, out = tc(args, JSON=False) 351 352 filters = [] 353 lines = out.split('\n') 354 for line in lines: 355 words = line.split() 356 if "handle" not in words: 357 continue 358 fltr = {} 359 for flag in flags: 360 fltr[flag] = flag in words 361 for name in named: 362 try: 363 idx = words.index(name) 364 fltr[name] = words[idx + 1] 365 except ValueError: 366 pass 367 filters.append(fltr) 368 369 if expected is not None: 370 fail(len(filters) != expected, 371 "%d ingress filters loaded, expected %d" % 372 (len(filters), expected)) 373 return filters 374 375 def cls_bpf_add_filter(self, bpf, da=False, skip_sw=False, skip_hw=False, 376 fail=True): 377 params = "" 378 if da: 379 params += " da" 380 if skip_sw: 381 params += " skip_sw" 382 if skip_hw: 383 params += " skip_hw" 384 return tc("filter add dev %s ingress bpf %s %s" % 385 (self['ifname'], bpf, params), fail=fail) 386 387 def set_ethtool_tc_offloads(self, enable, fail=True): 388 args = "hw-tc-offload %s" % ("on" if enable else "off") 389 return ethtool(self, "-K", args, fail=fail) 390 391################################################################################ 392def clean_up(): 393 for dev in devs: 394 dev.remove() 395 for f in files: 396 cmd("rm -f %s" % (f)) 397 for ns in netns: 398 cmd("ip netns delete %s" % (ns)) 399 400def pin_prog(file_name, idx=0): 401 progs = bpftool_prog_list(expected=(idx + 1)) 402 prog = progs[idx] 403 bpftool("prog pin id %d %s" % (prog["id"], file_name)) 404 files.append(file_name) 405 406 return file_name, bpf_pinned(file_name) 407 408def check_dev_info(other_ns, ns, pin_file=None, removed=False): 409 if removed: 410 bpftool_prog_list(expected=0) 411 ret, err = bpftool("prog show pin %s" % (pin_file), fail=False) 412 fail(ret == 0, "Showing prog with removed device did not fail") 413 fail(err["error"].find("No such device") == -1, 414 "Showing prog with removed device expected ENODEV, error is %s" % 415 (err["error"])) 416 return 417 progs = bpftool_prog_list(expected=int(not removed), ns=ns) 418 prog = progs[0] 419 420 fail("dev" not in prog.keys(), "Device parameters not reported") 421 dev = prog["dev"] 422 fail("ifindex" not in dev.keys(), "Device parameters not reported") 423 fail("ns_dev" not in dev.keys(), "Device parameters not reported") 424 fail("ns_inode" not in dev.keys(), "Device parameters not reported") 425 426 if not removed and not other_ns: 427 fail("ifname" not in dev.keys(), "Ifname not reported") 428 fail(dev["ifname"] != sim["ifname"], 429 "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"])) 430 else: 431 fail("ifname" in dev.keys(), "Ifname is reported for other ns") 432 if removed: 433 fail(dev["ifindex"] != 0, "Device perameters not zero on removed") 434 fail(dev["ns_dev"] != 0, "Device perameters not zero on removed") 435 fail(dev["ns_inode"] != 0, "Device perameters not zero on removed") 436 437# Parse command line 438parser = argparse.ArgumentParser() 439parser.add_argument("--log", help="output verbose log to given file") 440args = parser.parse_args() 441if args.log: 442 logfile = open(args.log, 'w+') 443 logfile.write("# -*-Org-*-") 444 445log("Prepare...", "", level=1) 446log_level_inc() 447 448# Check permissions 449skip(os.getuid() != 0, "test must be run as root") 450 451# Check tools 452ret, progs = bpftool("prog", fail=False) 453skip(ret != 0, "bpftool not installed") 454# Check no BPF programs are loaded 455skip(len(progs) != 0, "BPF programs already loaded on the system") 456 457# Check netdevsim 458ret, out = cmd("modprobe netdevsim", fail=False) 459skip(ret != 0, "netdevsim module could not be loaded") 460 461# Check debugfs 462_, out = cmd("mount") 463if out.find("/sys/kernel/debug type debugfs") == -1: 464 cmd("mount -t debugfs none /sys/kernel/debug") 465 466# Check samples are compiled 467samples = ["sample_ret0.o"] 468for s in samples: 469 ret, out = cmd("ls %s/%s" % (bpf_test_dir, s), fail=False) 470 skip(ret != 0, "sample %s/%s not found, please compile it" % 471 (bpf_test_dir, s)) 472 473# Check if net namespaces seem to work 474ns = mknetns() 475skip(ns is None, "Could not create a net namespace") 476cmd("ip netns delete %s" % (ns)) 477netns = [] 478 479try: 480 obj = bpf_obj("sample_ret0.o") 481 bytecode = bpf_bytecode("1,6 0 0 4294967295,") 482 483 start_test("Test destruction of generic XDP...") 484 sim = NetdevSim() 485 sim.set_xdp(obj, "generic") 486 sim.remove() 487 bpftool_prog_list_wait(expected=0) 488 489 sim = NetdevSim() 490 sim.tc_add_ingress() 491 492 start_test("Test TC non-offloaded...") 493 ret, _ = sim.cls_bpf_add_filter(obj, skip_hw=True, fail=False) 494 fail(ret != 0, "Software TC filter did not load") 495 496 start_test("Test TC non-offloaded isn't getting bound...") 497 ret, _ = sim.cls_bpf_add_filter(obj, fail=False) 498 fail(ret != 0, "Software TC filter did not load") 499 sim.dfs_get_bound_progs(expected=0) 500 501 sim.tc_flush_filters() 502 503 start_test("Test TC offloads are off by default...") 504 ret, _ = sim.cls_bpf_add_filter(obj, skip_sw=True, fail=False) 505 fail(ret == 0, "TC filter loaded without enabling TC offloads") 506 sim.wait_for_flush() 507 508 sim.set_ethtool_tc_offloads(True) 509 sim.dfs["bpf_tc_non_bound_accept"] = "Y" 510 511 start_test("Test TC offload by default...") 512 ret, _ = sim.cls_bpf_add_filter(obj, fail=False) 513 fail(ret != 0, "Software TC filter did not load") 514 sim.dfs_get_bound_progs(expected=0) 515 ingress = sim.tc_show_ingress(expected=1) 516 fltr = ingress[0] 517 fail(not fltr["in_hw"], "Filter not offloaded by default") 518 519 sim.tc_flush_filters() 520 521 start_test("Test TC cBPF bytcode tries offload by default...") 522 ret, _ = sim.cls_bpf_add_filter(bytecode, fail=False) 523 fail(ret != 0, "Software TC filter did not load") 524 sim.dfs_get_bound_progs(expected=0) 525 ingress = sim.tc_show_ingress(expected=1) 526 fltr = ingress[0] 527 fail(not fltr["in_hw"], "Bytecode not offloaded by default") 528 529 sim.tc_flush_filters() 530 sim.dfs["bpf_tc_non_bound_accept"] = "N" 531 532 start_test("Test TC cBPF unbound bytecode doesn't offload...") 533 ret, _ = sim.cls_bpf_add_filter(bytecode, skip_sw=True, fail=False) 534 fail(ret == 0, "TC bytecode loaded for offload") 535 sim.wait_for_flush() 536 537 start_test("Test TC offloads work...") 538 ret, _ = sim.cls_bpf_add_filter(obj, skip_sw=True, fail=False) 539 fail(ret != 0, "TC filter did not load with TC offloads enabled") 540 541 start_test("Test TC offload basics...") 542 dfs = sim.dfs_get_bound_progs(expected=1) 543 progs = bpftool_prog_list(expected=1) 544 ingress = sim.tc_show_ingress(expected=1) 545 546 dprog = dfs[0] 547 prog = progs[0] 548 fltr = ingress[0] 549 fail(fltr["skip_hw"], "TC does reports 'skip_hw' on offloaded filter") 550 fail(not fltr["in_hw"], "TC does not report 'in_hw' for offloaded filter") 551 fail(not fltr["skip_sw"], "TC does not report 'skip_sw' back") 552 553 start_test("Test TC offload is device-bound...") 554 fail(str(prog["id"]) != fltr["id"], "Program IDs don't match") 555 fail(prog["tag"] != fltr["tag"], "Program tags don't match") 556 fail(fltr["id"] != dprog["id"], "Program IDs don't match") 557 fail(dprog["state"] != "xlated", "Offloaded program state not translated") 558 fail(dprog["loaded"] != "Y", "Offloaded program is not loaded") 559 560 start_test("Test disabling TC offloads is rejected while filters installed...") 561 ret, _ = sim.set_ethtool_tc_offloads(False, fail=False) 562 fail(ret == 0, "Driver should refuse to disable TC offloads with filters installed...") 563 564 start_test("Test qdisc removal frees things...") 565 sim.tc_flush_filters() 566 sim.tc_show_ingress(expected=0) 567 568 start_test("Test disabling TC offloads is OK without filters...") 569 ret, _ = sim.set_ethtool_tc_offloads(False, fail=False) 570 fail(ret != 0, 571 "Driver refused to disable TC offloads without filters installed...") 572 573 sim.set_ethtool_tc_offloads(True) 574 575 start_test("Test destroying device gets rid of TC filters...") 576 sim.cls_bpf_add_filter(obj, skip_sw=True) 577 sim.remove() 578 bpftool_prog_list_wait(expected=0) 579 580 sim = NetdevSim() 581 sim.set_ethtool_tc_offloads(True) 582 583 start_test("Test destroying device gets rid of XDP...") 584 sim.set_xdp(obj, "offload") 585 sim.remove() 586 bpftool_prog_list_wait(expected=0) 587 588 sim = NetdevSim() 589 sim.set_ethtool_tc_offloads(True) 590 591 start_test("Test XDP prog reporting...") 592 sim.set_xdp(obj, "drv") 593 ipl = sim.ip_link_show(xdp=True) 594 progs = bpftool_prog_list(expected=1) 595 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], 596 "Loaded program has wrong ID") 597 598 start_test("Test XDP prog replace without force...") 599 ret, _ = sim.set_xdp(obj, "drv", fail=False) 600 fail(ret == 0, "Replaced XDP program without -force") 601 sim.wait_for_flush(total=1) 602 603 start_test("Test XDP prog replace with force...") 604 ret, _ = sim.set_xdp(obj, "drv", force=True, fail=False) 605 fail(ret != 0, "Could not replace XDP program with -force") 606 bpftool_prog_list_wait(expected=1) 607 ipl = sim.ip_link_show(xdp=True) 608 progs = bpftool_prog_list(expected=1) 609 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], 610 "Loaded program has wrong ID") 611 fail("dev" in progs[0].keys(), 612 "Device parameters reported for non-offloaded program") 613 614 start_test("Test XDP prog replace with bad flags...") 615 ret, _ = sim.set_xdp(obj, "offload", force=True, fail=False) 616 fail(ret == 0, "Replaced XDP program with a program in different mode") 617 ret, _ = sim.set_xdp(obj, "", force=True, fail=False) 618 fail(ret == 0, "Replaced XDP program with a program in different mode") 619 620 start_test("Test XDP prog remove with bad flags...") 621 ret, _ = sim.unset_xdp("offload", force=True, fail=False) 622 fail(ret == 0, "Removed program with a bad mode mode") 623 ret, _ = sim.unset_xdp("", force=True, fail=False) 624 fail(ret == 0, "Removed program with a bad mode mode") 625 626 start_test("Test MTU restrictions...") 627 ret, _ = sim.set_mtu(9000, fail=False) 628 fail(ret == 0, 629 "Driver should refuse to increase MTU to 9000 with XDP loaded...") 630 sim.unset_xdp("drv") 631 bpftool_prog_list_wait(expected=0) 632 sim.set_mtu(9000) 633 ret, _ = sim.set_xdp(obj, "drv", fail=False) 634 fail(ret == 0, "Driver should refuse to load program with MTU of 9000...") 635 sim.set_mtu(1500) 636 637 sim.wait_for_flush() 638 start_test("Test XDP offload...") 639 sim.set_xdp(obj, "offload") 640 ipl = sim.ip_link_show(xdp=True) 641 link_xdp = ipl["xdp"]["prog"] 642 progs = bpftool_prog_list(expected=1) 643 prog = progs[0] 644 fail(link_xdp["id"] != prog["id"], "Loaded program has wrong ID") 645 646 start_test("Test XDP offload is device bound...") 647 dfs = sim.dfs_get_bound_progs(expected=1) 648 dprog = dfs[0] 649 650 fail(prog["id"] != link_xdp["id"], "Program IDs don't match") 651 fail(prog["tag"] != link_xdp["tag"], "Program tags don't match") 652 fail(str(link_xdp["id"]) != dprog["id"], "Program IDs don't match") 653 fail(dprog["state"] != "xlated", "Offloaded program state not translated") 654 fail(dprog["loaded"] != "Y", "Offloaded program is not loaded") 655 656 start_test("Test removing XDP program many times...") 657 sim.unset_xdp("offload") 658 sim.unset_xdp("offload") 659 sim.unset_xdp("drv") 660 sim.unset_xdp("drv") 661 sim.unset_xdp("") 662 sim.unset_xdp("") 663 bpftool_prog_list_wait(expected=0) 664 665 start_test("Test attempt to use a program for a wrong device...") 666 sim2 = NetdevSim() 667 sim2.set_xdp(obj, "offload") 668 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp") 669 670 ret, _ = sim.set_xdp(pinned, "offload", fail=False) 671 fail(ret == 0, "Pinned program loaded for a different device accepted") 672 sim2.remove() 673 ret, _ = sim.set_xdp(pinned, "offload", fail=False) 674 fail(ret == 0, "Pinned program loaded for a removed device accepted") 675 rm(pin_file) 676 bpftool_prog_list_wait(expected=0) 677 678 start_test("Test mixing of TC and XDP...") 679 sim.tc_add_ingress() 680 sim.set_xdp(obj, "offload") 681 ret, _ = sim.cls_bpf_add_filter(obj, skip_sw=True, fail=False) 682 fail(ret == 0, "Loading TC when XDP active should fail") 683 sim.unset_xdp("offload") 684 sim.wait_for_flush() 685 686 sim.cls_bpf_add_filter(obj, skip_sw=True) 687 ret, _ = sim.set_xdp(obj, "offload", fail=False) 688 fail(ret == 0, "Loading XDP when TC active should fail") 689 690 start_test("Test binding TC from pinned...") 691 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp") 692 sim.tc_flush_filters(bound=1, total=1) 693 sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True) 694 sim.tc_flush_filters(bound=1, total=1) 695 696 start_test("Test binding XDP from pinned...") 697 sim.set_xdp(obj, "offload") 698 pin_file, pinned = pin_prog("/sys/fs/bpf/tmp2", idx=1) 699 700 sim.set_xdp(pinned, "offload", force=True) 701 sim.unset_xdp("offload") 702 sim.set_xdp(pinned, "offload", force=True) 703 sim.unset_xdp("offload") 704 705 start_test("Test offload of wrong type fails...") 706 ret, _ = sim.cls_bpf_add_filter(pinned, da=True, skip_sw=True, fail=False) 707 fail(ret == 0, "Managed to attach XDP program to TC") 708 709 start_test("Test asking for TC offload of two filters...") 710 sim.cls_bpf_add_filter(obj, da=True, skip_sw=True) 711 ret, _ = sim.cls_bpf_add_filter(obj, da=True, skip_sw=True, fail=False) 712 fail(ret == 0, "Managed to offload two TC filters at the same time") 713 714 sim.tc_flush_filters(bound=2, total=2) 715 716 start_test("Test if netdev removal waits for translation...") 717 delay_msec = 500 718 sim.dfs["bpf_bind_verifier_delay"] = delay_msec 719 start = time.time() 720 cmd_line = "tc filter add dev %s ingress bpf %s da skip_sw" % \ 721 (sim['ifname'], obj) 722 tc_proc = cmd(cmd_line, background=True, fail=False) 723 # Wait for the verifier to start 724 while sim.dfs_num_bound_progs() <= 2: 725 pass 726 sim.remove() 727 end = time.time() 728 ret, _ = cmd_result(tc_proc, fail=False) 729 time_diff = end - start 730 log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start, end, time_diff)) 731 732 fail(ret == 0, "Managed to load TC filter on a unregistering device") 733 delay_sec = delay_msec * 0.001 734 fail(time_diff < delay_sec, "Removal process took %s, expected %s" % 735 (time_diff, delay_sec)) 736 737 # Remove all pinned files and reinstantiate the netdev 738 clean_up() 739 bpftool_prog_list_wait(expected=0) 740 741 sim = NetdevSim() 742 sim.set_ethtool_tc_offloads(True) 743 sim.set_xdp(obj, "offload") 744 745 start_test("Test bpftool bound info reporting (own ns)...") 746 check_dev_info(False, "") 747 748 start_test("Test bpftool bound info reporting (other ns)...") 749 ns = mknetns() 750 sim.set_ns(ns) 751 check_dev_info(True, "") 752 753 start_test("Test bpftool bound info reporting (remote ns)...") 754 check_dev_info(False, ns) 755 756 start_test("Test bpftool bound info reporting (back to own ns)...") 757 sim.set_ns("") 758 check_dev_info(False, "") 759 760 pin_file, _ = pin_prog("/sys/fs/bpf/tmp") 761 sim.remove() 762 763 start_test("Test bpftool bound info reporting (removed dev)...") 764 check_dev_info(True, "", pin_file=pin_file, removed=True) 765 766 print("%s: OK" % (os.path.basename(__file__))) 767 768finally: 769 log("Clean up...", "", level=1) 770 log_level_inc() 771 clean_up() 772