RSHAPER - shape incoming traffic ================================ This is a module for versions 2.0, 2.2 and 2.4 of the Linux kernel, it is meant to limit the incoming bandwidth for packets aimed at different hosts. With "incoming" I mean traffic that enters the shaping host; if that host is a gateway between target hosts and the rest of the Internet, all the traffic of the target hosts will be shapeable. I see two interesting uses for this tool: * Limiting the bandwidth available to permanently connected hosts by installing rshaper on their gateway. This is interesting for ISP who offer housing and want to differentiate the offer. * Limiting download bandwidth from students' boxes or similar setups, by installing the rshaper directly on the target computer. This requires that the user of that computer can not gain superuser privileges. While the former issue can be addressed with the conventional shaper driver, the latter can't be easily addressed by the standard shaper. As a matter of facts, I have not been able to use the shaper to address the former situation, either; this because effective filtering can only be achieved through source-routing, but when I had to deal with this problem, the shaper only existed for Linux-2.1 while my production setup was constrained to be 2.0. While running rshaper with 2.0 and 2.2 requires patching the network driver, the 2.4 "netfilter" feature helps rshaper by avoiding the need to patch the netword driver. Moreover, with netfilter the rshaper can also shape outgoing traffic. INSTALLATION ============ First of all "make". You'll end up with an "rshaper.o" module, that can be loaded to your kernel. If your kernel sources are not in /usr/src/linux, you must tell make where they are by setting KERNELDIR in the environment or specifying it on the make command line. For example: make KERNELDIR=/usr/src/linux-2.4 As suggested, the network driver you are using needs to be slightly modified if you run version 2.0 or 2.2 of the kernel. The exact changes to these kernels depend on your particular setup, and are described in the following section. THEORY OF OPERATION =================== The idea is easy: whenever a packet is received through a network interface, the rshaper module delays notification of the packet to the network subsystem of Linux according to the expected data flow for the involved host. The same mechanism can be used for outgoing packets under 2.4. If you use version 2.4, you can skip the rest of this section, otherwise please read on. With 2.0 and 2.2, the network driver must be modified in order to call the shaper's receive function instead of the standard netif_rx(). Therefore, you should modify two lines of your network device driver. In case you use a NE2000 clone or another 8390-based ethernet device, you can use the patch included in this package as "8390-2.X.c.patch", where 2.X is your kernel version (2.0 or 2.2). If you are new to patches, please refer to the last section. If your ethernet driver is not an 8390-based one, you have to do your own changes (while I might offer patches for other devices, I am too lazy to do it, generally). The code is simple: (1) in global space add the following line: int (*net_shaper_rx_hook)(struct sk_buff *skb) = NULL; (2) Only for Linux-2.2 (not for Linux-2.0), add this too: EXPORT_SYMBOL(net_shaper_rx_hook) this line must appear after the definition of the hook. (3) in the receive function of the driver change netif_rx(skb) to if (net_shaper_rx_hook) (*net_shaper_rx_hook)(skb); else netif_rx(skb); NOTE 1: using non-8390-based modularized drivers with Linux-2.2 --------------------------------------------------------------- In version 2.2 of the Linux kernel, no symbol is exported by default when loading a module. That's why you need to use the "EXPORT_SYMBOL" macro. However, using the macro may be not enough: the symbol "EXPORT_SYMTAB" must be defined in order for the symbol table to be exported. To define the symbol, compile the module with "-DEXPORT_SYMTAB" or define the macro with "#define EXPORT_SYMTAB" in the module itself. This step is not needed for 8390.c (the driver used by NE2000 compatible devices) because that module already exports some symbols. NOTE 2: using non-modularized drivers ------------------------------------- If your ethernet driver(s) is linked in the kernel image, instead of being a module, you must also arrange for "net_shaper_rx_hook" to be exported to modules, so that the "rshaper.o" module will find it. To do this, apply the patch "ksyms-2.X.c.patch" (again, 2.X is your kernel version) to kernel/ksysms.c in the kernel sources. Please don't apply ksysms-2.X.c.patch if your network driver is a module. NOTE 3: using more than one network interface --------------------------------------------- If your network interfaces are of different kinds, change (3) above must be applied to all the drivers involved with shaping traffic, while change (1) must be applied differently: (1a) only one network driver must have this line: int (*net_shaper_rx_hook)(struct sk_buff *skb) = NULL; (1b) every other driver must have: extern int (*net_shaper_rx_hook)(struct sk_buff *skb); (2) if using version 2.2, only in the driver of (1a) above add: EXPORT_SYMBOL(net_shaper_rx_hook) (3) if needed, follow NOTE 1 above, only for the driver The module with modification (1a) must be loaded before the ones with modification (1b), otherwise loading will fail with ``unresolved symbol "net_shaper_rx_hook"'' CONFIGURATION (USING RSHAPERCTL) ================================ After reloading your modules or rebooting, you must load the "rshaper.o" module. To configure the bandwidth, then, use "./rshaperctl". For example: rshaperctl 192.168.1.2 6400 10 Limits the incoming bandwidth for the host to 6400 bytes per second and queues packets as long as the queue is shorter than 10 seconds. If the third argument is missing, it defaults to 5 seconds. Version 1.06 of the tool adds an internal limitation to the size of the queue, in order to try preventing memory saturation. The amount of pending data is limited by the macro RSHAPER_LIMIT_KB which can be defined at compile time and defaults to half a meg. Note that the memory requirements of the queue can be far greater than the amount of IP data being hosted, as rshaper has its own data structures to keep track of the packets. To remove the limit associate to an host, just use 0 as the allowed bandwidth: rshaperctl 192.168.1.2 0 From version 1.04 onwards, it is possible to use computer names in addition to IP numbers. You can also limit the bandwidth allocated to a network of computers. To this aim, you can add a netmask to the IP address. Both the following forms work: rshaperctl 192.168.1.16/255.255.255.240 19200 rshaperctl 192.168.1.16/28 19200 "rshaperctl", when called without arguments, shows the current configuration. Two options can be passed to rshaperctl: -n (numeric): don't decode IP numbers to name when reporting configuration information -t (no-title): don't print the title line in the report. This is useful if you feed the output to a script Any other option makes rshaperctl print an help message. More information about rshaperctl is available as a man page: rshaperctl.8. SHAPING OUTGOING TRAFFIC ======================== As suggested above, in kernel 2.4 is possible to manage both incoming and outgoing packets. The load-time parameter "mode" specifies whether the module handles received packets, transmitted ones or both directions. It is an integer parameter that can be set to: 0: Outgoing 1: Incoming (default) 2: 2 directions other values make the module barf and refuse to load. For example, for bidirectional shaping use: insmod rshaper.o mode=2 When rshaper works in mode 2, the same bandwidth limit is enforced for both directions. Mode 2, bidirectional shaping, can be interesting for leaf computers where you want to limit both download and upload speed. However, a router should not use mode 2. When a packet is forwarded through the router and matches a shaping rule, it will be shaped twice: both when entering the computer and when leaving from it. This in practice reduces the available bandwidth to less-than-half and reduses the effective length of the queue. We know how to fix the problem, but are reluctant to add computational overhead for every packet, so the simple rule is: "routers should not use mode 2, that would make no sense for them anyways". PATCHES (for users of Linux-2.0 and 2.2) ======================================== Patch files are the output of "diff -c" or "diff -u" (preferred). They describe how to change the original file to obtain a new one. A good feature of patches is that they are human-readable, so you can always know what is going on. To apply a patch, feed it to the standard input of the patch command. The command receives a few options on its command-line, the most needed being "-p". "-p" tells patch to discard path components: "patch -p1" for example discards one path-component in the file names it find in the patch file before looking for files. You should pass the correct "-p" option according to what your current directory is when you apply the patch file. Specifically, to apply the "8390-2.X.c" patch included in this distribution: cd /your/kernel/src; patch -p0 < /.../8390-2.X.c.patch or cd /your/kernel/src/drivers/net; patch -p2 < /.../8390-2.X.c.patch DISCLAIMER ========== This is not very refined, a lot of interesting things can be done and aren't; check shaper.c distributed with Linux-2.2 or netfilter distributed with Linux-2.4 to see some of the fine details that are missing from there. LICENSE ======= The code is released according to the GPL, in the hope you find it useful. Enjoy /alessandro and rodolfo