-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Jakub Kicinski
authored and
David S. Miller
committed
Nov 20, 2021
1 parent
a387ff8
commit 2c193f2
Showing
3 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); |