diff --git a/contrib/netem.sh b/contrib/netem.sh index 244b06026..c67d7a90a 100755 --- a/contrib/netem.sh +++ b/contrib/netem.sh @@ -1,18 +1,109 @@ #!/bin/bash +# +# Transparent Network Emulation Proxy for Layer 2 & 3 +# +# Dependencies: iptables, ebtables and iproute2 +# +# Author: Steffen Vogel -IF=eth1 +set -e # Abort on error +die() { echo "$1"; exit -1; } -# Reset everything -tc qdisc del dev $IF root +# Apply netem qdisc also for reverse path +REVERSE=0 -# Root qdisc -tc qdisc add dev $IF root handle 4000 prio bands 3 priomap 0 0 0 +# This scripts also supports L3 IP packets. Simply replace the MAC by IP addresses +# Dont forget to adjust FILTER accordingly! +LAYER=2 +MY="00:15:17:2e:fb:e8" +SRC="00:15:17:2e:f4:52" +DST="00:15:17:2e:f4:52" +SRC_IF=eth2 +DST_IF=eth2 -# Netem qdsics -tc qdisc add dev $IF parent 4000:2 handle 4020 netem delay 500000 -tc qdisc add dev $IF parent 4000:3 handle 4030 netem delay 1000000 +# Apply network emulation only to packets which match those {ip,eb}table rules +# Ethertype of GOOSE is 0x88b8 +FILTER="-s $SRC -p ipv4" +FILTER_REV="-s $DST -p ipv4" -# Filters -tc filter add dev $IF protocol ip u32 match ip dst 172.23.157.1 classid 4000:2 -tc filter add dev $IF protocol ip u32 match ip dst 172.23.157.3 classid 4000:3 +# Network emulation settings (see http://stuff.onse.fi/man?program=tc-netem§ion=8) +NETEM="delay 1000000 20000 distribution normal duplicate 4 loss 20" +NETEM_REV=$NETEM +# Tools +TC=/sbin/tc +if [ "$LAYER" -eq "2" ]; then + NF=/sbin/ebtables +elif [ "$LAYER" -eq "3" ]; then + NF=/sbin/iptables +fi + +# Test permissions +(( $(id -u) == 0 )) || die "This script must be executed as root (run: sudo $0)" + +# Test if tools are available +[ -x $NF ] || die "Please install $NF (run: sudo apt-get install ebtables iptables)" +[ -x $TC ] || die "Please install $TC (run: sudo apt-get install iproute2)" + +# Load kernel modules +modprobe sch_netem || die "The netem qdisc is not compiled in this kernel!" + +# Clear tables and chains to get a clean state +$NF -t nat -F +$NF -t nat -X + +# Add new chain, mark packets from $SRC and redirect them to $DEST + +# Insert new chain into flow +$NF -t nat -I PREROUTING $FILTER -j mark --mark-set 123 --mark-target CONTINUE +$NF -t nat -I PREROUTING $FILTER -j dnat --to-dst $DST --dnat-target CONTINUE + +$NF -t nat -I POSTROUTING --mark 123 -j snat --to-src $MY + +# Clean traffic control +$TC qdisc delete dev $DST_IF root || true +$TC qdisc delete dev $SRC_IF root || true + +# Add classful qdisc to egress (outgoing) network device +$TC qdisc replace dev $DST_IF root handle 4000 prio bands 4 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 +$TC qdisc add dev $DST_IF parent 4000:3 handle 4020 netem $NETEM +$TC filter add dev $DST_IF protocol ip handle 123 fw flowid 4000:3 + +if (( $REVERSE )); then + $NF -t nat -I PREROUTING $FILTER_REV -j mark --mark-set 124 --mark-target CONTINUE + $NF -t nat -I PREROUTING $FILTER_REV -j dnat --to-dst $SRC --dnat-target CONTINUE + + $NF -t nat -I POSTROUTING --mark 123 -j snat --to-src $MY + + # Add classful qdisc to egress (outgoing) network device + $TC qdisc replace dev $SRC_IF root handle 4000 prio bands 4 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1 + $TC qdisc add dev $SRC_IF parent 4000:4 handle 4021 netem $NETEM_REV + $TC filter add dev $SRC_IF protocol ip handle 124 fw flowid 4000:4 +fi + +echo -e "Successfully configured network emulation:\n" +echo -e "Netem Settings for $SRC ($SRC_IF) => $DST ($DST_IF):" +echo -e " $NETEM\n" +if (( $REVERSE )); then + echo -e "Netem Settings for $DST ($DST_IF) => $SRC ($SRC_IF):" + echo -e " $NETEM_REV" +fi + +# Some debug and status output +if [ -n $DEBUG ]; then + if [ "$SRC_IF" == "$DST_IF" ]; then + IFNS="$SRC_IF" + else + IFNS="$SRC_IF $DST_IF" + fi + + for inf in $IFNS; do + for cmd in qdisc filter class; do + echo -e "\nTC ==> $if: $cmd" + tc -d -p $cmd show dev $inf + done + done + + echo -e "\nTABLES ==>" + $NF -t nat -L +fi