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