net: devlink: track netdev with devlink_port assigned
Currently, ethernet drivers are using devlink_port_type_eth_set() and devlink_port_type_clear() to set devlink port type and link to related netdev. Instead of calling them directly, let the driver use SET_NETDEV_DEVLINK_PORT macro to assign devlink_port pointer and let devlink to track it. Note the devlink port pointer is static during the time netdevice is registered. In devlink code, use per-namespace netdev notifier to track the netdevices with devlink_port assigned and change the internal devlink_port type and related type pointer accordingly. Signed-off-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d41c9dbd12
commit
02a68a47ea
3 changed files with 99 additions and 9 deletions
|
@ -1999,6 +1999,11 @@ enum netdev_ml_priv_type {
|
||||||
* registered
|
* registered
|
||||||
* @offload_xstats_l3: L3 HW stats for this netdevice.
|
* @offload_xstats_l3: L3 HW stats for this netdevice.
|
||||||
*
|
*
|
||||||
|
* @devlink_port: Pointer to related devlink port structure.
|
||||||
|
* Assigned by a driver before netdev registration using
|
||||||
|
* SET_NETDEV_DEVLINK_PORT macro. This pointer is static
|
||||||
|
* during the time netdevice is registered.
|
||||||
|
*
|
||||||
* FIXME: cleanup struct net_device such that network protocol info
|
* FIXME: cleanup struct net_device such that network protocol info
|
||||||
* moves out.
|
* moves out.
|
||||||
*/
|
*/
|
||||||
|
@ -2349,9 +2354,22 @@ struct net_device {
|
||||||
netdevice_tracker watchdog_dev_tracker;
|
netdevice_tracker watchdog_dev_tracker;
|
||||||
netdevice_tracker dev_registered_tracker;
|
netdevice_tracker dev_registered_tracker;
|
||||||
struct rtnl_hw_stats64 *offload_xstats_l3;
|
struct rtnl_hw_stats64 *offload_xstats_l3;
|
||||||
|
|
||||||
|
struct devlink_port *devlink_port;
|
||||||
};
|
};
|
||||||
#define to_net_dev(d) container_of(d, struct net_device, dev)
|
#define to_net_dev(d) container_of(d, struct net_device, dev)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver should use this to assign devlink port instance to a netdevice
|
||||||
|
* before it registers the netdevice. Therefore devlink_port is static
|
||||||
|
* during the netdev lifetime after it is registered.
|
||||||
|
*/
|
||||||
|
#define SET_NETDEV_DEVLINK_PORT(dev, port) \
|
||||||
|
({ \
|
||||||
|
WARN_ON((dev)->reg_state != NETREG_UNINITIALIZED); \
|
||||||
|
((dev)->devlink_port = (port)); \
|
||||||
|
})
|
||||||
|
|
||||||
static inline bool netif_elide_gro(const struct net_device *dev)
|
static inline bool netif_elide_gro(const struct net_device *dev)
|
||||||
{
|
{
|
||||||
if (!(dev->features & NETIF_F_GRO) || dev->xdp_prog)
|
if (!(dev->features & NETIF_F_GRO) || dev->xdp_prog)
|
||||||
|
@ -2785,6 +2803,7 @@ enum netdev_cmd {
|
||||||
NETDEV_PRE_TYPE_CHANGE,
|
NETDEV_PRE_TYPE_CHANGE,
|
||||||
NETDEV_POST_TYPE_CHANGE,
|
NETDEV_POST_TYPE_CHANGE,
|
||||||
NETDEV_POST_INIT,
|
NETDEV_POST_INIT,
|
||||||
|
NETDEV_PRE_UNINIT,
|
||||||
NETDEV_RELEASE,
|
NETDEV_RELEASE,
|
||||||
NETDEV_NOTIFY_PEERS,
|
NETDEV_NOTIFY_PEERS,
|
||||||
NETDEV_JOIN,
|
NETDEV_JOIN,
|
||||||
|
|
|
@ -1621,10 +1621,10 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd)
|
||||||
N(UP) N(DOWN) N(REBOOT) N(CHANGE) N(REGISTER) N(UNREGISTER)
|
N(UP) N(DOWN) N(REBOOT) N(CHANGE) N(REGISTER) N(UNREGISTER)
|
||||||
N(CHANGEMTU) N(CHANGEADDR) N(GOING_DOWN) N(CHANGENAME) N(FEAT_CHANGE)
|
N(CHANGEMTU) N(CHANGEADDR) N(GOING_DOWN) N(CHANGENAME) N(FEAT_CHANGE)
|
||||||
N(BONDING_FAILOVER) N(PRE_UP) N(PRE_TYPE_CHANGE) N(POST_TYPE_CHANGE)
|
N(BONDING_FAILOVER) N(PRE_UP) N(PRE_TYPE_CHANGE) N(POST_TYPE_CHANGE)
|
||||||
N(POST_INIT) N(RELEASE) N(NOTIFY_PEERS) N(JOIN) N(CHANGEUPPER)
|
N(POST_INIT) N(PRE_UNINIT) N(RELEASE) N(NOTIFY_PEERS) N(JOIN)
|
||||||
N(RESEND_IGMP) N(PRECHANGEMTU) N(CHANGEINFODATA) N(BONDING_INFO)
|
N(CHANGEUPPER) N(RESEND_IGMP) N(PRECHANGEMTU) N(CHANGEINFODATA)
|
||||||
N(PRECHANGEUPPER) N(CHANGELOWERSTATE) N(UDP_TUNNEL_PUSH_INFO)
|
N(BONDING_INFO) N(PRECHANGEUPPER) N(CHANGELOWERSTATE)
|
||||||
N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN)
|
N(UDP_TUNNEL_PUSH_INFO) N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN)
|
||||||
N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO)
|
N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO)
|
||||||
N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
|
N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO)
|
||||||
N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
|
N(PRE_CHANGEADDR) N(OFFLOAD_XSTATS_ENABLE) N(OFFLOAD_XSTATS_DISABLE)
|
||||||
|
@ -10060,7 +10060,7 @@ int register_netdevice(struct net_device *dev)
|
||||||
dev->reg_state = ret ? NETREG_UNREGISTERED : NETREG_REGISTERED;
|
dev->reg_state = ret ? NETREG_UNREGISTERED : NETREG_REGISTERED;
|
||||||
write_unlock(&dev_base_lock);
|
write_unlock(&dev_base_lock);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_uninit;
|
goto err_uninit_notify;
|
||||||
|
|
||||||
__netdev_update_features(dev);
|
__netdev_update_features(dev);
|
||||||
|
|
||||||
|
@ -10107,6 +10107,8 @@ int register_netdevice(struct net_device *dev)
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
err_uninit_notify:
|
||||||
|
call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev);
|
||||||
err_uninit:
|
err_uninit:
|
||||||
if (dev->netdev_ops->ndo_uninit)
|
if (dev->netdev_ops->ndo_uninit)
|
||||||
dev->netdev_ops->ndo_uninit(dev);
|
dev->netdev_ops->ndo_uninit(dev);
|
||||||
|
@ -10856,6 +10858,8 @@ void unregister_netdevice_many_notify(struct list_head *head,
|
||||||
netdev_name_node_alt_flush(dev);
|
netdev_name_node_alt_flush(dev);
|
||||||
netdev_name_node_free(dev->name_node);
|
netdev_name_node_free(dev->name_node);
|
||||||
|
|
||||||
|
call_netdevice_notifiers(NETDEV_PRE_UNINIT, dev);
|
||||||
|
|
||||||
if (dev->netdev_ops->ndo_uninit)
|
if (dev->netdev_ops->ndo_uninit)
|
||||||
dev->netdev_ops->ndo_uninit(dev);
|
dev->netdev_ops->ndo_uninit(dev);
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ struct devlink {
|
||||||
refcount_t refcount;
|
refcount_t refcount;
|
||||||
struct completion comp;
|
struct completion comp;
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
struct notifier_block netdevice_nb;
|
||||||
char priv[] __aligned(NETDEV_ALIGN);
|
char priv[] __aligned(NETDEV_ALIGN);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9615,6 +9616,9 @@ void devlink_set_features(struct devlink *devlink, u64 features)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devlink_set_features);
|
EXPORT_SYMBOL_GPL(devlink_set_features);
|
||||||
|
|
||||||
|
static int devlink_netdevice_event(struct notifier_block *nb,
|
||||||
|
unsigned long event, void *ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* devlink_alloc_ns - Allocate new devlink instance resources
|
* devlink_alloc_ns - Allocate new devlink instance resources
|
||||||
* in specific namespace
|
* in specific namespace
|
||||||
|
@ -9645,10 +9649,13 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
|
||||||
|
|
||||||
ret = xa_alloc_cyclic(&devlinks, &devlink->index, devlink, xa_limit_31b,
|
ret = xa_alloc_cyclic(&devlinks, &devlink->index, devlink, xa_limit_31b,
|
||||||
&last_id, GFP_KERNEL);
|
&last_id, GFP_KERNEL);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
kfree(devlink);
|
goto err_xa_alloc;
|
||||||
return NULL;
|
|
||||||
}
|
devlink->netdevice_nb.notifier_call = devlink_netdevice_event;
|
||||||
|
ret = register_netdevice_notifier_net(net, &devlink->netdevice_nb);
|
||||||
|
if (ret)
|
||||||
|
goto err_register_netdevice_notifier;
|
||||||
|
|
||||||
devlink->dev = dev;
|
devlink->dev = dev;
|
||||||
devlink->ops = ops;
|
devlink->ops = ops;
|
||||||
|
@ -9675,6 +9682,12 @@ struct devlink *devlink_alloc_ns(const struct devlink_ops *ops,
|
||||||
init_completion(&devlink->comp);
|
init_completion(&devlink->comp);
|
||||||
|
|
||||||
return devlink;
|
return devlink;
|
||||||
|
|
||||||
|
err_register_netdevice_notifier:
|
||||||
|
xa_erase(&devlinks, devlink->index);
|
||||||
|
err_xa_alloc:
|
||||||
|
kfree(devlink);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devlink_alloc_ns);
|
EXPORT_SYMBOL_GPL(devlink_alloc_ns);
|
||||||
|
|
||||||
|
@ -9828,6 +9841,10 @@ void devlink_free(struct devlink *devlink)
|
||||||
WARN_ON(!list_empty(&devlink->port_list));
|
WARN_ON(!list_empty(&devlink->port_list));
|
||||||
|
|
||||||
xa_destroy(&devlink->snapshot_ids);
|
xa_destroy(&devlink->snapshot_ids);
|
||||||
|
|
||||||
|
unregister_netdevice_notifier_net(devlink_net(devlink),
|
||||||
|
&devlink->netdevice_nb);
|
||||||
|
|
||||||
xa_erase(&devlinks, devlink->index);
|
xa_erase(&devlinks, devlink->index);
|
||||||
|
|
||||||
kfree(devlink);
|
kfree(devlink);
|
||||||
|
@ -10121,6 +10138,56 @@ void devlink_port_type_clear(struct devlink_port *devlink_port)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(devlink_port_type_clear);
|
EXPORT_SYMBOL_GPL(devlink_port_type_clear);
|
||||||
|
|
||||||
|
static int devlink_netdevice_event(struct notifier_block *nb,
|
||||||
|
unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
|
||||||
|
struct devlink_port *devlink_port = netdev->devlink_port;
|
||||||
|
struct devlink *devlink;
|
||||||
|
|
||||||
|
devlink = container_of(nb, struct devlink, netdevice_nb);
|
||||||
|
|
||||||
|
if (!devlink_port || devlink_port->devlink != devlink)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
switch (event) {
|
||||||
|
case NETDEV_POST_INIT:
|
||||||
|
/* Set the type but not netdev pointer. It is going to be set
|
||||||
|
* later on by NETDEV_REGISTER event. Happens once during
|
||||||
|
* netdevice register
|
||||||
|
*/
|
||||||
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH,
|
||||||
|
NULL, true);
|
||||||
|
break;
|
||||||
|
case NETDEV_REGISTER:
|
||||||
|
/* Set the netdev on top of previously set type. Note this
|
||||||
|
* event happens also during net namespace change so here
|
||||||
|
* we take into account netdev pointer appearing in this
|
||||||
|
* namespace.
|
||||||
|
*/
|
||||||
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH,
|
||||||
|
netdev, true);
|
||||||
|
break;
|
||||||
|
case NETDEV_UNREGISTER:
|
||||||
|
/* Clear netdev pointer, but not the type. This event happens
|
||||||
|
* also during net namespace change so we need to clear
|
||||||
|
* pointer to netdev that is going to another net namespace.
|
||||||
|
*/
|
||||||
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH,
|
||||||
|
NULL, true);
|
||||||
|
break;
|
||||||
|
case NETDEV_PRE_UNINIT:
|
||||||
|
/* Clear the type and the netdev pointer. Happens one during
|
||||||
|
* netdevice unregister.
|
||||||
|
*/
|
||||||
|
__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET,
|
||||||
|
NULL, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
|
static int __devlink_port_attrs_set(struct devlink_port *devlink_port,
|
||||||
enum devlink_port_flavour flavour)
|
enum devlink_port_flavour flavour)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue