[IFB]: Use rtnl_link API
[safe/jmp/linux-2.6] / drivers / net / ifb.c
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/moduleparam.h>
36 #include <linux/list.h>
37 #include <net/pkt_sched.h>
38
39 #define TX_TIMEOUT  (2*HZ)
40
41 #define TX_Q_LIMIT    32
42 struct ifb_private {
43         struct list_head        list;
44         struct net_device       *dev;
45         struct net_device_stats stats;
46         struct tasklet_struct   ifb_tasklet;
47         int     tasklet_pending;
48         /* mostly debug stats leave in for now */
49         unsigned long   st_task_enter; /* tasklet entered */
50         unsigned long   st_txq_refl_try; /* transmit queue refill attempt */
51         unsigned long   st_rxq_enter; /* receive queue entered */
52         unsigned long   st_rx2tx_tran; /* receive to trasmit transfers */
53         unsigned long   st_rxq_notenter; /*receiveQ not entered, resched */
54         unsigned long   st_rx_frm_egr; /* received from egress path */
55         unsigned long   st_rx_frm_ing; /* received from ingress path */
56         unsigned long   st_rxq_check;
57         unsigned long   st_rxq_rsch;
58         struct sk_buff_head     rq;
59         struct sk_buff_head     tq;
60 };
61
62 static int numifbs = 2;
63
64 static void ri_tasklet(unsigned long dev);
65 static int ifb_xmit(struct sk_buff *skb, struct net_device *dev);
66 static struct net_device_stats *ifb_get_stats(struct net_device *dev);
67 static int ifb_open(struct net_device *dev);
68 static int ifb_close(struct net_device *dev);
69
70 static void ri_tasklet(unsigned long dev)
71 {
72
73         struct net_device *_dev = (struct net_device *)dev;
74         struct ifb_private *dp = netdev_priv(_dev);
75         struct net_device_stats *stats = &dp->stats;
76         struct sk_buff *skb;
77
78         dp->st_task_enter++;
79         if ((skb = skb_peek(&dp->tq)) == NULL) {
80                 dp->st_txq_refl_try++;
81                 if (netif_tx_trylock(_dev)) {
82                         dp->st_rxq_enter++;
83                         while ((skb = skb_dequeue(&dp->rq)) != NULL) {
84                                 skb_queue_tail(&dp->tq, skb);
85                                 dp->st_rx2tx_tran++;
86                         }
87                         netif_tx_unlock(_dev);
88                 } else {
89                         /* reschedule */
90                         dp->st_rxq_notenter++;
91                         goto resched;
92                 }
93         }
94
95         while ((skb = skb_dequeue(&dp->tq)) != NULL) {
96                 u32 from = G_TC_FROM(skb->tc_verd);
97
98                 skb->tc_verd = 0;
99                 skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
100                 stats->tx_packets++;
101                 stats->tx_bytes +=skb->len;
102
103                 skb->dev = __dev_get_by_index(skb->iif);
104                 if (!skb->dev) {
105                         dev_kfree_skb(skb);
106                         stats->tx_dropped++;
107                         break;
108                 }
109                 skb->iif = _dev->ifindex;
110
111                 if (from & AT_EGRESS) {
112                         dp->st_rx_frm_egr++;
113                         dev_queue_xmit(skb);
114                 } else if (from & AT_INGRESS) {
115                         dp->st_rx_frm_ing++;
116                         skb_pull(skb, skb->dev->hard_header_len);
117                         netif_rx(skb);
118                 } else
119                         BUG();
120         }
121
122         if (netif_tx_trylock(_dev)) {
123                 dp->st_rxq_check++;
124                 if ((skb = skb_peek(&dp->rq)) == NULL) {
125                         dp->tasklet_pending = 0;
126                         if (netif_queue_stopped(_dev))
127                                 netif_wake_queue(_dev);
128                 } else {
129                         dp->st_rxq_rsch++;
130                         netif_tx_unlock(_dev);
131                         goto resched;
132                 }
133                 netif_tx_unlock(_dev);
134         } else {
135 resched:
136                 dp->tasklet_pending = 1;
137                 tasklet_schedule(&dp->ifb_tasklet);
138         }
139
140 }
141
142 static void ifb_setup(struct net_device *dev)
143 {
144         /* Initialize the device structure. */
145         dev->get_stats = ifb_get_stats;
146         dev->hard_start_xmit = ifb_xmit;
147         dev->open = &ifb_open;
148         dev->stop = &ifb_close;
149         dev->destructor = free_netdev;
150
151         /* Fill in device structure with ethernet-generic values. */
152         ether_setup(dev);
153         dev->tx_queue_len = TX_Q_LIMIT;
154         dev->change_mtu = NULL;
155         dev->flags |= IFF_NOARP;
156         dev->flags &= ~IFF_MULTICAST;
157         SET_MODULE_OWNER(dev);
158         random_ether_addr(dev->dev_addr);
159 }
160
161 static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
162 {
163         struct ifb_private *dp = netdev_priv(dev);
164         struct net_device_stats *stats = &dp->stats;
165         int ret = 0;
166         u32 from = G_TC_FROM(skb->tc_verd);
167
168         stats->rx_packets++;
169         stats->rx_bytes+=skb->len;
170
171         if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->iif) {
172                 dev_kfree_skb(skb);
173                 stats->rx_dropped++;
174                 return ret;
175         }
176
177         if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) {
178                 netif_stop_queue(dev);
179         }
180
181         dev->trans_start = jiffies;
182         skb_queue_tail(&dp->rq, skb);
183         if (!dp->tasklet_pending) {
184                 dp->tasklet_pending = 1;
185                 tasklet_schedule(&dp->ifb_tasklet);
186         }
187
188         return ret;
189 }
190
191 static struct net_device_stats *ifb_get_stats(struct net_device *dev)
192 {
193         struct ifb_private *dp = netdev_priv(dev);
194         struct net_device_stats *stats = &dp->stats;
195
196         pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
197                 dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
198                 dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
199                 dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
200
201         return stats;
202 }
203
204 static LIST_HEAD(ifbs);
205
206 /* Number of ifb devices to be set up by this module. */
207 module_param(numifbs, int, 0);
208 MODULE_PARM_DESC(numifbs, "Number of ifb devices");
209
210 static int ifb_close(struct net_device *dev)
211 {
212         struct ifb_private *dp = netdev_priv(dev);
213
214         tasklet_kill(&dp->ifb_tasklet);
215         netif_stop_queue(dev);
216         skb_queue_purge(&dp->rq);
217         skb_queue_purge(&dp->tq);
218         return 0;
219 }
220
221 static int ifb_open(struct net_device *dev)
222 {
223         struct ifb_private *dp = netdev_priv(dev);
224
225         tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev);
226         skb_queue_head_init(&dp->rq);
227         skb_queue_head_init(&dp->tq);
228         netif_start_queue(dev);
229
230         return 0;
231 }
232
233 static int ifb_newlink(struct net_device *dev,
234                        struct nlattr *tb[], struct nlattr *data[])
235 {
236         struct ifb_private *priv = netdev_priv(dev);
237         int err;
238
239         err = register_netdevice(dev);
240         if (err < 0)
241                 return err;
242
243         priv->dev = dev;
244         list_add_tail(&priv->list, &ifbs);
245         return 0;
246 }
247
248 static void ifb_dellink(struct net_device *dev)
249 {
250         struct ifb_private *priv = netdev_priv(dev);
251
252         list_del(&priv->list);
253         unregister_netdevice(dev);
254 }
255
256 static struct rtnl_link_ops ifb_link_ops __read_mostly = {
257         .kind           = "ifb",
258         .priv_size      = sizeof(struct ifb_private),
259         .setup          = ifb_setup,
260         .newlink        = ifb_newlink,
261         .dellink        = ifb_dellink,
262 };
263
264 static int __init ifb_init_one(int index)
265 {
266         struct net_device *dev_ifb;
267         struct ifb_private *priv;
268         int err;
269
270         dev_ifb = alloc_netdev(sizeof(struct ifb_private),
271                                  "ifb%d", ifb_setup);
272
273         if (!dev_ifb)
274                 return -ENOMEM;
275
276         err = dev_alloc_name(dev_ifb, dev_ifb->name);
277         if (err < 0)
278                 goto err;
279
280         dev_ifb->rtnl_link_ops = &ifb_link_ops;
281         err = register_netdevice(dev_ifb);
282         if (err < 0)
283                 goto err;
284
285         priv = netdev_priv(dev_ifb);
286         priv->dev = dev_ifb;
287         list_add_tail(&priv->list, &ifbs);
288         return 0;
289
290 err:
291         free_netdev(dev_ifb);
292         return err;
293 }
294
295 static int __init ifb_init_module(void)
296 {
297         struct ifb_private *priv, *next;
298         int i, err;
299
300         rtnl_lock();
301         err = __rtnl_link_register(&ifb_link_ops);
302
303         for (i = 0; i < numifbs && !err; i++)
304                 err = ifb_init_one(i);
305         if (err) {
306                 list_for_each_entry_safe(priv, next, &ifbs, list)
307                         ifb_dellink(priv->dev);
308                 __rtnl_link_unregister(&ifb_link_ops);
309         }
310         rtnl_unlock();
311
312         return err;
313 }
314
315 static void __exit ifb_cleanup_module(void)
316 {
317         struct ifb_private *priv, *next;
318
319         rtnl_lock();
320         list_for_each_entry_safe(priv, next, &ifbs, list)
321                 ifb_dellink(priv->dev);
322
323         __rtnl_link_unregister(&ifb_link_ops);
324         rtnl_unlock();
325 }
326
327 module_init(ifb_init_module);
328 module_exit(ifb_cleanup_module);
329 MODULE_LICENSE("GPL");
330 MODULE_AUTHOR("Jamal Hadi Salim");
331 MODULE_ALIAS_RTNL_LINK("ifb");