Commit d314774c authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

netdev: network device operations infrastructure

This patch changes the network device internal API to move adminstrative
operations out of the network device structure and into a separate structure.

This patch involves some hackery to maintain compatablity between the
new and old model, so all 300+ drivers don't have to be changed at once.
For drivers that aren't converted yet, the netdevice_ops virt function list
still resides in the net_device structure. For old protocols, the new
net_device_ops are copied out to the old net_device pointers.

After the transistion is completed the nag message can be changed to
an WARN_ON, and the compatiablity code can be made configurable.

Some function pointers aren't moved:
* destructor can't be in net_device_ops because
  it may need to be referenced after the module is unloaded.
* neighbor setup is manipulated in a couple of places that need special
  consideration
* hard_start_xmit is in the fast path for transmit.
Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6b41e7dd
This diff is collapsed.
......@@ -32,6 +32,9 @@ config NET_NS
Allow user space to create what appear to be multiple instances
of the network stack.
config COMPAT_NET_DEV_OPS
def_bool y
source "net/packet/Kconfig"
source "net/unix/Kconfig"
source "net/xfrm/Kconfig"
......
......@@ -1059,6 +1059,7 @@ void dev_load(struct net *net, const char *name)
*/
int dev_open(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
int ret = 0;
ASSERT_RTNL();
......@@ -1081,11 +1082,11 @@ int dev_open(struct net_device *dev)
*/
set_bit(__LINK_STATE_START, &dev->state);
if (dev->validate_addr)
ret = dev->validate_addr(dev);
if (ops->ndo_validate_addr)
ret = ops->ndo_validate_addr(dev);
if (!ret && dev->open)
ret = dev->open(dev);
if (!ret && ops->ndo_open)
ret = ops->ndo_open(dev);
/*
* If it went open OK then:
......@@ -1129,6 +1130,7 @@ int dev_open(struct net_device *dev)
*/
int dev_close(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
ASSERT_RTNL();
might_sleep();
......@@ -1161,8 +1163,8 @@ int dev_close(struct net_device *dev)
* We allow it to be called even after a DETACH hot-plug
* event.
*/
if (dev->stop)
dev->stop(dev);
if (ops->ndo_stop)
ops->ndo_stop(dev);
/*
* Device is now down.
......@@ -2930,8 +2932,10 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
static void dev_change_rx_flags(struct net_device *dev, int flags)
{
if (dev->flags & IFF_UP && dev->change_rx_flags)
dev->change_rx_flags(dev, flags);
const struct net_device_ops *ops = dev->netdev_ops;
if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags)
ops->ndo_change_rx_flags(dev, flags);
}
static int __dev_set_promiscuity(struct net_device *dev, int inc)
......@@ -3051,6 +3055,8 @@ int dev_set_allmulti(struct net_device *dev, int inc)
*/
void __dev_set_rx_mode(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
/* dev_open will call this function so the list will stay sane. */
if (!(dev->flags&IFF_UP))
return;
......@@ -3058,8 +3064,8 @@ void __dev_set_rx_mode(struct net_device *dev)
if (!netif_device_present(dev))
return;
if (dev->set_rx_mode)
dev->set_rx_mode(dev);
if (ops->ndo_set_rx_mode)
ops->ndo_set_rx_mode(dev);
else {
/* Unicast addresses changes may only happen under the rtnl,
* therefore calling __dev_set_promiscuity here is safe.
......@@ -3072,8 +3078,8 @@ void __dev_set_rx_mode(struct net_device *dev)
dev->uc_promisc = 0;
}
if (dev->set_multicast_list)
dev->set_multicast_list(dev);
if (ops->ndo_set_multicast_list)
ops->ndo_set_multicast_list(dev);
}
}
......@@ -3432,6 +3438,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
*/
int dev_set_mtu(struct net_device *dev, int new_mtu)
{
const struct net_device_ops *ops = dev->netdev_ops;
int err;
if (new_mtu == dev->mtu)
......@@ -3445,10 +3452,11 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
return -ENODEV;
err = 0;
if (dev->change_mtu)
err = dev->change_mtu(dev, new_mtu);
if (ops->ndo_change_mtu)
err = ops->ndo_change_mtu(dev, new_mtu);
else
dev->mtu = new_mtu;
if (!err && dev->flags & IFF_UP)
call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
return err;
......@@ -3463,15 +3471,16 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
*/
int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
{
const struct net_device_ops *ops = dev->netdev_ops;
int err;
if (!dev->set_mac_address)
if (!ops->ndo_set_mac_address)
return -EOPNOTSUPP;
if (sa->sa_family != dev->type)
return -EINVAL;
if (!netif_device_present(dev))
return -ENODEV;
err = dev->set_mac_address(dev, sa);
err = ops->ndo_set_mac_address(dev, sa);
if (!err)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
return err;
......@@ -3551,6 +3560,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{
int err;
struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
const struct net_device_ops *ops = dev->netdev_ops;
if (!dev)
return -ENODEV;
......@@ -3578,15 +3588,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
return 0;
case SIOCSIFMAP:
if (dev->set_config) {
if (ops->ndo_set_config) {
if (!netif_device_present(dev))
return -ENODEV;
return dev->set_config(dev, &ifr->ifr_map);
return ops->ndo_set_config(dev, &ifr->ifr_map);
}
return -EOPNOTSUPP;
case SIOCADDMULTI:
if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
......@@ -3595,7 +3605,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
dev->addr_len, 1);
case SIOCDELMULTI:
if ((!dev->set_multicast_list && !dev->set_rx_mode) ||
if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) ||
ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL;
if (!netif_device_present(dev))
......@@ -3633,10 +3643,9 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
cmd == SIOCBRDELIF ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (dev->do_ioctl) {
if (ops->ndo_do_ioctl) {
if (netif_device_present(dev))
err = dev->do_ioctl(dev, ifr,
cmd);
err = ops->ndo_do_ioctl(dev, ifr, cmd);
else
err = -ENODEV;
}
......@@ -3897,8 +3906,8 @@ static void rollback_registered(struct net_device *dev)
*/
dev_addr_discard(dev);
if (dev->uninit)
dev->uninit(dev);
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
/* Notifier chain MUST detach us from master device. */
WARN_ON(dev->master);
......@@ -3988,7 +3997,7 @@ int register_netdevice(struct net_device *dev)
struct hlist_head *head;
struct hlist_node *p;
int ret;
struct net *net;
struct net *net = dev_net(dev);
BUG_ON(dev_boot_phase);
ASSERT_RTNL();
......@@ -3997,8 +4006,7 @@ int register_netdevice(struct net_device *dev)
/* When net_device's are persistent, this will be fatal. */
BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
BUG_ON(!dev_net(dev));
net = dev_net(dev);
BUG_ON(!net);
spin_lock_init(&dev->addr_list_lock);
netdev_set_addr_lockdep_class(dev);
......@@ -4006,9 +4014,46 @@ int register_netdevice(struct net_device *dev)
dev->iflink = -1;
#ifdef CONFIG_COMPAT_NET_DEV_OPS
/* Netdevice_ops API compatiability support.
* This is temporary until all network devices are converted.
*/
if (dev->netdev_ops) {
const struct net_device_ops *ops = dev->netdev_ops;
dev->init = ops->ndo_init;
dev->uninit = ops->ndo_uninit;
dev->open = ops->ndo_open;
dev->change_rx_flags = ops->ndo_change_rx_flags;
dev->set_rx_mode = ops->ndo_set_rx_mode;
dev->set_multicast_list = ops->ndo_set_multicast_list;
dev->set_mac_address = ops->ndo_set_mac_address;
dev->validate_addr = ops->ndo_validate_addr;
dev->do_ioctl = ops->ndo_do_ioctl;
dev->set_config = ops->ndo_set_config;
dev->change_mtu = ops->ndo_change_mtu;
dev->tx_timeout = ops->ndo_tx_timeout;
dev->get_stats = ops->ndo_get_stats;
dev->vlan_rx_register = ops->ndo_vlan_rx_register;
dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = ops->ndo_poll_controller;
#endif
} else {
char drivername[64];
pr_info("%s (%s): not using net_device_ops yet\n",
dev->name, netdev_drivername(dev, drivername, 64));
/* This works only because net_device_ops and the
compatiablity structure are the same. */
dev->netdev_ops = (void *) &(dev->init);
}
#endif
/* Init, if this function is available */
if (dev->init) {
ret = dev->init(dev);
if (dev->netdev_ops->ndo_init) {
ret = dev->netdev_ops->ndo_init(dev);
if (ret) {
if (ret > 0)
ret = -EIO;
......@@ -4086,8 +4131,8 @@ int register_netdevice(struct net_device *dev)
return ret;
err_uninit:
if (dev->uninit)
dev->uninit(dev);
if (dev->netdev_ops->ndo_uninit)
dev->netdev_ops->ndo_uninit(dev);
goto out;
}
......
......@@ -172,12 +172,13 @@ static void service_arp_queue(struct netpoll_info *npi)
void netpoll_poll(struct netpoll *np)
{
struct net_device *dev = np->dev;
const struct net_device_ops *ops = dev->netdev_ops;
if (!dev || !netif_running(dev) || !dev->poll_controller)
if (!dev || !netif_running(dev) || !ops->ndo_poll_controller)
return;
/* Process pending work on NIC */
dev->poll_controller(dev);
ops->ndo_poll_controller(dev);
poll_napi(dev);
......@@ -694,7 +695,7 @@ int netpoll_setup(struct netpoll *np)
atomic_inc(&npinfo->refcnt);
}
if (!ndev->poll_controller) {
if (!ndev->netdev_ops->ndo_poll_controller) {
printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
np->name, np->dev_name);
err = -ENOTSUPP;
......
......@@ -762,6 +762,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[])
static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct nlattr **tb, char *ifname, int modified)
{
const struct net_device_ops *ops = dev->netdev_ops;
int send_addr_notify = 0;
int err;
......@@ -783,7 +784,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct rtnl_link_ifmap *u_map;
struct ifmap k_map;
if (!dev->set_config) {
if (!ops->ndo_set_config) {
err = -EOPNOTSUPP;
goto errout;
}
......@@ -801,7 +802,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
k_map.dma = (unsigned char) u_map->dma;
k_map.port = (unsigned char) u_map->port;
err = dev->set_config(dev, &k_map);
err = ops->ndo_set_config(dev, &k_map);
if (err < 0)
goto errout;
......@@ -812,7 +813,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct sockaddr *sa;
int len;
if (!dev->set_mac_address) {
if (!ops->ndo_set_mac_address) {
err = -EOPNOTSUPP;
goto errout;
}
......@@ -831,7 +832,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
sa->sa_family = dev->type;
memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
dev->addr_len);
err = dev->set_mac_address(dev, sa);
err = ops->ndo_set_mac_address(dev, sa);
kfree(sa);
if (err)
goto errout;
......
......@@ -224,7 +224,7 @@ static void dev_watchdog(unsigned long arg)
char drivername[64];
WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
dev->name, netdev_drivername(dev, drivername, 64));
dev->tx_timeout(dev);
dev->netdev_ops->ndo_tx_timeout(dev);
}
if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies +
......@@ -239,7 +239,7 @@ static void dev_watchdog(unsigned long arg)
void __netdev_watchdog_up(struct net_device *dev)
{
if (dev->tx_timeout) {
if (dev->netdev_ops->ndo_tx_timeout) {
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment