netdevsim: implement dev probe/remove skeleton with port initialization
Implement netdevsim bus probing of netdevsim devices. For every probed device create a devlink instance. According to the user-passed value, create a number of ports represented by devlink port instances. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
ab1d0cc004
Коммит
8320d14591
|
@ -194,6 +194,21 @@ static struct attribute *nsim_bus_attrs[] = {
|
||||||
};
|
};
|
||||||
ATTRIBUTE_GROUPS(nsim_bus);
|
ATTRIBUTE_GROUPS(nsim_bus);
|
||||||
|
|
||||||
|
static int nsim_bus_probe(struct device *dev)
|
||||||
|
{
|
||||||
|
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||||
|
|
||||||
|
return nsim_dev_probe(nsim_bus_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nsim_bus_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||||
|
|
||||||
|
nsim_dev_remove(nsim_bus_dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int nsim_num_vf(struct device *dev)
|
int nsim_num_vf(struct device *dev)
|
||||||
{
|
{
|
||||||
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
|
||||||
|
@ -205,6 +220,8 @@ static struct bus_type nsim_bus = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.dev_name = DRV_NAME,
|
.dev_name = DRV_NAME,
|
||||||
.bus_groups = nsim_bus_groups,
|
.bus_groups = nsim_bus_groups,
|
||||||
|
.probe = nsim_bus_probe,
|
||||||
|
.remove = nsim_bus_remove,
|
||||||
.num_vf = nsim_num_vf,
|
.num_vf = nsim_num_vf,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -238,6 +255,18 @@ err_nsim_bus_dev_free:
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nsim_bus_dev *nsim_bus_dev_new_with_ns(struct netdevsim *ns)
|
||||||
|
{
|
||||||
|
struct nsim_bus_dev *nsim_bus_dev;
|
||||||
|
|
||||||
|
dev_hold(ns->netdev);
|
||||||
|
rtnl_unlock();
|
||||||
|
nsim_bus_dev = nsim_bus_dev_new(~0, 0);
|
||||||
|
rtnl_lock();
|
||||||
|
dev_put(ns->netdev);
|
||||||
|
return nsim_bus_dev;
|
||||||
|
}
|
||||||
|
|
||||||
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
|
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
|
||||||
{
|
{
|
||||||
device_unregister(&nsim_bus_dev->dev);
|
device_unregister(&nsim_bus_dev->dev);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <net/devlink.h>
|
#include <net/devlink.h>
|
||||||
|
@ -45,6 +46,30 @@ static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
|
||||||
debugfs_remove_recursive(nsim_dev->ddir);
|
debugfs_remove_recursive(nsim_dev->ddir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
|
||||||
|
struct nsim_dev_port *nsim_dev_port)
|
||||||
|
{
|
||||||
|
char port_ddir_name[16];
|
||||||
|
char dev_link_name[32];
|
||||||
|
|
||||||
|
sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
|
||||||
|
nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
|
||||||
|
nsim_dev->ports_ddir);
|
||||||
|
if (IS_ERR_OR_NULL(nsim_dev_port->ddir))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sprintf(dev_link_name, "../../../" DRV_NAME "%u",
|
||||||
|
nsim_dev->nsim_bus_dev->dev.id);
|
||||||
|
debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
|
||||||
|
{
|
||||||
|
debugfs_remove_recursive(nsim_dev_port->ddir);
|
||||||
|
}
|
||||||
|
|
||||||
static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
|
static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
|
||||||
{
|
{
|
||||||
struct nsim_dev *nsim_dev = priv;
|
struct nsim_dev *nsim_dev = priv;
|
||||||
|
@ -198,7 +223,8 @@ static const struct devlink_ops nsim_dev_devlink_ops = {
|
||||||
.reload = nsim_dev_reload,
|
.reload = nsim_dev_reload,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
|
static struct nsim_dev *
|
||||||
|
nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
|
||||||
{
|
{
|
||||||
struct nsim_dev *nsim_dev;
|
struct nsim_dev *nsim_dev;
|
||||||
struct devlink *devlink;
|
struct devlink *devlink;
|
||||||
|
@ -211,6 +237,7 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
|
||||||
nsim_dev->nsim_bus_dev = nsim_bus_dev;
|
nsim_dev->nsim_bus_dev = nsim_bus_dev;
|
||||||
nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id);
|
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);
|
get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
|
||||||
|
INIT_LIST_HEAD(&nsim_dev->port_list);
|
||||||
|
|
||||||
nsim_dev->fib_data = nsim_fib_create();
|
nsim_dev->fib_data = nsim_fib_create();
|
||||||
if (IS_ERR(nsim_dev->fib_data)) {
|
if (IS_ERR(nsim_dev->fib_data)) {
|
||||||
|
@ -249,20 +276,6 @@ err_devlink_free:
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct nsim_dev *
|
|
||||||
nsim_dev_create_with_ns(struct nsim_bus_dev *nsim_bus_dev,
|
|
||||||
struct netdevsim *ns)
|
|
||||||
{
|
|
||||||
struct nsim_dev *nsim_dev;
|
|
||||||
|
|
||||||
dev_hold(ns->netdev);
|
|
||||||
rtnl_unlock();
|
|
||||||
nsim_dev = nsim_dev_create(nsim_bus_dev);
|
|
||||||
rtnl_lock();
|
|
||||||
dev_put(ns->netdev);
|
|
||||||
return nsim_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsim_dev_destroy(struct nsim_dev *nsim_dev)
|
void nsim_dev_destroy(struct nsim_dev *nsim_dev)
|
||||||
{
|
{
|
||||||
struct devlink *devlink = priv_to_devlink(nsim_dev);
|
struct devlink *devlink = priv_to_devlink(nsim_dev);
|
||||||
|
@ -275,6 +288,93 @@ void nsim_dev_destroy(struct nsim_dev *nsim_dev)
|
||||||
devlink_free(devlink);
|
devlink_free(devlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
|
||||||
|
if (!nsim_dev_port)
|
||||||
|
return -ENOMEM;
|
||||||
|
nsim_dev_port->port_index = port_index;
|
||||||
|
|
||||||
|
devlink_port = &nsim_dev_port->devlink_port;
|
||||||
|
devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
|
||||||
|
port_index + 1, 0, 0,
|
||||||
|
nsim_dev->switch_id.id,
|
||||||
|
nsim_dev->switch_id.id_len);
|
||||||
|
err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
|
||||||
|
port_index);
|
||||||
|
if (err)
|
||||||
|
goto err_port_free;
|
||||||
|
|
||||||
|
err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
|
||||||
|
if (err)
|
||||||
|
goto err_dl_port_unregister;
|
||||||
|
|
||||||
|
list_add(&nsim_dev_port->list, &nsim_dev->port_list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_dl_port_unregister:
|
||||||
|
devlink_port_unregister(devlink_port);
|
||||||
|
err_port_free:
|
||||||
|
kfree(nsim_dev_port);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
|
||||||
|
{
|
||||||
|
struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
|
||||||
|
|
||||||
|
list_del(&nsim_dev_port->list);
|
||||||
|
nsim_dev_port_debugfs_exit(nsim_dev_port);
|
||||||
|
devlink_port_unregister(devlink_port);
|
||||||
|
kfree(nsim_dev_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev)
|
||||||
|
{
|
||||||
|
struct nsim_dev_port *nsim_dev_port, *tmp;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(nsim_dev_port, tmp,
|
||||||
|
&nsim_dev->port_list, list)
|
||||||
|
nsim_dev_port_del(nsim_dev_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
|
||||||
|
{
|
||||||
|
struct nsim_dev *nsim_dev;
|
||||||
|
int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count);
|
||||||
|
if (IS_ERR(nsim_dev))
|
||||||
|
return PTR_ERR(nsim_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);
|
||||||
|
if (err)
|
||||||
|
goto err_port_del_all;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_port_del_all:
|
||||||
|
nsim_dev_port_del_all(nsim_dev);
|
||||||
|
nsim_dev_destroy(nsim_dev);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
|
||||||
|
{
|
||||||
|
struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
|
||||||
|
|
||||||
|
nsim_dev_port_del_all(nsim_dev);
|
||||||
|
nsim_dev_destroy(nsim_dev);
|
||||||
|
}
|
||||||
|
|
||||||
int nsim_dev_init(void)
|
int nsim_dev_init(void)
|
||||||
{
|
{
|
||||||
nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
|
nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
|
||||||
|
|
|
@ -74,7 +74,6 @@ static void nsim_free(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct netdevsim *ns = netdev_priv(dev);
|
struct netdevsim *ns = netdev_priv(dev);
|
||||||
|
|
||||||
nsim_dev_destroy(ns->nsim_dev);
|
|
||||||
nsim_bus_dev_del(ns->nsim_bus_dev);
|
nsim_bus_dev_del(ns->nsim_bus_dev);
|
||||||
/* netdev and vf state will be freed out of device_release() */
|
/* netdev and vf state will be freed out of device_release() */
|
||||||
}
|
}
|
||||||
|
@ -364,26 +363,20 @@ static int nsim_newlink(struct net *src_net, struct net_device *dev,
|
||||||
struct netdevsim *ns = netdev_priv(dev);
|
struct netdevsim *ns = netdev_priv(dev);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
ns->nsim_bus_dev = nsim_bus_dev_new(~0, 0);
|
ns->netdev = dev;
|
||||||
|
ns->nsim_bus_dev = nsim_bus_dev_new_with_ns(ns);
|
||||||
if (IS_ERR(ns->nsim_bus_dev))
|
if (IS_ERR(ns->nsim_bus_dev))
|
||||||
return PTR_ERR(ns->nsim_bus_dev);
|
return PTR_ERR(ns->nsim_bus_dev);
|
||||||
|
|
||||||
SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
|
SET_NETDEV_DEV(dev, &ns->nsim_bus_dev->dev);
|
||||||
ns->netdev = dev;
|
|
||||||
|
|
||||||
ns->nsim_dev = nsim_dev_create_with_ns(ns->nsim_bus_dev, ns);
|
ns->nsim_dev = dev_get_drvdata(&ns->nsim_bus_dev->dev);
|
||||||
if (IS_ERR(ns->nsim_dev)) {
|
|
||||||
err = PTR_ERR(ns->nsim_dev);
|
|
||||||
goto err_dev_del;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = register_netdevice(dev);
|
err = register_netdevice(dev);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_dev_destroy;
|
goto err_dev_del;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_dev_destroy:
|
|
||||||
nsim_dev_destroy(ns->nsim_dev);
|
|
||||||
err_dev_del:
|
err_dev_del:
|
||||||
nsim_bus_dev_del(ns->nsim_bus_dev);
|
nsim_bus_dev_del(ns->nsim_bus_dev);
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/u64_stats_sync.h>
|
#include <linux/u64_stats_sync.h>
|
||||||
|
#include <net/devlink.h>
|
||||||
#include <net/xdp.h>
|
#include <net/xdp.h>
|
||||||
|
|
||||||
#define DRV_NAME "netdevsim"
|
#define DRV_NAME "netdevsim"
|
||||||
|
@ -130,6 +131,13 @@ enum nsim_resource_id {
|
||||||
NSIM_RESOURCE_IPV6_FIB_RULES,
|
NSIM_RESOURCE_IPV6_FIB_RULES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nsim_dev_port {
|
||||||
|
struct list_head list;
|
||||||
|
struct devlink_port devlink_port;
|
||||||
|
unsigned int port_index;
|
||||||
|
struct dentry *ddir;
|
||||||
|
};
|
||||||
|
|
||||||
struct nsim_dev {
|
struct nsim_dev {
|
||||||
struct nsim_bus_dev *nsim_bus_dev;
|
struct nsim_bus_dev *nsim_bus_dev;
|
||||||
struct nsim_fib_data *fib_data;
|
struct nsim_fib_data *fib_data;
|
||||||
|
@ -143,14 +151,13 @@ struct nsim_dev {
|
||||||
struct list_head bpf_bound_progs;
|
struct list_head bpf_bound_progs;
|
||||||
struct list_head bpf_bound_maps;
|
struct list_head bpf_bound_maps;
|
||||||
struct netdev_phys_item_id switch_id;
|
struct netdev_phys_item_id switch_id;
|
||||||
|
struct list_head port_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nsim_dev *
|
|
||||||
nsim_dev_create_with_ns(struct nsim_bus_dev *nsim_bus_dev,
|
|
||||||
struct netdevsim *ns);
|
|
||||||
void nsim_dev_destroy(struct nsim_dev *nsim_dev);
|
|
||||||
int nsim_dev_init(void);
|
int nsim_dev_init(void);
|
||||||
void nsim_dev_exit(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);
|
||||||
|
|
||||||
struct nsim_fib_data *nsim_fib_create(void);
|
struct nsim_fib_data *nsim_fib_create(void);
|
||||||
void nsim_fib_destroy(struct nsim_fib_data *fib_data);
|
void nsim_fib_destroy(struct nsim_fib_data *fib_data);
|
||||||
|
@ -201,6 +208,7 @@ struct nsim_bus_dev {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count);
|
struct nsim_bus_dev *nsim_bus_dev_new(unsigned int id, unsigned int port_count);
|
||||||
|
struct nsim_bus_dev *nsim_bus_dev_new_with_ns(struct netdevsim *ns);
|
||||||
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev);
|
void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev);
|
||||||
int nsim_bus_init(void);
|
int nsim_bus_init(void);
|
||||||
void nsim_bus_exit(void);
|
void nsim_bus_exit(void);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче