"Fossies" - the Fresh Open Source Software Archive

Member "aif-2.1.1/share/arno-iptables-firewall/plugins/60traffic-shaper.plugin" (16 Sep 2020, 15808 Bytes) of package /linux/privat/aif-2.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "60traffic-shaper.plugin": 2.1.0_vs_2.1.1.

    1 # ------------------------------------------------------------------------------
    2 #  -= Arno's Iptables Firewall(AIF) - (HTB/HFSC/CFQ) traffic shaper plugin =-
    3 #
    4 PLUGIN_NAME="Traffic Shaper Plugin"
    5 PLUGIN_VERSION="1.2.2a"
    6 PLUGIN_CONF_FILE="traffic-shaper.conf"
    7 #
    8 # Last changed          : July 21, 2015
    9 # Requirements          : kernel 2.6 + iproute
   10 # Comments              : This plugin will shape traffic. It borrows heavily on
   11 #                         the logic of Maciej's original script (below), with
   12 #                         some minor changes to the actual bins that traffic
   13 #                         goes into (I made the catch-all [default] for traffic
   14 #                         be a higher priority than browsing or bulk data
   15 #                         transfer).
   16 #                  [LRA]: Added htb support from astshape in AstLinux
   17 #                  [LRA]: Classify by DSCP class
   18 # Author                : (C) Copyright 2008-2010 by Philip Prindeville
   19 # Credits               : Maciej Blizinski
   20 # Credits               : Kristian Kielhofner
   21 # Credits               : Lonnie Abelbeck
   22 # Credits               : Arno van Amersfoort (CFQ)
   23 # Homepage              : http://www.voip-info.org/wiki/view/QoS+Linux+with+HFSC
   24 #                         http://media.blizinski.pl/code/hfsc.gz
   25 # Email                 : philipp AT redfish-solutions DOT com
   26 #                         (note: you must remove all spaces and substitute the @ and the .
   27 #                         at the proper locations!)
   28 # Notes                 : HTB/CFQ is well tested, HFSC is experimental
   29 # ------------------------------------------------------------------------------
   30 # This program is free software; you can redistribute it and/or
   31 # modify it under the terms of the GNU General Public License
   32 # version 2 as published by the Free Software Foundation.
   33 #
   34 # This program is distributed in the hope that it will be useful,
   35 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   36 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   37 # GNU General Public License for more details.
   38 #
   39 # You should have received a copy of the GNU General Public License
   40 # along with this program; if not, write to the Free Software
   41 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   42 # ------------------------------------------------------------------------------
   43 
   44 # Traffic classes:
   45 # 1:10 Highest Priority - Low Volume (ICMP, tcp-ACK, NTP, etc.)
   46 # 1:20 Streaming Media - VoIP (RTP, IAX2, etc.)
   47 # 1:30 Interactive - Shell (ssh, telnet, X, Vnc, etc.)
   48 # 1:40 Default (SIP-signaling)
   49 # 1:50 Bulk data transfer (HTTP, HTTPS, POP3, SMTP, FTP, etc.)
   50 # 1:60 Lowest priority (P2P)
   51 
   52 # Helper functions
   53 setclassbyport()
   54 {
   55   local pport="$1" class="$2" port sport proto IFS
   56 
   57   case $pport in
   58     t*) proto=tcp; port="${pport#t}" ;;
   59     u*) proto=udp; port="${pport#u}" ;;
   60     *)  printf "\033[40m\033[1;31m${INDENT}ERROR: Unknown protocol/port $pport!\n\033[0m" >&2
   61         return 1 ;;
   62   esac
   63 
   64   # We assume that on egress traffic, only the destination port is
   65   # significant, i.e. that we're not running any servers locally.
   66   iptables -t mangle -A SHAPER_CHAIN -m $proto -p $proto --dport $port -j CLASSIFY \
   67     --set-class $class
   68   iptables -t mangle -A SHAPER_CHAIN -m $proto -p $proto --dport $port -j RETURN
   69 
   70   # If we are running servers locally, include the protocol/port from the
   71   # SHAPER_LOCAL_SERVER_PORTS variable to also generate a --sport classify rule.
   72   # Note that this could have been done using an associative array in a single pass.
   73   IFS=' ,'
   74   for sport in $SHAPER_LOCAL_SERVER_PORTS; do
   75     if [ "$sport" = "$pport" ]; then
   76       iptables -t mangle -A SHAPER_CHAIN -m $proto -p $proto --sport $port -j CLASSIFY \
   77         --set-class $class
   78       iptables -t mangle -A SHAPER_CHAIN -m $proto -p $proto --sport $port -j RETURN
   79       break
   80     fi
   81   done
   82 
   83   return 0
   84 }
   85 
   86 
   87 classify_by_port()
   88 {
   89   local port IFS
   90 
   91   # Automatically set UDP 123 (NTP) to highest priority class
   92   setclassbyport u123 1:10
   93 
   94   IFS=' ,'
   95   for port in $SHAPER_STREAMINGMEDIA_PORTS; do
   96     setclassbyport $port 1:20
   97   done
   98 
   99   IFS=' ,'
  100   for port in $SHAPER_INTERACTIVE_PORTS; do
  101     setclassbyport $port 1:30
  102   done
  103 
  104   IFS=' ,'
  105   for port in $SHAPER_BULKDATA_PORTS; do
  106     setclassbyport $port 1:50
  107   done
  108 
  109   IFS=' ,'
  110   for port in $SHAPER_P2P_PORTS; do
  111     setclassbyport $port 1:60
  112   done
  113 }
  114 
  115 
  116 classify_special_packets()
  117 {
  118   # To speed up downloads while an upload is going on, put short ACK
  119   # packets in the high priority class:
  120   iptables -t mangle -A SHAPER_CHAIN \
  121     -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK ACK \
  122     -m length --length :64 \
  123     -j CLASSIFY --set-class 1:10
  124   iptables -t mangle -A SHAPER_CHAIN \
  125     -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK ACK \
  126     -m length --length :64 \
  127     -j RETURN
  128 
  129   # put large (512+) icmp packets in bulk category
  130   iptables -t mangle -A SHAPER_CHAIN \
  131     -p icmp \
  132     -m length --length 512: \
  133     -j CLASSIFY --set-class 1:50
  134   iptables -t mangle -A SHAPER_CHAIN \
  135     -p icmp \
  136     -m length --length 512: \
  137     -j RETURN
  138 
  139   # ICMP in the high priority class
  140   iptables -t mangle -A SHAPER_CHAIN \
  141     -p icmp \
  142     -m length --length :512 \
  143     -j CLASSIFY --set-class 1:10
  144   iptables -t mangle -A SHAPER_CHAIN \
  145     -p icmp \
  146     -m length --length :512 \
  147     -j RETURN
  148 }
  149 
  150 
  151 classify_by_dscp_class()
  152 {
  153   # Classify by DSCP class
  154   # Assume VoIP audio is marked as EF, and SIP as CS3
  155 
  156   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS7 -j CLASSIFY --set-class 1:10
  157   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS6 -j CLASSIFY --set-class 1:10
  158 
  159   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class EF -j CLASSIFY --set-class 1:20
  160 
  161   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS5 -j CLASSIFY --set-class 1:30
  162   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS4 -j CLASSIFY --set-class 1:30
  163   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF41 -j CLASSIFY --set-class 1:30
  164   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF42 -j CLASSIFY --set-class 1:30
  165   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF43 -j CLASSIFY --set-class 1:30
  166 
  167   # Default: --set-class 1:40
  168   # CS0, CS3, AF31, AF32, AF33, AF21, AF22, AF23
  169 
  170   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS2 -j CLASSIFY --set-class 1:50
  171   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF11 -j CLASSIFY --set-class 1:50
  172   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF12 -j CLASSIFY --set-class 1:50
  173   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class AF13 -j CLASSIFY --set-class 1:50
  174 
  175   iptables -t mangle -A SHAPER_CHAIN -m dscp --dscp-class CS1 -j CLASSIFY --set-class 1:60
  176 }
  177 
  178 
  179 incoming_traffic_limit()
  180 {
  181   local retval=0
  182 
  183   # Skip if DOWNLINK is 0
  184   if [ $DOWNLINK -eq 0 ]; then
  185     return 0
  186   fi
  187 
  188   # Try to control the incoming traffic as well.
  189   # Set up ingress qdisc
  190   tc qdisc add dev $1 handle ffff: ingress || retval=1
  191 
  192   # filter *everything* to it (0.0.0.0/0), drop everything that's
  193   # coming in too fast:
  194   tc filter add dev $1 parent ffff: protocol ip prio 100 u32 match ip src \
  195     0.0.0.0/0 police rate ${DOWNLINK}kbit burst $((1 * DOWNLINK / 10))k drop flowid :1 || retval=1
  196 
  197   return $retval
  198 }
  199 
  200 
  201 # HFSC start function
  202 plugin_start_hfsc()
  203 {
  204   local retval=0
  205 
  206   # Some required modules are already loaded by the main script:
  207   modprobe_multi nf_nat ip_nat
  208 
  209   modprobe sch_hfsc
  210 
  211   printf "${INDENT}Shaping as (Down/Up) %d/%d kb/s using '%s' for interface(s): %s\n" $DOWNLINK $UPLINK hfsc "$SHAPER_IF"
  212 
  213   iptables -t mangle -N SHAPER_CHAIN
  214 
  215   classify_special_packets
  216 
  217   classify_by_port
  218 
  219   classify_by_dscp_class
  220 
  221   IFS=' ,'
  222   for eif in $SHAPER_IF; do
  223 
  224     # tc doesn't take wildcards, so we need expansion done here
  225     for eif1 in $(wildcard_ifs $eif); do
  226 
  227       # add HFSC root qdisc
  228       tc qdisc add dev $eif1 root handle 1: hfsc default 40 || retval=1
  229 
  230       # add main rate limit class
  231       tc class add dev $eif1 parent 1: classid 1:1 hfsc \
  232          sc rate ${UPLINK}kbit ul rate ${UPLINK}kbit || retval=1
  233 
  234       # Highest Priority: guarantee 2/10 uplink for 50ms, then 1/10
  235       tc class add dev $eif1 parent 1:1 classid 1:10 hfsc \
  236         sc m1 $((2 * UPLINK / 10))kbit d 50ms m2 $((1 * UPLINK / 10))kbit \
  237         ul rate ${UPLINK}kbit || retval=1
  238 
  239       # Streaming Media: guarantee 5/10 uplink for 200ms, then 4/10
  240       tc class add dev $eif1 parent 1:1 classid 1:20 hfsc \
  241         sc m1 $((5 * UPLINK / 10))kbit d 200ms m2 $((4 * UPLINK / 10))kbit \
  242         ul rate ${UPLINK}kbit || retval=1
  243 
  244       # Interactive traffic: guarantee 3/10 uplink for 50ms, then 3/10
  245       tc class add dev $eif1 parent 1:1 classid 1:30 hfsc \
  246         sc m1 $((3 * UPLINK / 10))kbit d 50ms m2 $((3 * UPLINK / 10))kbit \
  247         ul rate ${UPLINK}kbit || retval=1
  248 
  249       # Default traffic: don't guarantee for 500ms, then guarentee 3/20
  250       tc class add dev $eif1 parent 1:1  classid 1:40 hfsc \
  251         sc m1           0 d    500ms m2 $((3 * UPLINK / 20))kbit \
  252         ul rate ${UPLINK}kbit || retval=1
  253 
  254       # Bulk data traffic: don't guarantee for 2 seconds, then guarantee 1/20
  255       tc class add dev $eif1 parent 1:1  classid 1:50 hfsc \
  256         sc m1           0 d    2s m2 $((1 * UPLINK / 20))kbit \
  257         ul rate ${UPLINK}kbit || retval=1
  258 
  259       # P2P traffic: don't guarantee anything
  260       tc class add dev $eif1 parent 1:1  classid 1:60 hfsc \
  261         sc m1           0 d    4s m2 1kbit \
  262         ul rate ${UPLINK}kbit || retval=1
  263 
  264       incoming_traffic_limit $eif1 || retval=1
  265     done
  266 
  267     # add SHAPER_CHAIN chain to mangle table in iptables
  268     iptables -t mangle -A POSTROUTING -o $eif -j SHAPER_CHAIN
  269   done
  270 
  271   return $retval
  272 }
  273 
  274 
  275 # HTB start function
  276 plugin_start_htb()
  277 {
  278   local retval=0
  279 
  280   # Some required modules are already loaded by the main script:
  281   modprobe_multi nf_nat ip_nat
  282 
  283   printf "${INDENT}Shaping as (Down/Up) %d/%d kb/s using '%s' for interface(s): %s\n" $DOWNLINK $UPLINK htb "$SHAPER_IF"
  284 
  285   iptables -t mangle -N SHAPER_CHAIN
  286 
  287   classify_special_packets
  288 
  289   classify_by_port
  290 
  291   classify_by_dscp_class
  292 
  293   IFS=' ,'
  294   for eif in $SHAPER_IF; do
  295 
  296     # tc doesn't take wildcards, so we need expansion done here
  297     for eif1 in $(wildcard_ifs $eif); do
  298       #install root HTB, point default traffic to 1:40
  299       tc qdisc add dev $eif1 root handle 1: htb default 40 || retval=1
  300 
  301       #shape everything at $UPLINK speed to prevent queing
  302       tc class add dev $eif1 parent 1: classid 1:1 htb rate ${UPLINK}kbit burst 6k || retval=1
  303 
  304       # highest priority class 1:10
  305       tc class add dev $eif1 parent 1:1 classid 1:10 htb rate ${UPLINK}kbit burst 6k prio 1 || retval=1
  306 
  307       # streaming media class 1:20
  308       tc class add dev $eif1 parent 1:1 classid 1:20 htb rate ${UPLINK}kbit burst 6k prio 2 || retval=1
  309 
  310       # interactive class 1:30
  311       tc class add dev $eif1 parent 1:1 classid 1:30 htb rate ${UPLINK}kbit burst 6k prio 3 || retval=1
  312 
  313       # default class 1:40
  314       tc class add dev $eif1 parent 1:1 classid 1:40 htb rate $((9*$UPLINK/10))kbit burst 6k prio 4 || retval=1
  315 
  316       # bulk class 1:50
  317       tc class add dev $eif1 parent 1:1 classid 1:50 htb rate $((8*$UPLINK/10))kbit burst 6k prio 5 || retval=1
  318 
  319       # p2p class 1:60
  320       tc class add dev $eif1 parent 1:1 classid 1:60 htb rate $((5*$UPLINK/10))kbit burst 6k prio 6 || retval=1
  321 
  322       # all get Stochastic Fairness
  323       tc qdisc add dev $eif1 parent 1:10 handle 10: sfq perturb 10 || retval=1
  324       tc qdisc add dev $eif1 parent 1:20 handle 20: sfq perturb 10 || retval=1
  325       tc qdisc add dev $eif1 parent 1:30 handle 30: sfq perturb 10 || retval=1
  326       tc qdisc add dev $eif1 parent 1:40 handle 40: sfq perturb 10 || retval=1
  327       tc qdisc add dev $eif1 parent 1:50 handle 50: sfq perturb 10 || retval=1
  328       tc qdisc add dev $eif1 parent 1:60 handle 60: sfq perturb 10 || retval=1
  329 
  330       incoming_traffic_limit $eif1 || retval=1
  331     done
  332 
  333     # add SHAPER_CHAIN chain to mangle table in iptables
  334     iptables -t mangle -A POSTROUTING -o $eif -j SHAPER_CHAIN
  335   done
  336 
  337   return $retval
  338 }
  339 
  340 
  341 plugin_cleanup()
  342 {
  343   IFS=' ,'
  344   for eif in $SHAPER_IF; do
  345 
  346     # tc doesn't take wildcards, so we need expansion done here
  347     for eif1 in $(wildcard_ifs $eif); do
  348       # Reset everything to a known state (cleared)
  349       tc qdisc del dev $eif1 root 2>/dev/null
  350       tc qdisc del dev $eif1 ingress 2>/dev/null
  351     done
  352 
  353     # Flush and delete tables
  354     iptables -t mangle -D POSTROUTING -o $eif -j SHAPER_CHAIN 2>/dev/null
  355   done
  356 
  357   iptables -t mangle -F SHAPER_CHAIN 2>/dev/null
  358   iptables -t mangle -X SHAPER_CHAIN 2>/dev/null
  359 }
  360 
  361 
  362 # CFQ start function - Stochastic Fairness Queueing (SFQ) is a simple
  363 # implementation of the fair queueing algorithms family. It's less accurate 
  364 # than others, but it also requires less calculations while being almost
  365 # perfectly fair
  366 plugin_start_cfq()
  367 {
  368   local retval=0
  369 
  370   echo "${INDENT}Shaping using Stochastic Fairness Queueing (SFQ) for interface(s): $SHAPER_IF"
  371 
  372   IFS=' ,'
  373   for eif in $SHAPER_IF; do
  374     # tc doesn't take wildcards, so we need expansion done here
  375     for eif1 in $(wildcard_ifs $eif); do
  376       tc qdisc add dev $eif1 root sfq perturb 10 || retval=1
  377     done
  378   done
  379 
  380   return $retval
  381 }
  382 
  383 
  384 # Plugin start function
  385 plugin_start()
  386 {
  387   local retval=0
  388 
  389   # Make sure everything is clean before we start:
  390   plugin_cleanup
  391 
  392   case $SHAPER_TYPE in
  393   hfsc) plugin_start_hfsc; retval=$? ;;
  394    htb) plugin_start_htb; retval=$? ;;
  395      *) plugin_start_cfq; retval=$? ;;
  396   esac
  397 
  398   return $retval
  399 }
  400 
  401 
  402 # Plugin stop function
  403 plugin_stop()
  404 {
  405   plugin_cleanup
  406 
  407   return 0
  408 }
  409 
  410 
  411 # Plugin status function
  412 plugin_status()
  413 {
  414   local retval=0
  415 
  416   IFS=' ,'
  417   # tc doesn't take wildcards, so we need expansion done here
  418   for eif in $(wildcard_ifs $SHAPER_IF); do
  419     echo "${INDENT}[qdisc]"
  420     tc -s qdisc show dev $eif || retval=1
  421 
  422     echo ""
  423     echo "${INDENT}[class]"
  424     tc -s class show dev $eif || retval=1
  425 
  426     echo ""
  427     echo "${INDENT}[filter]"
  428     tc -s filter show dev $eif || retval=1
  429   done
  430 
  431   echo ""
  432   echo "${INDENT}[iptables]"
  433   iptables -t mangle -L SHAPER_CHAIN -v -x 2>/dev/null |sed -e "s/^/$INDENT/"
  434 
  435   return $retval
  436 }
  437 
  438 
  439 # Sanity check environment before actual start
  440 plugin_sanity_check()
  441 {
  442   if [ -z "$UPLINK" -o -z "$DOWNLINK" ]; then
  443     printf "\033[40m\033[1;31m${INDENT}ERROR: The plugin config file is not properly set!\n\033[0m" >&2
  444     return 1
  445   fi
  446 
  447   if ! check_command tc; then
  448     printf "\033[40m\033[1;31m${INDENT}ERROR: Required binary \"tc\" is not available!\n\033[0m" >&2
  449     return 1
  450   fi
  451 
  452   return 0
  453 }
  454 
  455 
  456 ############
  457 # Mainline #
  458 ############
  459 
  460 # Set default for old config file
  461 SHAPER_IF="$EXT_IF"
  462 
  463 # Check where to find the config file
  464 CONF_FILE=""
  465 if [ -n "$PLUGIN_CONF_PATH" ]; then
  466   CONF_FILE="$PLUGIN_CONF_PATH/$PLUGIN_CONF_FILE"
  467 fi
  468 
  469 # Preinit to success:
  470 PLUGIN_RET_VAL=0
  471 
  472 # Check if the config file exists
  473 if [ ! -f "$CONF_FILE" ]; then
  474   printf "NOTE: Config file \"$CONF_FILE\" not found!\n        Plugin \"$PLUGIN_NAME v$PLUGIN_VERSION\" ignored!\n" >&2
  475 else
  476   # Source the plugin config file
  477   . "$CONF_FILE"
  478 
  479   if [ "$ENABLED" = "1" ] ||
  480      [ -n "$PLUGIN_LOAD_FILE" -a "$PLUGIN_CMD" = "stop" ] ||
  481      [ -n "$PLUGIN_LOAD_FILE" -a "$PLUGIN_CMD" = "status" ]; then
  482     # Show who we are:
  483     echo "${INDENT}$PLUGIN_NAME v$PLUGIN_VERSION"
  484 
  485     # Increment indention
  486     INDENT="$INDENT "
  487 
  488     # Only proceed if environment ok
  489     if ! plugin_sanity_check; then
  490       PLUGIN_RET_VAL=1
  491     else
  492       case $PLUGIN_CMD in
  493         start|'') plugin_start; PLUGIN_RET_VAL=$? ;;
  494         stop    ) plugin_stop; PLUGIN_RET_VAL=$? ;;
  495         status  ) plugin_status; PLUGIN_RET_VAL=$? ;;
  496         *       ) PLUGIN_RET_VAL=1; printf "\033[40m\033[1;31m${INDENT}ERROR: Invalid plugin option \"$PLUGIN_CMD\"!\033[0m\n" >&2 ;;
  497       esac
  498     fi
  499   fi
  500 fi