Merge a15d80a16d ("Merge branch 'ynl-tests'") into android-mainline

Steps on the way to 6.10-rc1

Change-Id: Ie4da9a2ce9c7bce8bc548f70d6a737f0559874d3
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2024-07-29 07:04:18 +00:00
26 changed files with 643 additions and 71 deletions
+1 -2
View File
@@ -132,8 +132,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
new_bus->phy_ignore_ta_mask = pdata->phy_ignore_ta_mask;
}
if (dev->of_node &&
of_device_is_compatible(dev->of_node, "microchip,mdio-smi0")) {
if (device_is_compatible(dev, "microchip,mdio-smi0")) {
bitbang->ctrl.op_c22_read = 0;
bitbang->ctrl.op_c22_write = 0;
bitbang->ctrl.override_op_c22 = 1;
+11
View File
@@ -140,6 +140,13 @@ nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
return 0;
}
static void
nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats)
{
fec_stats->corrected_blocks.total = 123;
fec_stats->uncorrectable_blocks.total = 4;
}
static int nsim_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
@@ -163,6 +170,7 @@ static const struct ethtool_ops nsim_ethtool_ops = {
.set_channels = nsim_set_channels,
.get_fecparam = nsim_get_fecparam,
.set_fecparam = nsim_set_fecparam,
.get_fec_stats = nsim_get_fec_stats,
.get_ts_info = nsim_get_ts_info,
};
@@ -182,6 +190,9 @@ void nsim_ethtool_init(struct netdevsim *ns)
nsim_ethtool_ring_init(ns);
ns->ethtool.pauseparam.report_stats_rx = true;
ns->ethtool.pauseparam.report_stats_tx = true;
ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
+49
View File
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <net/netdev_queues.h>
#include <net/netlink.h>
#include <net/pkt_cls.h>
#include <net/rtnetlink.h>
@@ -330,6 +331,53 @@ static const struct net_device_ops nsim_vf_netdev_ops = {
.ndo_set_features = nsim_set_features,
};
/* We don't have true per-queue stats, yet, so do some random fakery here.
* Only report stuff for queue 0.
*/
static void nsim_get_queue_stats_rx(struct net_device *dev, int idx,
struct netdev_queue_stats_rx *stats)
{
struct rtnl_link_stats64 rtstats = {};
if (!idx)
nsim_get_stats64(dev, &rtstats);
stats->packets = rtstats.rx_packets - !!rtstats.rx_packets;
stats->bytes = rtstats.rx_bytes;
}
static void nsim_get_queue_stats_tx(struct net_device *dev, int idx,
struct netdev_queue_stats_tx *stats)
{
struct rtnl_link_stats64 rtstats = {};
if (!idx)
nsim_get_stats64(dev, &rtstats);
stats->packets = rtstats.tx_packets - !!rtstats.tx_packets;
stats->bytes = rtstats.tx_bytes;
}
static void nsim_get_base_stats(struct net_device *dev,
struct netdev_queue_stats_rx *rx,
struct netdev_queue_stats_tx *tx)
{
struct rtnl_link_stats64 rtstats = {};
nsim_get_stats64(dev, &rtstats);
rx->packets = !!rtstats.rx_packets;
rx->bytes = 0;
tx->packets = !!rtstats.tx_packets;
tx->bytes = 0;
}
static const struct netdev_stat_ops nsim_stat_ops = {
.get_queue_stats_tx = nsim_get_queue_stats_tx,
.get_queue_stats_rx = nsim_get_queue_stats_rx,
.get_base_stats = nsim_get_base_stats,
};
static void nsim_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -360,6 +408,7 @@ static int nsim_init_netdevsim(struct netdevsim *ns)
ns->phc = phc;
ns->netdev->netdev_ops = &nsim_netdev_ops;
ns->netdev->stat_ops = &nsim_stat_ops;
err = nsim_udp_tunnels_info_create(ns->nsim_dev, ns->netdev);
if (err)
+1 -1
View File
@@ -13,7 +13,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2024.1"
#define BATADV_SOURCE_VERSION "2024.2"
#endif
/* B.A.T.M.A.N. parameters */
+2
View File
@@ -1266,6 +1266,8 @@ void batadv_purge_orig_ref(struct batadv_priv *bat_priv)
/* for all origins... */
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
if (hlist_empty(head))
continue;
list_lock = &hash->list_locks[i];
spin_lock_bh(list_lock);
+3 -44
View File
@@ -208,20 +208,6 @@ batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
return tt_global_entry;
}
/**
* batadv_tt_local_entry_free_rcu() - free the tt_local_entry
* @rcu: rcu pointer of the tt_local_entry
*/
static void batadv_tt_local_entry_free_rcu(struct rcu_head *rcu)
{
struct batadv_tt_local_entry *tt_local_entry;
tt_local_entry = container_of(rcu, struct batadv_tt_local_entry,
common.rcu);
kmem_cache_free(batadv_tl_cache, tt_local_entry);
}
/**
* batadv_tt_local_entry_release() - release tt_local_entry from lists and queue
* for free after rcu grace period
@@ -236,7 +222,7 @@ static void batadv_tt_local_entry_release(struct kref *ref)
batadv_softif_vlan_put(tt_local_entry->vlan);
call_rcu(&tt_local_entry->common.rcu, batadv_tt_local_entry_free_rcu);
kfree_rcu(tt_local_entry, common.rcu);
}
/**
@@ -254,20 +240,6 @@ batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)
batadv_tt_local_entry_release);
}
/**
* batadv_tt_global_entry_free_rcu() - free the tt_global_entry
* @rcu: rcu pointer of the tt_global_entry
*/
static void batadv_tt_global_entry_free_rcu(struct rcu_head *rcu)
{
struct batadv_tt_global_entry *tt_global_entry;
tt_global_entry = container_of(rcu, struct batadv_tt_global_entry,
common.rcu);
kmem_cache_free(batadv_tg_cache, tt_global_entry);
}
/**
* batadv_tt_global_entry_release() - release tt_global_entry from lists and
* queue for free after rcu grace period
@@ -282,7 +254,7 @@ void batadv_tt_global_entry_release(struct kref *ref)
batadv_tt_global_del_orig_list(tt_global_entry);
call_rcu(&tt_global_entry->common.rcu, batadv_tt_global_entry_free_rcu);
kfree_rcu(tt_global_entry, common.rcu);
}
/**
@@ -407,19 +379,6 @@ static void batadv_tt_global_size_dec(struct batadv_orig_node *orig_node,
batadv_tt_global_size_mod(orig_node, vid, -1);
}
/**
* batadv_tt_orig_list_entry_free_rcu() - free the orig_entry
* @rcu: rcu pointer of the orig_entry
*/
static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
{
struct batadv_tt_orig_list_entry *orig_entry;
orig_entry = container_of(rcu, struct batadv_tt_orig_list_entry, rcu);
kmem_cache_free(batadv_tt_orig_cache, orig_entry);
}
/**
* batadv_tt_orig_list_entry_release() - release tt orig entry from lists and
* queue for free after rcu grace period
@@ -433,7 +392,7 @@ static void batadv_tt_orig_list_entry_release(struct kref *ref)
refcount);
batadv_orig_node_put(orig_entry->orig_node);
call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
kfree_rcu(orig_entry, rcu);
}
/**
+3 -3
View File
@@ -1415,7 +1415,7 @@ static ssize_t bql_show_stall_thrs(struct netdev_queue *queue, char *buf)
{
struct dql *dql = &queue->dql;
return sprintf(buf, "%u\n", jiffies_to_msecs(dql->stall_thrs));
return sysfs_emit(buf, "%u\n", jiffies_to_msecs(dql->stall_thrs));
}
static ssize_t bql_set_stall_thrs(struct netdev_queue *queue,
@@ -1447,7 +1447,7 @@ static struct netdev_queue_attribute bql_stall_thrs_attribute __ro_after_init =
static ssize_t bql_show_stall_max(struct netdev_queue *queue, char *buf)
{
return sprintf(buf, "%u\n", READ_ONCE(queue->dql.stall_max));
return sysfs_emit(buf, "%u\n", READ_ONCE(queue->dql.stall_max));
}
static ssize_t bql_set_stall_max(struct netdev_queue *queue,
@@ -1464,7 +1464,7 @@ static ssize_t bql_show_stall_cnt(struct netdev_queue *queue, char *buf)
{
struct dql *dql = &queue->dql;
return sprintf(buf, "%lu\n", dql->stall_cnt);
return sysfs_emit(buf, "%lu\n", dql->stall_cnt);
}
static struct netdev_queue_attribute bql_stall_cnt_attribute __ro_after_init =
+2 -2
View File
@@ -175,7 +175,7 @@ static void fqdir_free_fn(struct work_struct *work)
}
}
static DECLARE_WORK(fqdir_free_work, fqdir_free_fn);
static DECLARE_DELAYED_WORK(fqdir_free_work, fqdir_free_fn);
static void fqdir_work_fn(struct work_struct *work)
{
@@ -184,7 +184,7 @@ static void fqdir_work_fn(struct work_struct *work)
rhashtable_free_and_destroy(&fqdir->rhashtable, inet_frags_free_cb, NULL);
if (llist_add(&fqdir->free_list, &fqdir_free_list))
queue_work(system_wq, &fqdir_free_work);
queue_delayed_work(system_wq, &fqdir_free_work, HZ);
}
int fqdir_init(struct fqdir **fqdirp, struct inet_frags *f, struct net *net)
+2
View File
@@ -1034,6 +1034,8 @@ bool ip_tunnel_parm_to_user(void __user *data, struct ip_tunnel_parm_kern *kp)
!ip_tunnel_flags_is_be16_compat(kp->o_flags))
return false;
memset(&p, 0, sizeof(p));
strscpy(p.name, kp->name);
p.link = kp->link;
p.i_flags = ip_tunnel_flags_to_be16(kp->i_flags);
+11 -7
View File
@@ -234,7 +234,8 @@ static int __ip6addrlbl_add(struct net *net, struct ip6addrlbl_entry *newp,
hlist_add_head_rcu(&newp->list, &net->ipv6.ip6addrlbl_table.head);
out:
if (!ret)
net->ipv6.ip6addrlbl_table.seq++;
WRITE_ONCE(net->ipv6.ip6addrlbl_table.seq,
net->ipv6.ip6addrlbl_table.seq + 1);
return ret;
}
@@ -445,7 +446,7 @@ static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
};
static int ip6addrlbl_fill(struct sk_buff *skb,
struct ip6addrlbl_entry *p,
const struct ip6addrlbl_entry *p,
u32 lseq,
u32 portid, u32 seq, int event,
unsigned int flags)
@@ -498,7 +499,8 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
struct net *net = sock_net(skb->sk);
struct ip6addrlbl_entry *p;
int idx = 0, s_idx = cb->args[0];
int err;
int err = 0;
u32 lseq;
if (cb->strict_check) {
err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
@@ -507,10 +509,11 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
rcu_read_lock();
lseq = READ_ONCE(net->ipv6.ip6addrlbl_table.seq);
hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
if (idx >= s_idx) {
err = ip6addrlbl_fill(skb, p,
net->ipv6.ip6addrlbl_table.seq,
lseq,
NETLINK_CB(cb->skb).portid,
nlh->nlmsg_seq,
RTM_NEWADDRLABEL,
@@ -522,7 +525,7 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
rcu_read_unlock();
cb->args[0] = idx;
return skb->len;
return err;
}
static inline int ip6addrlbl_msgsize(void)
@@ -614,7 +617,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
rcu_read_lock();
p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
lseq = net->ipv6.ip6addrlbl_table.seq;
lseq = READ_ONCE(net->ipv6.ip6addrlbl_table.seq);
if (p)
err = ip6addrlbl_fill(skb, p, lseq,
NETLINK_CB(in_skb).portid,
@@ -647,6 +650,7 @@ int __init ipv6_addr_label_rtnl_register(void)
return ret;
ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
ip6addrlbl_get,
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED |
RTNL_FLAG_DUMP_UNLOCKED);
return ret;
}
+1 -11
View File
@@ -174,11 +174,6 @@ vti6_tnl_unlink(struct vti6_net *ip6n, struct ip6_tnl *t)
}
}
static void vti6_dev_free(struct net_device *dev)
{
free_percpu(dev->tstats);
}
static int vti6_tnl_create2(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
@@ -892,7 +887,6 @@ static const struct net_device_ops vti6_netdev_ops = {
.ndo_uninit = vti6_dev_uninit,
.ndo_start_xmit = vti6_tnl_xmit,
.ndo_siocdevprivate = vti6_siocdevprivate,
.ndo_get_stats64 = dev_get_tstats64,
.ndo_get_iflink = ip6_tnl_get_iflink,
};
@@ -907,9 +901,8 @@ static void vti6_dev_setup(struct net_device *dev)
{
dev->netdev_ops = &vti6_netdev_ops;
dev->header_ops = &ip_tunnel_header_ops;
dev->needs_free_netdev = true;
dev->priv_destructor = vti6_dev_free;
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
dev->type = ARPHRD_TUNNEL6;
dev->min_mtu = IPV4_MIN_MTU;
dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);
@@ -931,9 +924,6 @@ static inline int vti6_dev_init_gen(struct net_device *dev)
t->dev = dev;
t->net = dev_net(dev);
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
if (!dev->tstats)
return -ENOMEM;
netdev_hold(dev, &t->dev_tracker, GFP_KERNEL);
netdev_lockdep_set_classes(dev);
return 0;
+9 -1
View File
@@ -17,6 +17,7 @@ TARGETS += devices
TARGETS += dmabuf-heaps
TARGETS += drivers/dma-buf
TARGETS += drivers/s390x/uvdevice
TARGETS += drivers/net
TARGETS += drivers/net/bonding
TARGETS += drivers/net/team
TARGETS += dt
@@ -116,6 +117,13 @@ TARGETS += zram
TARGETS_HOTPLUG = cpu-hotplug
TARGETS_HOTPLUG += memory-hotplug
# Networking tests want the net/lib target, include it automatically
ifneq ($(filter net drivers/net,$(TARGETS)),)
ifeq ($(filter net/lib,$(TARGETS)),)
INSTALL_DEP_TARGETS := net/lib
endif
endif
# User can optionally provide a TARGETS skiplist. By default we skip
# BPF since it has cutting edge build time dependencies which require
# more effort to install.
@@ -245,7 +253,7 @@ ifdef INSTALL_PATH
install -m 744 run_kselftest.sh $(INSTALL_PATH)/
rm -f $(TEST_LIST)
@ret=1; \
for TARGET in $(TARGETS); do \
for TARGET in $(TARGETS) $(INSTALL_DEP_TARGETS); do \
BUILD_TARGET=$$BUILD/$$TARGET; \
$(MAKE) OUTPUT=$$BUILD_TARGET -C $$TARGET install \
INSTALL_PATH=$(INSTALL_PATH)/$$TARGET \
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
TEST_INCLUDES := $(wildcard lib/py/*.py)
TEST_PROGS := stats.py
include ../../lib.mk
@@ -0,0 +1,30 @@
Running tests
=============
Tests are executed within kselftest framework like any other tests.
By default tests execute against software drivers such as netdevsim.
All tests must support running against a real device (SW-only tests
should instead be placed in net/ or drivers/net/netdevsim, HW-only
tests in drivers/net/hw).
Set appropriate variables to point the tests at a real device.
Variables
=========
Variables can be set in the environment or by creating a net.config
file in the same directory as this README file. Example::
$ NETIF=eth0 ./some_test.sh
or::
$ cat tools/testing/selftests/drivers/net/net.config
# Variable set in a file
NETIF=eth0
NETIF
~~~~~
Name of the netdevice against which the test should be executed.
When empty or not set software devices will be used.
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
import sys
from pathlib import Path
KSFT_DIR = (Path(__file__).parent / "../../../..").resolve()
try:
sys.path.append(KSFT_DIR.as_posix())
from net.lib.py import *
except ModuleNotFoundError as e:
ksft_pr("Failed importing `net` library from kernel sources")
ksft_pr(str(e))
ktap_result(True, comment="SKIP")
sys.exit(4)
from .env import *
@@ -0,0 +1,52 @@
# SPDX-License-Identifier: GPL-2.0
import os
import shlex
from pathlib import Path
from lib.py import ip
from lib.py import NetdevSimDev
class NetDrvEnv:
def __init__(self, src_path):
self._ns = None
self.env = os.environ.copy()
self._load_env_file(src_path)
if 'NETIF' in self.env:
self.dev = ip("link show dev " + self.env['NETIF'], json=True)[0]
else:
self._ns = NetdevSimDev()
self.dev = self._ns.nsims[0].dev
self.ifindex = self.dev['ifindex']
def __enter__(self):
return self
def __exit__(self, ex_type, ex_value, ex_tb):
"""
__exit__ gets called at the end of a "with" block.
"""
self.__del__()
def __del__(self):
if self._ns:
self._ns.remove()
self._ns = None
def _load_env_file(self, src_path):
src_dir = Path(src_path).parent.resolve()
if not (src_dir / "net.config").exists():
return
lexer = shlex.shlex(open((src_dir / "net.config").as_posix(), 'r').read())
k = None
for token in lexer:
if k is None:
k = token
self.env[k] = ""
elif token == "=":
pass
else:
self.env[k] = token
k = None
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
from lib.py import ksft_run, ksft_in, ksft_true, KsftSkipEx, KsftXfailEx
from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError
from lib.py import NetDrvEnv
ethnl = EthtoolFamily()
netfam = NetdevFamily()
rtnl = RtnlFamily()
def check_pause(cfg) -> None:
global ethnl
try:
ethnl.pause_get({"header": {"dev-index": cfg.ifindex}})
except NlError as e:
if e.error == 95:
raise KsftXfailEx("pause not supported by the device")
raise
data = ethnl.pause_get({"header": {"dev-index": cfg.ifindex,
"flags": {'stats'}}})
ksft_true(data['stats'], "driver does not report stats")
def check_fec(cfg) -> None:
global ethnl
try:
ethnl.fec_get({"header": {"dev-index": cfg.ifindex}})
except NlError as e:
if e.error == 95:
raise KsftXfailEx("FEC not supported by the device")
raise
data = ethnl.fec_get({"header": {"dev-index": cfg.ifindex,
"flags": {'stats'}}})
ksft_true(data['stats'], "driver does not report stats")
def pkt_byte_sum(cfg) -> None:
global netfam, rtnl
def get_qstat(test):
global netfam
stats = netfam.qstats_get({}, dump=True)
if stats:
for qs in stats:
if qs["ifindex"]== test.ifindex:
return qs
qstat = get_qstat(cfg)
if qstat is None:
raise KsftSkipEx("qstats not supported by the device")
for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']:
ksft_in(key, qstat, "Drivers should always report basic keys")
# Compare stats, rtnl stats and qstats must match,
# but the interface may be up, so do a series of dumps
# each time the more "recent" stats must be higher or same.
def stat_cmp(rstat, qstat):
for key in ['tx-packets', 'tx-bytes', 'rx-packets', 'rx-bytes']:
if rstat[key] != qstat[key]:
return rstat[key] - qstat[key]
return 0
for _ in range(10):
rtstat = rtnl.getlink({"ifi-index": cfg.ifindex})['stats']
if stat_cmp(rtstat, qstat) < 0:
raise Exception("RTNL stats are lower, fetched later")
qstat = get_qstat(cfg)
if stat_cmp(rtstat, qstat) > 0:
raise Exception("Qstats are lower, fetched later")
def main() -> None:
with NetDrvEnv(__file__) as cfg:
ksft_run([check_pause, check_fec, pkt_byte_sum],
args=(cfg, ))
if __name__ == "__main__":
main()
+1
View File
@@ -34,6 +34,7 @@ TEST_PROGS += gre_gso.sh
TEST_PROGS += cmsg_so_mark.sh
TEST_PROGS += cmsg_time.sh cmsg_ipv6.sh
TEST_PROGS += netns-name.sh
TEST_PROGS += nl_netdev.py
TEST_PROGS += srv6_end_dt46_l3vpn_test.sh
TEST_PROGS += srv6_end_dt4_l3vpn_test.sh
TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
+8
View File
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
TEST_FILES := ../../../../../Documentation/netlink/specs
TEST_FILES += ../../../../net/ynl
TEST_INCLUDES := $(wildcard py/*.py)
include ../../lib.mk
@@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
from .consts import KSRC
from .ksft import *
from .nsim import *
from .utils import *
from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
import sys
from pathlib import Path
KSFT_DIR = (Path(__file__).parent / "../../..").resolve()
KSRC = (Path(__file__).parent / "../../../../../..").resolve()
KSFT_MAIN_NAME = Path(sys.argv[0]).with_suffix("").name
@@ -0,0 +1,96 @@
# SPDX-License-Identifier: GPL-2.0
import builtins
from .consts import KSFT_MAIN_NAME
KSFT_RESULT = None
class KsftSkipEx(Exception):
pass
class KsftXfailEx(Exception):
pass
def ksft_pr(*objs, **kwargs):
print("#", *objs, **kwargs)
def ksft_eq(a, b, comment=""):
global KSFT_RESULT
if a != b:
KSFT_RESULT = False
ksft_pr("Check failed", a, "!=", b, comment)
def ksft_true(a, comment=""):
global KSFT_RESULT
if not a:
KSFT_RESULT = False
ksft_pr("Check failed", a, "does not eval to True", comment)
def ksft_in(a, b, comment=""):
global KSFT_RESULT
if a not in b:
KSFT_RESULT = False
ksft_pr("Check failed", a, "not in", b, comment)
def ksft_ge(a, b, comment=""):
global KSFT_RESULT
if a < b:
KSFT_RESULT = False
ksft_pr("Check failed", a, "<", b, comment)
def ktap_result(ok, cnt=1, case="", comment=""):
res = ""
if not ok:
res += "not "
res += "ok "
res += str(cnt) + " "
res += KSFT_MAIN_NAME
if case:
res += "." + str(case.__name__)
if comment:
res += " # " + comment
print(res)
def ksft_run(cases, args=()):
totals = {"pass": 0, "fail": 0, "skip": 0, "xfail": 0}
print("KTAP version 1")
print("1.." + str(len(cases)))
global KSFT_RESULT
cnt = 0
for case in cases:
KSFT_RESULT = True
cnt += 1
try:
case(*args)
except KsftSkipEx as e:
ktap_result(True, cnt, case, comment="SKIP " + str(e))
totals['skip'] += 1
continue
except KsftXfailEx as e:
ktap_result(True, cnt, case, comment="XFAIL " + str(e))
totals['xfail'] += 1
continue
except Exception as e:
for line in str(e).split('\n'):
ksft_pr("Exception|", line)
ktap_result(False, cnt, case)
totals['fail'] += 1
continue
ktap_result(KSFT_RESULT, cnt, case)
totals['pass'] += 1
print(
f"# Totals: pass:{totals['pass']} fail:{totals['fail']} xfail:{totals['xfail']} xpass:0 skip:{totals['skip']} error:0"
)
+115
View File
@@ -0,0 +1,115 @@
# SPDX-License-Identifier: GPL-2.0
import json
import os
import random
import re
import time
from .utils import cmd, ip
class NetdevSim:
"""
Class for netdevsim netdevice and its attributes.
"""
def __init__(self, nsimdev, port_index, ifname, ns=None):
# In case udev renamed the netdev to according to new schema,
# check if the name matches the port_index.
nsimnamere = re.compile(r"eni\d+np(\d+)")
match = nsimnamere.match(ifname)
if match and int(match.groups()[0]) != port_index + 1:
raise Exception("netdevice name mismatches the expected one")
self.nsimdev = nsimdev
self.port_index = port_index
ret = ip("-j link show dev %s" % ifname, ns=ns)
self.dev = json.loads(ret.stdout)[0]
def dfs_write(self, path, val):
self.nsimdev.dfs_write(f'ports/{self.port_index}/' + path, val)
class NetdevSimDev:
"""
Class for netdevsim bus device and its attributes.
"""
@staticmethod
def ctrl_write(path, val):
fullpath = os.path.join("/sys/bus/netdevsim/", path)
with open(fullpath, "w") as f:
f.write(val)
def dfs_write(self, path, val):
fullpath = os.path.join(f"/sys/kernel/debug/netdevsim/netdevsim{self.addr}/", path)
with open(fullpath, "w") as f:
f.write(val)
def __init__(self, port_count=1, ns=None):
# nsim will spawn in init_net, we'll set to actual ns once we switch it there
self.ns = None
if not os.path.exists("/sys/bus/netdevsim"):
cmd("modprobe netdevsim")
addr = random.randrange(1 << 15)
while True:
try:
self.ctrl_write("new_device", "%u %u" % (addr, port_count))
except OSError as e:
if e.errno == errno.ENOSPC:
addr = random.randrange(1 << 15)
continue
raise e
break
self.addr = addr
# As probe of netdevsim device might happen from a workqueue,
# so wait here until all netdevs appear.
self.wait_for_netdevs(port_count)
if ns:
cmd(f"devlink dev reload netdevsim/netdevsim{addr} netns {ns.name}")
self.ns = ns
cmd("udevadm settle", ns=self.ns)
ifnames = self.get_ifnames()
self.dfs_dir = "/sys/kernel/debug/netdevsim/netdevsim%u/" % addr
self.nsims = []
for port_index in range(port_count):
self.nsims.append(NetdevSim(self, port_index, ifnames[port_index],
ns=ns))
def get_ifnames(self):
ifnames = []
listdir = cmd(f"ls /sys/bus/netdevsim/devices/netdevsim{self.addr}/net/",
ns=self.ns).stdout.split()
for ifname in listdir:
ifnames.append(ifname)
ifnames.sort()
return ifnames
def wait_for_netdevs(self, port_count):
timeout = 5
timeout_start = time.time()
while True:
try:
ifnames = self.get_ifnames()
except FileNotFoundError as e:
ifnames = []
if len(ifnames) == port_count:
break
if time.time() < timeout_start + timeout:
continue
raise Exception("netdevices did not appear within timeout")
def remove(self):
self.ctrl_write("del_device", "%u" % (self.addr, ))
def remove_nsim(self, nsim):
self.nsims.remove(nsim)
self.ctrl_write("devices/netdevsim%u/del_port" % (self.addr, ),
"%u" % (nsim.port_index, ))
@@ -0,0 +1,47 @@
# SPDX-License-Identifier: GPL-2.0
import json as _json
import subprocess
class cmd:
def __init__(self, comm, shell=True, fail=True, ns=None, background=False):
if ns:
if isinstance(ns, NetNS):
ns = ns.name
comm = f'ip netns exec {ns} ' + comm
self.stdout = None
self.stderr = None
self.ret = None
self.comm = comm
self.proc = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
if not background:
self.process(terminate=False, fail=fail)
def process(self, terminate=True, fail=None):
if terminate:
self.proc.terminate()
stdout, stderr = self.proc.communicate()
self.stdout = stdout.decode("utf-8")
self.stderr = stderr.decode("utf-8")
self.proc.stdout.close()
self.proc.stderr.close()
self.ret = self.proc.returncode
if self.proc.returncode != 0 and fail:
if len(stderr) > 0 and stderr[-1] == "\n":
stderr = stderr[:-1]
raise Exception("Command failed: %s\n%s" % (self.proc.args, stderr))
def ip(args, json=None, ns=None):
cmd_str = "ip "
if json:
cmd_str += '-j '
cmd_str += args
cmd_obj = cmd(cmd_str, ns=ns)
if json:
return _json.loads(cmd_obj.stdout)
return cmd_obj
+49
View File
@@ -0,0 +1,49 @@
# SPDX-License-Identifier: GPL-2.0
import sys
from pathlib import Path
from .consts import KSRC, KSFT_DIR
from .ksft import ksft_pr, ktap_result
# Resolve paths
try:
if (KSFT_DIR / "kselftest-list.txt").exists():
# Running in "installed" selftests
tools_full_path = KSFT_DIR
SPEC_PATH = KSFT_DIR / "net/lib/specs"
sys.path.append(tools_full_path.as_posix())
from net.lib.ynl.lib import YnlFamily, NlError
else:
# Running in tree
tools_full_path = KSRC / "tools"
SPEC_PATH = KSRC / "Documentation/netlink/specs"
sys.path.append(tools_full_path.as_posix())
from net.ynl.lib import YnlFamily, NlError
except ModuleNotFoundError as e:
ksft_pr("Failed importing `ynl` library from kernel sources")
ksft_pr(str(e))
ktap_result(True, comment="SKIP")
sys.exit(4)
#
# Wrapper classes, loading the right specs
# Set schema='' to avoid jsonschema validation, it's slow
#
class EthtoolFamily(YnlFamily):
def __init__(self):
super().__init__((SPEC_PATH / Path('ethtool.yaml')).as_posix(),
schema='')
class RtnlFamily(YnlFamily):
def __init__(self):
super().__init__((SPEC_PATH / Path('rt_link.yaml')).as_posix(),
schema='')
class NetdevFamily(YnlFamily):
def __init__(self):
super().__init__((SPEC_PATH / Path('netdev.yaml')).as_posix(),
schema='')
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0
from lib.py import ksft_run, ksft_pr, ksft_eq, ksft_ge, NetdevFamily
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 main() -> None:
nf = NetdevFamily()
ksft_run([empty_check, lo_check], args=(nf, ))
if __name__ == "__main__":
main()