mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 05:44:11 +00:00
net: kunit: add a test for dev_addr_lists
Add a KUnit test for the dev_addr API. Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a387ff8e5d
commit
2c193f2cb1
3 changed files with 243 additions and 0 deletions
|
@ -455,4 +455,9 @@ config ETHTOOL_NETLINK
|
||||||
netlink. It provides better extensibility and some new features,
|
netlink. It provides better extensibility and some new features,
|
||||||
e.g. notification messages.
|
e.g. notification messages.
|
||||||
|
|
||||||
|
config NETDEV_ADDR_LIST_TEST
|
||||||
|
tristate "Unit tests for device address list"
|
||||||
|
default KUNIT_ALL_TESTS
|
||||||
|
depends on KUNIT
|
||||||
|
|
||||||
endif # if NET
|
endif # if NET
|
||||||
|
|
|
@ -13,6 +13,8 @@ obj-y += dev.o dev_addr_lists.o dst.o netevent.o \
|
||||||
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
|
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
|
||||||
fib_notifier.o xdp.o flow_offload.o gro.o
|
fib_notifier.o xdp.o flow_offload.o gro.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
|
||||||
|
|
||||||
obj-y += net-sysfs.o
|
obj-y += net-sysfs.o
|
||||||
obj-$(CONFIG_PAGE_POOL) += page_pool.o
|
obj-$(CONFIG_PAGE_POOL) += page_pool.o
|
||||||
obj-$(CONFIG_PROC_FS) += net-procfs.o
|
obj-$(CONFIG_PROC_FS) += net-procfs.o
|
||||||
|
|
236
net/core/dev_addr_lists_test.c
Normal file
236
net/core/dev_addr_lists_test.c
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <kunit/test.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
static const struct net_device_ops dummy_netdev_ops = {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dev_addr_test_priv {
|
||||||
|
u32 addr_seen;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dev_addr_test_sync(struct net_device *netdev, const unsigned char *a)
|
||||||
|
{
|
||||||
|
struct dev_addr_test_priv *datp = netdev_priv(netdev);
|
||||||
|
|
||||||
|
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
|
||||||
|
datp->addr_seen |= 1 << a[0];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_addr_test_unsync(struct net_device *netdev,
|
||||||
|
const unsigned char *a)
|
||||||
|
{
|
||||||
|
struct dev_addr_test_priv *datp = netdev_priv(netdev);
|
||||||
|
|
||||||
|
if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
|
||||||
|
datp->addr_seen &= ~(1 << a[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dev_addr_test_init(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct dev_addr_test_priv *datp;
|
||||||
|
struct net_device *netdev;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
netdev = alloc_etherdev(sizeof(*datp));
|
||||||
|
KUNIT_ASSERT_TRUE(test, !!netdev);
|
||||||
|
|
||||||
|
test->priv = netdev;
|
||||||
|
netdev->netdev_ops = &dummy_netdev_ops;
|
||||||
|
|
||||||
|
err = register_netdev(netdev);
|
||||||
|
if (err) {
|
||||||
|
free_netdev(netdev);
|
||||||
|
KUNIT_FAIL(test, "Can't register netdev %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_exit(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
|
||||||
|
rtnl_unlock();
|
||||||
|
unregister_netdev(netdev);
|
||||||
|
free_netdev(netdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_basic(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
KUNIT_EXPECT_TRUE(test, !!netdev->dev_addr);
|
||||||
|
|
||||||
|
memset(addr, 2, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
|
||||||
|
|
||||||
|
memset(addr, 3, sizeof(addr));
|
||||||
|
dev_addr_set(netdev, addr);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_sync_one(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
struct dev_addr_test_priv *datp;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
datp = netdev_priv(netdev);
|
||||||
|
|
||||||
|
memset(addr, 1, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
KUNIT_EXPECT_EQ(test, 2, datp->addr_seen);
|
||||||
|
|
||||||
|
memset(addr, 2, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
|
||||||
|
datp->addr_seen = 0;
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
/* It's not going to sync anything because the main address is
|
||||||
|
* considered synced and we overwrite in place.
|
||||||
|
*/
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, datp->addr_seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_add_del(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
struct dev_addr_test_priv *datp;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
datp = netdev_priv(netdev);
|
||||||
|
|
||||||
|
for (i = 1; i < 4; i++) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
}
|
||||||
|
/* Add 3 again */
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
|
||||||
|
|
||||||
|
for (i = 1; i < 4; i++) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
KUNIT_EXPECT_EQ(test, 1, datp->addr_seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_del_main(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
|
||||||
|
memset(addr, 1, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
|
||||||
|
KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_add_set(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
struct dev_addr_test_priv *datp;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
datp = netdev_priv(netdev);
|
||||||
|
|
||||||
|
/* There is no external API like dev_addr_add_excl(),
|
||||||
|
* so shuffle the tree a little bit and exploit aliasing.
|
||||||
|
*/
|
||||||
|
for (i = 1; i < 16; i++) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
|
||||||
|
NETDEV_HW_ADDR_T_LAN));
|
||||||
|
memset(addr, 0, sizeof(addr));
|
||||||
|
eth_hw_addr_set(netdev, addr);
|
||||||
|
|
||||||
|
__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
|
||||||
|
dev_addr_test_unsync);
|
||||||
|
KUNIT_EXPECT_EQ(test, 0xffff, datp->addr_seen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dev_addr_test_add_excl(struct kunit *test)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = test->priv;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_uc_add_excl(netdev, addr));
|
||||||
|
}
|
||||||
|
KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i += 2) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
|
||||||
|
}
|
||||||
|
for (i = 1; i < 10; i += 2) {
|
||||||
|
memset(addr, i, sizeof(addr));
|
||||||
|
KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kunit_case dev_addr_test_cases[] = {
|
||||||
|
KUNIT_CASE(dev_addr_test_basic),
|
||||||
|
KUNIT_CASE(dev_addr_test_sync_one),
|
||||||
|
KUNIT_CASE(dev_addr_test_add_del),
|
||||||
|
KUNIT_CASE(dev_addr_test_del_main),
|
||||||
|
KUNIT_CASE(dev_addr_test_add_set),
|
||||||
|
KUNIT_CASE(dev_addr_test_add_excl),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct kunit_suite dev_addr_test_suite = {
|
||||||
|
.name = "dev-addr-list-test",
|
||||||
|
.test_cases = dev_addr_test_cases,
|
||||||
|
.init = dev_addr_test_init,
|
||||||
|
.exit = dev_addr_test_exit,
|
||||||
|
};
|
||||||
|
kunit_test_suite(dev_addr_test_suite);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
Loading…
Reference in a new issue