16aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik/* drivers/net/ifb.c: 2253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 3253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim The purpose of this driver is to provide a device that allows 4253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim for sharing of resources: 5253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 6253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 1) qdiscs/policies that are per device as opposed to system wide. 7253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim ifb allows for a device which can be redirected to thus providing 8253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim an impression of sharing. 9253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 10253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 2) Allows for queueing incoming traffic for shaping instead of 116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik dropping. 126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 13253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim The original concept is based on what is known as the IMQ 14253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim driver initially written by Martin Devera, later rewritten 15253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim by Patrick McHardy and then maintained by Andre Correa. 16253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 17253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim You need the tc action mirror or redirect to feed this device 18253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim packets. 19253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 20253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim This program is free software; you can redistribute it and/or 21253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim modify it under the terms of the GNU General Public License 22253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim as published by the Free Software Foundation; either version 23253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 2 of the License, or (at your option) any later version. 246aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 25253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim Authors: Jamal Hadi Salim (2005) 266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 27253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim*/ 28253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 29253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 30253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/module.h> 31253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/kernel.h> 32253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/netdevice.h> 33253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/etherdevice.h> 34253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/init.h> 35a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 36253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#include <linux/moduleparam.h> 376aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#include <net/pkt_sched.h> 38881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman#include <net/net_namespace.h> 39253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 40253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim#define TX_Q_LIMIT 32 41253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstruct ifb_private { 42253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct tasklet_struct ifb_tasklet; 43253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim int tasklet_pending; 443b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 453b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger struct u64_stats_sync rsync; 46253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct sk_buff_head rq; 473b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64 rx_packets; 483b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64 rx_bytes; 493b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 503b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger struct u64_stats_sync tsync; 51253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct sk_buff_head tq; 523b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64 tx_packets; 533b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64 tx_bytes; 54253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim}; 55253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 5635eaa31e5d6b0653c11b5661572152295b45b7a7Richard Lucassenstatic int numifbs = 2; 57253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 58253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic void ri_tasklet(unsigned long dev); 59424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemmingerstatic netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); 60253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int ifb_open(struct net_device *dev); 61253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int ifb_close(struct net_device *dev); 62253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 636aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzikstatic void ri_tasklet(unsigned long dev) 64253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 65253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct net_device *_dev = (struct net_device *)dev; 66253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct ifb_private *dp = netdev_priv(_dev); 67c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller struct netdev_queue *txq; 68253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct sk_buff *skb; 69253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 70c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller txq = netdev_get_tx_queue(_dev, 0); 71253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if ((skb = skb_peek(&dp->tq)) == NULL) { 72c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller if (__netif_tx_trylock(txq)) { 73957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao skb_queue_splice_tail_init(&dp->rq, &dp->tq); 74c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller __netif_tx_unlock(txq); 75253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } else { 76253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim /* reschedule */ 77253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim goto resched; 78253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 79253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 80253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 817edc3453e54432a9f1c636b6481f1107c9db19bdEric Dumazet while ((skb = __skb_dequeue(&dp->tq)) != NULL) { 82253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim u32 from = G_TC_FROM(skb->tc_verd); 83253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 84253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim skb->tc_verd = 0; 85253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim skb->tc_verd = SET_TC_NCLS(skb->tc_verd); 863b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 873b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64_stats_update_begin(&dp->tsync); 883b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger dp->tx_packets++; 893b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger dp->tx_bytes += skb->len; 903b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64_stats_update_end(&dp->tsync); 91c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy 9205e8689c9a3a208bf75b60662778d81e23eac460Eric Dumazet rcu_read_lock(); 938964be4a9a5ca8cab1219bb046db2f6d1936227cEric Dumazet skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif); 94c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy if (!skb->dev) { 9505e8689c9a3a208bf75b60662778d81e23eac460Eric Dumazet rcu_read_unlock(); 96c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy dev_kfree_skb(skb); 973b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger _dev->stats.tx_dropped++; 9875c1c82566f23dd539fb7ccbf57a1caa7ba82628Changli Gao if (skb_queue_len(&dp->tq) != 0) 9975c1c82566f23dd539fb7ccbf57a1caa7ba82628Changli Gao goto resched; 100c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy break; 101c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy } 10205e8689c9a3a208bf75b60662778d81e23eac460Eric Dumazet rcu_read_unlock(); 1038964be4a9a5ca8cab1219bb046db2f6d1936227cEric Dumazet skb->skb_iif = _dev->ifindex; 104c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy 105253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if (from & AT_EGRESS) { 106253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev_queue_xmit(skb); 107253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } else if (from & AT_INGRESS) { 108c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy skb_pull(skb, skb->dev->hard_header_len); 1091a75972c61f2c224eb5283c183f9f6b17fb09b6bEric Dumazet netif_receive_skb(skb); 110c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy } else 111c01003c20563d1e75ec9828d21743919d2b43977Patrick McHardy BUG(); 112253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 113253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 114c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller if (__netif_tx_trylock(txq)) { 115253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if ((skb = skb_peek(&dp->rq)) == NULL) { 116253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dp->tasklet_pending = 0; 117253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if (netif_queue_stopped(_dev)) 118253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim netif_wake_queue(_dev); 119253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } else { 120c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller __netif_tx_unlock(txq); 121253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim goto resched; 122253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 123c3f26a269c2421f97f10cf8ed05d5099b573af4dDavid S. Miller __netif_tx_unlock(txq); 124253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } else { 125253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimresched: 126253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dp->tasklet_pending = 1; 127253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim tasklet_schedule(&dp->ifb_tasklet); 128253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 129253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 130253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 131253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 1323b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemmingerstatic struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, 1333b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger struct rtnl_link_stats64 *stats) 1343b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger{ 1353b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger struct ifb_private *dp = netdev_priv(dev); 1363b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger unsigned int start; 1373b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1383b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger do { 1393b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger start = u64_stats_fetch_begin_bh(&dp->rsync); 1403b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->rx_packets = dp->rx_packets; 1413b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->rx_bytes = dp->rx_bytes; 1423b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger } while (u64_stats_fetch_retry_bh(&dp->rsync, start)); 1433b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1443b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger do { 1453b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger start = u64_stats_fetch_begin_bh(&dp->tsync); 1463b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1473b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->tx_packets = dp->tx_packets; 1483b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->tx_bytes = dp->tx_bytes; 1493b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1503b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger } while (u64_stats_fetch_retry_bh(&dp->tsync, start)); 1513b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1523b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->rx_dropped = dev->stats.rx_dropped; 1533b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger stats->tx_dropped = dev->stats.tx_dropped; 1543b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1553b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger return stats; 1563b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger} 1573b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1583b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger 1598dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemmingerstatic const struct net_device_ops ifb_netdev_ops = { 1608dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger .ndo_open = ifb_open, 1618dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger .ndo_stop = ifb_close, 1623b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger .ndo_get_stats64 = ifb_stats64, 163008298231abbeb91bc7be9e8b078607b816d1a4aStephen Hemminger .ndo_start_xmit = ifb_xmit, 164008298231abbeb91bc7be9e8b078607b816d1a4aStephen Hemminger .ndo_validate_addr = eth_validate_addr, 1658dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger}; 1668dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger 16734324dc2bf27c1773045fea63cb11f7e2a6ad2b9Michał Mirosław#define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \ 16839980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6 | \ 16939980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX) 17039980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet 1719ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardystatic void ifb_setup(struct net_device *dev) 172253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 173253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim /* Initialize the device structure. */ 1749ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy dev->destructor = free_netdev; 1758dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger dev->netdev_ops = &ifb_netdev_ops; 176253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 177253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim /* Fill in device structure with ethernet-generic values. */ 178253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim ether_setup(dev); 179253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev->tx_queue_len = TX_Q_LIMIT; 1808dfcdf342d9e8294a3292005f9158022289dfd67Stephen Hemminger 18139980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet dev->features |= IFB_FEATURES; 18239980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet dev->vlan_features |= IFB_FEATURES; 18339980292fda20b38baf95bfa577db8b678eecc86Eric Dumazet 184253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev->flags |= IFF_NOARP; 185253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev->flags &= ~IFF_MULTICAST; 186550fd08c2cebad61c548def135f67aba284c6162Neil Horman dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); 187f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka eth_hw_addr_random(dev); 188253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 189253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 190424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemmingerstatic netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) 191253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 192253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct ifb_private *dp = netdev_priv(dev); 193253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim u32 from = G_TC_FROM(skb->tc_verd); 194253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 1953b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64_stats_update_begin(&dp->rsync); 1963b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger dp->rx_packets++; 1973b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger dp->rx_bytes += skb->len; 1983b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger u64_stats_update_end(&dp->rsync); 199253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 2008964be4a9a5ca8cab1219bb046db2f6d1936227cEric Dumazet if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) { 201253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev_kfree_skb(skb); 2023b0c9cbb6e5fe25a4162be68ed1459b6f7432da9stephen hemminger dev->stats.rx_dropped++; 203424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger return NETDEV_TX_OK; 204253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 205253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 206253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { 207253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim netif_stop_queue(dev); 208253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 209253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 210957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao __skb_queue_tail(&dp->rq, skb); 211253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if (!dp->tasklet_pending) { 212253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dp->tasklet_pending = 1; 213253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim tasklet_schedule(&dp->ifb_tasklet); 214253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim } 215253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 216424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger return NETDEV_TX_OK; 217253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 218253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 219253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int ifb_close(struct net_device *dev) 220253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 221253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct ifb_private *dp = netdev_priv(dev); 222253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 223253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim tasklet_kill(&dp->ifb_tasklet); 224253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim netif_stop_queue(dev); 225957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao __skb_queue_purge(&dp->rq); 226957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao __skb_queue_purge(&dp->tq); 227253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim return 0; 228253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 229253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 230253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int ifb_open(struct net_device *dev) 231253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 232253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct ifb_private *dp = netdev_priv(dev); 233253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 234253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev); 235957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao __skb_queue_head_init(&dp->rq); 236957fca95e3521e471aac4c2e4cfbc21f399bdd84Changli Gao __skb_queue_head_init(&dp->tq); 237253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim netif_start_queue(dev); 238253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 239253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim return 0; 240253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 241253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 2420e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardystatic int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) 2430e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy{ 2440e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (tb[IFLA_ADDRESS]) { 2450e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 2460e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return -EINVAL; 2470e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 2480e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return -EADDRNOTAVAIL; 2490e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy } 2500e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return 0; 2510e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy} 2520e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy 2539ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardystatic struct rtnl_link_ops ifb_link_ops __read_mostly = { 2549ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy .kind = "ifb", 2559ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy .priv_size = sizeof(struct ifb_private), 2569ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy .setup = ifb_setup, 2570e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy .validate = ifb_validate, 2589ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy}; 2599ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy 2602d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy/* Number of ifb devices to be set up by this module. */ 2612d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardymodule_param(numifbs, int, 0); 2622d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardyMODULE_PARM_DESC(numifbs, "Number of ifb devices"); 2632d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy 264253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int __init ifb_init_one(int index) 265253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 266253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim struct net_device *dev_ifb; 267253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim int err; 268253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 269253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim dev_ifb = alloc_netdev(sizeof(struct ifb_private), 270253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim "ifb%d", ifb_setup); 271253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 272253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim if (!dev_ifb) 273253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim return -ENOMEM; 274253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 2759ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy dev_ifb->rtnl_link_ops = &ifb_link_ops; 2769ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy err = register_netdevice(dev_ifb); 2779ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy if (err < 0) 2789ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy goto err; 27994833dfb8c98ed4ca1944dd2c1339d88a2d1c758Jarek Poplawski 2809ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy return 0; 28162b7ffcaaa4e91ed547fc55758076ac536bd5571Patrick McHardy 2829ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardyerr: 2839ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy free_netdev(dev_ifb); 2849ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy return err; 2856aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik} 286253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 287253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic int __init ifb_init_module(void) 2886aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{ 2899ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy int i, err; 2909ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy 2919ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy rtnl_lock(); 2929ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy err = __rtnl_link_register(&ifb_link_ops); 29362b7ffcaaa4e91ed547fc55758076ac536bd5571Patrick McHardy 294253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim for (i = 0; i < numifbs && !err; i++) 2956aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik err = ifb_init_one(i); 2962d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy if (err) 2979ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy __rtnl_link_unregister(&ifb_link_ops); 2989ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardy rtnl_unlock(); 299253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 300253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim return err; 3016aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik} 302253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 303253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimstatic void __exit ifb_cleanup_module(void) 304253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim{ 3052d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy rtnl_link_unregister(&ifb_link_ops); 306253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim} 307253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salim 308253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimmodule_init(ifb_init_module); 309253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi Salimmodule_exit(ifb_cleanup_module); 310253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi SalimMODULE_LICENSE("GPL"); 311253af4235d24ddfcd9f5403485e9273b33d8fa5eJamal Hadi SalimMODULE_AUTHOR("Jamal Hadi Salim"); 3129ba2cd656021e7f70038ba9d551224e04d0bfcefPatrick McHardyMODULE_ALIAS_RTNL_LINK("ifb"); 313