diff --git a/drivers/net/netdevsim/bus.c b/drivers/net/netdevsim/bus.c index 1ee14e1bb12d..549c399f29da 100644 --- a/drivers/net/netdevsim/bus.c +++ b/drivers/net/netdevsim/bus.c @@ -91,8 +91,44 @@ static struct device_attribute nsim_bus_dev_numvfs_attr = __ATTR(sriov_numvfs, 0664, nsim_bus_dev_numvfs_show, nsim_bus_dev_numvfs_store); +static ssize_t +new_port_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); + unsigned int port_index; + int ret; + + ret = kstrtouint(buf, 0, &port_index); + if (ret) + return ret; + ret = nsim_dev_port_add(nsim_bus_dev, port_index); + return ret ? ret : count; +} + +static struct device_attribute nsim_bus_dev_new_port_attr = __ATTR_WO(new_port); + +static ssize_t +del_port_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev); + unsigned int port_index; + int ret; + + ret = kstrtouint(buf, 0, &port_index); + if (ret) + return ret; + ret = nsim_dev_port_del(nsim_bus_dev, port_index); + return ret ? ret : count; +} + +static struct device_attribute nsim_bus_dev_del_port_attr = __ATTR_WO(del_port); + static struct attribute *nsim_bus_dev_attrs[] = { &nsim_bus_dev_numvfs_attr.attr, + &nsim_bus_dev_new_port_attr.attr, + &nsim_bus_dev_del_port_attr.attr, NULL, }; diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index 6ee9d43ae252..2fa1b2061370 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +239,7 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count) nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id); get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len); INIT_LIST_HEAD(&nsim_dev->port_list); + mutex_init(&nsim_dev->port_list_lock); nsim_dev->fib_data = nsim_fib_create(); if (IS_ERR(nsim_dev->fib_data)) { @@ -285,10 +287,12 @@ void nsim_dev_destroy(struct nsim_dev *nsim_dev) devlink_unregister(devlink); devlink_resources_unregister(devlink, NULL); nsim_fib_destroy(nsim_dev->fib_data); + mutex_destroy(&nsim_dev->port_list_lock); devlink_free(devlink); } -static int nsim_dev_port_add(struct nsim_dev *nsim_dev, unsigned int port_index) +static int __nsim_dev_port_add(struct nsim_dev *nsim_dev, + unsigned int port_index) { struct nsim_dev_port *nsim_dev_port; struct devlink_port *devlink_port; @@ -324,7 +328,7 @@ err_port_free: return err; } -static void nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) +static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port) { struct devlink_port *devlink_port = &nsim_dev_port->devlink_port; @@ -340,7 +344,7 @@ static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev) list_for_each_entry_safe(nsim_dev_port, tmp, &nsim_dev->port_list, list) - nsim_dev_port_del(nsim_dev_port); + __nsim_dev_port_del(nsim_dev_port); } int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) @@ -355,7 +359,7 @@ int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev) dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev); for (i = 0; i < nsim_bus_dev->port_count; i++) { - err = nsim_dev_port_add(nsim_dev, i); + err = __nsim_dev_port_add(nsim_dev, i); if (err) goto err_port_del_all; } @@ -375,6 +379,49 @@ void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev) nsim_dev_destroy(nsim_dev); } +static struct nsim_dev_port * +__nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index) +{ + struct nsim_dev_port *nsim_dev_port; + + list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list) + if (nsim_dev_port->port_index == port_index) + return nsim_dev_port; + return NULL; +} + +int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, + unsigned int port_index) +{ + struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); + int err; + + mutex_lock(&nsim_dev->port_list_lock); + if (__nsim_dev_port_lookup(nsim_dev, port_index)) + err = -EEXIST; + else + err = __nsim_dev_port_add(nsim_dev, port_index); + mutex_unlock(&nsim_dev->port_list_lock); + return err; +} + +int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, + unsigned int port_index) +{ + struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev); + struct nsim_dev_port *nsim_dev_port; + int err = 0; + + mutex_lock(&nsim_dev->port_list_lock); + nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index); + if (!nsim_dev_port) + err = -ENOENT; + else + __nsim_dev_port_del(nsim_dev_port); + mutex_unlock(&nsim_dev->port_list_lock); + return err; +} + int nsim_dev_init(void) { nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL); diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 0e6ca85e5487..6b60589cab91 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -152,12 +152,17 @@ struct nsim_dev { struct list_head bpf_bound_maps; struct netdev_phys_item_id switch_id; struct list_head port_list; + struct mutex port_list_lock; /* protects port list */ }; int nsim_dev_init(void); void nsim_dev_exit(void); int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev); void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev); +int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev, + unsigned int port_index); +int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev, + unsigned int port_index); struct nsim_fib_data *nsim_fib_create(void); void nsim_fib_destroy(struct nsim_fib_data *fib_data);