Blame view

drivers/net/ifb.c 7.15 KB
6aa20a223   Jeff Garzik   drivers/net: Trim...
1
  /* drivers/net/ifb.c:
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
2
3
4
5
6
7
8
9
10
  
  	The purpose of this driver is to provide a device that allows
  	for sharing of resources:
  
  	1) qdiscs/policies that are per device as opposed to system wide.
  	ifb allows for a device which can be redirected to thus providing
  	an impression of sharing.
  
  	2) Allows for queueing incoming traffic for shaping instead of
6aa20a223   Jeff Garzik   drivers/net: Trim...
11
  	dropping.
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
12
13
14
15
16
17
18
19
20
21
22
  	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.
  
  	You need the tc action  mirror or redirect to feed this device
         	packets.
  
  	This program is free software; you can redistribute it and/or
  	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.
6aa20a223   Jeff Garzik   drivers/net: Trim...
23

253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
24
    	Authors:	Jamal Hadi Salim (2005)
6aa20a223   Jeff Garzik   drivers/net: Trim...
25

253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
26
  */
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
27
28
29
30
31
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/init.h>
a6b7a4078   Alexey Dobriyan   net: remove inter...
32
  #include <linux/interrupt.h>
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
33
  #include <linux/moduleparam.h>
6aa20a223   Jeff Garzik   drivers/net: Trim...
34
  #include <net/pkt_sched.h>
881d966b4   Eric W. Biederman   [NET]: Make the d...
35
  #include <net/net_namespace.h>
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
36

253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
37
38
  #define TX_Q_LIMIT    32
  struct ifb_private {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
39
40
  	struct tasklet_struct   ifb_tasklet;
  	int     tasklet_pending;
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
41
42
  
  	struct u64_stats_sync	rsync;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
43
  	struct sk_buff_head     rq;
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
44
45
46
47
  	u64 rx_packets;
  	u64 rx_bytes;
  
  	struct u64_stats_sync	tsync;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
48
  	struct sk_buff_head     tq;
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
49
50
  	u64 tx_packets;
  	u64 tx_bytes;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
51
  };
35eaa31e5   Richard Lucassen   [NET]: Increase d...
52
  static int numifbs = 2;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
53
54
  
  static void ri_tasklet(unsigned long dev);
424efe9ca   Stephen Hemminger   netdev: convert p...
55
  static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
56
57
  static int ifb_open(struct net_device *dev);
  static int ifb_close(struct net_device *dev);
6aa20a223   Jeff Garzik   drivers/net: Trim...
58
  static void ri_tasklet(unsigned long dev)
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
59
  {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
60
61
  	struct net_device *_dev = (struct net_device *)dev;
  	struct ifb_private *dp = netdev_priv(_dev);
c3f26a269   David S. Miller   netdev: Fix lockd...
62
  	struct netdev_queue *txq;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
63
  	struct sk_buff *skb;
c3f26a269   David S. Miller   netdev: Fix lockd...
64
  	txq = netdev_get_tx_queue(_dev, 0);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
65
  	if ((skb = skb_peek(&dp->tq)) == NULL) {
c3f26a269   David S. Miller   netdev: Fix lockd...
66
  		if (__netif_tx_trylock(txq)) {
957fca95e   Changli Gao   ifb: use the lock...
67
  			skb_queue_splice_tail_init(&dp->rq, &dp->tq);
c3f26a269   David S. Miller   netdev: Fix lockd...
68
  			__netif_tx_unlock(txq);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
69
70
  		} else {
  			/* reschedule */
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
71
72
73
  			goto resched;
  		}
  	}
7edc3453e   Eric Dumazet   ifb: fix a lockde...
74
  	while ((skb = __skb_dequeue(&dp->tq)) != NULL) {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
75
76
77
78
  		u32 from = G_TC_FROM(skb->tc_verd);
  
  		skb->tc_verd = 0;
  		skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
79
80
81
82
83
  
  		u64_stats_update_begin(&dp->tsync);
  		dp->tx_packets++;
  		dp->tx_bytes += skb->len;
  		u64_stats_update_end(&dp->tsync);
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
84

05e8689c9   Eric Dumazet   ifb: RCU locking ...
85
  		rcu_read_lock();
8964be4a9   Eric Dumazet   net: rename skb->...
86
  		skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
87
  		if (!skb->dev) {
05e8689c9   Eric Dumazet   ifb: RCU locking ...
88
  			rcu_read_unlock();
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
89
  			dev_kfree_skb(skb);
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
90
  			_dev->stats.tx_dropped++;
75c1c8256   Changli Gao   ifb: goto resched...
91
92
  			if (skb_queue_len(&dp->tq) != 0)
  				goto resched;
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
93
94
  			break;
  		}
05e8689c9   Eric Dumazet   ifb: RCU locking ...
95
  		rcu_read_unlock();
8964be4a9   Eric Dumazet   net: rename skb->...
96
  		skb->skb_iif = _dev->ifindex;
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
97

253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
98
  		if (from & AT_EGRESS) {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
99
100
  			dev_queue_xmit(skb);
  		} else if (from & AT_INGRESS) {
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
101
  			skb_pull(skb, skb->dev->hard_header_len);
1a75972c6   Eric Dumazet   ifb: use netif_re...
102
  			netif_receive_skb(skb);
c01003c20   Patrick McHardy   [IFB]: Fix crash ...
103
104
  		} else
  			BUG();
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
105
  	}
c3f26a269   David S. Miller   netdev: Fix lockd...
106
  	if (__netif_tx_trylock(txq)) {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
107
108
109
110
111
  		if ((skb = skb_peek(&dp->rq)) == NULL) {
  			dp->tasklet_pending = 0;
  			if (netif_queue_stopped(_dev))
  				netif_wake_queue(_dev);
  		} else {
c3f26a269   David S. Miller   netdev: Fix lockd...
112
  			__netif_tx_unlock(txq);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
113
114
  			goto resched;
  		}
c3f26a269   David S. Miller   netdev: Fix lockd...
115
  		__netif_tx_unlock(txq);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
116
117
118
119
120
121
122
  	} else {
  resched:
  		dp->tasklet_pending = 1;
  		tasklet_schedule(&dp->ifb_tasklet);
  	}
  
  }
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev,
  					     struct rtnl_link_stats64 *stats)
  {
  	struct ifb_private *dp = netdev_priv(dev);
  	unsigned int start;
  
  	do {
  		start = u64_stats_fetch_begin_bh(&dp->rsync);
  		stats->rx_packets = dp->rx_packets;
  		stats->rx_bytes = dp->rx_bytes;
  	} while (u64_stats_fetch_retry_bh(&dp->rsync, start));
  
  	do {
  		start = u64_stats_fetch_begin_bh(&dp->tsync);
  
  		stats->tx_packets = dp->tx_packets;
  		stats->tx_bytes = dp->tx_bytes;
  
  	} while (u64_stats_fetch_retry_bh(&dp->tsync, start));
  
  	stats->rx_dropped = dev->stats.rx_dropped;
  	stats->tx_dropped = dev->stats.tx_dropped;
  
  	return stats;
  }
8dfcdf342   Stephen Hemminger   ifb: convert to n...
148
  static const struct net_device_ops ifb_netdev_ops = {
8dfcdf342   Stephen Hemminger   ifb: convert to n...
149
150
  	.ndo_open	= ifb_open,
  	.ndo_stop	= ifb_close,
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
151
  	.ndo_get_stats64 = ifb_stats64,
008298231   Stephen Hemminger   netdev: add more ...
152
153
  	.ndo_start_xmit	= ifb_xmit,
  	.ndo_validate_addr = eth_validate_addr,
8dfcdf342   Stephen Hemminger   ifb: convert to n...
154
  };
34324dc2b   Michał Mirosław   net: remove NETIF...
155
  #define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG  | NETIF_F_FRAGLIST	| \
39980292f   Eric Dumazet   ifb: add performa...
156
157
  		      NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6	| \
  		      NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
158
  static void ifb_setup(struct net_device *dev)
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
159
160
  {
  	/* Initialize the device structure. */
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
161
  	dev->destructor = free_netdev;
8dfcdf342   Stephen Hemminger   ifb: convert to n...
162
  	dev->netdev_ops = &ifb_netdev_ops;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
163
164
165
166
  
  	/* Fill in device structure with ethernet-generic values. */
  	ether_setup(dev);
  	dev->tx_queue_len = TX_Q_LIMIT;
8dfcdf342   Stephen Hemminger   ifb: convert to n...
167

39980292f   Eric Dumazet   ifb: add performa...
168
169
  	dev->features |= IFB_FEATURES;
  	dev->vlan_features |= IFB_FEATURES;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
170
171
  	dev->flags |= IFF_NOARP;
  	dev->flags &= ~IFF_MULTICAST;
550fd08c2   Neil Horman   net: Audit driver...
172
  	dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
173
174
  	random_ether_addr(dev->dev_addr);
  }
424efe9ca   Stephen Hemminger   netdev: convert p...
175
  static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
176
177
  {
  	struct ifb_private *dp = netdev_priv(dev);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
178
  	u32 from = G_TC_FROM(skb->tc_verd);
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
179
180
181
182
  	u64_stats_update_begin(&dp->rsync);
  	dp->rx_packets++;
  	dp->rx_bytes += skb->len;
  	u64_stats_update_end(&dp->rsync);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
183

8964be4a9   Eric Dumazet   net: rename skb->...
184
  	if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) {
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
185
  		dev_kfree_skb(skb);
3b0c9cbb6   stephen hemminger   ifb: convert to 6...
186
  		dev->stats.rx_dropped++;
424efe9ca   Stephen Hemminger   netdev: convert p...
187
  		return NETDEV_TX_OK;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
188
189
190
191
192
  	}
  
  	if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) {
  		netif_stop_queue(dev);
  	}
957fca95e   Changli Gao   ifb: use the lock...
193
  	__skb_queue_tail(&dp->rq, skb);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
194
195
196
197
  	if (!dp->tasklet_pending) {
  		dp->tasklet_pending = 1;
  		tasklet_schedule(&dp->ifb_tasklet);
  	}
424efe9ca   Stephen Hemminger   netdev: convert p...
198
  	return NETDEV_TX_OK;
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
199
  }
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
200
201
202
203
204
205
  static int ifb_close(struct net_device *dev)
  {
  	struct ifb_private *dp = netdev_priv(dev);
  
  	tasklet_kill(&dp->ifb_tasklet);
  	netif_stop_queue(dev);
957fca95e   Changli Gao   ifb: use the lock...
206
207
  	__skb_queue_purge(&dp->rq);
  	__skb_queue_purge(&dp->tq);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
208
209
210
211
212
213
214
215
  	return 0;
  }
  
  static int ifb_open(struct net_device *dev)
  {
  	struct ifb_private *dp = netdev_priv(dev);
  
  	tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev);
957fca95e   Changli Gao   ifb: use the lock...
216
217
  	__skb_queue_head_init(&dp->rq);
  	__skb_queue_head_init(&dp->tq);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
218
219
220
221
  	netif_start_queue(dev);
  
  	return 0;
  }
0e06877c6   Patrick McHardy   [RTNETLINK]: rtnl...
222
223
224
225
226
227
228
229
230
231
  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;
  }
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
232
233
234
235
  static struct rtnl_link_ops ifb_link_ops __read_mostly = {
  	.kind		= "ifb",
  	.priv_size	= sizeof(struct ifb_private),
  	.setup		= ifb_setup,
0e06877c6   Patrick McHardy   [RTNETLINK]: rtnl...
236
  	.validate	= ifb_validate,
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
237
  };
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
238
239
240
  /* Number of ifb devices to be set up by this module. */
  module_param(numifbs, int, 0);
  MODULE_PARM_DESC(numifbs, "Number of ifb devices");
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
241
242
243
244
245
246
247
248
249
250
  static int __init ifb_init_one(int index)
  {
  	struct net_device *dev_ifb;
  	int err;
  
  	dev_ifb = alloc_netdev(sizeof(struct ifb_private),
  				 "ifb%d", ifb_setup);
  
  	if (!dev_ifb)
  		return -ENOMEM;
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
251
252
253
254
  	dev_ifb->rtnl_link_ops = &ifb_link_ops;
  	err = register_netdevice(dev_ifb);
  	if (err < 0)
  		goto err;
94833dfb8   Jarek Poplawski   [NET] ifb: set se...
255

9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
256
  	return 0;
62b7ffcaa   Patrick McHardy   [IFB]: Keep ifb d...
257

9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
258
259
260
  err:
  	free_netdev(dev_ifb);
  	return err;
6aa20a223   Jeff Garzik   drivers/net: Trim...
261
  }
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
262
263
  
  static int __init ifb_init_module(void)
6aa20a223   Jeff Garzik   drivers/net: Trim...
264
  {
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
265
266
267
268
  	int i, err;
  
  	rtnl_lock();
  	err = __rtnl_link_register(&ifb_link_ops);
62b7ffcaa   Patrick McHardy   [IFB]: Keep ifb d...
269

253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
270
  	for (i = 0; i < numifbs && !err; i++)
6aa20a223   Jeff Garzik   drivers/net: Trim...
271
  		err = ifb_init_one(i);
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
272
  	if (err)
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
273
  		__rtnl_link_unregister(&ifb_link_ops);
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
274
  	rtnl_unlock();
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
275
276
  
  	return err;
6aa20a223   Jeff Garzik   drivers/net: Trim...
277
  }
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
278
279
280
  
  static void __exit ifb_cleanup_module(void)
  {
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
281
  	rtnl_link_unregister(&ifb_link_ops);
253af4235   Jamal Hadi Salim   [NET]: Add IFB (I...
282
283
284
285
286
287
  }
  
  module_init(ifb_init_module);
  module_exit(ifb_cleanup_module);
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Jamal Hadi Salim");
9ba2cd656   Patrick McHardy   [IFB]: Use rtnl_l...
288
  MODULE_ALIAS_RTNL_LINK("ifb");