Skip to content

Commit 7957922

Browse files
Jakub Kicinskiborkmann
authored andcommitted
netdevsim: add SR-IOV functionality
dummy driver was extended with VF-related netdev APIs for testing SR-IOV-related software. netdevsim did not exist back then. Implement SR-IOV functionality in netdevsim. Notable difference is that since netdevsim has no module parameters, we will actually create a device with sriov_numvfs attribute for each netdev. The zero MAC address is accepted as some HW use it to mean any address is allowed. Link state is also now validated. Signed-off-by: Jakub Kicinski <[email protected]> Reviewed-by: Quentin Monnet <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 417ec26 commit 7957922

File tree

2 files changed

+284
-2
lines changed

2 files changed

+284
-2
lines changed

drivers/net/netdevsim/netdev.c

Lines changed: 272 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,125 @@
2525

2626
#include "netdevsim.h"
2727

28+
struct nsim_vf_config {
29+
int link_state;
30+
u16 min_tx_rate;
31+
u16 max_tx_rate;
32+
u16 vlan;
33+
__be16 vlan_proto;
34+
u16 qos;
35+
u8 vf_mac[ETH_ALEN];
36+
bool spoofchk_enabled;
37+
bool trusted;
38+
bool rss_query_enabled;
39+
};
40+
41+
static u32 nsim_dev_id;
42+
43+
static int nsim_num_vf(struct device *dev)
44+
{
45+
struct netdevsim *ns = to_nsim(dev);
46+
47+
return ns->num_vfs;
48+
}
49+
50+
static struct bus_type nsim_bus = {
51+
.name = DRV_NAME,
52+
.dev_name = DRV_NAME,
53+
.num_vf = nsim_num_vf,
54+
};
55+
56+
static int nsim_vfs_enable(struct netdevsim *ns, unsigned int num_vfs)
57+
{
58+
ns->vfconfigs = kcalloc(num_vfs, sizeof(struct nsim_vf_config),
59+
GFP_KERNEL);
60+
if (!ns->vfconfigs)
61+
return -ENOMEM;
62+
ns->num_vfs = num_vfs;
63+
64+
return 0;
65+
}
66+
67+
static void nsim_vfs_disable(struct netdevsim *ns)
68+
{
69+
kfree(ns->vfconfigs);
70+
ns->vfconfigs = NULL;
71+
ns->num_vfs = 0;
72+
}
73+
74+
static ssize_t
75+
nsim_numvfs_store(struct device *dev, struct device_attribute *attr,
76+
const char *buf, size_t count)
77+
{
78+
struct netdevsim *ns = to_nsim(dev);
79+
unsigned int num_vfs;
80+
int ret;
81+
82+
ret = kstrtouint(buf, 0, &num_vfs);
83+
if (ret)
84+
return ret;
85+
86+
rtnl_lock();
87+
if (ns->num_vfs == num_vfs)
88+
goto exit_good;
89+
if (ns->num_vfs && num_vfs) {
90+
ret = -EBUSY;
91+
goto exit_unlock;
92+
}
93+
94+
if (num_vfs) {
95+
ret = nsim_vfs_enable(ns, num_vfs);
96+
if (ret)
97+
goto exit_unlock;
98+
} else {
99+
nsim_vfs_disable(ns);
100+
}
101+
exit_good:
102+
ret = count;
103+
exit_unlock:
104+
rtnl_unlock();
105+
106+
return ret;
107+
}
108+
109+
static ssize_t
110+
nsim_numvfs_show(struct device *dev, struct device_attribute *attr, char *buf)
111+
{
112+
struct netdevsim *ns = to_nsim(dev);
113+
114+
return sprintf(buf, "%u\n", ns->num_vfs);
115+
}
116+
117+
static struct device_attribute nsim_numvfs_attr =
118+
__ATTR(sriov_numvfs, 0664, nsim_numvfs_show, nsim_numvfs_store);
119+
120+
static struct attribute *nsim_dev_attrs[] = {
121+
&nsim_numvfs_attr.attr,
122+
NULL,
123+
};
124+
125+
static const struct attribute_group nsim_dev_attr_group = {
126+
.attrs = nsim_dev_attrs,
127+
};
128+
129+
static const struct attribute_group *nsim_dev_attr_groups[] = {
130+
&nsim_dev_attr_group,
131+
NULL,
132+
};
133+
134+
static void nsim_dev_release(struct device *dev)
135+
{
136+
struct netdevsim *ns = to_nsim(dev);
137+
138+
nsim_vfs_disable(ns);
139+
free_netdev(ns->netdev);
140+
}
141+
142+
struct device_type nsim_dev_type = {
143+
.groups = nsim_dev_attr_groups,
144+
.release = nsim_dev_release,
145+
};
146+
28147
static int nsim_init(struct net_device *dev)
29148
{
30149
struct netdevsim *ns = netdev_priv(dev);
@@ -37,8 +156,19 @@ static int nsim_init(struct net_device *dev)
37156
if (err)
38157
goto err_debugfs_destroy;
39158

159+
ns->dev.id = nsim_dev_id++;
160+
ns->dev.bus = &nsim_bus;
161+
ns->dev.type = &nsim_dev_type;
162+
err = device_register(&ns->dev);
163+
if (err)
164+
goto err_bpf_uninit;
165+
166+
SET_NETDEV_DEV(dev, &ns->dev);
167+
40168
return 0;
41169

170+
err_bpf_uninit:
171+
nsim_bpf_uninit(ns);
42172
err_debugfs_destroy:
43173
debugfs_remove_recursive(ns->ddir);
44174
return err;
@@ -52,6 +182,14 @@ static void nsim_uninit(struct net_device *dev)
52182
nsim_bpf_uninit(ns);
53183
}
54184

185+
static void nsim_free(struct net_device *dev)
186+
{
187+
struct netdevsim *ns = netdev_priv(dev);
188+
189+
device_unregister(&ns->dev);
190+
/* netdev and vf state will be freed out of device_release() */
191+
}
192+
55193
static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
56194
{
57195
struct netdevsim *ns = netdev_priv(dev);
@@ -122,6 +260,123 @@ nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f)
122260
}
123261
}
124262

263+
static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
264+
{
265+
struct netdevsim *ns = netdev_priv(dev);
266+
267+
/* Only refuse multicast addresses, zero address can mean unset/any. */
268+
if (vf >= ns->num_vfs || is_multicast_ether_addr(mac))
269+
return -EINVAL;
270+
memcpy(ns->vfconfigs[vf].vf_mac, mac, ETH_ALEN);
271+
272+
return 0;
273+
}
274+
275+
static int nsim_set_vf_vlan(struct net_device *dev, int vf,
276+
u16 vlan, u8 qos, __be16 vlan_proto)
277+
{
278+
struct netdevsim *ns = netdev_priv(dev);
279+
280+
if (vf >= ns->num_vfs || vlan > 4095 || qos > 7)
281+
return -EINVAL;
282+
283+
ns->vfconfigs[vf].vlan = vlan;
284+
ns->vfconfigs[vf].qos = qos;
285+
ns->vfconfigs[vf].vlan_proto = vlan_proto;
286+
287+
return 0;
288+
}
289+
290+
static int nsim_set_vf_rate(struct net_device *dev, int vf, int min, int max)
291+
{
292+
struct netdevsim *ns = netdev_priv(dev);
293+
294+
if (vf >= ns->num_vfs)
295+
return -EINVAL;
296+
297+
ns->vfconfigs[vf].min_tx_rate = min;
298+
ns->vfconfigs[vf].max_tx_rate = max;
299+
300+
return 0;
301+
}
302+
303+
static int nsim_set_vf_spoofchk(struct net_device *dev, int vf, bool val)
304+
{
305+
struct netdevsim *ns = netdev_priv(dev);
306+
307+
if (vf >= ns->num_vfs)
308+
return -EINVAL;
309+
ns->vfconfigs[vf].spoofchk_enabled = val;
310+
311+
return 0;
312+
}
313+
314+
static int nsim_set_vf_rss_query_en(struct net_device *dev, int vf, bool val)
315+
{
316+
struct netdevsim *ns = netdev_priv(dev);
317+
318+
if (vf >= ns->num_vfs)
319+
return -EINVAL;
320+
ns->vfconfigs[vf].rss_query_enabled = val;
321+
322+
return 0;
323+
}
324+
325+
static int nsim_set_vf_trust(struct net_device *dev, int vf, bool val)
326+
{
327+
struct netdevsim *ns = netdev_priv(dev);
328+
329+
if (vf >= ns->num_vfs)
330+
return -EINVAL;
331+
ns->vfconfigs[vf].trusted = val;
332+
333+
return 0;
334+
}
335+
336+
static int
337+
nsim_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivi)
338+
{
339+
struct netdevsim *ns = netdev_priv(dev);
340+
341+
if (vf >= ns->num_vfs)
342+
return -EINVAL;
343+
344+
ivi->vf = vf;
345+
ivi->linkstate = ns->vfconfigs[vf].link_state;
346+
ivi->min_tx_rate = ns->vfconfigs[vf].min_tx_rate;
347+
ivi->max_tx_rate = ns->vfconfigs[vf].max_tx_rate;
348+
ivi->vlan = ns->vfconfigs[vf].vlan;
349+
ivi->vlan_proto = ns->vfconfigs[vf].vlan_proto;
350+
ivi->qos = ns->vfconfigs[vf].qos;
351+
memcpy(&ivi->mac, ns->vfconfigs[vf].vf_mac, ETH_ALEN);
352+
ivi->spoofchk = ns->vfconfigs[vf].spoofchk_enabled;
353+
ivi->trusted = ns->vfconfigs[vf].trusted;
354+
ivi->rss_query_en = ns->vfconfigs[vf].rss_query_enabled;
355+
356+
return 0;
357+
}
358+
359+
static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
360+
{
361+
struct netdevsim *ns = netdev_priv(dev);
362+
363+
if (vf >= ns->num_vfs)
364+
return -EINVAL;
365+
366+
switch (state) {
367+
case IFLA_VF_LINK_STATE_AUTO:
368+
case IFLA_VF_LINK_STATE_ENABLE:
369+
case IFLA_VF_LINK_STATE_DISABLE:
370+
break;
371+
default:
372+
return -EINVAL;
373+
}
374+
375+
ns->vfconfigs[vf].link_state = state;
376+
377+
return 0;
378+
}
379+
125380
static int
126381
nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
127382
{
@@ -153,6 +408,14 @@ static const struct net_device_ops nsim_netdev_ops = {
153408
.ndo_validate_addr = eth_validate_addr,
154409
.ndo_change_mtu = nsim_change_mtu,
155410
.ndo_get_stats64 = nsim_get_stats64,
411+
.ndo_set_vf_mac = nsim_set_vf_mac,
412+
.ndo_set_vf_vlan = nsim_set_vf_vlan,
413+
.ndo_set_vf_rate = nsim_set_vf_rate,
414+
.ndo_set_vf_spoofchk = nsim_set_vf_spoofchk,
415+
.ndo_set_vf_trust = nsim_set_vf_trust,
416+
.ndo_get_vf_config = nsim_get_vf_config,
417+
.ndo_set_vf_link_state = nsim_set_vf_link_state,
418+
.ndo_set_vf_rss_query_en = nsim_set_vf_rss_query_en,
156419
.ndo_setup_tc = nsim_setup_tc,
157420
.ndo_set_features = nsim_set_features,
158421
.ndo_bpf = nsim_bpf,
@@ -164,7 +427,7 @@ static void nsim_setup(struct net_device *dev)
164427
eth_hw_addr_random(dev);
165428

166429
dev->netdev_ops = &nsim_netdev_ops;
167-
dev->needs_free_netdev = true;
430+
dev->priv_destructor = nsim_free;
168431

169432
dev->tx_queue_len = 0;
170433
dev->flags |= IFF_NOARP;
@@ -209,12 +472,18 @@ static int __init nsim_module_init(void)
209472
if (IS_ERR(nsim_ddir))
210473
return PTR_ERR(nsim_ddir);
211474

212-
err = rtnl_link_register(&nsim_link_ops);
475+
err = bus_register(&nsim_bus);
213476
if (err)
214477
goto err_debugfs_destroy;
215478

479+
err = rtnl_link_register(&nsim_link_ops);
480+
if (err)
481+
goto err_unreg_bus;
482+
216483
return 0;
217484

485+
err_unreg_bus:
486+
bus_unregister(&nsim_bus);
218487
err_debugfs_destroy:
219488
debugfs_remove_recursive(nsim_ddir);
220489
return err;
@@ -223,6 +492,7 @@ static int __init nsim_module_init(void)
223492
static void __exit nsim_module_exit(void)
224493
{
225494
rtnl_link_unregister(&nsim_link_ops);
495+
bus_unregister(&nsim_bus);
226496
debugfs_remove_recursive(nsim_ddir);
227497
}
228498

drivers/net/netdevsim/netdevsim.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
* THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
1414
*/
1515

16+
#include <linux/device.h>
1617
#include <linux/kernel.h>
1718
#include <linux/list.h>
1819
#include <linux/netdevice.h>
@@ -26,6 +27,7 @@
2627

2728
struct bpf_prog;
2829
struct dentry;
30+
struct nsim_vf_config;
2931

3032
struct netdevsim {
3133
struct net_device *netdev;
@@ -34,8 +36,13 @@ struct netdevsim {
3436
u64 tx_bytes;
3537
struct u64_stats_sync syncp;
3638

39+
struct device dev;
40+
3741
struct dentry *ddir;
3842

43+
unsigned int num_vfs;
44+
struct nsim_vf_config *vfconfigs;
45+
3946
struct bpf_prog *bpf_offloaded;
4047
u32 bpf_offloaded_id;
4148

@@ -64,3 +71,8 @@ int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf);
6471
int nsim_bpf_disable_tc(struct netdevsim *ns);
6572
int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
6673
void *type_data, void *cb_priv);
74+
75+
static inline struct netdevsim *to_nsim(struct device *ptr)
76+
{
77+
return container_of(ptr, struct netdevsim, dev);
78+
}

0 commit comments

Comments
 (0)