1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | |
3 | #include <kunit/test.h> |
4 | #include <linux/etherdevice.h> |
5 | #include <linux/netdevice.h> |
6 | #include <linux/rtnetlink.h> |
7 | |
8 | static const struct net_device_ops dummy_netdev_ops = { |
9 | }; |
10 | |
11 | struct dev_addr_test_priv { |
12 | u32 addr_seen; |
13 | }; |
14 | |
15 | static int dev_addr_test_sync(struct net_device *netdev, const unsigned char *a) |
16 | { |
17 | struct dev_addr_test_priv *datp = netdev_priv(dev: netdev); |
18 | |
19 | if (a[0] < 31 && !memchr_inv(p: a, c: a[0], ETH_ALEN)) |
20 | datp->addr_seen |= 1 << a[0]; |
21 | return 0; |
22 | } |
23 | |
24 | static int dev_addr_test_unsync(struct net_device *netdev, |
25 | const unsigned char *a) |
26 | { |
27 | struct dev_addr_test_priv *datp = netdev_priv(dev: netdev); |
28 | |
29 | if (a[0] < 31 && !memchr_inv(p: a, c: a[0], ETH_ALEN)) |
30 | datp->addr_seen &= ~(1 << a[0]); |
31 | return 0; |
32 | } |
33 | |
34 | static int dev_addr_test_init(struct kunit *test) |
35 | { |
36 | struct dev_addr_test_priv *datp; |
37 | struct net_device *netdev; |
38 | int err; |
39 | |
40 | netdev = alloc_etherdev(sizeof(*datp)); |
41 | KUNIT_ASSERT_TRUE(test, !!netdev); |
42 | |
43 | test->priv = netdev; |
44 | netdev->netdev_ops = &dummy_netdev_ops; |
45 | |
46 | err = register_netdev(dev: netdev); |
47 | if (err) { |
48 | free_netdev(dev: netdev); |
49 | KUNIT_FAIL(test, "Can't register netdev %d" , err); |
50 | } |
51 | |
52 | rtnl_lock(); |
53 | return 0; |
54 | } |
55 | |
56 | static void dev_addr_test_exit(struct kunit *test) |
57 | { |
58 | struct net_device *netdev = test->priv; |
59 | |
60 | rtnl_unlock(); |
61 | unregister_netdev(dev: netdev); |
62 | free_netdev(dev: netdev); |
63 | } |
64 | |
65 | static void dev_addr_test_basic(struct kunit *test) |
66 | { |
67 | struct net_device *netdev = test->priv; |
68 | u8 addr[ETH_ALEN]; |
69 | |
70 | KUNIT_EXPECT_TRUE(test, !!netdev->dev_addr); |
71 | |
72 | memset(addr, 2, sizeof(addr)); |
73 | eth_hw_addr_set(dev: netdev, addr); |
74 | KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr)); |
75 | |
76 | memset(addr, 3, sizeof(addr)); |
77 | dev_addr_set(dev: netdev, addr); |
78 | KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr)); |
79 | } |
80 | |
81 | static void dev_addr_test_sync_one(struct kunit *test) |
82 | { |
83 | struct net_device *netdev = test->priv; |
84 | struct dev_addr_test_priv *datp; |
85 | u8 addr[ETH_ALEN]; |
86 | |
87 | datp = netdev_priv(dev: netdev); |
88 | |
89 | memset(addr, 1, sizeof(addr)); |
90 | eth_hw_addr_set(dev: netdev, addr); |
91 | |
92 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
93 | unsync: dev_addr_test_unsync); |
94 | KUNIT_EXPECT_EQ(test, 2, datp->addr_seen); |
95 | |
96 | memset(addr, 2, sizeof(addr)); |
97 | eth_hw_addr_set(dev: netdev, addr); |
98 | |
99 | datp->addr_seen = 0; |
100 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
101 | unsync: dev_addr_test_unsync); |
102 | /* It's not going to sync anything because the main address is |
103 | * considered synced and we overwrite in place. |
104 | */ |
105 | KUNIT_EXPECT_EQ(test, 0, datp->addr_seen); |
106 | } |
107 | |
108 | static void dev_addr_test_add_del(struct kunit *test) |
109 | { |
110 | struct net_device *netdev = test->priv; |
111 | struct dev_addr_test_priv *datp; |
112 | u8 addr[ETH_ALEN]; |
113 | int i; |
114 | |
115 | datp = netdev_priv(dev: netdev); |
116 | |
117 | for (i = 1; i < 4; i++) { |
118 | memset(addr, i, sizeof(addr)); |
119 | KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr, |
120 | NETDEV_HW_ADDR_T_LAN)); |
121 | } |
122 | /* Add 3 again */ |
123 | KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr, |
124 | NETDEV_HW_ADDR_T_LAN)); |
125 | |
126 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
127 | unsync: dev_addr_test_unsync); |
128 | KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen); |
129 | |
130 | KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr, |
131 | NETDEV_HW_ADDR_T_LAN)); |
132 | |
133 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
134 | unsync: dev_addr_test_unsync); |
135 | KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen); |
136 | |
137 | for (i = 1; i < 4; i++) { |
138 | memset(addr, i, sizeof(addr)); |
139 | KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr, |
140 | NETDEV_HW_ADDR_T_LAN)); |
141 | } |
142 | |
143 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
144 | unsync: dev_addr_test_unsync); |
145 | KUNIT_EXPECT_EQ(test, 1, datp->addr_seen); |
146 | } |
147 | |
148 | static void dev_addr_test_del_main(struct kunit *test) |
149 | { |
150 | struct net_device *netdev = test->priv; |
151 | u8 addr[ETH_ALEN]; |
152 | |
153 | memset(addr, 1, sizeof(addr)); |
154 | eth_hw_addr_set(dev: netdev, addr); |
155 | |
156 | KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr, |
157 | NETDEV_HW_ADDR_T_LAN)); |
158 | KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr, |
159 | NETDEV_HW_ADDR_T_LAN)); |
160 | KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr, |
161 | NETDEV_HW_ADDR_T_LAN)); |
162 | KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr, |
163 | NETDEV_HW_ADDR_T_LAN)); |
164 | } |
165 | |
166 | static void dev_addr_test_add_set(struct kunit *test) |
167 | { |
168 | struct net_device *netdev = test->priv; |
169 | struct dev_addr_test_priv *datp; |
170 | u8 addr[ETH_ALEN]; |
171 | int i; |
172 | |
173 | datp = netdev_priv(dev: netdev); |
174 | |
175 | /* There is no external API like dev_addr_add_excl(), |
176 | * so shuffle the tree a little bit and exploit aliasing. |
177 | */ |
178 | for (i = 1; i < 16; i++) { |
179 | memset(addr, i, sizeof(addr)); |
180 | KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr, |
181 | NETDEV_HW_ADDR_T_LAN)); |
182 | } |
183 | |
184 | memset(addr, i, sizeof(addr)); |
185 | eth_hw_addr_set(dev: netdev, addr); |
186 | KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr, |
187 | NETDEV_HW_ADDR_T_LAN)); |
188 | memset(addr, 0, sizeof(addr)); |
189 | eth_hw_addr_set(dev: netdev, addr); |
190 | |
191 | __hw_addr_sync_dev(list: &netdev->dev_addrs, dev: netdev, sync: dev_addr_test_sync, |
192 | unsync: dev_addr_test_unsync); |
193 | KUNIT_EXPECT_EQ(test, 0xffff, datp->addr_seen); |
194 | } |
195 | |
196 | static void dev_addr_test_add_excl(struct kunit *test) |
197 | { |
198 | struct net_device *netdev = test->priv; |
199 | u8 addr[ETH_ALEN]; |
200 | int i; |
201 | |
202 | for (i = 0; i < 10; i++) { |
203 | memset(addr, i, sizeof(addr)); |
204 | KUNIT_EXPECT_EQ(test, 0, dev_uc_add_excl(netdev, addr)); |
205 | } |
206 | KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr)); |
207 | |
208 | for (i = 0; i < 10; i += 2) { |
209 | memset(addr, i, sizeof(addr)); |
210 | KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr)); |
211 | } |
212 | for (i = 1; i < 10; i += 2) { |
213 | memset(addr, i, sizeof(addr)); |
214 | KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr)); |
215 | } |
216 | } |
217 | |
218 | static struct kunit_case dev_addr_test_cases[] = { |
219 | KUNIT_CASE(dev_addr_test_basic), |
220 | KUNIT_CASE(dev_addr_test_sync_one), |
221 | KUNIT_CASE(dev_addr_test_add_del), |
222 | KUNIT_CASE(dev_addr_test_del_main), |
223 | KUNIT_CASE(dev_addr_test_add_set), |
224 | KUNIT_CASE(dev_addr_test_add_excl), |
225 | {} |
226 | }; |
227 | |
228 | static struct kunit_suite dev_addr_test_suite = { |
229 | .name = "dev-addr-list-test" , |
230 | .test_cases = dev_addr_test_cases, |
231 | .init = dev_addr_test_init, |
232 | .exit = dev_addr_test_exit, |
233 | }; |
234 | kunit_test_suite(dev_addr_test_suite); |
235 | |
236 | MODULE_DESCRIPTION("KUnit tests for struct netdev_hw_addr_list" ); |
237 | MODULE_LICENSE("GPL" ); |
238 | |