Skip to content

Commit 465fa80

Browse files
spikehNipaLocal
authored andcommitted
netdevsim: allow two netdevsim ports to be connected
Add a debugfs file in /sys/kernel/debug/netdevsim/netdevsimN/ports/A/peer Writing "M B" to this file will link port A of netdevsim N with port B of netdevsim M. Reading this file will return the linked netdevsim id and port, if any. Signed-off-by: David Wei <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent a7cc028 commit 465fa80

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

drivers/net/netdevsim/bus.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,13 @@ void nsim_bus_exit(void)
364364
driver_unregister(&nsim_driver);
365365
bus_unregister(&nsim_bus);
366366
}
367+
368+
struct nsim_bus_dev *nsim_bus_dev_get(unsigned int id)
369+
{
370+
struct nsim_bus_dev *nsim_bus_dev;
371+
list_for_each_entry(nsim_bus_dev, &nsim_bus_dev_list, list) {
372+
if (nsim_bus_dev->dev.id == id)
373+
return nsim_bus_dev;
374+
}
375+
return NULL;
376+
}

drivers/net/netdevsim/dev.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,88 @@ static const struct file_operations nsim_dev_rate_parent_fops = {
388388
.owner = THIS_MODULE,
389389
};
390390

391+
static ssize_t nsim_dev_peer_read(struct file *file, char __user *data,
392+
size_t count, loff_t *ppos)
393+
{
394+
struct nsim_dev_port *nsim_dev_port;
395+
struct netdevsim *peer;
396+
unsigned int id, port;
397+
char buf[23];
398+
ssize_t len;
399+
400+
nsim_dev_port = file->private_data;
401+
rcu_read_lock();
402+
peer = rcu_dereference(nsim_dev_port->ns->peer);
403+
if (!peer) {
404+
len = scnprintf(buf, sizeof(buf), "\n");
405+
goto out;
406+
}
407+
408+
id = peer->nsim_bus_dev->dev.id;
409+
port = peer->nsim_dev_port->port_index;
410+
len = scnprintf(buf, sizeof(buf), "%u %u\n", id, port);
411+
412+
out:
413+
rcu_read_unlock();
414+
return simple_read_from_buffer(data, count, ppos, buf, len);
415+
}
416+
417+
static ssize_t nsim_dev_peer_write(struct file *file,
418+
const char __user *data,
419+
size_t count, loff_t *ppos)
420+
{
421+
struct nsim_dev_port *nsim_dev_port, *peer_dev_port;
422+
struct nsim_bus_dev *peer_bus_dev;
423+
struct nsim_dev *peer_dev;
424+
unsigned int id, port;
425+
char buf[22];
426+
ssize_t ret;
427+
428+
if (count >= sizeof(buf))
429+
return -ENOSPC;
430+
431+
ret = copy_from_user(buf, data, count);
432+
if (ret)
433+
return -EFAULT;
434+
buf[count] = '\0';
435+
436+
ret = sscanf(buf, "%u %u", &id, &port);
437+
if (ret != 2) {
438+
pr_err("Format for adding a peer is \"id port\" (uint uint)");
439+
return -EINVAL;
440+
}
441+
442+
/* invalid netdevsim id */
443+
peer_bus_dev = nsim_bus_dev_get(id);
444+
if (!peer_bus_dev)
445+
return -EINVAL;
446+
447+
/* cannot link to self */
448+
nsim_dev_port = file->private_data;
449+
if (nsim_dev_port->ns->nsim_bus_dev == peer_bus_dev &&
450+
nsim_dev_port->port_index == port)
451+
return -EINVAL;
452+
453+
peer_dev = dev_get_drvdata(&peer_bus_dev->dev);
454+
list_for_each_entry(peer_dev_port, &peer_dev->port_list, list) {
455+
if (peer_dev_port->port_index != port)
456+
continue;
457+
rcu_assign_pointer(nsim_dev_port->ns->peer, peer_dev_port->ns);
458+
rcu_assign_pointer(peer_dev_port->ns->peer, nsim_dev_port->ns);
459+
return count;
460+
}
461+
462+
return -EINVAL;
463+
}
464+
465+
static const struct file_operations nsim_dev_peer_fops = {
466+
.open = simple_open,
467+
.read = nsim_dev_peer_read,
468+
.write = nsim_dev_peer_write,
469+
.llseek = generic_file_llseek,
470+
.owner = THIS_MODULE,
471+
};
472+
391473
static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
392474
struct nsim_dev_port *nsim_dev_port)
393475
{
@@ -418,6 +500,9 @@ static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
418500
}
419501
debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
420502

503+
debugfs_create_file("peer", 0600, nsim_dev_port->ddir,
504+
nsim_dev_port, &nsim_dev_peer_fops);
505+
421506
return 0;
422507
}
423508

drivers/net/netdevsim/netdev.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
388388
ns->nsim_dev = nsim_dev;
389389
ns->nsim_dev_port = nsim_dev_port;
390390
ns->nsim_bus_dev = nsim_dev->nsim_bus_dev;
391+
RCU_INIT_POINTER(ns->peer, NULL);
391392
SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
392393
SET_NETDEV_DEVLINK_PORT(dev, &nsim_dev_port->devlink_port);
393394
nsim_ethtool_init(ns);
@@ -407,9 +408,14 @@ nsim_create(struct nsim_dev *nsim_dev, struct nsim_dev_port *nsim_dev_port)
407408
void nsim_destroy(struct netdevsim *ns)
408409
{
409410
struct net_device *dev = ns->netdev;
411+
struct netdevsim *peer;
410412

411413
rtnl_lock();
414+
peer = rtnl_dereference(ns->peer);
415+
RCU_INIT_POINTER(ns->peer, NULL);
412416
unregister_netdevice(dev);
417+
if (peer)
418+
RCU_INIT_POINTER(peer->peer, NULL);
413419
if (nsim_dev_port_is_pf(ns->nsim_dev_port)) {
414420
nsim_macsec_teardown(ns);
415421
nsim_ipsec_teardown(ns);

drivers/net/netdevsim/netdevsim.h

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

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

130131
struct netdevsim *
@@ -417,3 +418,5 @@ struct nsim_bus_dev {
417418

418419
int nsim_bus_init(void);
419420
void nsim_bus_exit(void);
421+
422+
struct nsim_bus_dev *nsim_bus_dev_get(unsigned int id);

0 commit comments

Comments
 (0)