xref: /openbmc/linux/net/sched/sch_teql.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /* net/sched/sch_teql.c	"True" (or "trivial") link equalizer.
2*1da177e4SLinus Torvalds  *
3*1da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
4*1da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
5*1da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
6*1da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
9*1da177e4SLinus Torvalds  */
10*1da177e4SLinus Torvalds 
11*1da177e4SLinus Torvalds #include <linux/module.h>
12*1da177e4SLinus Torvalds #include <asm/uaccess.h>
13*1da177e4SLinus Torvalds #include <asm/system.h>
14*1da177e4SLinus Torvalds #include <linux/bitops.h>
15*1da177e4SLinus Torvalds #include <linux/types.h>
16*1da177e4SLinus Torvalds #include <linux/kernel.h>
17*1da177e4SLinus Torvalds #include <linux/sched.h>
18*1da177e4SLinus Torvalds #include <linux/string.h>
19*1da177e4SLinus Torvalds #include <linux/mm.h>
20*1da177e4SLinus Torvalds #include <linux/socket.h>
21*1da177e4SLinus Torvalds #include <linux/sockios.h>
22*1da177e4SLinus Torvalds #include <linux/in.h>
23*1da177e4SLinus Torvalds #include <linux/errno.h>
24*1da177e4SLinus Torvalds #include <linux/interrupt.h>
25*1da177e4SLinus Torvalds #include <linux/if_ether.h>
26*1da177e4SLinus Torvalds #include <linux/inet.h>
27*1da177e4SLinus Torvalds #include <linux/netdevice.h>
28*1da177e4SLinus Torvalds #include <linux/etherdevice.h>
29*1da177e4SLinus Torvalds #include <linux/notifier.h>
30*1da177e4SLinus Torvalds #include <linux/init.h>
31*1da177e4SLinus Torvalds #include <net/ip.h>
32*1da177e4SLinus Torvalds #include <net/route.h>
33*1da177e4SLinus Torvalds #include <linux/skbuff.h>
34*1da177e4SLinus Torvalds #include <linux/moduleparam.h>
35*1da177e4SLinus Torvalds #include <net/sock.h>
36*1da177e4SLinus Torvalds #include <net/pkt_sched.h>
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds /*
39*1da177e4SLinus Torvalds    How to setup it.
40*1da177e4SLinus Torvalds    ----------------
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds    After loading this module you will find a new device teqlN
43*1da177e4SLinus Torvalds    and new qdisc with the same name. To join a slave to the equalizer
44*1da177e4SLinus Torvalds    you should just set this qdisc on a device f.e.
45*1da177e4SLinus Torvalds 
46*1da177e4SLinus Torvalds    # tc qdisc add dev eth0 root teql0
47*1da177e4SLinus Torvalds    # tc qdisc add dev eth1 root teql0
48*1da177e4SLinus Torvalds 
49*1da177e4SLinus Torvalds    That's all. Full PnP 8)
50*1da177e4SLinus Torvalds 
51*1da177e4SLinus Torvalds    Applicability.
52*1da177e4SLinus Torvalds    --------------
53*1da177e4SLinus Torvalds 
54*1da177e4SLinus Torvalds    1. Slave devices MUST be active devices, i.e., they must raise the tbusy
55*1da177e4SLinus Torvalds       signal and generate EOI events. If you want to equalize virtual devices
56*1da177e4SLinus Torvalds       like tunnels, use a normal eql device.
57*1da177e4SLinus Torvalds    2. This device puts no limitations on physical slave characteristics
58*1da177e4SLinus Torvalds       f.e. it will equalize 9600baud line and 100Mb ethernet perfectly :-)
59*1da177e4SLinus Torvalds       Certainly, large difference in link speeds will make the resulting
60*1da177e4SLinus Torvalds       eqalized link unusable, because of huge packet reordering.
61*1da177e4SLinus Torvalds       I estimate an upper useful difference as ~10 times.
62*1da177e4SLinus Torvalds    3. If the slave requires address resolution, only protocols using
63*1da177e4SLinus Torvalds       neighbour cache (IPv4/IPv6) will work over the equalized link.
64*1da177e4SLinus Torvalds       Other protocols are still allowed to use the slave device directly,
65*1da177e4SLinus Torvalds       which will not break load balancing, though native slave
66*1da177e4SLinus Torvalds       traffic will have the highest priority.  */
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds struct teql_master
69*1da177e4SLinus Torvalds {
70*1da177e4SLinus Torvalds 	struct Qdisc_ops qops;
71*1da177e4SLinus Torvalds 	struct net_device *dev;
72*1da177e4SLinus Torvalds 	struct Qdisc *slaves;
73*1da177e4SLinus Torvalds 	struct list_head master_list;
74*1da177e4SLinus Torvalds 	struct net_device_stats stats;
75*1da177e4SLinus Torvalds };
76*1da177e4SLinus Torvalds 
77*1da177e4SLinus Torvalds struct teql_sched_data
78*1da177e4SLinus Torvalds {
79*1da177e4SLinus Torvalds 	struct Qdisc *next;
80*1da177e4SLinus Torvalds 	struct teql_master *m;
81*1da177e4SLinus Torvalds 	struct neighbour *ncache;
82*1da177e4SLinus Torvalds 	struct sk_buff_head q;
83*1da177e4SLinus Torvalds };
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds #define NEXT_SLAVE(q) (((struct teql_sched_data*)qdisc_priv(q))->next)
86*1da177e4SLinus Torvalds 
87*1da177e4SLinus Torvalds #define FMASK (IFF_BROADCAST|IFF_POINTOPOINT|IFF_BROADCAST)
88*1da177e4SLinus Torvalds 
89*1da177e4SLinus Torvalds /* "teql*" qdisc routines */
90*1da177e4SLinus Torvalds 
91*1da177e4SLinus Torvalds static int
92*1da177e4SLinus Torvalds teql_enqueue(struct sk_buff *skb, struct Qdisc* sch)
93*1da177e4SLinus Torvalds {
94*1da177e4SLinus Torvalds 	struct net_device *dev = sch->dev;
95*1da177e4SLinus Torvalds 	struct teql_sched_data *q = qdisc_priv(sch);
96*1da177e4SLinus Torvalds 
97*1da177e4SLinus Torvalds 	__skb_queue_tail(&q->q, skb);
98*1da177e4SLinus Torvalds 	if (q->q.qlen <= dev->tx_queue_len) {
99*1da177e4SLinus Torvalds 		sch->bstats.bytes += skb->len;
100*1da177e4SLinus Torvalds 		sch->bstats.packets++;
101*1da177e4SLinus Torvalds 		return 0;
102*1da177e4SLinus Torvalds 	}
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds 	__skb_unlink(skb, &q->q);
105*1da177e4SLinus Torvalds 	kfree_skb(skb);
106*1da177e4SLinus Torvalds 	sch->qstats.drops++;
107*1da177e4SLinus Torvalds 	return NET_XMIT_DROP;
108*1da177e4SLinus Torvalds }
109*1da177e4SLinus Torvalds 
110*1da177e4SLinus Torvalds static int
111*1da177e4SLinus Torvalds teql_requeue(struct sk_buff *skb, struct Qdisc* sch)
112*1da177e4SLinus Torvalds {
113*1da177e4SLinus Torvalds 	struct teql_sched_data *q = qdisc_priv(sch);
114*1da177e4SLinus Torvalds 
115*1da177e4SLinus Torvalds 	__skb_queue_head(&q->q, skb);
116*1da177e4SLinus Torvalds 	sch->qstats.requeues++;
117*1da177e4SLinus Torvalds 	return 0;
118*1da177e4SLinus Torvalds }
119*1da177e4SLinus Torvalds 
120*1da177e4SLinus Torvalds static struct sk_buff *
121*1da177e4SLinus Torvalds teql_dequeue(struct Qdisc* sch)
122*1da177e4SLinus Torvalds {
123*1da177e4SLinus Torvalds 	struct teql_sched_data *dat = qdisc_priv(sch);
124*1da177e4SLinus Torvalds 	struct sk_buff *skb;
125*1da177e4SLinus Torvalds 
126*1da177e4SLinus Torvalds 	skb = __skb_dequeue(&dat->q);
127*1da177e4SLinus Torvalds 	if (skb == NULL) {
128*1da177e4SLinus Torvalds 		struct net_device *m = dat->m->dev->qdisc->dev;
129*1da177e4SLinus Torvalds 		if (m) {
130*1da177e4SLinus Torvalds 			dat->m->slaves = sch;
131*1da177e4SLinus Torvalds 			netif_wake_queue(m);
132*1da177e4SLinus Torvalds 		}
133*1da177e4SLinus Torvalds 	}
134*1da177e4SLinus Torvalds 	sch->q.qlen = dat->q.qlen + dat->m->dev->qdisc->q.qlen;
135*1da177e4SLinus Torvalds 	return skb;
136*1da177e4SLinus Torvalds }
137*1da177e4SLinus Torvalds 
138*1da177e4SLinus Torvalds static __inline__ void
139*1da177e4SLinus Torvalds teql_neigh_release(struct neighbour *n)
140*1da177e4SLinus Torvalds {
141*1da177e4SLinus Torvalds 	if (n)
142*1da177e4SLinus Torvalds 		neigh_release(n);
143*1da177e4SLinus Torvalds }
144*1da177e4SLinus Torvalds 
145*1da177e4SLinus Torvalds static void
146*1da177e4SLinus Torvalds teql_reset(struct Qdisc* sch)
147*1da177e4SLinus Torvalds {
148*1da177e4SLinus Torvalds 	struct teql_sched_data *dat = qdisc_priv(sch);
149*1da177e4SLinus Torvalds 
150*1da177e4SLinus Torvalds 	skb_queue_purge(&dat->q);
151*1da177e4SLinus Torvalds 	sch->q.qlen = 0;
152*1da177e4SLinus Torvalds 	teql_neigh_release(xchg(&dat->ncache, NULL));
153*1da177e4SLinus Torvalds }
154*1da177e4SLinus Torvalds 
155*1da177e4SLinus Torvalds static void
156*1da177e4SLinus Torvalds teql_destroy(struct Qdisc* sch)
157*1da177e4SLinus Torvalds {
158*1da177e4SLinus Torvalds 	struct Qdisc *q, *prev;
159*1da177e4SLinus Torvalds 	struct teql_sched_data *dat = qdisc_priv(sch);
160*1da177e4SLinus Torvalds 	struct teql_master *master = dat->m;
161*1da177e4SLinus Torvalds 
162*1da177e4SLinus Torvalds 	if ((prev = master->slaves) != NULL) {
163*1da177e4SLinus Torvalds 		do {
164*1da177e4SLinus Torvalds 			q = NEXT_SLAVE(prev);
165*1da177e4SLinus Torvalds 			if (q == sch) {
166*1da177e4SLinus Torvalds 				NEXT_SLAVE(prev) = NEXT_SLAVE(q);
167*1da177e4SLinus Torvalds 				if (q == master->slaves) {
168*1da177e4SLinus Torvalds 					master->slaves = NEXT_SLAVE(q);
169*1da177e4SLinus Torvalds 					if (q == master->slaves) {
170*1da177e4SLinus Torvalds 						master->slaves = NULL;
171*1da177e4SLinus Torvalds 						spin_lock_bh(&master->dev->queue_lock);
172*1da177e4SLinus Torvalds 						qdisc_reset(master->dev->qdisc);
173*1da177e4SLinus Torvalds 						spin_unlock_bh(&master->dev->queue_lock);
174*1da177e4SLinus Torvalds 					}
175*1da177e4SLinus Torvalds 				}
176*1da177e4SLinus Torvalds 				skb_queue_purge(&dat->q);
177*1da177e4SLinus Torvalds 				teql_neigh_release(xchg(&dat->ncache, NULL));
178*1da177e4SLinus Torvalds 				break;
179*1da177e4SLinus Torvalds 			}
180*1da177e4SLinus Torvalds 
181*1da177e4SLinus Torvalds 		} while ((prev = q) != master->slaves);
182*1da177e4SLinus Torvalds 	}
183*1da177e4SLinus Torvalds }
184*1da177e4SLinus Torvalds 
185*1da177e4SLinus Torvalds static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
186*1da177e4SLinus Torvalds {
187*1da177e4SLinus Torvalds 	struct net_device *dev = sch->dev;
188*1da177e4SLinus Torvalds 	struct teql_master *m = (struct teql_master*)sch->ops;
189*1da177e4SLinus Torvalds 	struct teql_sched_data *q = qdisc_priv(sch);
190*1da177e4SLinus Torvalds 
191*1da177e4SLinus Torvalds 	if (dev->hard_header_len > m->dev->hard_header_len)
192*1da177e4SLinus Torvalds 		return -EINVAL;
193*1da177e4SLinus Torvalds 
194*1da177e4SLinus Torvalds 	if (m->dev == dev)
195*1da177e4SLinus Torvalds 		return -ELOOP;
196*1da177e4SLinus Torvalds 
197*1da177e4SLinus Torvalds 	q->m = m;
198*1da177e4SLinus Torvalds 
199*1da177e4SLinus Torvalds 	skb_queue_head_init(&q->q);
200*1da177e4SLinus Torvalds 
201*1da177e4SLinus Torvalds 	if (m->slaves) {
202*1da177e4SLinus Torvalds 		if (m->dev->flags & IFF_UP) {
203*1da177e4SLinus Torvalds 			if ((m->dev->flags&IFF_POINTOPOINT && !(dev->flags&IFF_POINTOPOINT))
204*1da177e4SLinus Torvalds 			    || (m->dev->flags&IFF_BROADCAST && !(dev->flags&IFF_BROADCAST))
205*1da177e4SLinus Torvalds 			    || (m->dev->flags&IFF_MULTICAST && !(dev->flags&IFF_MULTICAST))
206*1da177e4SLinus Torvalds 			    || dev->mtu < m->dev->mtu)
207*1da177e4SLinus Torvalds 				return -EINVAL;
208*1da177e4SLinus Torvalds 		} else {
209*1da177e4SLinus Torvalds 			if (!(dev->flags&IFF_POINTOPOINT))
210*1da177e4SLinus Torvalds 				m->dev->flags &= ~IFF_POINTOPOINT;
211*1da177e4SLinus Torvalds 			if (!(dev->flags&IFF_BROADCAST))
212*1da177e4SLinus Torvalds 				m->dev->flags &= ~IFF_BROADCAST;
213*1da177e4SLinus Torvalds 			if (!(dev->flags&IFF_MULTICAST))
214*1da177e4SLinus Torvalds 				m->dev->flags &= ~IFF_MULTICAST;
215*1da177e4SLinus Torvalds 			if (dev->mtu < m->dev->mtu)
216*1da177e4SLinus Torvalds 				m->dev->mtu = dev->mtu;
217*1da177e4SLinus Torvalds 		}
218*1da177e4SLinus Torvalds 		q->next = NEXT_SLAVE(m->slaves);
219*1da177e4SLinus Torvalds 		NEXT_SLAVE(m->slaves) = sch;
220*1da177e4SLinus Torvalds 	} else {
221*1da177e4SLinus Torvalds 		q->next = sch;
222*1da177e4SLinus Torvalds 		m->slaves = sch;
223*1da177e4SLinus Torvalds 		m->dev->mtu = dev->mtu;
224*1da177e4SLinus Torvalds 		m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
225*1da177e4SLinus Torvalds 	}
226*1da177e4SLinus Torvalds 	return 0;
227*1da177e4SLinus Torvalds }
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds /* "teql*" netdevice routines */
230*1da177e4SLinus Torvalds 
231*1da177e4SLinus Torvalds static int
232*1da177e4SLinus Torvalds __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
233*1da177e4SLinus Torvalds {
234*1da177e4SLinus Torvalds 	struct teql_sched_data *q = qdisc_priv(dev->qdisc);
235*1da177e4SLinus Torvalds 	struct neighbour *mn = skb->dst->neighbour;
236*1da177e4SLinus Torvalds 	struct neighbour *n = q->ncache;
237*1da177e4SLinus Torvalds 
238*1da177e4SLinus Torvalds 	if (mn->tbl == NULL)
239*1da177e4SLinus Torvalds 		return -EINVAL;
240*1da177e4SLinus Torvalds 	if (n && n->tbl == mn->tbl &&
241*1da177e4SLinus Torvalds 	    memcmp(n->primary_key, mn->primary_key, mn->tbl->key_len) == 0) {
242*1da177e4SLinus Torvalds 		atomic_inc(&n->refcnt);
243*1da177e4SLinus Torvalds 	} else {
244*1da177e4SLinus Torvalds 		n = __neigh_lookup_errno(mn->tbl, mn->primary_key, dev);
245*1da177e4SLinus Torvalds 		if (IS_ERR(n))
246*1da177e4SLinus Torvalds 			return PTR_ERR(n);
247*1da177e4SLinus Torvalds 	}
248*1da177e4SLinus Torvalds 	if (neigh_event_send(n, skb_res) == 0) {
249*1da177e4SLinus Torvalds 		int err;
250*1da177e4SLinus Torvalds 		read_lock(&n->lock);
251*1da177e4SLinus Torvalds 		err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len);
252*1da177e4SLinus Torvalds 		read_unlock(&n->lock);
253*1da177e4SLinus Torvalds 		if (err < 0) {
254*1da177e4SLinus Torvalds 			neigh_release(n);
255*1da177e4SLinus Torvalds 			return -EINVAL;
256*1da177e4SLinus Torvalds 		}
257*1da177e4SLinus Torvalds 		teql_neigh_release(xchg(&q->ncache, n));
258*1da177e4SLinus Torvalds 		return 0;
259*1da177e4SLinus Torvalds 	}
260*1da177e4SLinus Torvalds 	neigh_release(n);
261*1da177e4SLinus Torvalds 	return (skb_res == NULL) ? -EAGAIN : 1;
262*1da177e4SLinus Torvalds }
263*1da177e4SLinus Torvalds 
264*1da177e4SLinus Torvalds static __inline__ int
265*1da177e4SLinus Torvalds teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
266*1da177e4SLinus Torvalds {
267*1da177e4SLinus Torvalds 	if (dev->hard_header == NULL ||
268*1da177e4SLinus Torvalds 	    skb->dst == NULL ||
269*1da177e4SLinus Torvalds 	    skb->dst->neighbour == NULL)
270*1da177e4SLinus Torvalds 		return 0;
271*1da177e4SLinus Torvalds 	return __teql_resolve(skb, skb_res, dev);
272*1da177e4SLinus Torvalds }
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
275*1da177e4SLinus Torvalds {
276*1da177e4SLinus Torvalds 	struct teql_master *master = (void*)dev->priv;
277*1da177e4SLinus Torvalds 	struct Qdisc *start, *q;
278*1da177e4SLinus Torvalds 	int busy;
279*1da177e4SLinus Torvalds 	int nores;
280*1da177e4SLinus Torvalds 	int len = skb->len;
281*1da177e4SLinus Torvalds 	struct sk_buff *skb_res = NULL;
282*1da177e4SLinus Torvalds 
283*1da177e4SLinus Torvalds 	start = master->slaves;
284*1da177e4SLinus Torvalds 
285*1da177e4SLinus Torvalds restart:
286*1da177e4SLinus Torvalds 	nores = 0;
287*1da177e4SLinus Torvalds 	busy = 0;
288*1da177e4SLinus Torvalds 
289*1da177e4SLinus Torvalds 	if ((q = start) == NULL)
290*1da177e4SLinus Torvalds 		goto drop;
291*1da177e4SLinus Torvalds 
292*1da177e4SLinus Torvalds 	do {
293*1da177e4SLinus Torvalds 		struct net_device *slave = q->dev;
294*1da177e4SLinus Torvalds 
295*1da177e4SLinus Torvalds 		if (slave->qdisc_sleeping != q)
296*1da177e4SLinus Torvalds 			continue;
297*1da177e4SLinus Torvalds 		if (netif_queue_stopped(slave) || ! netif_running(slave)) {
298*1da177e4SLinus Torvalds 			busy = 1;
299*1da177e4SLinus Torvalds 			continue;
300*1da177e4SLinus Torvalds 		}
301*1da177e4SLinus Torvalds 
302*1da177e4SLinus Torvalds 		switch (teql_resolve(skb, skb_res, slave)) {
303*1da177e4SLinus Torvalds 		case 0:
304*1da177e4SLinus Torvalds 			if (spin_trylock(&slave->xmit_lock)) {
305*1da177e4SLinus Torvalds 				slave->xmit_lock_owner = smp_processor_id();
306*1da177e4SLinus Torvalds 				if (!netif_queue_stopped(slave) &&
307*1da177e4SLinus Torvalds 				    slave->hard_start_xmit(skb, slave) == 0) {
308*1da177e4SLinus Torvalds 					slave->xmit_lock_owner = -1;
309*1da177e4SLinus Torvalds 					spin_unlock(&slave->xmit_lock);
310*1da177e4SLinus Torvalds 					master->slaves = NEXT_SLAVE(q);
311*1da177e4SLinus Torvalds 					netif_wake_queue(dev);
312*1da177e4SLinus Torvalds 					master->stats.tx_packets++;
313*1da177e4SLinus Torvalds 					master->stats.tx_bytes += len;
314*1da177e4SLinus Torvalds 					return 0;
315*1da177e4SLinus Torvalds 				}
316*1da177e4SLinus Torvalds 				slave->xmit_lock_owner = -1;
317*1da177e4SLinus Torvalds 				spin_unlock(&slave->xmit_lock);
318*1da177e4SLinus Torvalds 			}
319*1da177e4SLinus Torvalds 			if (netif_queue_stopped(dev))
320*1da177e4SLinus Torvalds 				busy = 1;
321*1da177e4SLinus Torvalds 			break;
322*1da177e4SLinus Torvalds 		case 1:
323*1da177e4SLinus Torvalds 			master->slaves = NEXT_SLAVE(q);
324*1da177e4SLinus Torvalds 			return 0;
325*1da177e4SLinus Torvalds 		default:
326*1da177e4SLinus Torvalds 			nores = 1;
327*1da177e4SLinus Torvalds 			break;
328*1da177e4SLinus Torvalds 		}
329*1da177e4SLinus Torvalds 		__skb_pull(skb, skb->nh.raw - skb->data);
330*1da177e4SLinus Torvalds 	} while ((q = NEXT_SLAVE(q)) != start);
331*1da177e4SLinus Torvalds 
332*1da177e4SLinus Torvalds 	if (nores && skb_res == NULL) {
333*1da177e4SLinus Torvalds 		skb_res = skb;
334*1da177e4SLinus Torvalds 		goto restart;
335*1da177e4SLinus Torvalds 	}
336*1da177e4SLinus Torvalds 
337*1da177e4SLinus Torvalds 	if (busy) {
338*1da177e4SLinus Torvalds 		netif_stop_queue(dev);
339*1da177e4SLinus Torvalds 		return 1;
340*1da177e4SLinus Torvalds 	}
341*1da177e4SLinus Torvalds 	master->stats.tx_errors++;
342*1da177e4SLinus Torvalds 
343*1da177e4SLinus Torvalds drop:
344*1da177e4SLinus Torvalds 	master->stats.tx_dropped++;
345*1da177e4SLinus Torvalds 	dev_kfree_skb(skb);
346*1da177e4SLinus Torvalds 	return 0;
347*1da177e4SLinus Torvalds }
348*1da177e4SLinus Torvalds 
349*1da177e4SLinus Torvalds static int teql_master_open(struct net_device *dev)
350*1da177e4SLinus Torvalds {
351*1da177e4SLinus Torvalds 	struct Qdisc * q;
352*1da177e4SLinus Torvalds 	struct teql_master *m = (void*)dev->priv;
353*1da177e4SLinus Torvalds 	int mtu = 0xFFFE;
354*1da177e4SLinus Torvalds 	unsigned flags = IFF_NOARP|IFF_MULTICAST;
355*1da177e4SLinus Torvalds 
356*1da177e4SLinus Torvalds 	if (m->slaves == NULL)
357*1da177e4SLinus Torvalds 		return -EUNATCH;
358*1da177e4SLinus Torvalds 
359*1da177e4SLinus Torvalds 	flags = FMASK;
360*1da177e4SLinus Torvalds 
361*1da177e4SLinus Torvalds 	q = m->slaves;
362*1da177e4SLinus Torvalds 	do {
363*1da177e4SLinus Torvalds 		struct net_device *slave = q->dev;
364*1da177e4SLinus Torvalds 
365*1da177e4SLinus Torvalds 		if (slave == NULL)
366*1da177e4SLinus Torvalds 			return -EUNATCH;
367*1da177e4SLinus Torvalds 
368*1da177e4SLinus Torvalds 		if (slave->mtu < mtu)
369*1da177e4SLinus Torvalds 			mtu = slave->mtu;
370*1da177e4SLinus Torvalds 		if (slave->hard_header_len > LL_MAX_HEADER)
371*1da177e4SLinus Torvalds 			return -EINVAL;
372*1da177e4SLinus Torvalds 
373*1da177e4SLinus Torvalds 		/* If all the slaves are BROADCAST, master is BROADCAST
374*1da177e4SLinus Torvalds 		   If all the slaves are PtP, master is PtP
375*1da177e4SLinus Torvalds 		   Otherwise, master is NBMA.
376*1da177e4SLinus Torvalds 		 */
377*1da177e4SLinus Torvalds 		if (!(slave->flags&IFF_POINTOPOINT))
378*1da177e4SLinus Torvalds 			flags &= ~IFF_POINTOPOINT;
379*1da177e4SLinus Torvalds 		if (!(slave->flags&IFF_BROADCAST))
380*1da177e4SLinus Torvalds 			flags &= ~IFF_BROADCAST;
381*1da177e4SLinus Torvalds 		if (!(slave->flags&IFF_MULTICAST))
382*1da177e4SLinus Torvalds 			flags &= ~IFF_MULTICAST;
383*1da177e4SLinus Torvalds 	} while ((q = NEXT_SLAVE(q)) != m->slaves);
384*1da177e4SLinus Torvalds 
385*1da177e4SLinus Torvalds 	m->dev->mtu = mtu;
386*1da177e4SLinus Torvalds 	m->dev->flags = (m->dev->flags&~FMASK) | flags;
387*1da177e4SLinus Torvalds 	netif_start_queue(m->dev);
388*1da177e4SLinus Torvalds 	return 0;
389*1da177e4SLinus Torvalds }
390*1da177e4SLinus Torvalds 
391*1da177e4SLinus Torvalds static int teql_master_close(struct net_device *dev)
392*1da177e4SLinus Torvalds {
393*1da177e4SLinus Torvalds 	netif_stop_queue(dev);
394*1da177e4SLinus Torvalds 	return 0;
395*1da177e4SLinus Torvalds }
396*1da177e4SLinus Torvalds 
397*1da177e4SLinus Torvalds static struct net_device_stats *teql_master_stats(struct net_device *dev)
398*1da177e4SLinus Torvalds {
399*1da177e4SLinus Torvalds 	struct teql_master *m = (void*)dev->priv;
400*1da177e4SLinus Torvalds 	return &m->stats;
401*1da177e4SLinus Torvalds }
402*1da177e4SLinus Torvalds 
403*1da177e4SLinus Torvalds static int teql_master_mtu(struct net_device *dev, int new_mtu)
404*1da177e4SLinus Torvalds {
405*1da177e4SLinus Torvalds 	struct teql_master *m = (void*)dev->priv;
406*1da177e4SLinus Torvalds 	struct Qdisc *q;
407*1da177e4SLinus Torvalds 
408*1da177e4SLinus Torvalds 	if (new_mtu < 68)
409*1da177e4SLinus Torvalds 		return -EINVAL;
410*1da177e4SLinus Torvalds 
411*1da177e4SLinus Torvalds 	q = m->slaves;
412*1da177e4SLinus Torvalds 	if (q) {
413*1da177e4SLinus Torvalds 		do {
414*1da177e4SLinus Torvalds 			if (new_mtu > q->dev->mtu)
415*1da177e4SLinus Torvalds 				return -EINVAL;
416*1da177e4SLinus Torvalds 		} while ((q=NEXT_SLAVE(q)) != m->slaves);
417*1da177e4SLinus Torvalds 	}
418*1da177e4SLinus Torvalds 
419*1da177e4SLinus Torvalds 	dev->mtu = new_mtu;
420*1da177e4SLinus Torvalds 	return 0;
421*1da177e4SLinus Torvalds }
422*1da177e4SLinus Torvalds 
423*1da177e4SLinus Torvalds static __init void teql_master_setup(struct net_device *dev)
424*1da177e4SLinus Torvalds {
425*1da177e4SLinus Torvalds 	struct teql_master *master = dev->priv;
426*1da177e4SLinus Torvalds 	struct Qdisc_ops *ops = &master->qops;
427*1da177e4SLinus Torvalds 
428*1da177e4SLinus Torvalds 	master->dev	= dev;
429*1da177e4SLinus Torvalds 	ops->priv_size  = sizeof(struct teql_sched_data);
430*1da177e4SLinus Torvalds 
431*1da177e4SLinus Torvalds 	ops->enqueue	=	teql_enqueue;
432*1da177e4SLinus Torvalds 	ops->dequeue	=	teql_dequeue;
433*1da177e4SLinus Torvalds 	ops->requeue	=	teql_requeue;
434*1da177e4SLinus Torvalds 	ops->init	=	teql_qdisc_init;
435*1da177e4SLinus Torvalds 	ops->reset	=	teql_reset;
436*1da177e4SLinus Torvalds 	ops->destroy	=	teql_destroy;
437*1da177e4SLinus Torvalds 	ops->owner	=	THIS_MODULE;
438*1da177e4SLinus Torvalds 
439*1da177e4SLinus Torvalds 	dev->open		= teql_master_open;
440*1da177e4SLinus Torvalds 	dev->hard_start_xmit	= teql_master_xmit;
441*1da177e4SLinus Torvalds 	dev->stop		= teql_master_close;
442*1da177e4SLinus Torvalds 	dev->get_stats		= teql_master_stats;
443*1da177e4SLinus Torvalds 	dev->change_mtu		= teql_master_mtu;
444*1da177e4SLinus Torvalds 	dev->type		= ARPHRD_VOID;
445*1da177e4SLinus Torvalds 	dev->mtu		= 1500;
446*1da177e4SLinus Torvalds 	dev->tx_queue_len	= 100;
447*1da177e4SLinus Torvalds 	dev->flags		= IFF_NOARP;
448*1da177e4SLinus Torvalds 	dev->hard_header_len	= LL_MAX_HEADER;
449*1da177e4SLinus Torvalds 	SET_MODULE_OWNER(dev);
450*1da177e4SLinus Torvalds }
451*1da177e4SLinus Torvalds 
452*1da177e4SLinus Torvalds static LIST_HEAD(master_dev_list);
453*1da177e4SLinus Torvalds static int max_equalizers = 1;
454*1da177e4SLinus Torvalds module_param(max_equalizers, int, 0);
455*1da177e4SLinus Torvalds MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
456*1da177e4SLinus Torvalds 
457*1da177e4SLinus Torvalds static int __init teql_init(void)
458*1da177e4SLinus Torvalds {
459*1da177e4SLinus Torvalds 	int i;
460*1da177e4SLinus Torvalds 	int err = -ENODEV;
461*1da177e4SLinus Torvalds 
462*1da177e4SLinus Torvalds 	for (i = 0; i < max_equalizers; i++) {
463*1da177e4SLinus Torvalds 		struct net_device *dev;
464*1da177e4SLinus Torvalds 		struct teql_master *master;
465*1da177e4SLinus Torvalds 
466*1da177e4SLinus Torvalds 		dev = alloc_netdev(sizeof(struct teql_master),
467*1da177e4SLinus Torvalds 				  "teql%d", teql_master_setup);
468*1da177e4SLinus Torvalds 		if (!dev) {
469*1da177e4SLinus Torvalds 			err = -ENOMEM;
470*1da177e4SLinus Torvalds 			break;
471*1da177e4SLinus Torvalds 		}
472*1da177e4SLinus Torvalds 
473*1da177e4SLinus Torvalds 		if ((err = register_netdev(dev))) {
474*1da177e4SLinus Torvalds 			free_netdev(dev);
475*1da177e4SLinus Torvalds 			break;
476*1da177e4SLinus Torvalds 		}
477*1da177e4SLinus Torvalds 
478*1da177e4SLinus Torvalds 		master = dev->priv;
479*1da177e4SLinus Torvalds 
480*1da177e4SLinus Torvalds 		strlcpy(master->qops.id, dev->name, IFNAMSIZ);
481*1da177e4SLinus Torvalds 		err = register_qdisc(&master->qops);
482*1da177e4SLinus Torvalds 
483*1da177e4SLinus Torvalds 		if (err) {
484*1da177e4SLinus Torvalds 			unregister_netdev(dev);
485*1da177e4SLinus Torvalds 			free_netdev(dev);
486*1da177e4SLinus Torvalds 			break;
487*1da177e4SLinus Torvalds 		}
488*1da177e4SLinus Torvalds 
489*1da177e4SLinus Torvalds 		list_add_tail(&master->master_list, &master_dev_list);
490*1da177e4SLinus Torvalds 	}
491*1da177e4SLinus Torvalds 	return i ? 0 : err;
492*1da177e4SLinus Torvalds }
493*1da177e4SLinus Torvalds 
494*1da177e4SLinus Torvalds static void __exit teql_exit(void)
495*1da177e4SLinus Torvalds {
496*1da177e4SLinus Torvalds 	struct teql_master *master, *nxt;
497*1da177e4SLinus Torvalds 
498*1da177e4SLinus Torvalds 	list_for_each_entry_safe(master, nxt, &master_dev_list, master_list) {
499*1da177e4SLinus Torvalds 
500*1da177e4SLinus Torvalds 		list_del(&master->master_list);
501*1da177e4SLinus Torvalds 
502*1da177e4SLinus Torvalds 		unregister_qdisc(&master->qops);
503*1da177e4SLinus Torvalds 		unregister_netdev(master->dev);
504*1da177e4SLinus Torvalds 		free_netdev(master->dev);
505*1da177e4SLinus Torvalds 	}
506*1da177e4SLinus Torvalds }
507*1da177e4SLinus Torvalds 
508*1da177e4SLinus Torvalds module_init(teql_init);
509*1da177e4SLinus Torvalds module_exit(teql_exit);
510*1da177e4SLinus Torvalds 
511*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
512