11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Equalizer Load-balancer for serial network interfaces. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) Copyright 1995 Simon "Guru Aleph-Null" Janes 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NCM: Network and Communications Management, Inc. 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) Copyright 2002 David S. Miller (davem@redhat.com) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software may be used and distributed according to the terms 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the GNU General Public License, incorporated herein by reference. 116aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The author may be reached as simon@ncm.com, or C/O 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NCM 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Attn: Simon Janes 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6803 Whittier Ave 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * McLean VA 22101 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phone: 1-703-847-0040 ext 103 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sources: 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * skeleton.c by Donald Becker. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Inspirations: 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The Harried and Overworked Alan Cox 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Conspiracies: 266aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * The Alan Cox and Mike McLagan plot to get someone else to do the code, 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * which turned out to be me. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Log: eql.c,v $ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.2 1996/04/11 17:51:52 guru 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added one-line eql_remove_slave patch. 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.1 1996/04/11 17:44:17 guru 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initial revision 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.13 1996/01/21 15:17:18 alan 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tx_queue_len changes. 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reformatted. 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.12 1995/03/22 21:07:51 anarchy 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added capable() checks on configuration. 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Moved header file. 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.11 1995/01/19 23:14:31 guru 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (priority_Bps) + bytes_queued * 8; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.10 1995/01/19 23:07:53 guru 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * back to 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (priority_Bps) + bytes_queued; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.9 1995/01/19 22:38:20 guru 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (priority_Bps) + bytes_queued * 4; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.8 1995/01/19 22:30:55 guru 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * slave_load = (ULONG_MAX - (ULONG_MAX / 2)) - 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (priority_Bps) + bytes_queued * 2; 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.7 1995/01/19 21:52:35 guru 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * printk's trimmed out. 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.6 1995/01/19 21:49:56 guru 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is working pretty well. I gained 1 K/s in speed.. now it's just 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * robustness and printk's to be diked out. 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.5 1995/01/18 22:29:59 guru 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * still crashes the kernel when the lock_wait thing is woken up. 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.4 1995/01/18 21:59:47 guru 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Broken set-bit locking snapshot 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.3 1995/01/17 22:09:18 guru 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * infinite sleep in a lock somewhere.. 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.2 1995/01/15 16:46:06 guru 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Log trimmed of non-pertinent 1.x branch messages 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 3.1 1995/01/15 14:41:45 guru 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * New Scheduler and timer stuff... 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.15 1995/01/15 14:29:02 guru 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Will make 1.14 (now 1.15) the 3.0 branch, and the 1.12 the 2.0 branch, the one 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the dumber scheduler 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.14 1995/01/15 02:37:08 guru 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shock.. the kept-new-versions could have zonked working 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stuff.. shudder 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.13 1995/01/15 02:36:31 guru 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * big changes 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scheduler was torn out and replaced with something smarter 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * global names not prefixed with eql_ were renamed to protect 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * against namespace collisions 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a few more abstract interfaces were added to facilitate any 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * potential change of datastructure. the driver is still using 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a linked list of slaves. going to a heap would be a bit of 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an overkill. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this compiles fine with no warnings. 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the locking mechanism and timer stuff must be written however, 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this version will not work otherwise 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sorry, I had to rewrite most of this for 2.5.x -DaveM 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11463f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11563f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches 116d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/capability.h> 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 1205a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 123881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman#include <net/net_namespace.h> 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if.h> 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_eql.h> 12809e79d6ea65d66e0a5e9ba76865320e74832dc7cEric Dumazet#include <linux/pkt_sched.h> 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_open(struct net_device *dev); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_close(struct net_device *dev); 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); 135424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemmingerstatic netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define eql_is_slave(dev) ((dev->flags & IFF_SLAVE) == IFF_SLAVE) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define eql_is_master(dev) ((dev->flags & IFF_MASTER) == IFF_MASTER) 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14014a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarerstatic void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void eql_timer(unsigned long param) 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = (equalizer_t *) param; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *this, *tmp, *head; 1466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 14709e79d6ea65d66e0a5e9ba76865320e74832dc7cEric Dumazet spin_lock(&eql->queue.lock); 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &eql->queue.all_slaves; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(this, tmp, head) { 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave = list_entry(this, slave_t, list); 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slave->dev->flags & IFF_UP) == IFF_UP) { 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->bytes_queued -= slave->priority_Bps; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave->bytes_queued < 0) 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->bytes_queued = 0; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15714a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer eql_kill_one_slave(&eql->queue, slave); 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16109e79d6ea65d66e0a5e9ba76865320e74832dc7cEric Dumazet spin_unlock(&eql->queue.lock); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&eql->timer); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 167aec464bbee32e1d67cba0072c50774c5298ef762Stephen Hemmingerstatic const char version[] __initconst = 16863f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches "Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)"; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17099921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemmingerstatic const struct net_device_ops eql_netdev_ops = { 17199921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger .ndo_open = eql_open, 17299921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger .ndo_stop = eql_close, 17399921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger .ndo_do_ioctl = eql_ioctl, 17499921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger .ndo_start_xmit = eql_slave_xmit, 17599921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger}; 17699921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __init eql_setup(struct net_device *dev) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(dev); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&eql->timer); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->timer.data = (unsigned long) eql; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->timer.expires = jiffies + EQL_DEFAULT_RESCHED_IVAL; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->timer.function = eql_timer; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(&eql->queue.lock); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(&eql->queue.all_slaves); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->queue.master_dev = dev; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19099921b7e64f7726e7134046f8e1e8004e2711f30Stephen Hemminger dev->netdev_ops = &eql_netdev_ops; 1916aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now we undo some of the things that eth_setup does 1946aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * that we don't like 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1966aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->mtu = EQL_DEFAULT_MTU; /* set to 576 in if_eql.h */ 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags = IFF_MASTER; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->type = ARPHRD_SLIP; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 5; /* Hands them off fast */ 20293f154b594fe47e4a7e5358b309add449a046cd3Eric Dumazet dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_open(struct net_device *dev) 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(dev); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* XXX We should force this off automatically for the user. */ 21063f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches netdev_info(dev, 21163f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches "remember to turn off Van-Jacobson compression on your slave devices\n"); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2135d9428de1a9785f10a4339f80b717be665ba51c7Eric Sesterhenn BUG_ON(!list_empty(&eql->queue.all_slaves)); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->min_slaves = 1; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&eql->timer); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22314a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarerstatic void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&slave->list); 22614a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer queue->num_slaves--; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->dev->flags &= ~IFF_SLAVE; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave->dev); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(slave); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void eql_kill_slave_queue(slave_queue_t *queue) 2336aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *head, *tmp, *this; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&queue->lock); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &queue->all_slaves; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(this, tmp, head) { 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *s = list_entry(this, slave_t, list); 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24214a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer eql_kill_one_slave(queue, s); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&queue->lock); 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_close(struct net_device *dev) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(dev); 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The timer has to be stopped first before we start hacking away 2546aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik * at the data structure it scans every so often... 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_timer_sync(&eql->timer); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql_kill_slave_queue(&eql->queue); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_enslave(struct net_device *dev, slaving_request_t __user *srq); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_emancipate(struct net_device *dev, slaving_request_t __user *srq); 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *sc); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *sc); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mc); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mc); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2746aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd != EQL_GETMASTRCFG && cmd != EQL_GETSLAVECFG && 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !capable(CAP_NET_ADMIN)) 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_ENSLAVE: 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_enslave(dev, ifr->ifr_data); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_EMANCIPATE: 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_emancipate(dev, ifr->ifr_data); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_GETSLAVECFG: 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_g_slave_cfg(dev, ifr->ifr_data); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_SETSLAVECFG: 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_s_slave_cfg(dev, ifr->ifr_data); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_GETMASTRCFG: 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_g_master_cfg(dev, ifr->ifr_data); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case EQL_SETMASTRCFG: 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return eql_s_master_cfg(dev, ifr->ifr_data); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EOPNOTSUPP; 294ee289b6440c3b0ccb9459495783e8c299bec6604Joe Perches } 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* queue->lock must be held */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic slave_t *__eql_schedule_slaves(slave_queue_t *queue) 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long best_load = ~0UL; 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *this, *tmp, *head; 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *best_slave; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_slave = NULL; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make a pass to set the best slave. */ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &queue->all_slaves; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(this, tmp, head) { 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave = list_entry(this, slave_t, list); 3106aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik unsigned long slave_load, bytes_queued, priority_Bps; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Go through the slave list once, updating best_slave 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whenever a new best_load is found. 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bytes_queued = slave->bytes_queued; 3166aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik priority_Bps = slave->priority_Bps; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((slave->dev->flags & IFF_UP) == IFF_UP) { 3186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik slave_load = (~0UL - (~0UL / 2)) - 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (priority_Bps) + bytes_queued * 8; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave_load < best_load) { 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_load = slave_load; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds best_slave = slave; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We found a dead slave, kill it. */ 32714a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer eql_kill_one_slave(queue, slave); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return best_slave; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 333424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemmingerstatic netdev_tx_t eql_slave_xmit(struct sk_buff *skb, struct net_device *dev) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(dev); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&eql->queue.lock); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave = __eql_schedule_slaves(&eql->queue); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *slave_dev = slave->dev; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb->dev = slave_dev; 34509e79d6ea65d66e0a5e9ba76865320e74832dc7cEric Dumazet skb->priority = TC_PRIO_FILLER; 3466aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik slave->bytes_queued += skb->len; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_queue_xmit(skb); 34809f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_packets++; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 35009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik dev->stats.tx_dropped++; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb(skb); 3526aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik } 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&eql->queue.lock); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3566ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Private ioctl functions 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* queue->lock must be held */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic slave_t *__eql_find_slave_dev(slave_queue_t *queue, struct net_device *dev) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *this, *head; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &queue->all_slaves; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(this, head) { 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave = list_entry(this, slave_t, list); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave->dev == dev) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return slave; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int eql_is_full(slave_queue_t *queue) 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(queue->master_dev); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (queue->num_slaves >= eql->max_slaves) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* queue->lock must be held */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!eql_is_full(queue)) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *duplicate_slave = NULL; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds duplicate_slave = __eql_find_slave_dev(queue, slave->dev); 39537d2e7316007b4583e5783c608efdd3b2284b74dStephen Hemminger if (duplicate_slave) 39614a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer eql_kill_one_slave(queue, duplicate_slave); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&slave->list, &queue->all_slaves); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds queue->num_slaves++; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->dev->flags |= IFF_SLAVE; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOSPC; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_enslave(struct net_device *master_dev, slaving_request_t __user *srqp) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *slave_dev; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slaving_request_t srq; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 416881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman slave_dev = dev_get_by_name(&init_net, srq.slave_name); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave_dev) { 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((master_dev->flags & IFF_UP) == IFF_UP) { 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* slave is not a master & not already a slave: */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!eql_is_master(slave_dev) && 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !eql_is_slave(slave_dev)) { 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(master_dev); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!s) { 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave_dev); 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(s, 0, sizeof(*s)); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->dev = slave_dev; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->priority = srq.priority; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->priority_bps = srq.priority; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s->priority_Bps = srq.priority / 8; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&eql->queue.lock); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = __eql_insert_slave(&eql->queue, s); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave_dev); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(s); 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&eql->queue.lock); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave_dev); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_emancipate(struct net_device *master_dev, slaving_request_t __user *srqp) 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(master_dev); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *slave_dev; 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slaving_request_t srq; 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 464881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman slave_dev = dev_get_by_name(&init_net, srq.slave_name); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave_dev) { 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&eql->queue.lock); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eql_is_slave(slave_dev)) { 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave = __eql_find_slave_dev(&eql->queue, 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_dev); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave) { 47414a59e1829cd5782ad1a8979e594578f49f3e2c1Loic Le Loarer eql_kill_one_slave(&eql->queue, slave); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave_dev); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&eql->queue.lock); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql = netdev_priv(dev); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *slave_dev; 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_config_t sc; 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&sc, scp, sizeof (slave_config_t))) 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 497881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman slave_dev = dev_get_by_name(&init_net, sc.slave_name); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slave_dev) 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&eql->queue.lock); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eql_is_slave(slave_dev)) { 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave = __eql_find_slave_dev(&eql->queue, slave_dev); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave) { 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sc.priority = slave->priority; 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&eql->queue.lock); 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_put(slave_dev); 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ret && copy_to_user(scp, &sc, sizeof (slave_config_t))) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EFAULT; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_t *slave; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *slave_dev; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave_config_t sc; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&sc, scp, sizeof (slave_config_t))) 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 532881d966b48b035ab3f3aeaae0f3d3f9b584f45b2Eric W. Biederman slave_dev = dev_get_by_name(&init_net, sc.slave_name); 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!slave_dev) 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -EINVAL; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql = netdev_priv(dev); 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_bh(&eql->queue.lock); 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eql_is_slave(slave_dev)) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave = __eql_find_slave_dev(&eql->queue, slave_dev); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (slave) { 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->priority = sc.priority; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->priority_bps = sc.priority; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slave->priority_Bps = sc.priority / 8; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_bh(&eql->queue.lock); 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55193889d7574ec90bb4455929ad0536d8df74bc730Yang Hongyang dev_put(slave_dev); 55293889d7574ec90bb4455929ad0536d8df74bc730Yang Hongyang 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mcp) 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master_config_t mc; 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56144467187dc22fdd33a1a06ea0ba86ce20be3fe3cDan Rosenberg memset(&mc, 0, sizeof(master_config_t)); 56244467187dc22fdd33a1a06ea0ba86ce20be3fe3cDan Rosenberg 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eql_is_master(dev)) { 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql = netdev_priv(dev); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mc.max_slaves = eql->max_slaves; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mc.min_slaves = eql->min_slaves; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(mcp, &mc, sizeof (master_config_t))) 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mcp) 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds equalizer_t *eql; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master_config_t mc; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(&mc, mcp, sizeof (master_config_t))) 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (eql_is_master(dev)) { 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql = netdev_priv(dev); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->max_slaves = mc.max_slaves; 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds eql->min_slaves = mc.min_slaves; 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_eql; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init eql_init_module(void) 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 59763f97425166a1a16279c1a5720e9dfcb2c12ad1bJoe Perches pr_info("%s\n", version); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_eql = alloc_netdev(sizeof(equalizer_t), "eql", eql_setup); 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev_eql) 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = register_netdev(dev_eql); 6046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (err) 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev_eql); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit eql_cleanup_module(void) 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_netdev(dev_eql); 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(dev_eql); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(eql_init_module); 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(eql_cleanup_module); 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 618