3 # Copyright (C) 2017 Netronome Systems, Inc.
4 # Copyright (c) 2019 Mellanox Technologies. All rights reserved
6 # This software is licensed under the GNU General License Version 2,
7 # June 1991 as shown in the file COPYING in the top-level directory of this
10 # THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
11 # WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
12 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 # FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
14 # OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
15 # THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
17 from datetime
import datetime
35 bpf_test_dir
= os
.path
.dirname(os
.path
.realpath(__file__
))
36 pp
= pprint
.PrettyPrinter()
37 devs
= [] # devices we created for clean up
38 files
= [] # files to be removed
39 netns
= [] # net namespaces to be removed
41 def log_get_sec(level
=0):
42 return "*" * (log_level
+ level
)
44 def log_level_inc(add
=1):
48 def log_level_dec(sub
=1):
52 def log_level_set(level
):
56 def log(header
, data
, level
=None):
58 Output to an optional log.
65 if not isinstance(data
, str):
66 data
= pp
.pformat(data
)
69 logfile
.write("\n" + log_get_sec() + " ")
71 if len(header
) and len(data
.strip()):
79 log("SKIP: " + msg
, "", level
=1)
86 tb
= "".join(traceback
.extract_stack().format())
88 log("FAIL: " + msg
, tb
, level
=1)
96 def cmd(cmd
, shell
=True, include_stderr
=False, background
=False, fail
=True):
98 Run a command in subprocess and return tuple of (retval, stdout);
99 optionally return stderr as well as third value.
101 proc
= subprocess
.Popen(cmd
, shell
=shell
, stdout
=subprocess
.PIPE
,
102 stderr
=subprocess
.PIPE
)
104 msg
= "%s START: %s" % (log_get_sec(1),
105 datetime
.now().strftime("%H:%M:%S.%f"))
106 log("BKG " + proc
.args
, msg
)
109 return cmd_result(proc
, include_stderr
=include_stderr
, fail
=fail
)
111 def cmd_result(proc
, include_stderr
=False, fail
=False):
112 stdout
, stderr
= proc
.communicate()
113 stdout
= stdout
.decode("utf-8")
114 stderr
= stderr
.decode("utf-8")
118 stderr
= "\n" + stderr
119 if stderr
[-1] == "\n":
123 log("CMD " + proc
.args
,
124 "RETCODE: %d\n%s STDOUT:\n%s%s STDERR:%s\n%s END: %s" %
125 (proc
.returncode
, sec
, stdout
, sec
, stderr
,
126 sec
, datetime
.now().strftime("%H:%M:%S.%f")))
128 if proc
.returncode
!= 0 and fail
:
129 if len(stderr
) > 0 and stderr
[-1] == "\n":
131 raise Exception("Command failed: %s\n%s" % (proc
.args
, stderr
))
134 return proc
.returncode
, stdout
, stderr
136 return proc
.returncode
, stdout
139 cmd("rm -f %s" % (f
))
143 def tool(name
, args
, flags
, JSON
=True, ns
="", fail
=True, include_stderr
=False):
146 params
+= "%s " % (flags
["json"])
149 ns
= "ip netns exec %s " % (ns
)
152 ret
, stdout
, stderr
= cmd(ns
+ name
+ " " + params
+ args
,
153 fail
=fail
, include_stderr
=True)
155 ret
, stdout
= cmd(ns
+ name
+ " " + params
+ args
,
156 fail
=fail
, include_stderr
=False)
158 if JSON
and len(stdout
.strip()) != 0:
159 out
= json
.loads(stdout
)
164 return ret
, out
, stderr
168 def bpftool(args
, JSON
=True, ns
="", fail
=True, include_stderr
=False):
169 return tool("bpftool", args
, {"json":"-p"}, JSON
=JSON
, ns
=ns
,
170 fail
=fail
, include_stderr
=include_stderr
)
172 def bpftool_prog_list(expected
=None, ns
=""):
173 _
, progs
= bpftool("prog show", JSON
=True, ns
=ns
, fail
=True)
174 # Remove the base progs
178 if expected
is not None:
179 if len(progs
) != expected
:
180 fail(True, "%d BPF programs loaded, expected %d" %
181 (len(progs
), expected
))
184 def bpftool_map_list(expected
=None, ns
=""):
185 _
, maps
= bpftool("map show", JSON
=True, ns
=ns
, fail
=True)
186 # Remove the base maps
190 if expected
is not None:
191 if len(maps
) != expected
:
192 fail(True, "%d BPF maps loaded, expected %d" %
193 (len(maps
), expected
))
196 def bpftool_prog_list_wait(expected
=0, n_retry
=20):
197 for i
in range(n_retry
):
198 nprogs
= len(bpftool_prog_list())
199 if nprogs
== expected
:
202 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected
, nprogs
))
204 def bpftool_map_list_wait(expected
=0, n_retry
=20):
205 for i
in range(n_retry
):
206 nmaps
= len(bpftool_map_list())
207 if nmaps
== expected
:
210 raise Exception("Time out waiting for map counts to stabilize want %d, have %d" % (expected
, nmaps
))
212 def bpftool_prog_load(sample
, file_name
, maps
=[], prog_type
="xdp", dev
=None,
213 fail
=True, include_stderr
=False):
214 args
= "prog load %s %s" % (os
.path
.join(bpf_test_dir
, sample
), file_name
)
215 if prog_type
is not None:
216 args
+= " type " + prog_type
218 args
+= " dev " + dev
220 args
+= " map " + " map ".join(maps
)
222 res
= bpftool(args
, fail
=fail
, include_stderr
=include_stderr
)
224 files
.append(file_name
)
227 def ip(args
, force
=False, JSON
=True, ns
="", fail
=True, include_stderr
=False):
229 args
= "-force " + args
230 return tool("ip", args
, {"json":"-j"}, JSON
=JSON
, ns
=ns
,
231 fail
=fail
, include_stderr
=include_stderr
)
233 def tc(args
, JSON
=True, ns
="", fail
=True, include_stderr
=False):
234 return tool("tc", args
, {"json":"-p"}, JSON
=JSON
, ns
=ns
,
235 fail
=fail
, include_stderr
=include_stderr
)
237 def ethtool(dev
, opt
, args
, fail
=True):
238 return cmd("ethtool %s %s %s" % (opt
, dev
["ifname"], args
), fail
=fail
)
240 def bpf_obj(name
, sec
=".text", path
=bpf_test_dir
,):
241 return "obj %s sec %s" % (os
.path
.join(path
, name
), sec
)
243 def bpf_pinned(name
):
244 return "pinned %s" % (name
)
246 def bpf_bytecode(bytecode
):
247 return "bytecode \"%s\"" % (bytecode
)
249 def mknetns(n_retry
=10):
250 for i
in range(n_retry
):
251 name
= ''.join([random
.choice(string
.ascii_letters
) for i
in range(8)])
252 ret
, _
= ip("netns add %s" % (name
), fail
=False)
258 def int2str(fmt
, val
):
260 for b
in struct
.pack(fmt
, val
):
262 return " ".join(map(lambda x
: str(x
), ret
))
267 inttab
.append(int(i
, 16))
268 ba
= bytearray(inttab
)
271 elif len(strtab
) == 8:
274 raise Exception("String array of len %d can't be unpacked to an int" %
276 return struct
.unpack(fmt
, ba
)[0]
280 Class for accessing DebugFS directories as a dictionary.
283 def __init__(self
, path
):
285 self
._dict
= self
._debugfs
_dir
_read
(path
)
288 return len(self
._dict
.keys())
290 def __getitem__(self
, key
):
292 key
= list(self
._dict
.keys())[key
]
293 return self
._dict
[key
]
295 def __setitem__(self
, key
, value
):
296 log("DebugFS set %s = %s" % (key
, value
), "")
299 cmd("echo '%s' > %s/%s" % (value
, self
.path
, key
))
302 _
, out
= cmd('cat %s/%s' % (self
.path
, key
))
303 self
._dict
[key
] = out
.strip()
305 def _debugfs_dir_read(self
, path
):
308 log("DebugFS state for %s" % (path
), "")
311 _
, out
= cmd('ls ' + path
)
312 for f
in out
.split():
316 p
= os
.path
.join(path
, f
)
317 if not os
.stat(p
).st_mode
& stat
.S_IRUSR
:
320 if os
.path
.isfile(p
):
321 _
, out
= cmd('cat %s/%s' % (path
, f
))
323 elif os
.path
.isdir(p
):
324 dfs
[f
] = DebugfsDir(p
)
326 raise Exception("%s is neither file nor directory" % (p
))
329 log("DebugFS state", dfs
)
336 Class for netdevsim bus device and its attributes.
339 def ctrl_write(path
, val
):
340 fullpath
= os
.path
.join("/sys/bus/netdevsim/", path
)
342 with
open(fullpath
, "w") as f
:
345 log("WRITE %s: %r" % (fullpath
, val
), -e
.errno
)
347 log("WRITE %s: %r" % (fullpath
, val
), 0)
349 def __init__(self
, port_count
=1):
353 self
.ctrl_write("new_device", "%u %u" % (addr
, port_count
))
355 if e
.errno
== errno
.ENOSPC
:
362 # As probe of netdevsim device might happen from a workqueue,
363 # so wait here until all netdevs appear.
364 self
.wait_for_netdevs(port_count
)
366 ret
, out
= cmd("udevadm settle", fail
=False)
368 raise Exception("udevadm settle failed")
369 ifnames
= self
.get_ifnames()
372 self
.dfs_dir
= "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
375 for port_index
in range(port_count
):
376 self
.nsims
.append(NetdevSim(self
, port_index
, ifnames
[port_index
]))
378 def get_ifnames(self
):
380 listdir
= os
.listdir("/sys/bus/netdevsim/devices/netdevsim%u/net/" % self
.addr
)
381 for ifname
in listdir
:
382 ifnames
.append(ifname
)
386 def wait_for_netdevs(self
, port_count
):
388 timeout_start
= time
.time()
392 ifnames
= self
.get_ifnames()
393 except FileNotFoundError
as e
:
395 if len(ifnames
) == port_count
:
397 if time
.time() < timeout_start
+ timeout
:
399 raise Exception("netdevices did not appear within timeout")
401 def dfs_num_bound_progs(self
):
402 path
= os
.path
.join(self
.dfs_dir
, "bpf_bound_progs")
403 _
, progs
= cmd('ls %s' % (path
))
404 return len(progs
.split())
406 def dfs_get_bound_progs(self
, expected
):
407 progs
= DebugfsDir(os
.path
.join(self
.dfs_dir
, "bpf_bound_progs"))
408 if expected
is not None:
409 if len(progs
) != expected
:
410 fail(True, "%d BPF programs bound, expected %d" %
411 (len(progs
), expected
))
415 self
.ctrl_write("del_device", "%u" % (self
.addr
, ))
418 def remove_nsim(self
, nsim
):
419 self
.nsims
.remove(nsim
)
420 self
.ctrl_write("devices/netdevsim%u/del_port" % (self
.addr
, ),
421 "%u" % (nsim
.port_index
, ))
425 Class for netdevsim netdevice and its attributes.
428 def __init__(self
, nsimdev
, port_index
, ifname
):
429 # In case udev renamed the netdev to according to new schema,
430 # check if the name matches the port_index.
431 nsimnamere
= re
.compile("eni\d+np(\d+)")
432 match
= nsimnamere
.match(ifname
)
433 if match
and int(match
.groups()[0]) != port_index
+ 1:
434 raise Exception("netdevice name mismatches the expected one")
436 self
.nsimdev
= nsimdev
437 self
.port_index
= port_index
439 self
.dfs_dir
= "%s/ports/%u/" % (nsimdev
.dfs_dir
, port_index
)
441 _
, [self
.dev
] = ip("link show dev %s" % ifname
)
443 def __getitem__(self
, key
):
447 self
.nsimdev
.remove_nsim(self
)
449 def dfs_refresh(self
):
450 self
.dfs
= DebugfsDir(self
.dfs_dir
)
453 def dfs_read(self
, f
):
454 path
= os
.path
.join(self
.dfs_dir
, f
)
455 _
, data
= cmd('cat %s' % (path
))
458 def wait_for_flush(self
, bound
=0, total
=0, n_retry
=20):
459 for i
in range(n_retry
):
460 nbound
= self
.nsimdev
.dfs_num_bound_progs()
461 nprogs
= len(bpftool_prog_list())
462 if nbound
== bound
and nprogs
== total
:
465 raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound
, total
, nbound
, nprogs
))
467 def set_ns(self
, ns
):
468 name
= "1" if ns
== "" else ns
469 ip("link set dev %s netns %s" % (self
.dev
["ifname"], name
), ns
=self
.ns
)
472 def set_mtu(self
, mtu
, fail
=True):
473 return ip("link set dev %s mtu %d" % (self
.dev
["ifname"], mtu
),
476 def set_xdp(self
, bpf
, mode
, force
=False, JSON
=True, verbose
=False,
477 fail
=True, include_stderr
=False):
480 return ip("link set dev %s xdp%s %s" % (self
.dev
["ifname"], mode
, bpf
),
481 force
=force
, JSON
=JSON
,
482 fail
=fail
, include_stderr
=include_stderr
)
484 def unset_xdp(self
, mode
, force
=False, JSON
=True,
485 fail
=True, include_stderr
=False):
486 return ip("link set dev %s xdp%s off" % (self
.dev
["ifname"], mode
),
487 force
=force
, JSON
=JSON
,
488 fail
=fail
, include_stderr
=include_stderr
)
490 def ip_link_show(self
, xdp
):
491 _
, link
= ip("link show dev %s" % (self
['ifname']))
493 raise Exception("Multiple objects on ip link show")
496 fail(xdp
!= "xdp" in link
,
497 "XDP program not reporting in iplink (reported %s, expected %s)" %
498 ("xdp" in link
, xdp
))
501 def tc_add_ingress(self
):
502 tc("qdisc add dev %s ingress" % (self
['ifname']))
504 def tc_del_ingress(self
):
505 tc("qdisc del dev %s ingress" % (self
['ifname']))
507 def tc_flush_filters(self
, bound
=0, total
=0):
508 self
.tc_del_ingress()
509 self
.tc_add_ingress()
510 self
.wait_for_flush(bound
=bound
, total
=total
)
512 def tc_show_ingress(self
, expected
=None):
513 # No JSON support, oh well...
514 flags
= ["skip_sw", "skip_hw", "in_hw"]
515 named
= ["protocol", "pref", "chain", "handle", "id", "tag"]
517 args
= "-s filter show dev %s ingress" % (self
['ifname'])
518 _
, out
= tc(args
, JSON
=False)
521 lines
= out
.split('\n')
524 if "handle" not in words
:
528 fltr
[flag
] = flag
in words
531 idx
= words
.index(name
)
532 fltr
[name
] = words
[idx
+ 1]
537 if expected
is not None:
538 fail(len(filters
) != expected
,
539 "%d ingress filters loaded, expected %d" %
540 (len(filters
), expected
))
543 def cls_filter_op(self
, op
, qdisc
="ingress", prio
=None, handle
=None,
544 chain
=None, cls
="", params
="",
545 fail
=True, include_stderr
=False):
548 spec
+= " prio %d" % (prio
)
550 spec
+= " handle %s" % (handle
)
551 if chain
is not None:
552 spec
+= " chain %d" % (chain
)
554 return tc("filter {op} dev {dev} {qdisc} {spec} {cls} {params}"\
555 .format(op
=op
, dev
=self
['ifname'], qdisc
=qdisc
, spec
=spec
,
556 cls
=cls
, params
=params
),
557 fail
=fail
, include_stderr
=include_stderr
)
559 def cls_bpf_add_filter(self
, bpf
, op
="add", prio
=None, handle
=None,
560 chain
=None, da
=False, verbose
=False,
561 skip_sw
=False, skip_hw
=False,
562 fail
=True, include_stderr
=False):
575 return self
.cls_filter_op(op
=op
, prio
=prio
, handle
=handle
, cls
=cls
,
576 chain
=chain
, params
=params
,
577 fail
=fail
, include_stderr
=include_stderr
)
579 def set_ethtool_tc_offloads(self
, enable
, fail
=True):
580 args
= "hw-tc-offload %s" % ("on" if enable
else "off")
581 return ethtool(self
, "-K", args
, fail
=fail
)
583 ################################################################################
585 global files
, netns
, devs
590 cmd("rm -f %s" % (f
))
592 cmd("ip netns delete %s" % (ns
))
596 def pin_prog(file_name
, idx
=0):
597 progs
= bpftool_prog_list(expected
=(idx
+ 1))
599 bpftool("prog pin id %d %s" % (prog
["id"], file_name
))
600 files
.append(file_name
)
602 return file_name
, bpf_pinned(file_name
)
604 def pin_map(file_name
, idx
=0, expected
=1):
605 maps
= bpftool_map_list(expected
=expected
)
607 bpftool("map pin id %d %s" % (m
["id"], file_name
))
608 files
.append(file_name
)
610 return file_name
, bpf_pinned(file_name
)
612 def check_dev_info_removed(prog_file
=None, map_file
=None):
613 bpftool_prog_list(expected
=0)
614 ret
, err
= bpftool("prog show pin %s" % (prog_file
), fail
=False)
615 fail(ret
== 0, "Showing prog with removed device did not fail")
616 fail(err
["error"].find("No such device") == -1,
617 "Showing prog with removed device expected ENODEV, error is %s" %
620 bpftool_map_list(expected
=0)
621 ret
, err
= bpftool("map show pin %s" % (map_file
), fail
=False)
622 fail(ret
== 0, "Showing map with removed device did not fail")
623 fail(err
["error"].find("No such device") == -1,
624 "Showing map with removed device expected ENODEV, error is %s" %
627 def check_dev_info(other_ns
, ns
, prog_file
=None, map_file
=None, removed
=False):
628 progs
= bpftool_prog_list(expected
=1, ns
=ns
)
631 fail("dev" not in prog
.keys(), "Device parameters not reported")
633 fail("ifindex" not in dev
.keys(), "Device parameters not reported")
634 fail("ns_dev" not in dev
.keys(), "Device parameters not reported")
635 fail("ns_inode" not in dev
.keys(), "Device parameters not reported")
638 fail("ifname" not in dev
.keys(), "Ifname not reported")
639 fail(dev
["ifname"] != sim
["ifname"],
640 "Ifname incorrect %s vs %s" % (dev
["ifname"], sim
["ifname"]))
642 fail("ifname" in dev
.keys(), "Ifname is reported for other ns")
644 maps
= bpftool_map_list(expected
=2, ns
=ns
)
646 fail("dev" not in m
.keys(), "Device parameters not reported")
647 fail(dev
!= m
["dev"], "Map's device different than program's")
649 def check_extack(output
, reference
, args
):
652 lines
= output
.split("\n")
653 comp
= len(lines
) >= 2 and lines
[1] == 'Error: ' + reference
654 fail(not comp
, "Missing or incorrect netlink extack message")
656 def check_extack_nsim(output
, reference
, args
):
657 check_extack(output
, "netdevsim: " + reference
, args
)
659 def check_no_extack(res
, needle
):
660 fail((res
[1] + res
[2]).count(needle
) or (res
[1] + res
[2]).count("Warning:"),
661 "Found '%s' in command output, leaky extack?" % (needle
))
663 def check_verifier_log(output
, reference
):
664 lines
= output
.split("\n")
665 for l
in reversed(lines
):
668 fail(True, "Missing or incorrect message from netdevsim in verifier log")
670 def check_multi_basic(two_xdps
):
671 fail(two_xdps
["mode"] != 4, "Bad mode reported with multiple programs")
672 fail("prog" in two_xdps
, "Base program reported in multi program mode")
673 fail(len(two_xdps
["attached"]) != 2,
674 "Wrong attached program count with two programs")
675 fail(two_xdps
["attached"][0]["prog"]["id"] ==
676 two_xdps
["attached"][1]["prog"]["id"],
677 "Offloaded and other programs have the same id")
679 def test_spurios_extack(sim
, obj
, skip_hw
, needle
):
680 res
= sim
.cls_bpf_add_filter(obj
, prio
=1, handle
=1, skip_hw
=skip_hw
,
682 check_no_extack(res
, needle
)
683 res
= sim
.cls_bpf_add_filter(obj
, op
="replace", prio
=1, handle
=1,
684 skip_hw
=skip_hw
, include_stderr
=True)
685 check_no_extack(res
, needle
)
686 res
= sim
.cls_filter_op(op
="delete", prio
=1, handle
=1, cls
="bpf",
688 check_no_extack(res
, needle
)
690 def test_multi_prog(simdev
, sim
, obj
, modename
, modeid
):
691 start_test("Test multi-attachment XDP - %s + offload..." %
692 (modename
or "default", ))
693 sim
.set_xdp(obj
, "offload")
694 xdp
= sim
.ip_link_show(xdp
=True)["xdp"]
695 offloaded
= sim
.dfs_read("bpf_offloaded_id")
696 fail("prog" not in xdp
, "Base program not reported in single program mode")
697 fail(len(xdp
["attached"]) != 1,
698 "Wrong attached program count with one program")
700 sim
.set_xdp(obj
, modename
)
701 two_xdps
= sim
.ip_link_show(xdp
=True)["xdp"]
703 fail(xdp
["attached"][0] not in two_xdps
["attached"],
704 "Offload program not reported after other activated")
705 check_multi_basic(two_xdps
)
707 offloaded2
= sim
.dfs_read("bpf_offloaded_id")
708 fail(offloaded
!= offloaded2
,
709 "Offload ID changed after loading other program")
711 start_test("Test multi-attachment XDP - replace...")
712 ret
, _
, err
= sim
.set_xdp(obj
, "offload", fail
=False, include_stderr
=True)
713 fail(ret
== 0, "Replaced one of programs without -force")
714 check_extack(err
, "XDP program already attached.", args
)
716 if modename
== "" or modename
== "drv":
717 othermode
= "" if modename
== "drv" else "drv"
718 start_test("Test multi-attachment XDP - detach...")
719 ret
, _
, err
= sim
.unset_xdp(othermode
, force
=True,
720 fail
=False, include_stderr
=True)
721 fail(ret
== 0, "Removed program with a bad mode")
722 check_extack(err
, "program loaded with different flags.", args
)
724 sim
.unset_xdp("offload")
725 xdp
= sim
.ip_link_show(xdp
=True)["xdp"]
726 offloaded
= sim
.dfs_read("bpf_offloaded_id")
728 fail(xdp
["mode"] != modeid
, "Bad mode reported after multiple programs")
729 fail("prog" not in xdp
,
730 "Base program not reported after multi program mode")
731 fail(xdp
["attached"][0] not in two_xdps
["attached"],
732 "Offload program not reported after other activated")
733 fail(len(xdp
["attached"]) != 1,
734 "Wrong attached program count with remaining programs")
735 fail(offloaded
!= "0", "Offload ID reported with only other program left")
737 start_test("Test multi-attachment XDP - reattach...")
738 sim
.set_xdp(obj
, "offload")
739 two_xdps
= sim
.ip_link_show(xdp
=True)["xdp"]
741 fail(xdp
["attached"][0] not in two_xdps
["attached"],
742 "Other program not reported after offload activated")
743 check_multi_basic(two_xdps
)
745 start_test("Test multi-attachment XDP - device remove...")
748 simdev
= NetdevSimDev()
750 sim
.set_ethtool_tc_offloads(True)
754 parser
= argparse
.ArgumentParser()
755 parser
.add_argument("--log", help="output verbose log to given file")
756 args
= parser
.parse_args()
758 logfile
= open(args
.log
, 'w+')
759 logfile
.write("# -*-Org-*-")
761 log("Prepare...", "", level
=1)
765 skip(os
.getuid() != 0, "test must be run as root")
768 ret
, progs
= bpftool("prog", fail
=False)
769 skip(ret
!= 0, "bpftool not installed")
771 _
, base_maps
= bpftool("map")
774 ret
, out
= cmd("modprobe netdevsim", fail
=False)
775 skip(ret
!= 0, "netdevsim module could not be loaded")
778 _
, out
= cmd("mount")
779 if out
.find("/sys/kernel/debug type debugfs") == -1:
780 cmd("mount -t debugfs none /sys/kernel/debug")
782 # Check samples are compiled
783 samples
= ["sample_ret0.o", "sample_map_ret0.o"]
785 ret
, out
= cmd("ls %s/%s" % (bpf_test_dir
, s
), fail
=False)
786 skip(ret
!= 0, "sample %s/%s not found, please compile it" %
789 # Check if iproute2 is built with libmnl (needed by extack support)
790 _
, _
, err
= cmd("tc qdisc delete dev lo handle 0",
791 fail
=False, include_stderr
=True)
792 if err
.find("Error: Failed to find qdisc with specified handle.") == -1:
793 print("Warning: no extack message in iproute2 output, libmnl missing?")
794 log("Warning: no extack message in iproute2 output, libmnl missing?", "")
797 # Check if net namespaces seem to work
799 skip(ns
is None, "Could not create a net namespace")
800 cmd("ip netns delete %s" % (ns
))
804 obj
= bpf_obj("sample_ret0.o")
805 bytecode
= bpf_bytecode("1,6 0 0 4294967295,")
807 start_test("Test destruction of generic XDP...")
808 simdev
= NetdevSimDev()
810 sim
.set_xdp(obj
, "generic")
812 bpftool_prog_list_wait(expected
=0)
814 simdev
= NetdevSimDev()
818 start_test("Test TC non-offloaded...")
819 ret
, _
= sim
.cls_bpf_add_filter(obj
, skip_hw
=True, fail
=False)
820 fail(ret
!= 0, "Software TC filter did not load")
822 start_test("Test TC non-offloaded isn't getting bound...")
823 ret
, _
= sim
.cls_bpf_add_filter(obj
, fail
=False)
824 fail(ret
!= 0, "Software TC filter did not load")
825 simdev
.dfs_get_bound_progs(expected
=0)
827 sim
.tc_flush_filters()
829 start_test("Test TC offloads are off by default...")
830 ret
, _
, err
= sim
.cls_bpf_add_filter(obj
, skip_sw
=True,
831 fail
=False, include_stderr
=True)
832 fail(ret
== 0, "TC filter loaded without enabling TC offloads")
833 check_extack(err
, "TC offload is disabled on net device.", args
)
836 sim
.set_ethtool_tc_offloads(True)
837 sim
.dfs
["bpf_tc_non_bound_accept"] = "Y"
839 start_test("Test TC offload by default...")
840 ret
, _
= sim
.cls_bpf_add_filter(obj
, fail
=False)
841 fail(ret
!= 0, "Software TC filter did not load")
842 simdev
.dfs_get_bound_progs(expected
=0)
843 ingress
= sim
.tc_show_ingress(expected
=1)
845 fail(not fltr
["in_hw"], "Filter not offloaded by default")
847 sim
.tc_flush_filters()
849 start_test("Test TC cBPF bytcode tries offload by default...")
850 ret
, _
= sim
.cls_bpf_add_filter(bytecode
, fail
=False)
851 fail(ret
!= 0, "Software TC filter did not load")
852 simdev
.dfs_get_bound_progs(expected
=0)
853 ingress
= sim
.tc_show_ingress(expected
=1)
855 fail(not fltr
["in_hw"], "Bytecode not offloaded by default")
857 sim
.tc_flush_filters()
858 sim
.dfs
["bpf_tc_non_bound_accept"] = "N"
860 start_test("Test TC cBPF unbound bytecode doesn't offload...")
861 ret
, _
, err
= sim
.cls_bpf_add_filter(bytecode
, skip_sw
=True,
862 fail
=False, include_stderr
=True)
863 fail(ret
== 0, "TC bytecode loaded for offload")
864 check_extack_nsim(err
, "netdevsim configured to reject unbound programs.",
868 start_test("Test non-0 chain offload...")
869 ret
, _
, err
= sim
.cls_bpf_add_filter(obj
, chain
=1, prio
=1, handle
=1,
871 fail
=False, include_stderr
=True)
872 fail(ret
== 0, "Offloaded a filter to chain other than 0")
873 check_extack(err
, "Driver supports only offload of chain 0.", args
)
874 sim
.tc_flush_filters()
876 start_test("Test TC replace...")
877 sim
.cls_bpf_add_filter(obj
, prio
=1, handle
=1)
878 sim
.cls_bpf_add_filter(obj
, op
="replace", prio
=1, handle
=1)
879 sim
.cls_filter_op(op
="delete", prio
=1, handle
=1, cls
="bpf")
881 sim
.cls_bpf_add_filter(obj
, prio
=1, handle
=1, skip_sw
=True)
882 sim
.cls_bpf_add_filter(obj
, op
="replace", prio
=1, handle
=1, skip_sw
=True)
883 sim
.cls_filter_op(op
="delete", prio
=1, handle
=1, cls
="bpf")
885 sim
.cls_bpf_add_filter(obj
, prio
=1, handle
=1, skip_hw
=True)
886 sim
.cls_bpf_add_filter(obj
, op
="replace", prio
=1, handle
=1, skip_hw
=True)
887 sim
.cls_filter_op(op
="delete", prio
=1, handle
=1, cls
="bpf")
889 start_test("Test TC replace bad flags...")
892 ret
, _
= sim
.cls_bpf_add_filter(obj
, op
="replace", prio
=1, handle
=1,
893 skip_sw
=(j
== 1), skip_hw
=(j
== 2),
895 fail(bool(ret
) != bool(j
),
896 "Software TC incorrect load in replace test, iteration %d" %
898 sim
.cls_filter_op(op
="delete", prio
=1, handle
=1, cls
="bpf")
900 start_test("Test spurious extack from the driver...")
901 test_spurios_extack(sim
, obj
, False, "netdevsim")
902 test_spurios_extack(sim
, obj
, True, "netdevsim")
904 sim
.set_ethtool_tc_offloads(False)
906 test_spurios_extack(sim
, obj
, False, "TC offload is disabled")
907 test_spurios_extack(sim
, obj
, True, "TC offload is disabled")
909 sim
.set_ethtool_tc_offloads(True)
911 sim
.tc_flush_filters()
913 start_test("Test TC offloads work...")
914 ret
, _
, err
= sim
.cls_bpf_add_filter(obj
, verbose
=True, skip_sw
=True,
915 fail
=False, include_stderr
=True)
916 fail(ret
!= 0, "TC filter did not load with TC offloads enabled")
917 check_verifier_log(err
, "[netdevsim] Hello from netdevsim!")
919 start_test("Test TC offload basics...")
920 dfs
= simdev
.dfs_get_bound_progs(expected
=1)
921 progs
= bpftool_prog_list(expected
=1)
922 ingress
= sim
.tc_show_ingress(expected
=1)
927 fail(fltr
["skip_hw"], "TC does reports 'skip_hw' on offloaded filter")
928 fail(not fltr
["in_hw"], "TC does not report 'in_hw' for offloaded filter")
929 fail(not fltr
["skip_sw"], "TC does not report 'skip_sw' back")
931 start_test("Test TC offload is device-bound...")
932 fail(str(prog
["id"]) != fltr
["id"], "Program IDs don't match")
933 fail(prog
["tag"] != fltr
["tag"], "Program tags don't match")
934 fail(fltr
["id"] != dprog
["id"], "Program IDs don't match")
935 fail(dprog
["state"] != "xlated", "Offloaded program state not translated")
936 fail(dprog
["loaded"] != "Y", "Offloaded program is not loaded")
938 start_test("Test disabling TC offloads is rejected while filters installed...")
939 ret
, _
= sim
.set_ethtool_tc_offloads(False, fail
=False)
940 fail(ret
== 0, "Driver should refuse to disable TC offloads with filters installed...")
942 start_test("Test qdisc removal frees things...")
943 sim
.tc_flush_filters()
944 sim
.tc_show_ingress(expected
=0)
946 start_test("Test disabling TC offloads is OK without filters...")
947 ret
, _
= sim
.set_ethtool_tc_offloads(False, fail
=False)
949 "Driver refused to disable TC offloads without filters installed...")
951 sim
.set_ethtool_tc_offloads(True)
953 start_test("Test destroying device gets rid of TC filters...")
954 sim
.cls_bpf_add_filter(obj
, skip_sw
=True)
956 bpftool_prog_list_wait(expected
=0)
958 simdev
= NetdevSimDev()
960 sim
.set_ethtool_tc_offloads(True)
962 start_test("Test destroying device gets rid of XDP...")
963 sim
.set_xdp(obj
, "offload")
965 bpftool_prog_list_wait(expected
=0)
967 simdev
= NetdevSimDev()
969 sim
.set_ethtool_tc_offloads(True)
971 start_test("Test XDP prog reporting...")
972 sim
.set_xdp(obj
, "drv")
973 ipl
= sim
.ip_link_show(xdp
=True)
974 progs
= bpftool_prog_list(expected
=1)
975 fail(ipl
["xdp"]["prog"]["id"] != progs
[0]["id"],
976 "Loaded program has wrong ID")
978 start_test("Test XDP prog replace without force...")
979 ret
, _
= sim
.set_xdp(obj
, "drv", fail
=False)
980 fail(ret
== 0, "Replaced XDP program without -force")
981 sim
.wait_for_flush(total
=1)
983 start_test("Test XDP prog replace with force...")
984 ret
, _
= sim
.set_xdp(obj
, "drv", force
=True, fail
=False)
985 fail(ret
!= 0, "Could not replace XDP program with -force")
986 bpftool_prog_list_wait(expected
=1)
987 ipl
= sim
.ip_link_show(xdp
=True)
988 progs
= bpftool_prog_list(expected
=1)
989 fail(ipl
["xdp"]["prog"]["id"] != progs
[0]["id"],
990 "Loaded program has wrong ID")
991 fail("dev" in progs
[0].keys(),
992 "Device parameters reported for non-offloaded program")
994 start_test("Test XDP prog replace with bad flags...")
995 ret
, _
, err
= sim
.set_xdp(obj
, "generic", force
=True,
996 fail
=False, include_stderr
=True)
997 fail(ret
== 0, "Replaced XDP program with a program in different mode")
999 "native and generic XDP can't be active at the same time.",
1001 ret
, _
, err
= sim
.set_xdp(obj
, "", force
=True,
1002 fail
=False, include_stderr
=True)
1003 fail(ret
== 0, "Replaced XDP program with a program in different mode")
1004 check_extack(err
, "program loaded with different flags.", args
)
1006 start_test("Test XDP prog remove with bad flags...")
1007 ret
, _
, err
= sim
.unset_xdp("", force
=True,
1008 fail
=False, include_stderr
=True)
1009 fail(ret
== 0, "Removed program with a bad mode")
1010 check_extack(err
, "program loaded with different flags.", args
)
1012 start_test("Test MTU restrictions...")
1013 ret
, _
= sim
.set_mtu(9000, fail
=False)
1015 "Driver should refuse to increase MTU to 9000 with XDP loaded...")
1016 sim
.unset_xdp("drv")
1017 bpftool_prog_list_wait(expected
=0)
1019 ret
, _
, err
= sim
.set_xdp(obj
, "drv", fail
=False, include_stderr
=True)
1020 fail(ret
== 0, "Driver should refuse to load program with MTU of 9000...")
1021 check_extack_nsim(err
, "MTU too large w/ XDP enabled.", args
)
1024 sim
.wait_for_flush()
1025 start_test("Test non-offload XDP attaching to HW...")
1026 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/nooffload")
1027 nooffload
= bpf_pinned("/sys/fs/bpf/nooffload")
1028 ret
, _
, err
= sim
.set_xdp(nooffload
, "offload",
1029 fail
=False, include_stderr
=True)
1030 fail(ret
== 0, "attached non-offloaded XDP program to HW")
1031 check_extack_nsim(err
, "xdpoffload of non-bound program.", args
)
1032 rm("/sys/fs/bpf/nooffload")
1034 start_test("Test offload XDP attaching to drv...")
1035 bpftool_prog_load("sample_ret0.o", "/sys/fs/bpf/offload",
1037 offload
= bpf_pinned("/sys/fs/bpf/offload")
1038 ret
, _
, err
= sim
.set_xdp(offload
, "drv", fail
=False, include_stderr
=True)
1039 fail(ret
== 0, "attached offloaded XDP program to drv")
1040 check_extack(err
, "using device-bound program without HW_MODE flag is not supported.", args
)
1041 rm("/sys/fs/bpf/offload")
1042 sim
.wait_for_flush()
1044 start_test("Test XDP offload...")
1045 _
, _
, err
= sim
.set_xdp(obj
, "offload", verbose
=True, include_stderr
=True)
1046 ipl
= sim
.ip_link_show(xdp
=True)
1047 link_xdp
= ipl
["xdp"]["prog"]
1048 progs
= bpftool_prog_list(expected
=1)
1050 fail(link_xdp
["id"] != prog
["id"], "Loaded program has wrong ID")
1051 check_verifier_log(err
, "[netdevsim] Hello from netdevsim!")
1053 start_test("Test XDP offload is device bound...")
1054 dfs
= simdev
.dfs_get_bound_progs(expected
=1)
1057 fail(prog
["id"] != link_xdp
["id"], "Program IDs don't match")
1058 fail(prog
["tag"] != link_xdp
["tag"], "Program tags don't match")
1059 fail(str(link_xdp
["id"]) != dprog
["id"], "Program IDs don't match")
1060 fail(dprog
["state"] != "xlated", "Offloaded program state not translated")
1061 fail(dprog
["loaded"] != "Y", "Offloaded program is not loaded")
1063 start_test("Test removing XDP program many times...")
1064 sim
.unset_xdp("offload")
1065 sim
.unset_xdp("offload")
1066 sim
.unset_xdp("drv")
1067 sim
.unset_xdp("drv")
1070 bpftool_prog_list_wait(expected
=0)
1072 start_test("Test attempt to use a program for a wrong device...")
1073 simdev2
= NetdevSimDev()
1074 sim2
, = simdev2
.nsims
1075 sim2
.set_xdp(obj
, "offload")
1076 pin_file
, pinned
= pin_prog("/sys/fs/bpf/tmp")
1078 ret
, _
, err
= sim
.set_xdp(pinned
, "offload",
1079 fail
=False, include_stderr
=True)
1080 fail(ret
== 0, "Pinned program loaded for a different device accepted")
1081 check_extack_nsim(err
, "program bound to different dev.", args
)
1083 ret
, _
, err
= sim
.set_xdp(pinned
, "offload",
1084 fail
=False, include_stderr
=True)
1085 fail(ret
== 0, "Pinned program loaded for a removed device accepted")
1086 check_extack_nsim(err
, "xdpoffload of non-bound program.", args
)
1088 bpftool_prog_list_wait(expected
=0)
1090 simdev
, sim
= test_multi_prog(simdev
, sim
, obj
, "", 1)
1091 simdev
, sim
= test_multi_prog(simdev
, sim
, obj
, "drv", 1)
1092 simdev
, sim
= test_multi_prog(simdev
, sim
, obj
, "generic", 2)
1094 start_test("Test mixing of TC and XDP...")
1095 sim
.tc_add_ingress()
1096 sim
.set_xdp(obj
, "offload")
1097 ret
, _
, err
= sim
.cls_bpf_add_filter(obj
, skip_sw
=True,
1098 fail
=False, include_stderr
=True)
1099 fail(ret
== 0, "Loading TC when XDP active should fail")
1100 check_extack_nsim(err
, "driver and netdev offload states mismatch.", args
)
1101 sim
.unset_xdp("offload")
1102 sim
.wait_for_flush()
1104 sim
.cls_bpf_add_filter(obj
, skip_sw
=True)
1105 ret
, _
, err
= sim
.set_xdp(obj
, "offload", fail
=False, include_stderr
=True)
1106 fail(ret
== 0, "Loading XDP when TC active should fail")
1107 check_extack_nsim(err
, "TC program is already loaded.", args
)
1109 start_test("Test binding TC from pinned...")
1110 pin_file
, pinned
= pin_prog("/sys/fs/bpf/tmp")
1111 sim
.tc_flush_filters(bound
=1, total
=1)
1112 sim
.cls_bpf_add_filter(pinned
, da
=True, skip_sw
=True)
1113 sim
.tc_flush_filters(bound
=1, total
=1)
1115 start_test("Test binding XDP from pinned...")
1116 sim
.set_xdp(obj
, "offload")
1117 pin_file
, pinned
= pin_prog("/sys/fs/bpf/tmp2", idx
=1)
1119 sim
.set_xdp(pinned
, "offload", force
=True)
1120 sim
.unset_xdp("offload")
1121 sim
.set_xdp(pinned
, "offload", force
=True)
1122 sim
.unset_xdp("offload")
1124 start_test("Test offload of wrong type fails...")
1125 ret
, _
= sim
.cls_bpf_add_filter(pinned
, da
=True, skip_sw
=True, fail
=False)
1126 fail(ret
== 0, "Managed to attach XDP program to TC")
1128 start_test("Test asking for TC offload of two filters...")
1129 sim
.cls_bpf_add_filter(obj
, da
=True, skip_sw
=True)
1130 ret
, _
, err
= sim
.cls_bpf_add_filter(obj
, da
=True, skip_sw
=True,
1131 fail
=False, include_stderr
=True)
1132 fail(ret
== 0, "Managed to offload two TC filters at the same time")
1133 check_extack_nsim(err
, "driver and netdev offload states mismatch.", args
)
1135 sim
.tc_flush_filters(bound
=2, total
=2)
1137 start_test("Test if netdev removal waits for translation...")
1139 sim
.dfs
["dev/bpf_bind_verifier_delay"] = delay_msec
1141 cmd_line
= "tc filter add dev %s ingress bpf %s da skip_sw" % \
1142 (sim
['ifname'], obj
)
1143 tc_proc
= cmd(cmd_line
, background
=True, fail
=False)
1144 # Wait for the verifier to start
1145 while simdev
.dfs_num_bound_progs() <= 2:
1149 ret
, _
= cmd_result(tc_proc
, fail
=False)
1150 time_diff
= end
- start
1151 log("Time", "start:\t%s\nend:\t%s\ndiff:\t%s" % (start
, end
, time_diff
))
1153 fail(ret
== 0, "Managed to load TC filter on a unregistering device")
1154 delay_sec
= delay_msec
* 0.001
1155 fail(time_diff
< delay_sec
, "Removal process took %s, expected %s" %
1156 (time_diff
, delay_sec
))
1158 # Remove all pinned files and reinstantiate the netdev
1160 bpftool_prog_list_wait(expected
=0)
1162 simdev
= NetdevSimDev()
1164 map_obj
= bpf_obj("sample_map_ret0.o")
1165 start_test("Test loading program with maps...")
1166 sim
.set_xdp(map_obj
, "offload", JSON
=False) # map fixup msg breaks JSON
1168 start_test("Test bpftool bound info reporting (own ns)...")
1169 check_dev_info(False, "")
1171 start_test("Test bpftool bound info reporting (other ns)...")
1174 check_dev_info(True, "")
1176 start_test("Test bpftool bound info reporting (remote ns)...")
1177 check_dev_info(False, ns
)
1179 start_test("Test bpftool bound info reporting (back to own ns)...")
1181 check_dev_info(False, "")
1183 prog_file
, _
= pin_prog("/sys/fs/bpf/tmp_prog")
1184 map_file
, _
= pin_map("/sys/fs/bpf/tmp_map", idx
=1, expected
=2)
1187 start_test("Test bpftool bound info reporting (removed dev)...")
1188 check_dev_info_removed(prog_file
=prog_file
, map_file
=map_file
)
1190 # Remove all pinned files and reinstantiate the netdev
1192 bpftool_prog_list_wait(expected
=0)
1194 simdev
= NetdevSimDev()
1197 start_test("Test map update (no flags)...")
1198 sim
.set_xdp(map_obj
, "offload", JSON
=False) # map fixup msg breaks JSON
1199 maps
= bpftool_map_list(expected
=2)
1200 array
= maps
[0] if maps
[0]["type"] == "array" else maps
[1]
1201 htab
= maps
[0] if maps
[0]["type"] == "hash" else maps
[1]
1204 bpftool("map update id %d key %s value %s" %
1205 (m
["id"], int2str("I", i
), int2str("Q", i
* 3)))
1208 ret
, _
= bpftool("map update id %d key %s value %s" %
1209 (m
["id"], int2str("I", 3), int2str("Q", 3 * 3)),
1211 fail(ret
== 0, "added too many entries")
1213 start_test("Test map update (exists)...")
1216 bpftool("map update id %d key %s value %s exist" %
1217 (m
["id"], int2str("I", i
), int2str("Q", i
* 3)))
1220 ret
, err
= bpftool("map update id %d key %s value %s exist" %
1221 (m
["id"], int2str("I", 3), int2str("Q", 3 * 3)),
1223 fail(ret
== 0, "updated non-existing key")
1224 fail(err
["error"].find("No such file or directory") == -1,
1225 "expected ENOENT, error is '%s'" % (err
["error"]))
1227 start_test("Test map update (noexist)...")
1230 ret
, err
= bpftool("map update id %d key %s value %s noexist" %
1231 (m
["id"], int2str("I", i
), int2str("Q", i
* 3)),
1233 fail(ret
== 0, "updated existing key")
1234 fail(err
["error"].find("File exists") == -1,
1235 "expected EEXIST, error is '%s'" % (err
["error"]))
1237 start_test("Test map dump...")
1239 _
, entries
= bpftool("map dump id %d" % (m
["id"]))
1241 key
= str2int(entries
[i
]["key"])
1242 fail(key
!= i
, "expected key %d, got %d" % (key
, i
))
1243 val
= str2int(entries
[i
]["value"])
1244 fail(val
!= i
* 3, "expected value %d, got %d" % (val
, i
* 3))
1246 start_test("Test map getnext...")
1248 _
, entry
= bpftool("map getnext id %d" % (m
["id"]))
1249 key
= str2int(entry
["next_key"])
1250 fail(key
!= 0, "next key %d, expected %d" % (key
, 0))
1251 _
, entry
= bpftool("map getnext id %d key %s" %
1252 (m
["id"], int2str("I", 0)))
1253 key
= str2int(entry
["next_key"])
1254 fail(key
!= 1, "next key %d, expected %d" % (key
, 1))
1255 ret
, err
= bpftool("map getnext id %d key %s" %
1256 (m
["id"], int2str("I", 1)), fail
=False)
1257 fail(ret
== 0, "got next key past the end of map")
1258 fail(err
["error"].find("No such file or directory") == -1,
1259 "expected ENOENT, error is '%s'" % (err
["error"]))
1261 start_test("Test map delete (htab)...")
1263 bpftool("map delete id %d key %s" % (htab
["id"], int2str("I", i
)))
1265 start_test("Test map delete (array)...")
1267 ret
, err
= bpftool("map delete id %d key %s" %
1268 (htab
["id"], int2str("I", i
)), fail
=False)
1269 fail(ret
== 0, "removed entry from an array")
1270 fail(err
["error"].find("No such file or directory") == -1,
1271 "expected ENOENT, error is '%s'" % (err
["error"]))
1273 start_test("Test map remove...")
1274 sim
.unset_xdp("offload")
1275 bpftool_map_list_wait(expected
=0)
1278 simdev
= NetdevSimDev()
1280 sim
.set_xdp(map_obj
, "offload", JSON
=False) # map fixup msg breaks JSON
1282 bpftool_map_list_wait(expected
=0)
1284 start_test("Test map creation fail path...")
1285 simdev
= NetdevSimDev()
1287 sim
.dfs
["bpf_map_accept"] = "N"
1288 ret
, _
= sim
.set_xdp(map_obj
, "offload", JSON
=False, fail
=False)
1290 "netdevsim didn't refuse to create a map with offload disabled")
1294 start_test("Test multi-dev ASIC program reuse...")
1295 simdevA
= NetdevSimDev()
1296 simA
, = simdevA
.nsims
1297 simdevB
= NetdevSimDev(3)
1298 simB1
, simB2
, simB3
= simdevB
.nsims
1299 sims
= (simA
, simB1
, simB2
, simB3
)
1300 simB
= (simB1
, simB2
, simB3
)
1302 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA",
1304 progA
= bpf_pinned("/sys/fs/bpf/nsimA")
1305 bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB",
1306 dev
=simB1
['ifname'])
1307 progB
= bpf_pinned("/sys/fs/bpf/nsimB")
1309 simA
.set_xdp(progA
, "offload", JSON
=False)
1310 for d
in simdevB
.nsims
:
1311 d
.set_xdp(progB
, "offload", JSON
=False)
1313 start_test("Test multi-dev ASIC cross-dev replace...")
1314 ret
, _
= simA
.set_xdp(progB
, "offload", force
=True, JSON
=False, fail
=False)
1315 fail(ret
== 0, "cross-ASIC program allowed")
1316 for d
in simdevB
.nsims
:
1317 ret
, _
= d
.set_xdp(progA
, "offload", force
=True, JSON
=False, fail
=False)
1318 fail(ret
== 0, "cross-ASIC program allowed")
1320 start_test("Test multi-dev ASIC cross-dev install...")
1322 d
.unset_xdp("offload")
1324 ret
, _
, err
= simA
.set_xdp(progB
, "offload", force
=True, JSON
=False,
1325 fail
=False, include_stderr
=True)
1326 fail(ret
== 0, "cross-ASIC program allowed")
1327 check_extack_nsim(err
, "program bound to different dev.", args
)
1328 for d
in simdevB
.nsims
:
1329 ret
, _
, err
= d
.set_xdp(progA
, "offload", force
=True, JSON
=False,
1330 fail
=False, include_stderr
=True)
1331 fail(ret
== 0, "cross-ASIC program allowed")
1332 check_extack_nsim(err
, "program bound to different dev.", args
)
1334 start_test("Test multi-dev ASIC cross-dev map reuse...")
1336 mapA
= bpftool("prog show %s" % (progA
))[1]["map_ids"][0]
1337 mapB
= bpftool("prog show %s" % (progB
))[1]["map_ids"][0]
1339 ret
, _
= bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
1340 dev
=simB3
['ifname'],
1341 maps
=["idx 0 id %d" % (mapB
)],
1343 fail(ret
!= 0, "couldn't reuse a map on the same ASIC")
1344 rm("/sys/fs/bpf/nsimB_")
1346 ret
, _
, err
= bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimA_",
1348 maps
=["idx 0 id %d" % (mapB
)],
1349 fail
=False, include_stderr
=True)
1350 fail(ret
== 0, "could reuse a map on a different ASIC")
1351 fail(err
.count("offload device mismatch between prog and map") == 0,
1352 "error message missing for cross-ASIC map")
1354 ret
, _
, err
= bpftool_prog_load("sample_map_ret0.o", "/sys/fs/bpf/nsimB_",
1355 dev
=simB1
['ifname'],
1356 maps
=["idx 0 id %d" % (mapA
)],
1357 fail
=False, include_stderr
=True)
1358 fail(ret
== 0, "could reuse a map on a different ASIC")
1359 fail(err
.count("offload device mismatch between prog and map") == 0,
1360 "error message missing for cross-ASIC map")
1362 start_test("Test multi-dev ASIC cross-dev destruction...")
1363 bpftool_prog_list_wait(expected
=2)
1366 bpftool_prog_list_wait(expected
=1)
1368 ifnameB
= bpftool("prog show %s" % (progB
))[1]["dev"]["ifname"]
1369 fail(ifnameB
!= simB1
['ifname'], "program not bound to original device")
1371 bpftool_prog_list_wait(expected
=1)
1373 start_test("Test multi-dev ASIC cross-dev destruction - move...")
1374 ifnameB
= bpftool("prog show %s" % (progB
))[1]["dev"]["ifname"]
1375 fail(ifnameB
not in (simB2
['ifname'], simB3
['ifname']),
1376 "program not bound to remaining devices")
1379 ifnameB
= bpftool("prog show %s" % (progB
))[1]["dev"]["ifname"]
1380 fail(ifnameB
!= simB3
['ifname'], "program not bound to remaining device")
1384 bpftool_prog_list_wait(expected
=0)
1386 start_test("Test multi-dev ASIC cross-dev destruction - orphaned...")
1387 ret
, out
= bpftool("prog show %s" % (progB
), fail
=False)
1388 fail(ret
== 0, "got information about orphaned program")
1389 fail("error" not in out
, "no error reported for get info on orphaned")
1390 fail(out
["error"] != "can't get prog info: No such device",
1391 "wrong error for get info on orphaned")
1393 print("%s: OK" % (os
.path
.basename(__file__
)))
1396 log("Clean up...", "", level
=1)