mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-08-15 21:46:42 +00:00

Instead of using '0' and '1' for napi threaded state use an enum with 'disabled' and 'enabled' states. Tested: ./tools/testing/selftests/net/nl_netdev.py TAP version 13 1..7 ok 1 nl_netdev.empty_check ok 2 nl_netdev.lo_check ok 3 nl_netdev.page_pool_check ok 4 nl_netdev.napi_list_check ok 5 nl_netdev.dev_set_threaded ok 6 nl_netdev.napi_set_threaded ok 7 nl_netdev.nsim_rxq_reset_down # Totals: pass:7 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Samiullah Khawaja <skhawaja@google.com> Link: https://patch.msgid.link/20250723013031.2911384-4-skhawaja@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
255 lines
8.0 KiB
Python
Executable File
255 lines
8.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
import time
|
|
from os import system
|
|
from lib.py import ksft_run, ksft_exit, ksft_pr
|
|
from lib.py import ksft_eq, ksft_ge, ksft_ne, ksft_busy_wait
|
|
from lib.py import NetdevFamily, NetdevSimDev, ip
|
|
|
|
|
|
def empty_check(nf) -> None:
|
|
devs = nf.dev_get({}, dump=True)
|
|
ksft_ge(len(devs), 1)
|
|
|
|
|
|
def lo_check(nf) -> None:
|
|
lo_info = nf.dev_get({"ifindex": 1})
|
|
ksft_eq(len(lo_info['xdp-features']), 0)
|
|
ksft_eq(len(lo_info['xdp-rx-metadata-features']), 0)
|
|
|
|
|
|
def napi_list_check(nf) -> None:
|
|
with NetdevSimDev(queue_count=100) as nsimdev:
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
|
|
ksft_eq(len(napis), 100)
|
|
|
|
for q in [50, 0, 99]:
|
|
for i in range(4):
|
|
nsim.dfs_write("queue_reset", f"{q} {i}")
|
|
napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
|
|
ksft_eq(len(napis), 100,
|
|
comment=f"queue count after reset queue {q} mode {i}")
|
|
|
|
def napi_set_threaded(nf) -> None:
|
|
"""
|
|
Test that verifies various cases of napi threaded
|
|
set and unset at napi and device level.
|
|
"""
|
|
with NetdevSimDev(queue_count=2) as nsimdev:
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
|
|
ksft_eq(len(napis), 2)
|
|
|
|
napi0_id = napis[0]['id']
|
|
napi1_id = napis[1]['id']
|
|
|
|
# set napi threaded and verify
|
|
nf.napi_set({'id': napi0_id, 'threaded': "enabled"})
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "enabled")
|
|
ksft_ne(napi0.get('pid'), None)
|
|
|
|
# check it is not set for napi1
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "disabled")
|
|
ksft_eq(napi1.get('pid'), None)
|
|
|
|
ip(f"link set dev {nsim.ifname} down")
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
# verify if napi threaded is still set
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "enabled")
|
|
ksft_ne(napi0.get('pid'), None)
|
|
|
|
# check it is still not set for napi1
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "disabled")
|
|
ksft_eq(napi1.get('pid'), None)
|
|
|
|
# unset napi threaded and verify
|
|
nf.napi_set({'id': napi0_id, 'threaded': "disabled"})
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "disabled")
|
|
ksft_eq(napi0.get('pid'), None)
|
|
|
|
# set threaded at device level
|
|
system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded")
|
|
|
|
# check napi threaded is set for both napis
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "enabled")
|
|
ksft_ne(napi0.get('pid'), None)
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "enabled")
|
|
ksft_ne(napi1.get('pid'), None)
|
|
|
|
# unset threaded at device level
|
|
system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
|
|
|
|
# check napi threaded is unset for both napis
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "disabled")
|
|
ksft_eq(napi0.get('pid'), None)
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "disabled")
|
|
ksft_eq(napi1.get('pid'), None)
|
|
|
|
# set napi threaded for napi0
|
|
nf.napi_set({'id': napi0_id, 'threaded': 1})
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "enabled")
|
|
ksft_ne(napi0.get('pid'), None)
|
|
|
|
# unset threaded at device level
|
|
system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
|
|
|
|
# check napi threaded is unset for both napis
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "disabled")
|
|
ksft_eq(napi0.get('pid'), None)
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "disabled")
|
|
ksft_eq(napi1.get('pid'), None)
|
|
|
|
def dev_set_threaded(nf) -> None:
|
|
"""
|
|
Test that verifies various cases of napi threaded
|
|
set and unset at device level using sysfs.
|
|
"""
|
|
with NetdevSimDev(queue_count=2) as nsimdev:
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
napis = nf.napi_get({'ifindex': nsim.ifindex}, dump=True)
|
|
ksft_eq(len(napis), 2)
|
|
|
|
napi0_id = napis[0]['id']
|
|
napi1_id = napis[1]['id']
|
|
|
|
# set threaded
|
|
system(f"echo 1 > /sys/class/net/{nsim.ifname}/threaded")
|
|
|
|
# check napi threaded is set for both napis
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "enabled")
|
|
ksft_ne(napi0.get('pid'), None)
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "enabled")
|
|
ksft_ne(napi1.get('pid'), None)
|
|
|
|
# unset threaded
|
|
system(f"echo 0 > /sys/class/net/{nsim.ifname}/threaded")
|
|
|
|
# check napi threaded is unset for both napis
|
|
napi0 = nf.napi_get({'id': napi0_id})
|
|
ksft_eq(napi0['threaded'], "disabled")
|
|
ksft_eq(napi0.get('pid'), None)
|
|
napi1 = nf.napi_get({'id': napi1_id})
|
|
ksft_eq(napi1['threaded'], "disabled")
|
|
ksft_eq(napi1.get('pid'), None)
|
|
|
|
def nsim_rxq_reset_down(nf) -> None:
|
|
"""
|
|
Test that the queue API supports resetting a queue
|
|
while the interface is down. We should convert this
|
|
test to testing real HW once more devices support
|
|
queue API.
|
|
"""
|
|
with NetdevSimDev(queue_count=4) as nsimdev:
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
ip(f"link set dev {nsim.ifname} down")
|
|
for i in [0, 2, 3]:
|
|
nsim.dfs_write("queue_reset", f"1 {i}")
|
|
|
|
|
|
def page_pool_check(nf) -> None:
|
|
with NetdevSimDev() as nsimdev:
|
|
nsim = nsimdev.nsims[0]
|
|
|
|
def up():
|
|
ip(f"link set dev {nsim.ifname} up")
|
|
|
|
def down():
|
|
ip(f"link set dev {nsim.ifname} down")
|
|
|
|
def get_pp():
|
|
pp_list = nf.page_pool_get({}, dump=True)
|
|
return [pp for pp in pp_list if pp.get("ifindex") == nsim.ifindex]
|
|
|
|
# No page pools when down
|
|
down()
|
|
ksft_eq(len(get_pp()), 0)
|
|
|
|
# Up, empty page pool appears
|
|
up()
|
|
pp_list = get_pp()
|
|
ksft_ge(len(pp_list), 0)
|
|
refs = sum([pp["inflight"] for pp in pp_list])
|
|
ksft_eq(refs, 0)
|
|
|
|
# Down, it disappears, again
|
|
down()
|
|
pp_list = get_pp()
|
|
ksft_eq(len(pp_list), 0)
|
|
|
|
# Up, allocate a page
|
|
up()
|
|
nsim.dfs_write("pp_hold", "y")
|
|
pp_list = nf.page_pool_get({}, dump=True)
|
|
refs = sum([pp["inflight"] for pp in pp_list if pp.get("ifindex") == nsim.ifindex])
|
|
ksft_ge(refs, 1)
|
|
|
|
# Now let's leak a page
|
|
down()
|
|
pp_list = get_pp()
|
|
ksft_eq(len(pp_list), 1)
|
|
refs = sum([pp["inflight"] for pp in pp_list])
|
|
ksft_eq(refs, 1)
|
|
attached = [pp for pp in pp_list if "detach-time" not in pp]
|
|
ksft_eq(len(attached), 0)
|
|
|
|
# New pp can get created, and we'll have two
|
|
up()
|
|
pp_list = get_pp()
|
|
attached = [pp for pp in pp_list if "detach-time" not in pp]
|
|
detached = [pp for pp in pp_list if "detach-time" in pp]
|
|
ksft_eq(len(attached), 1)
|
|
ksft_eq(len(detached), 1)
|
|
|
|
# Free the old page and the old pp is gone
|
|
nsim.dfs_write("pp_hold", "n")
|
|
# Freeing check is once a second so we may need to retry
|
|
ksft_busy_wait(lambda: len(get_pp()) == 1, deadline=2)
|
|
|
|
# And down...
|
|
down()
|
|
ksft_eq(len(get_pp()), 0)
|
|
|
|
# Last, leave the page hanging for destroy, nothing to check
|
|
# we're trying to exercise the orphaning path in the kernel
|
|
up()
|
|
nsim.dfs_write("pp_hold", "y")
|
|
|
|
|
|
def main() -> None:
|
|
nf = NetdevFamily()
|
|
ksft_run([empty_check, lo_check, page_pool_check, napi_list_check,
|
|
dev_set_threaded, napi_set_threaded, nsim_rxq_reset_down],
|
|
args=(nf, ))
|
|
ksft_exit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|