X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fifb.c;h=801f088c134f81370bcca650c30e2a33c2dd6b05;hb=51f2be24328957f9e2acf116b1b1d2dfd10bf41f;hp=1b699259b4ec47fda9f9b7605078b97890fb1dbe;hpb=253af4235d24ddfcd9f5403485e9273b33d8fa5e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 1b69925..801f088 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -1,4 +1,4 @@ -/* drivers/net/ifb.c: +/* drivers/net/ifb.c: The purpose of this driver is to provide a device that allows for sharing of resources: @@ -8,8 +8,8 @@ an impression of sharing. 2) Allows for queueing incoming traffic for shaping instead of - dropping. - + dropping. + The original concept is based on what is known as the IMQ driver initially written by Martin Devera, later rewritten by Patrick McHardy and then maintained by Andre Correa. @@ -21,26 +21,25 @@ modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + Authors: Jamal Hadi Salim (2005) - + */ -#include #include #include #include #include #include #include -#include +#include +#include #define TX_TIMEOUT (2*HZ) - + #define TX_Q_LIMIT 32 struct ifb_private { - struct net_device_stats stats; struct tasklet_struct ifb_tasklet; int tasklet_pending; /* mostly debug stats leave in for now */ @@ -57,32 +56,33 @@ struct ifb_private { struct sk_buff_head tq; }; -static int numifbs = 1; +static int numifbs = 2; static void ri_tasklet(unsigned long dev); -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ifb_get_stats(struct net_device *dev); +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); -static void ri_tasklet(unsigned long dev) +static void ri_tasklet(unsigned long dev) { struct net_device *_dev = (struct net_device *)dev; struct ifb_private *dp = netdev_priv(_dev); - struct net_device_stats *stats = &dp->stats; + struct net_device_stats *stats = &_dev->stats; + struct netdev_queue *txq; struct sk_buff *skb; + txq = netdev_get_tx_queue(_dev, 0); dp->st_task_enter++; if ((skb = skb_peek(&dp->tq)) == NULL) { dp->st_txq_refl_try++; - if (spin_trylock(&_dev->xmit_lock)) { + if (__netif_tx_trylock(txq)) { dp->st_rxq_enter++; while ((skb = skb_dequeue(&dp->rq)) != NULL) { skb_queue_tail(&dp->tq, skb); dp->st_rx2tx_tran++; } - spin_unlock(&_dev->xmit_lock); + __netif_tx_unlock(txq); } else { /* reschedule */ dp->st_rxq_notenter++; @@ -97,20 +97,27 @@ static void ri_tasklet(unsigned long dev) skb->tc_verd = SET_TC_NCLS(skb->tc_verd); stats->tx_packets++; stats->tx_bytes +=skb->len; + + skb->dev = __dev_get_by_index(&init_net, skb->iif); + if (!skb->dev) { + dev_kfree_skb(skb); + stats->tx_dropped++; + break; + } + skb->iif = _dev->ifindex; + if (from & AT_EGRESS) { dp->st_rx_frm_egr++; dev_queue_xmit(skb); } else if (from & AT_INGRESS) { - dp->st_rx_frm_ing++; + skb_pull(skb, skb->dev->hard_header_len); netif_rx(skb); - } else { - dev_kfree_skb(skb); - stats->tx_dropped++; - } + } else + BUG(); } - if (spin_trylock(&_dev->xmit_lock)) { + if (__netif_tx_trylock(txq)) { dp->st_rxq_check++; if ((skb = skb_peek(&dp->rq)) == NULL) { dp->tasklet_pending = 0; @@ -118,10 +125,10 @@ static void ri_tasklet(unsigned long dev) netif_wake_queue(_dev); } else { dp->st_rxq_rsch++; - spin_unlock(&_dev->xmit_lock); + __netif_tx_unlock(txq); goto resched; } - spin_unlock(&_dev->xmit_lock); + __netif_tx_unlock(txq); } else { resched: dp->tasklet_pending = 1; @@ -130,54 +137,42 @@ resched: } -static void __init ifb_setup(struct net_device *dev) +static const struct net_device_ops ifb_netdev_ops = { + .ndo_open = ifb_open, + .ndo_stop = ifb_close, + .ndo_start_xmit = ifb_xmit, + .ndo_validate_addr = eth_validate_addr, +}; + +static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->get_stats = ifb_get_stats; - dev->hard_start_xmit = ifb_xmit; - dev->open = &ifb_open; - dev->stop = &ifb_close; + dev->destructor = free_netdev; + dev->netdev_ops = &ifb_netdev_ops; /* Fill in device structure with ethernet-generic values. */ ether_setup(dev); dev->tx_queue_len = TX_Q_LIMIT; - dev->change_mtu = NULL; + dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; - SET_MODULE_OWNER(dev); + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; random_ether_addr(dev->dev_addr); } -static int ifb_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; - int ret = 0; + struct net_device_stats *stats = &dev->stats; u32 from = G_TC_FROM(skb->tc_verd); - stats->tx_packets++; - stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->rx_bytes+=skb->len; - if (!from || !skb->input_dev) { -dropped: + if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) { dev_kfree_skb(skb); stats->rx_dropped++; - return ret; - } else { - /* - * note we could be going - * ingress -> egress or - * egress -> ingress - */ - skb->dev = skb->input_dev; - skb->input_dev = dev; - if (from & AT_INGRESS) { - skb_pull(skb, skb->dev->hard_header_len); - } else { - if (!(from & AT_EGRESS)) { - goto dropped; - } - } + return NETDEV_TX_OK; } if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { @@ -191,28 +186,9 @@ dropped: tasklet_schedule(&dp->ifb_tasklet); } - return ret; -} - -static struct net_device_stats *ifb_get_stats(struct net_device *dev) -{ - struct ifb_private *dp = netdev_priv(dev); - struct net_device_stats *stats = &dp->stats; - - pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n", - dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter, - dp->st_rx2tx_tran dp->st_rxq_notenter, dp->st_rx_frm_egr, - dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch ); - - return stats; + return NETDEV_TX_OK; } -static struct net_device **ifbs; - -/* Number of ifb devices to be set up by this module. */ -module_param(numifbs, int, 0); -MODULE_PARM_DESC(numifbs, "Number of ifb devices"); - static int ifb_close(struct net_device *dev) { struct ifb_private *dp = netdev_priv(dev); @@ -236,6 +212,28 @@ static int ifb_open(struct net_device *dev) return 0; } +static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + return 0; +} + +static struct rtnl_link_ops ifb_link_ops __read_mostly = { + .kind = "ifb", + .priv_size = sizeof(struct ifb_private), + .setup = ifb_setup, + .validate = ifb_validate, +}; + +/* Number of ifb devices to be set up by this module. */ +module_param(numifbs, int, 0); +MODULE_PARM_DESC(numifbs, "Number of ifb devices"); + static int __init ifb_init_one(int index) { struct net_device *dev_ifb; @@ -247,48 +245,45 @@ static int __init ifb_init_one(int index) if (!dev_ifb) return -ENOMEM; - if ((err = register_netdev(dev_ifb))) { - free_netdev(dev_ifb); - dev_ifb = NULL; - } else { - ifbs[index] = dev_ifb; - } + err = dev_alloc_name(dev_ifb, dev_ifb->name); + if (err < 0) + goto err; + + dev_ifb->rtnl_link_ops = &ifb_link_ops; + err = register_netdevice(dev_ifb); + if (err < 0) + goto err; + + return 0; +err: + free_netdev(dev_ifb); return err; } -static void ifb_free_one(int index) +static int __init ifb_init_module(void) { - unregister_netdev(ifbs[index]); - free_netdev(ifbs[index]); -} + int i, err; + + rtnl_lock(); + err = __rtnl_link_register(&ifb_link_ops); -static int __init ifb_init_module(void) -{ - int i, err = 0; - ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL); - if (!ifbs) - return -ENOMEM; for (i = 0; i < numifbs && !err; i++) - err = ifb_init_one(i); - if (err) { - while (--i >= 0) - ifb_free_one(i); - } + err = ifb_init_one(i); + if (err) + __rtnl_link_unregister(&ifb_link_ops); + rtnl_unlock(); return err; -} +} static void __exit ifb_cleanup_module(void) { - int i; - - for (i = 0; i < numifbs; i++) - ifb_free_one(i); - kfree(ifbs); + rtnl_link_unregister(&ifb_link_ops); } module_init(ifb_init_module); module_exit(ifb_cleanup_module); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jamal Hadi Salim"); +MODULE_ALIAS_RTNL_LINK("ifb");