RSHAPER - shape incoming traffic
6 g0 G) C* y9 A. \1 h$ A' g ================================
* d9 z K. t, }( U$ k# x6 }
0 A7 y: F4 s4 ~. @% Z3 s( }This is a module for versions 2.0, 2.2 and 2.4 of the Linux kernel, it
7 G$ E) \( V8 x2 h% v2 `. jis meant to limit the incoming bandwidth for packets aimed at# Q7 c& ~! i" g' u
different hosts. With "incoming" I mean traffic that enters the
! ^" T! S- P7 ashaping host; if that host is a gateway between target hosts and the* I5 n3 {: k& j! {$ d% y) {
rest of the Internet, all the traffic of the target hosts will be8 h" U3 ^# |% A J* r8 Q) o; E
shapeable.
7 {3 k3 c/ S( C. e R9 c5 @! A5 s$ t; O% E5 L( _9 u
I see two interesting uses for this tool:
" \: `5 l2 _! [
% c+ d; I" ]1 L* C * Limiting the bandwidth available to permanently connected
9 z0 h; Z9 b1 @& Q5 h. L hosts by installing rshaper on their gateway. This is
* I# z- G7 Q. T+ K& e4 Y interesting for ISP who offer housing and want to1 Y$ j% \) l1 n
differentiate the offer.
* \9 c( K$ s* C) N$ B7 D3 ~0 \6 g2 K, ?: M
* Limiting download bandwidth from students' boxes or similar
4 k# c' c q' q setups, by installing the rshaper directly on the0 m" [6 U$ t" @9 ^. F6 t; R
target computer. This requires that the user of that
& Y6 Q; E6 W: L, y4 d1 b computer can not gain superuser privileges.) [( M" Q7 n6 l6 q) E
1 A+ l# S# ]' L
While the former issue can be addressed with the conventional shaper D+ V4 W1 j3 p) r4 _
driver, the latter can't be easily addressed by the standard, Z1 K. N! b) O6 s7 l1 z
shaper. As a matter of facts, I have not been able to use the shaper
' \$ v' K- h8 f: P2 d: s) l! zto address the former situation, either; this because effective
9 K+ D& R7 j0 I/ w) Q; V0 M2 efiltering can only be achieved through source-routing, but when I had- d" [" J0 `( p% M- m: y% H5 x
to deal with this problem, the shaper only existed for Linux-2.1
# M3 i% U1 P' w* V5 g7 x; Hwhile my production setup was constrained to be 2.0.3 {* ^" |* B% u$ J% L
7 M% ?: u8 N! E9 d
While running rshaper with 2.0 and 2.2 requires patching the network
. N# H2 n e7 P6 ~9 fdriver, the 2.4 "netfilter" feature helps rshaper by avoiding the need' V8 J) T8 R8 N! O
to patch the netword driver. Moreover, with netfilter the rshaper can
& a& p- }, ^1 i1 G/ T8 h1 lalso shape outgoing traffic.% A# R- b* `8 R1 z
2 e* Z9 |7 D" _3 T4 n$ r
INSTALLATION
) z& _# W: t+ ?: o ============: _7 r+ O7 x+ j; d
& V' ~' s1 y3 k6 Q' g6 {/ rFirst of all "make". You'll end up with an "rshaper.o" module, that3 i4 M+ p3 X" E1 o/ c
can be loaded to your kernel. If your kernel sources are not in
^; _) t3 Q" ?0 ^* S7 m! L/usr/src/linux, you must tell make where they are by setting KERNELDIR
% `' H7 s4 l' @in the environment or specifying it on the make command line. For" k q! h- H( ^/ }% J' K- ~& [
example:% L. M; k+ r0 ~' R
3 u2 Y' }$ W' R$ p$ L0 ?; _0 Y8 A7 @ make KERNELDIR=/usr/src/linux-2.4, J3 Q5 m/ s7 J# V/ v1 |$ p7 A2 D
1 |: e2 g! J5 T- \2 t2 zAs suggested, the network driver you are using needs to be slightly
+ ?/ q3 [9 X- r4 l5 tmodified if you run version 2.0 or 2.2 of the kernel. The exact; z F( I6 i O/ Q6 \8 x) V
changes to these kernels depend on your particular setup, and are2 m+ l7 g0 m6 ^: P( D1 o) N
described in the following section.% \7 e. D' p% M4 _
5 k7 E& i: _: N4 o" q7 ^5 S
THEORY OF OPERATION* X2 B% M0 d& o0 \
===================0 E! y0 B/ @3 Q
6 i6 K3 v2 L/ A, U" `The idea is easy: whenever a packet is received through a network
# v4 t0 L$ I% f+ P7 ]) [interface, the rshaper module delays notification of the packet to the$ Z$ f" b8 b, |# _# [$ F: Q
network subsystem of Linux according to the expected data flow for the" k) e* f' ^- H% }/ Y/ s
involved host. The same mechanism can be used for outgoing packets! m" K8 Q$ Y9 N$ M
under 2.4. If you use version 2.4, you can skip the rest of this1 l: E1 X9 m# X$ j
section, otherwise please read on.8 J% T; }( E, \
+ g/ ]& y9 g: Z* } c1 I4 f7 U
With 2.0 and 2.2, the network driver must be modified in order to call3 i3 i( G$ T! i! P
the shaper's receive function instead of the standard netif_rx().' y7 ]6 {3 R3 Z. D
Therefore, you should modify two lines of your network device driver.7 z2 H" J8 S( ?/ g& m4 ~+ c. {
3 R' }: t& M" V! \( j. f+ NIn case you use a NE2000 clone or another 8390-based ethernet device,1 [' |* r+ \# z# N9 {' Z9 T
you can use the patch included in this package as "8390-2.X.c.patch",) ]/ @( m+ }9 ^0 |, z, D% d8 Q6 U T
where 2.X is your kernel version (2.0 or 2.2). If you are new to9 ~ S0 D6 ]3 x. {
patches, please refer to the last section.
% K" U0 I% V' V G6 _0 E8 h' d1 T
6 w3 E C9 X' l- i1 ~. `5 p) hIf your ethernet driver is not an 8390-based one, you have to do your
' {0 ^/ I, ?1 F6 ]: mown changes (while I might offer patches for other devices, I am too3 I' {3 ^( [1 t1 C$ n& {
lazy to do it, generally).
2 _* ^/ D" R9 N" Q+ N X/ X
5 W/ ]& n* j1 D9 y2 _ N: p" FThe code is simple:. T% v% J, ]: D! y
& E- y) z2 m% }5 E. Z! I# ^- O (1) in global space add the following line:
5 w5 p: E( q0 K/ g( p int (*net_shaper_rx_hook)(struct sk_buff *skb) = NULL;
/ o9 n3 K. z2 a1 f- s% f4 _% q2 b& t& W4 t. a
(2) Only for Linux-2.2 (not for Linux-2.0), add this too:
; k6 O3 m- C) w8 F2 G3 F# K5 f f EXPORT_SYMBOL(net_shaper_rx_hook)
* h0 r& |1 g" v4 V, j4 H; V this line must appear after the definition of the hook.
% {" _5 h5 E4 j$ R2 g. F5 D) Q; ]7 x0 j, p9 A& @" U
(3) in the receive function of the driver change0 S9 y& @% p Q F
netif_rx(skb)5 h8 n T- s0 a0 @8 q1 } i8 w
to
' J& K2 H$ g, ^& }: t5 ] v if (net_shaper_rx_hook). q0 a: B" C# V3 S# e) Y( i* y
(*net_shaper_rx_hook)(skb);. O8 T% V- T" R" |# V0 F
else
$ t& Y( T0 L0 {+ V# J1 e2 p netif_rx(skb);
+ V6 V% J/ U4 E) O' R# c7 Q' V- }% P6 X8 ?5 Q8 k
NOTE 1: using non-8390-based modularized drivers with Linux-2.2
9 Q2 M7 @0 ^( c6 ~) C% q O ---------------------------------------------------------------
1 d+ B# Z( M9 H3 z2 `9 i* P$ B5 V g4 k5 c3 s5 b# @0 R! T
In version 2.2 of the Linux kernel, no symbol is exported by default: Z+ R% x# h$ |; j* X
when loading a module. That's why you need to use the "EXPORT_SYMBOL"
6 p" W' h G; y9 Lmacro. However, using the macro may be not enough: the symbol
5 A% F: h" z( ~0 I$ S( F7 ?+ i3 F9 P"EXPORT_SYMTAB" must be defined in order for the symbol table to be
) m; @# [6 {- k0 o r9 j) Eexported./ C. m8 w" e) y1 E' k1 m
) [7 i7 {# ~) pTo define the symbol, compile the module with "-DEXPORT_SYMTAB" or7 t; R% U8 a0 s+ D4 c# H( H
define the macro with "#define EXPORT_SYMTAB" in the module itself.. ~, c3 a& m* y9 R* h1 d! u
This step is not needed for 8390.c (the driver used by NE2000
0 l* J* F/ n3 ~: E, s! bcompatible devices) because that module already exports some symbols.9 e: l" e5 W- O1 c; U8 f
9 H# t# U5 x/ i# E
NOTE 2: using non-modularized drivers0 z- d( Z- E0 I# y' k I [
-------------------------------------
: |/ o2 W7 R5 Q
3 P$ F) U- ~) Y8 _If your ethernet driver(s) is linked in the kernel image, instead of
. Y1 b! f6 d W" Pbeing a module, you must also arrange for "net_shaper_rx_hook" to be- r3 H l8 T8 { p
exported to modules, so that the "rshaper.o" module will find it. To
: _8 j( T+ ]8 j1 h7 M% [do this, apply the patch "ksyms-2.X.c.patch" (again, 2.X is your
, V/ W( b, i7 c$ D% U3 jkernel version) to kernel/ksysms.c in the kernel sources.5 x' i7 F4 p! E e I
9 A$ P2 i% s& r4 a
Please don't apply ksysms-2.X.c.patch if your network driver is a
* Y+ N/ q+ U; Nmodule.% O: u: T0 {0 C. b6 y+ I1 e
. L6 t. e% [/ V9 ~+ c! R' R) l. X# q* M. z. F H" J; V
NOTE 3: using more than one network interface( u% J1 A) p( J: c' ]* W
---------------------------------------------& ]0 n+ E+ T/ e9 _4 G1 F! J* E
9 z( g4 R9 Z" p; S% b
If your network interfaces are of different kinds, change (3) above
/ v0 t8 y1 J& i7 Mmust be applied to all the drivers involved with shaping traffic,
/ C8 W# z8 v0 ~; o' p Mwhile change (1) must be applied differently:8 f" p- l. y, j, T6 f" Y2 U
& m, _- Q% y, P+ I/ J
(1a) only one network driver must have this line:
( q9 r8 V4 s3 r; w' G int (*net_shaper_rx_hook)(struct sk_buff *skb) = NULL;& s4 s. T5 T) d# `$ i! `4 E/ p' N
. D' |4 y8 ]" j/ G, M# [ (1b) every other driver must have:4 m- y5 L) d4 _8 m! j
extern int (*net_shaper_rx_hook)(struct sk_buff *skb);
- n1 b; h0 @- r$ F3 |8 V* T4 n2 d0 X& {! b+ `
(2) if using version 2.2, only in the driver of (1a) above add:
% k9 Z* U( T k7 h0 {' S EXPORT_SYMBOL(net_shaper_rx_hook)
Y4 f5 u# w z
, z5 k6 T. N7 D5 `) J; B7 \ (3) if needed, follow NOTE 1 above, only for the driver # l9 v2 f& v: C7 ~! }' c" t" r1 P# I% q
) z5 p. S# }3 T' z5 b8 _" `
The module with modification (1a) must be loaded before the ones with
! x( M- D* D2 qmodification (1b), otherwise loading will fail with ``unresolved9 ~* o, r6 X4 e; E% [+ g
symbol "net_shaper_rx_hook"''$ ?% t( B' i4 {6 R( D9 U* K T
6 m, E+ n) P- Q* C6 _. E7 V1 R3 B
" s! |; I& m* p8 {6 ^$ }
; a0 ?1 T X9 E. F& c5 ~ CONFIGURATION (USING RSHAPERCTL)9 i4 T1 U7 `; `- [
================================
# p9 C, `$ F* d0 q/ N7 G/ l5 c3 j# e' w$ ?5 d" {
After reloading your modules or rebooting, you must load the
: }6 ~7 x4 F5 S n" a& C" s r"rshaper.o" module. To configure the bandwidth, then, use+ R( w6 v( a8 e" {5 `
"./rshaperctl". For example:# m3 v, T w( r
0 F. p6 h I% B* W
rshaperctl 192.168.1.2 6400 10
( G' x' h% L. b* G1 @: s9 D1 Q" b5 D2 Q# M0 `% b, Y. C
Limits the incoming bandwidth for the host to 6400 bytes per second
; w) X9 [4 U4 ]# v2 v3 Sand queues packets as long as the queue is shorter than 10 seconds.
. r! L7 h/ x7 j7 f4 ~, S3 `If the third argument is missing, it defaults to 5 seconds.0 M4 T3 _0 M3 D6 {: v0 x" h3 R! [
# Q9 [' W9 z" t6 M4 @
Version 1.06 of the tool adds an internal limitation to the size of# `; H" p& `# t
the queue, in order to try preventing memory saturation. The amount
5 N1 m2 ]* ?) I: }9 Zof pending data is limited by the macro RSHAPER_LIMIT_KB which can be3 h6 x B( u& @
defined at compile time and defaults to half a meg. Note that the
9 D! X, |: c& Q. J! m% z, f8 R7 Zmemory requirements of the queue can be far greater than the amount of0 z, B. K8 }1 ^9 J" G9 j W
IP data being hosted, as rshaper has its own data structures to keep
/ ~" R, \( A V2 R( ]& utrack of the packets.' C' J+ x, d3 k3 G
3 v: J+ O7 Z1 U4 D) A% z8 B: l
To remove the limit associate to an host, just use 0 as the allowed5 o6 a2 m2 u0 C/ h( C" j
bandwidth: j4 z; e( Z* y, @+ O
7 s# E( \- M) A- V7 D# X' y3 }( b# A
rshaperctl 192.168.1.2 07 Y% i1 X3 A0 Z" e$ J
; c- h* P, {5 Q9 h C: E8 T7 yFrom version 1.04 onwards, it is possible to use computer names in
9 x& J, g0 F( _9 ~8 r: Zaddition to IP numbers.
/ @2 G% t ~7 A& A" P) E- ]; k Z: G9 ?# q7 m- ^$ P
You can also limit the bandwidth allocated to a network of computers.
6 G* O- v2 e, }1 J2 yTo this aim, you can add a netmask to the IP address. Both the9 V% x, o: Y& i
following forms work:/ t% Y# q# u; n; D- U* A4 \
% q) I6 W4 `) r8 N8 r; q' ?0 X7 H& [
rshaperctl 192.168.1.16/255.255.255.240 19200* ]9 Z6 X$ A; p' x; Y/ y
rshaperctl 192.168.1.16/28 192003 w5 f) `3 b. |4 A1 X4 ?
8 [7 F+ n$ C" D7 F
"rshaperctl", when called without arguments, shows the current
% f' |& p. {7 K& Tconfiguration. Two options can be passed to rshaperctl:
( M5 y7 U, M8 `- o' }) M$ n4 Z' ]: p" K! K, O+ n$ T& M: V- B
-n (numeric): don't decode IP numbers to name when reporting
9 F' U* U5 M+ ^ Z7 P/ g# p configuration information$ R4 b/ s; y W# z- N# L# m+ v
-t (no-title): don't print the title line in the report. This: L( R6 s7 L* z# C8 l, @5 a
is useful if you feed the output to a script/ w! `8 ~$ v( F- [
; P2 p ~3 U. [2 ^3 G" f" T
Any other option makes rshaperctl print an help message. More: R+ h: Y% L6 n) u& T* v1 ^
information about rshaperctl is available as a man page: rshaperctl.8./ j1 I/ h# c2 F+ m2 o/ p
1 [4 g$ u4 P ~" H* m! \1 G* P
SHAPING OUTGOING TRAFFIC- Y6 F( z w4 T8 q8 K- V
========================5 k/ l( X0 e4 l* c* O0 o+ P( M
" ?8 N( O5 G" H# L: s
As suggested above, in kernel 2.4 is possible to manage both incoming
3 ~# |* p0 d' O( land outgoing packets. The load-time parameter "mode" specifies
* B- M& M6 t7 A# i# Gwhether the module handles received packets, transmitted ones or both
$ x# @0 h' B q# q% Fdirections. It is an integer parameter that can be set to:
$ z9 F) \+ m& H2 X1 E6 O3 m+ K4 h) v' A7 k0 D8 P- r7 O
0: Outgoing 9 `" J/ O2 y- u# b, k
1: Incoming (default). ?- l1 Q t5 x) g9 o0 U& ]/ W
2: 2 directions8 ?0 k# b$ p8 {* j5 a3 x; l9 \
) P; Q% C$ u) h: ^* l7 h8 M* Z; b* t
other values make the module barf and refuse to load. For example, for
0 z- T' t9 D V4 s1 s# ibidirectional shaping use:3 x; `( ?/ S8 ]) \2 @3 c& P7 p: Y7 U
, T- D( {8 l7 `. \+ X2 }
insmod rshaper.o mode=2
0 @$ U) ?* p" L/ V9 @3 n; B5 E
6 }) H( r% o) y7 o6 j. T# W N' h/ [When rshaper works in mode 2, the same bandwidth limit is enforced9 g) m2 d& b+ A5 ]) R }
for both directions.
: z0 j3 Y3 y! v6 T" K' U. N; C# Z+ e! G& S+ O+ O& F3 I
Mode 2, bidirectional shaping, can be interesting for leaf computers
- j- c z2 z: S C6 P. _where you want to limit both download and upload speed. However, a
6 R" V; b9 B# q* Xrouter should not use mode 2. When a packet is forwarded through the; h* m2 P D- C6 L
router and matches a shaping rule, it will be shaped twice: both when3 w+ k3 z9 b3 s. }' o
entering the computer and when leaving from it. This in practice5 h- d! n% O% k! @$ r! X, b
reduces the available bandwidth to less-than-half and reduses the
( h- k0 k G, q* C! M$ Seffective length of the queue.5 ^* |5 y5 o$ `5 K. i, ~( ~2 b
" D, y0 E8 Z* v* j3 h7 X6 jWe know how to fix the problem, but are reluctant to add computational! m/ }8 {$ x9 u1 D" p
overhead for every packet, so the simple rule is: "routers should not2 q/ c. a9 k! E" y, C
use mode 2, that would make no sense for them anyways".6 |2 w/ K' ^" b
/ M+ ]+ {5 Q4 S. X& \- l) s7 I
PATCHES (for users of Linux-2.0 and 2.2) w* g g6 N# a+ D- {% h
========================================/ x+ o3 A5 F: [1 h
, V: e: {) y% h; q. n7 \7 U& z( O: d+ ?Patch files are the output of "diff -c" or "diff -u" (preferred). They% m% Y4 i5 [5 ^2 g
describe how to change the original file to obtain a new one. A good
8 {+ Y [) J2 ^+ h5 \' O k% h" Gfeature of patches is that they are human-readable, so you can always4 p; D* |) T2 @; H% i
know what is going on.! j1 H' P; i* {( T# r
0 c. Y4 \3 [( a% MTo apply a patch, feed it to the standard input of the patch command.
& _9 D9 O& k$ l' f) Y( ]The command receives a few options on its command-line, the most
. y; C( h+ L- ]; |+ r# u& lneeded being "-p". "-p" tells patch to discard path components: "patch) S. [# F) n4 [$ W9 W6 i
-p1" for example discards one path-component in the file names it find
$ u# o# W. E! U' }8 Vin the patch file before looking for files. You should pass the: L5 g! [, |6 Z$ I- T! O! z* F
correct "-p" option according to what your current directory is when
1 m9 N: ^! h3 i: E/ ]0 Pyou apply the patch file.
8 E( q8 ]4 y$ L* `4 C9 [
9 Q# {1 l, V* l4 dSpecifically, to apply the "8390-2.X.c" patch included in this
, O" h- c! P, F3 J8 s8 f4 ddistribution:
* ]5 ?" g: l# P2 U# G
& X p$ O* ~8 j/ S5 j5 L0 \) l; I cd /your/kernel/src; patch -p0 < /.../8390-2.X.c.patch
O' j8 _* {8 n; V! z5 C `; q; B* Mor: G0 x$ P+ u. t) E
cd /your/kernel/src/drivers/net; patch -p2 < /.../8390-2.X.c.patch, t& ^( J6 c1 Z5 ?
! |3 m& u9 A: D4 b$ G3 f, x5 |: r7 W% p" T5 R* L$ O
DISCLAIMER
# V. n& ]% j; w+ Z: F ==========" m8 E5 R: |( F. U2 o
+ w$ Q/ [% r: H* k3 n- h8 D+ ]! {
This is not very refined, a lot of interesting things can be done and& i; P# C# L1 }8 W- a. w# }4 J
aren't; check shaper.c distributed with Linux-2.2 or netfilter
# p) F$ Y/ b0 Y) `distributed with Linux-2.4 to see some of the fine details that are6 m8 G! d* ]! j6 w6 y& H
missing from there.& [$ u2 W" y6 W$ S
7 K! t: ^$ N4 P+ T( P, Z+ F4 ?" Z
LICENSE
( |" z/ }* w* N) a. ` =======
# a/ V& p; X# V6 |/ ~: _ c) I8 l. V0 }8 ^# m! s6 n: l4 B
The code is released according to the GPL, in the hope you find it
; W0 V8 y8 d: T# t- j5 W$ t$ a& ruseful.
Y; F2 { O+ s O! f
4 q" s# Z7 Y0 CEnjoy% f4 q9 m+ N' ~8 r+ H
/alessandro and rodolfo |