• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /* drivers/net/ifb.c:
2  
3  	The purpose of this driver is to provide a device that allows
4  	for sharing of resources:
5  
6  	1) qdiscs/policies that are per device as opposed to system wide.
7  	ifb allows for a device which can be redirected to thus providing
8  	an impression of sharing.
9  
10  	2) Allows for queueing incoming traffic for shaping instead of
11  	dropping.
12  
13  	The original concept is based on what is known as the IMQ
14  	driver initially written by Martin Devera, later rewritten
15  	by Patrick McHardy and then maintained by Andre Correa.
16  
17  	You need the tc action  mirror or redirect to feed this device
18         	packets.
19  
20  	This program is free software; you can redistribute it and/or
21  	modify it under the terms of the GNU General Public License
22  	as published by the Free Software Foundation; either version
23  	2 of the License, or (at your option) any later version.
24  
25    	Authors:	Jamal Hadi Salim (2005)
26  
27  */
28  
29  
30  #include <linux/module.h>
31  #include <linux/kernel.h>
32  #include <linux/netdevice.h>
33  #include <linux/etherdevice.h>
34  #include <linux/init.h>
35  #include <linux/interrupt.h>
36  #include <linux/moduleparam.h>
37  #include <net/pkt_sched.h>
38  #include <net/net_namespace.h>
39  
40  #define TX_Q_LIMIT    32
41  struct ifb_q_private {
42  	struct net_device	*dev;
43  	struct tasklet_struct   ifb_tasklet;
44  	int			tasklet_pending;
45  	int			txqnum;
46  	struct sk_buff_head     rq;
47  	u64			rx_packets;
48  	u64			rx_bytes;
49  	struct u64_stats_sync	rsync;
50  
51  	struct u64_stats_sync	tsync;
52  	u64			tx_packets;
53  	u64			tx_bytes;
54  	struct sk_buff_head     tq;
55  } ____cacheline_aligned_in_smp;
56  
57  struct ifb_dev_private {
58  	struct ifb_q_private *tx_private;
59  };
60  
61  static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev);
62  static int ifb_open(struct net_device *dev);
63  static int ifb_close(struct net_device *dev);
64  
ifb_ri_tasklet(unsigned long _txp)65  static void ifb_ri_tasklet(unsigned long _txp)
66  {
67  	struct ifb_q_private *txp = (struct ifb_q_private *)_txp;
68  	struct netdev_queue *txq;
69  	struct sk_buff *skb;
70  
71  	txq = netdev_get_tx_queue(txp->dev, txp->txqnum);
72  	skb = skb_peek(&txp->tq);
73  	if (!skb) {
74  		if (!__netif_tx_trylock(txq))
75  			goto resched;
76  		skb_queue_splice_tail_init(&txp->rq, &txp->tq);
77  		__netif_tx_unlock(txq);
78  	}
79  
80  	while ((skb = __skb_dequeue(&txp->tq)) != NULL) {
81  		u32 from = G_TC_FROM(skb->tc_verd);
82  
83  		skb->tc_verd = 0;
84  		skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
85  
86  		u64_stats_update_begin(&txp->tsync);
87  		txp->tx_packets++;
88  		txp->tx_bytes += skb->len;
89  		u64_stats_update_end(&txp->tsync);
90  
91  		rcu_read_lock();
92  		skb->dev = dev_get_by_index_rcu(dev_net(txp->dev), skb->skb_iif);
93  		if (!skb->dev) {
94  			rcu_read_unlock();
95  			dev_kfree_skb(skb);
96  			txp->dev->stats.tx_dropped++;
97  			if (skb_queue_len(&txp->tq) != 0)
98  				goto resched;
99  			break;
100  		}
101  		rcu_read_unlock();
102  		skb->skb_iif = txp->dev->ifindex;
103  
104  		if (from & AT_EGRESS) {
105  			dev_queue_xmit(skb);
106  		} else if (from & AT_INGRESS) {
107  			skb_pull(skb, skb->mac_len);
108  			netif_receive_skb(skb);
109  		} else
110  			BUG();
111  	}
112  
113  	if (__netif_tx_trylock(txq)) {
114  		skb = skb_peek(&txp->rq);
115  		if (!skb) {
116  			txp->tasklet_pending = 0;
117  			if (netif_tx_queue_stopped(txq))
118  				netif_tx_wake_queue(txq);
119  		} else {
120  			__netif_tx_unlock(txq);
121  			goto resched;
122  		}
123  		__netif_tx_unlock(txq);
124  	} else {
125  resched:
126  		txp->tasklet_pending = 1;
127  		tasklet_schedule(&txp->ifb_tasklet);
128  	}
129  
130  }
131  
ifb_stats64(struct net_device * dev,struct rtnl_link_stats64 * stats)132  static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev,
133  					     struct rtnl_link_stats64 *stats)
134  {
135  	struct ifb_dev_private *dp = netdev_priv(dev);
136  	struct ifb_q_private *txp = dp->tx_private;
137  	unsigned int start;
138  	u64 packets, bytes;
139  	int i;
140  
141  	for (i = 0; i < dev->num_tx_queues; i++,txp++) {
142  		do {
143  			start = u64_stats_fetch_begin_irq(&txp->rsync);
144  			packets = txp->rx_packets;
145  			bytes = txp->rx_bytes;
146  		} while (u64_stats_fetch_retry_irq(&txp->rsync, start));
147  		stats->rx_packets += packets;
148  		stats->rx_bytes += bytes;
149  
150  		do {
151  			start = u64_stats_fetch_begin_irq(&txp->tsync);
152  			packets = txp->tx_packets;
153  			bytes = txp->tx_bytes;
154  		} while (u64_stats_fetch_retry_irq(&txp->tsync, start));
155  		stats->tx_packets += packets;
156  		stats->tx_bytes += bytes;
157  	}
158  	stats->rx_dropped = dev->stats.rx_dropped;
159  	stats->tx_dropped = dev->stats.tx_dropped;
160  
161  	return stats;
162  }
163  
ifb_dev_init(struct net_device * dev)164  static int ifb_dev_init(struct net_device *dev)
165  {
166  	struct ifb_dev_private *dp = netdev_priv(dev);
167  	struct ifb_q_private *txp;
168  	int i;
169  
170  	txp = kcalloc(dev->num_tx_queues, sizeof(*txp), GFP_KERNEL);
171  	if (!txp)
172  		return -ENOMEM;
173  	dp->tx_private = txp;
174  	for (i = 0; i < dev->num_tx_queues; i++,txp++) {
175  		txp->txqnum = i;
176  		txp->dev = dev;
177  		__skb_queue_head_init(&txp->rq);
178  		__skb_queue_head_init(&txp->tq);
179  		u64_stats_init(&txp->rsync);
180  		u64_stats_init(&txp->tsync);
181  		tasklet_init(&txp->ifb_tasklet, ifb_ri_tasklet,
182  			     (unsigned long)txp);
183  		netif_tx_start_queue(netdev_get_tx_queue(dev, i));
184  	}
185  	return 0;
186  }
187  
188  static const struct net_device_ops ifb_netdev_ops = {
189  	.ndo_open	= ifb_open,
190  	.ndo_stop	= ifb_close,
191  	.ndo_get_stats64 = ifb_stats64,
192  	.ndo_start_xmit	= ifb_xmit,
193  	.ndo_validate_addr = eth_validate_addr,
194  	.ndo_init	= ifb_dev_init,
195  };
196  
197  #define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST	| \
198  		      NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6	| \
199  		      NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX		| \
200  		      NETIF_F_HW_VLAN_STAG_TX)
201  
ifb_dev_free(struct net_device * dev)202  static void ifb_dev_free(struct net_device *dev)
203  {
204  	struct ifb_dev_private *dp = netdev_priv(dev);
205  	struct ifb_q_private *txp = dp->tx_private;
206  	int i;
207  
208  	for (i = 0; i < dev->num_tx_queues; i++,txp++) {
209  		tasklet_kill(&txp->ifb_tasklet);
210  		__skb_queue_purge(&txp->rq);
211  		__skb_queue_purge(&txp->tq);
212  	}
213  	kfree(dp->tx_private);
214  	free_netdev(dev);
215  }
216  
ifb_setup(struct net_device * dev)217  static void ifb_setup(struct net_device *dev)
218  {
219  	/* Initialize the device structure. */
220  	dev->netdev_ops = &ifb_netdev_ops;
221  
222  	/* Fill in device structure with ethernet-generic values. */
223  	ether_setup(dev);
224  	dev->tx_queue_len = TX_Q_LIMIT;
225  
226  	dev->features |= IFB_FEATURES;
227  	dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX |
228  					       NETIF_F_HW_VLAN_STAG_TX);
229  
230  	dev->flags |= IFF_NOARP;
231  	dev->flags &= ~IFF_MULTICAST;
232  	dev->priv_flags &= ~IFF_TX_SKB_SHARING;
233  	netif_keep_dst(dev);
234  	eth_hw_addr_random(dev);
235  	dev->destructor = ifb_dev_free;
236  }
237  
ifb_xmit(struct sk_buff * skb,struct net_device * dev)238  static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
239  {
240  	struct ifb_dev_private *dp = netdev_priv(dev);
241  	u32 from = G_TC_FROM(skb->tc_verd);
242  	struct ifb_q_private *txp = dp->tx_private + skb_get_queue_mapping(skb);
243  
244  	u64_stats_update_begin(&txp->rsync);
245  	txp->rx_packets++;
246  	txp->rx_bytes += skb->len;
247  	u64_stats_update_end(&txp->rsync);
248  
249  	if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) {
250  		dev_kfree_skb(skb);
251  		dev->stats.rx_dropped++;
252  		return NETDEV_TX_OK;
253  	}
254  
255  	if (skb_queue_len(&txp->rq) >= dev->tx_queue_len)
256  		netif_tx_stop_queue(netdev_get_tx_queue(dev, txp->txqnum));
257  
258  	__skb_queue_tail(&txp->rq, skb);
259  	if (!txp->tasklet_pending) {
260  		txp->tasklet_pending = 1;
261  		tasklet_schedule(&txp->ifb_tasklet);
262  	}
263  
264  	return NETDEV_TX_OK;
265  }
266  
ifb_close(struct net_device * dev)267  static int ifb_close(struct net_device *dev)
268  {
269  	netif_tx_stop_all_queues(dev);
270  	return 0;
271  }
272  
ifb_open(struct net_device * dev)273  static int ifb_open(struct net_device *dev)
274  {
275  	netif_tx_start_all_queues(dev);
276  	return 0;
277  }
278  
ifb_validate(struct nlattr * tb[],struct nlattr * data[])279  static int ifb_validate(struct nlattr *tb[], struct nlattr *data[])
280  {
281  	if (tb[IFLA_ADDRESS]) {
282  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
283  			return -EINVAL;
284  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
285  			return -EADDRNOTAVAIL;
286  	}
287  	return 0;
288  }
289  
290  static struct rtnl_link_ops ifb_link_ops __read_mostly = {
291  	.kind		= "ifb",
292  	.priv_size	= sizeof(struct ifb_dev_private),
293  	.setup		= ifb_setup,
294  	.validate	= ifb_validate,
295  };
296  
297  /* Number of ifb devices to be set up by this module.
298   * Note that these legacy devices have one queue.
299   * Prefer something like : ip link add ifb10 numtxqueues 8 type ifb
300   */
301  static int numifbs = 2;
302  module_param(numifbs, int, 0);
303  MODULE_PARM_DESC(numifbs, "Number of ifb devices");
304  
ifb_init_one(int index)305  static int __init ifb_init_one(int index)
306  {
307  	struct net_device *dev_ifb;
308  	int err;
309  
310  	dev_ifb = alloc_netdev(sizeof(struct ifb_dev_private), "ifb%d",
311  			       NET_NAME_UNKNOWN, ifb_setup);
312  
313  	if (!dev_ifb)
314  		return -ENOMEM;
315  
316  	dev_ifb->rtnl_link_ops = &ifb_link_ops;
317  	err = register_netdevice(dev_ifb);
318  	if (err < 0)
319  		goto err;
320  
321  	return 0;
322  
323  err:
324  	free_netdev(dev_ifb);
325  	return err;
326  }
327  
ifb_init_module(void)328  static int __init ifb_init_module(void)
329  {
330  	int i, err;
331  
332  	rtnl_lock();
333  	err = __rtnl_link_register(&ifb_link_ops);
334  	if (err < 0)
335  		goto out;
336  
337  	for (i = 0; i < numifbs && !err; i++) {
338  		err = ifb_init_one(i);
339  		cond_resched();
340  	}
341  	if (err)
342  		__rtnl_link_unregister(&ifb_link_ops);
343  
344  out:
345  	rtnl_unlock();
346  
347  	return err;
348  }
349  
ifb_cleanup_module(void)350  static void __exit ifb_cleanup_module(void)
351  {
352  	rtnl_link_unregister(&ifb_link_ops);
353  }
354  
355  module_init(ifb_init_module);
356  module_exit(ifb_cleanup_module);
357  MODULE_LICENSE("GPL");
358  MODULE_AUTHOR("Jamal Hadi Salim");
359  MODULE_ALIAS_RTNL_LINK("ifb");
360