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 ...@@ -32,6 +32,9 @@ config NET_NS
Allow user space to create what appear to be multiple instances Allow user space to create what appear to be multiple instances
of the network stack. of the network stack.
config COMPAT_NET_DEV_OPS
def_bool y
source "net/packet/Kconfig" source "net/packet/Kconfig"
source "net/unix/Kconfig" source "net/unix/Kconfig"
source "net/xfrm/Kconfig" source "net/xfrm/Kconfig"
......
...@@ -1059,6 +1059,7 @@ void dev_load(struct net *net, const char *name) ...@@ -1059,6 +1059,7 @@ void dev_load(struct net *net, const char *name)
*/ */
int dev_open(struct net_device *dev) int dev_open(struct net_device *dev)
{ {
const struct net_device_ops *ops = dev->netdev_ops;
int ret = 0; int ret = 0;
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -1081,11 +1082,11 @@ int dev_open(struct net_device *dev) ...@@ -1081,11 +1082,11 @@ int dev_open(struct net_device *dev)
*/ */
set_bit(__LINK_STATE_START, &dev->state); set_bit(__LINK_STATE_START, &dev->state);
if (dev->validate_addr) if (ops->ndo_validate_addr)
ret = dev->validate_addr(dev); ret = ops->ndo_validate_addr(dev);
if (!ret && dev->open) if (!ret && ops->ndo_open)
ret = dev->open(dev); ret = ops->ndo_open(dev);
/* /*
* If it went open OK then: * If it went open OK then:
...@@ -1129,6 +1130,7 @@ int dev_open(struct net_device *dev) ...@@ -1129,6 +1130,7 @@ int dev_open(struct net_device *dev)
*/ */
int dev_close(struct net_device *dev) int dev_close(struct net_device *dev)
{ {
const struct net_device_ops *ops = dev->netdev_ops;
ASSERT_RTNL(); ASSERT_RTNL();
might_sleep(); might_sleep();
...@@ -1161,8 +1163,8 @@ int dev_close(struct net_device *dev) ...@@ -1161,8 +1163,8 @@ int dev_close(struct net_device *dev)
* We allow it to be called even after a DETACH hot-plug * We allow it to be called even after a DETACH hot-plug
* event. * event.
*/ */
if (dev->stop) if (ops->ndo_stop)
dev->stop(dev); ops->ndo_stop(dev);
/* /*
* Device is now down. * Device is now down.
...@@ -2930,8 +2932,10 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) ...@@ -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) static void dev_change_rx_flags(struct net_device *dev, int flags)
{ {
if (dev->flags & IFF_UP && dev->change_rx_flags) const struct net_device_ops *ops = dev->netdev_ops;
dev->change_rx_flags(dev, flags);
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) 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) ...@@ -3051,6 +3055,8 @@ int dev_set_allmulti(struct net_device *dev, int inc)
*/ */
void __dev_set_rx_mode(struct net_device *dev) 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. */ /* dev_open will call this function so the list will stay sane. */
if (!(dev->flags&IFF_UP)) if (!(dev->flags&IFF_UP))
return; return;
...@@ -3058,8 +3064,8 @@ void __dev_set_rx_mode(struct net_device *dev) ...@@ -3058,8 +3064,8 @@ void __dev_set_rx_mode(struct net_device *dev)
if (!netif_device_present(dev)) if (!netif_device_present(dev))
return; return;
if (dev->set_rx_mode) if (ops->ndo_set_rx_mode)
dev->set_rx_mode(dev); ops->ndo_set_rx_mode(dev);
else { else {
/* Unicast addresses changes may only happen under the rtnl, /* Unicast addresses changes may only happen under the rtnl,
* therefore calling __dev_set_promiscuity here is safe. * therefore calling __dev_set_promiscuity here is safe.
...@@ -3072,8 +3078,8 @@ void __dev_set_rx_mode(struct net_device *dev) ...@@ -3072,8 +3078,8 @@ void __dev_set_rx_mode(struct net_device *dev)
dev->uc_promisc = 0; dev->uc_promisc = 0;
} }
if (dev->set_multicast_list) if (ops->ndo_set_multicast_list)
dev->set_multicast_list(dev); ops->ndo_set_multicast_list(dev);
} }
} }
...@@ -3432,6 +3438,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) ...@@ -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) int dev_set_mtu(struct net_device *dev, int new_mtu)
{ {
const struct net_device_ops *ops = dev->netdev_ops;
int err; int err;
if (new_mtu == dev->mtu) if (new_mtu == dev->mtu)
...@@ -3445,10 +3452,11 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) ...@@ -3445,10 +3452,11 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
return -ENODEV; return -ENODEV;
err = 0; err = 0;
if (dev->change_mtu) if (ops->ndo_change_mtu)
err = dev->change_mtu(dev, new_mtu); err = ops->ndo_change_mtu(dev, new_mtu);
else else
dev->mtu = new_mtu; dev->mtu = new_mtu;
if (!err && dev->flags & IFF_UP) if (!err && dev->flags & IFF_UP)
call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); call_netdevice_notifiers(NETDEV_CHANGEMTU, dev);
return err; return err;
...@@ -3463,15 +3471,16 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) ...@@ -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) int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
{ {
const struct net_device_ops *ops = dev->netdev_ops;
int err; int err;
if (!dev->set_mac_address) if (!ops->ndo_set_mac_address)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (sa->sa_family != dev->type) if (sa->sa_family != dev->type)
return -EINVAL; return -EINVAL;
if (!netif_device_present(dev)) if (!netif_device_present(dev))
return -ENODEV; return -ENODEV;
err = dev->set_mac_address(dev, sa); err = ops->ndo_set_mac_address(dev, sa);
if (!err) if (!err)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
return err; return err;
...@@ -3551,6 +3560,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ...@@ -3551,6 +3560,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{ {
int err; int err;
struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);
const struct net_device_ops *ops = dev->netdev_ops;
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
...@@ -3578,15 +3588,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ...@@ -3578,15 +3588,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
return 0; return 0;
case SIOCSIFMAP: case SIOCSIFMAP:
if (dev->set_config) { if (ops->ndo_set_config) {
if (!netif_device_present(dev)) if (!netif_device_present(dev))
return -ENODEV; return -ENODEV;
return dev->set_config(dev, &ifr->ifr_map); return ops->ndo_set_config(dev, &ifr->ifr_map);
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
case SIOCADDMULTI: 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) ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL; return -EINVAL;
if (!netif_device_present(dev)) if (!netif_device_present(dev))
...@@ -3595,7 +3605,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ...@@ -3595,7 +3605,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
dev->addr_len, 1); dev->addr_len, 1);
case SIOCDELMULTI: 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) ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
return -EINVAL; return -EINVAL;
if (!netif_device_present(dev)) if (!netif_device_present(dev))
...@@ -3633,10 +3643,9 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) ...@@ -3633,10 +3643,9 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
cmd == SIOCBRDELIF || cmd == SIOCBRDELIF ||
cmd == SIOCWANDEV) { cmd == SIOCWANDEV) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
if (dev->do_ioctl) { if (ops->ndo_do_ioctl) {
if (netif_device_present(dev)) if (netif_device_present(dev))
err = dev->do_ioctl(dev, ifr, err = ops->ndo_do_ioctl(dev, ifr, cmd);
cmd);
else else
err = -ENODEV; err = -ENODEV;
} }
...@@ -3897,8 +3906,8 @@ static void rollback_registered(struct net_device *dev) ...@@ -3897,8 +3906,8 @@ static void rollback_registered(struct net_device *dev)
*/ */
dev_addr_discard(dev); dev_addr_discard(dev);
if (dev->uninit) if (dev->netdev_ops->ndo_uninit)
dev->uninit(dev); dev->netdev_ops->ndo_uninit(dev);
/* Notifier chain MUST detach us from master device. */ /* Notifier chain MUST detach us from master device. */
WARN_ON(dev->master); WARN_ON(dev->master);
...@@ -3988,7 +3997,7 @@ int register_netdevice(struct net_device *dev) ...@@ -3988,7 +3997,7 @@ int register_netdevice(struct net_device *dev)
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *p; struct hlist_node *p;
int ret; int ret;
struct net *net; struct net *net = dev_net(dev);
BUG_ON(dev_boot_phase); BUG_ON(dev_boot_phase);
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -3997,8 +4006,7 @@ int register_netdevice(struct net_device *dev) ...@@ -3997,8 +4006,7 @@ int register_netdevice(struct net_device *dev)
/* When net_device's are persistent, this will be fatal. */ /* When net_device's are persistent, this will be fatal. */
BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
BUG_ON(!dev_net(dev)); BUG_ON(!net);
net = dev_net(dev);
spin_lock_init(&dev->addr_list_lock); spin_lock_init(&dev->addr_list_lock);
netdev_set_addr_lockdep_class(dev); netdev_set_addr_lockdep_class(dev);
...@@ -4006,9 +4014,46 @@ int register_netdevice(struct net_device *dev) ...@@ -4006,9 +4014,46 @@ int register_netdevice(struct net_device *dev)
dev->iflink = -1; 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 */ /* Init, if this function is available */
if (dev->init) { if (dev->netdev_ops->ndo_init) {
ret = dev->init(dev); ret = dev->netdev_ops->ndo_init(dev);
if (ret) { if (ret) {
if (ret > 0) if (ret > 0)
ret = -EIO; ret = -EIO;
...@@ -4086,8 +4131,8 @@ int register_netdevice(struct net_device *dev) ...@@ -4086,8 +4131,8 @@ int register_netdevice(struct net_device *dev)
return ret; return ret;
err_uninit: err_uninit:
if (dev->uninit) if (dev->netdev_ops->ndo_uninit)
dev->uninit(dev); dev->netdev_ops->ndo_uninit(dev);
goto out; goto out;
} }
......
...@@ -172,12 +172,13 @@ static void service_arp_queue(struct netpoll_info *npi) ...@@ -172,12 +172,13 @@ static void service_arp_queue(struct netpoll_info *npi)
void netpoll_poll(struct netpoll *np) void netpoll_poll(struct netpoll *np)
{ {
struct net_device *dev = np->dev; 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; return;
/* Process pending work on NIC */ /* Process pending work on NIC */
dev->poll_controller(dev); ops->ndo_poll_controller(dev);
poll_napi(dev); poll_napi(dev);
...@@ -694,7 +695,7 @@ int netpoll_setup(struct netpoll *np) ...@@ -694,7 +695,7 @@ int netpoll_setup(struct netpoll *np)
atomic_inc(&npinfo->refcnt); 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", printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
np->name, np->dev_name); np->name, np->dev_name);
err = -ENOTSUPP; err = -ENOTSUPP;
......
...@@ -762,6 +762,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) ...@@ -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, static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct nlattr **tb, char *ifname, int modified) struct nlattr **tb, char *ifname, int modified)
{ {
const struct net_device_ops *ops = dev->netdev_ops;
int send_addr_notify = 0; int send_addr_notify = 0;
int err; int err;
...@@ -783,7 +784,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, ...@@ -783,7 +784,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct rtnl_link_ifmap *u_map; struct rtnl_link_ifmap *u_map;
struct ifmap k_map; struct ifmap k_map;
if (!dev->set_config) { if (!ops->ndo_set_config) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto errout; goto errout;
} }
...@@ -801,7 +802,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, ...@@ -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.dma = (unsigned char) u_map->dma;
k_map.port = (unsigned char) u_map->port; 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) if (err < 0)
goto errout; goto errout;
...@@ -812,7 +813,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, ...@@ -812,7 +813,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
struct sockaddr *sa; struct sockaddr *sa;
int len; int len;
if (!dev->set_mac_address) { if (!ops->ndo_set_mac_address) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto errout; goto errout;
} }
...@@ -831,7 +832,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, ...@@ -831,7 +832,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
sa->sa_family = dev->type; sa->sa_family = dev->type;
memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
dev->addr_len); dev->addr_len);
err = dev->set_mac_address(dev, sa); err = ops->ndo_set_mac_address(dev, sa);
kfree(sa); kfree(sa);
if (err) if (err)
goto errout; goto errout;
......
...@@ -224,7 +224,7 @@ static void dev_watchdog(unsigned long arg) ...@@ -224,7 +224,7 @@ static void dev_watchdog(unsigned long arg)
char drivername[64]; char drivername[64];
WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n", WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
dev->name, netdev_drivername(dev, drivername, 64)); dev->name, netdev_drivername(dev, drivername, 64));
dev->tx_timeout(dev); dev->netdev_ops->ndo_tx_timeout(dev);
} }
if (!mod_timer(&dev->watchdog_timer, if (!mod_timer(&dev->watchdog_timer,
round_jiffies(jiffies + round_jiffies(jiffies +
...@@ -239,7 +239,7 @@ static void dev_watchdog(unsigned long arg) ...@@ -239,7 +239,7 @@ static void dev_watchdog(unsigned long arg)
void __netdev_watchdog_up(struct net_device *dev) void __netdev_watchdog_up(struct net_device *dev)
{ {
if (dev->tx_timeout) { if (dev->netdev_ops->ndo_tx_timeout) {
if (dev->watchdog_timeo <= 0) if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ; dev->watchdog_timeo = 5*HZ;
if (!mod_timer(&dev->watchdog_timer, 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