Skip to content

Commit f532957

Browse files
spikehdavem330
authored andcommitted
netdevsim: allow two netdevsim ports to be connected
Add two netdevsim bus attribute to sysfs: /sys/bus/netdevsim/link_device /sys/bus/netdevsim/unlink_device Writing "A M B N" to link_device will link netdevsim M in netnsid A with netdevsim N in netnsid B. Writing "A M" to unlink_device will unlink netdevsim M in netnsid A from its peer, if any. rtnl_lock is taken to ensure nothing changes during the linking. Signed-off-by: David Wei <[email protected]> Reviewed-by: Maciek Machnikowski <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e2d890a commit f532957

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed

drivers/net/netdevsim/bus.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,154 @@ del_device_store(const struct bus_type *bus, const char *buf, size_t count)
232232
}
233233
static BUS_ATTR_WO(del_device);
234234

235+
static ssize_t link_device_store(const struct bus_type *bus, const char *buf, size_t count)
236+
{
237+
struct netdevsim *nsim_a, *nsim_b, *peer;
238+
struct net_device *dev_a, *dev_b;
239+
unsigned int ifidx_a, ifidx_b;
240+
int netnsfd_a, netnsfd_b, err;
241+
struct net *ns_a, *ns_b;
242+
243+
err = sscanf(buf, "%d:%u %d:%u", &netnsfd_a, &ifidx_a, &netnsfd_b,
244+
&ifidx_b);
245+
if (err != 4) {
246+
pr_err("Format for linking two devices is \"netnsfd_a:ifidx_a netnsfd_b:ifidx_b\" (int uint int uint).\n");
247+
return -EINVAL;
248+
}
249+
250+
ns_a = get_net_ns_by_fd(netnsfd_a);
251+
if (IS_ERR(ns_a)) {
252+
pr_err("Could not find netns with fd: %d\n", netnsfd_a);
253+
return -EINVAL;
254+
}
255+
256+
ns_b = get_net_ns_by_fd(netnsfd_b);
257+
if (IS_ERR(ns_b)) {
258+
pr_err("Could not find netns with fd: %d\n", netnsfd_b);
259+
put_net(ns_a);
260+
return -EINVAL;
261+
}
262+
263+
err = -EINVAL;
264+
rtnl_lock();
265+
dev_a = __dev_get_by_index(ns_a, ifidx_a);
266+
if (!dev_a) {
267+
pr_err("Could not find device with ifindex %u in netnsfd %d\n",
268+
ifidx_a, netnsfd_a);
269+
goto out_err;
270+
}
271+
272+
if (!netdev_is_nsim(dev_a)) {
273+
pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
274+
ifidx_a, netnsfd_a);
275+
goto out_err;
276+
}
277+
278+
dev_b = __dev_get_by_index(ns_b, ifidx_b);
279+
if (!dev_b) {
280+
pr_err("Could not find device with ifindex %u in netnsfd %d\n",
281+
ifidx_b, netnsfd_b);
282+
goto out_err;
283+
}
284+
285+
if (!netdev_is_nsim(dev_b)) {
286+
pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
287+
ifidx_b, netnsfd_b);
288+
goto out_err;
289+
}
290+
291+
if (dev_a == dev_b) {
292+
pr_err("Cannot link a netdevsim to itself\n");
293+
goto out_err;
294+
}
295+
296+
err = -EBUSY;
297+
nsim_a = netdev_priv(dev_a);
298+
peer = rtnl_dereference(nsim_a->peer);
299+
if (peer) {
300+
pr_err("Netdevsim %d:%u is already linked\n", netnsfd_a,
301+
ifidx_a);
302+
goto out_err;
303+
}
304+
305+
nsim_b = netdev_priv(dev_b);
306+
peer = rtnl_dereference(nsim_b->peer);
307+
if (peer) {
308+
pr_err("Netdevsim %d:%u is already linked\n", netnsfd_b,
309+
ifidx_b);
310+
goto out_err;
311+
}
312+
313+
err = 0;
314+
rcu_assign_pointer(nsim_a->peer, nsim_b);
315+
rcu_assign_pointer(nsim_b->peer, nsim_a);
316+
317+
out_err:
318+
put_net(ns_b);
319+
put_net(ns_a);
320+
rtnl_unlock();
321+
322+
return !err ? count : err;
323+
}
324+
static BUS_ATTR_WO(link_device);
325+
326+
static ssize_t unlink_device_store(const struct bus_type *bus, const char *buf, size_t count)
327+
{
328+
struct netdevsim *nsim, *peer;
329+
struct net_device *dev;
330+
unsigned int ifidx;
331+
int netnsfd, err;
332+
struct net *ns;
333+
334+
err = sscanf(buf, "%u:%u", &netnsfd, &ifidx);
335+
if (err != 2) {
336+
pr_err("Format for unlinking a device is \"netnsfd:ifidx\" (int uint).\n");
337+
return -EINVAL;
338+
}
339+
340+
ns = get_net_ns_by_fd(netnsfd);
341+
if (IS_ERR(ns)) {
342+
pr_err("Could not find netns with fd: %d\n", netnsfd);
343+
return -EINVAL;
344+
}
345+
346+
err = -EINVAL;
347+
rtnl_lock();
348+
dev = __dev_get_by_index(ns, ifidx);
349+
if (!dev) {
350+
pr_err("Could not find device with ifindex %u in netnsfd %d\n",
351+
ifidx, netnsfd);
352+
goto out_put_netns;
353+
}
354+
355+
if (!netdev_is_nsim(dev)) {
356+
pr_err("Device with ifindex %u in netnsfd %d is not a netdevsim\n",
357+
ifidx, netnsfd);
358+
goto out_put_netns;
359+
}
360+
361+
nsim = netdev_priv(dev);
362+
peer = rtnl_dereference(nsim->peer);
363+
if (!peer)
364+
goto out_put_netns;
365+
366+
err = 0;
367+
RCU_INIT_POINTER(nsim->peer, NULL);
368+
RCU_INIT_POINTER(peer->peer, NULL);
369+
370+
out_put_netns:
371+
put_net(ns);
372+
rtnl_unlock();
373+
374+
return !err ? count : err;
375+
}
376+
static BUS_ATTR_WO(unlink_device);
377+
235378
static struct attribute *nsim_bus_attrs[] = {
236379
&bus_attr_new_device.attr,
237380
&bus_attr_del_device.attr,
381+
&bus_attr_link_device.attr,
382+
&bus_attr_unlink_device.attr,
238383
NULL
239384
};
240385
ATTRIBUTE_GROUPS(nsim_bus);

drivers/net/netdevsim/netdev.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,8 +413,13 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
413413
void nsim_destroy(struct netdevsim *ns)
414414
{
415415
struct net_device *dev = ns->netdev;
416+
struct netdevsim *peer;
416417

417418
rtnl_lock();
419+
peer = rtnl_dereference(ns->peer);
420+
if (peer)
421+
RCU_INIT_POINTER(peer->peer, NULL);
422+
RCU_INIT_POINTER(ns->peer, NULL);
418423
unregister_netdevice(dev);
419424
if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {
420425
nsim_macsec_teardown(ns);
@@ -427,6 +432,11 @@ void nsim_destroy(struct netdevsim *ns)
427432
free_netdev(dev);
428433
}
429434

435+
bool netdev_is_nsim(struct net_device *dev)
436+
{
437+
return dev->netdev_ops == &nsim_netdev_ops;
438+
}
439+
430440
static int nsim_validate(struct nlattr *tb[], struct nlattr *data[],
431441
struct netlink_ext_ack *extack)
432442
{

drivers/net/netdevsim/netdevsim.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,13 @@ struct netdevsim {
125125
} udp_ports;
126126

127127
struct nsim_ethtool ethtool;
128+
struct netdevsim __rcu *peer;
128129
};
129130

130131
struct netdevsim *
131132
nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port);
132133
void nsim_destroy(struct netdevsim *ns);
134+
bool netdev_is_nsim(struct net_device *dev);
133135

134136
void nsim_ethtool_init(struct netdevsim *ns);
135137

0 commit comments

Comments
 (0)