summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xhfsc_shaper.sh274
-rwxr-xr-xqos.pl314
2 files changed, 0 insertions, 588 deletions
diff --git a/hfsc_shaper.sh b/hfsc_shaper.sh
deleted file mode 100755
index 3504c68..0000000
--- a/hfsc_shaper.sh
+++ /dev/null
@@ -1,274 +0,0 @@
-#!/bin/bash
-#----------------------------------------------------
-# File: hfsc_shaper.sh
-# Version: 0.2
-# Edited: Florian "Bluewind" Pritz <bluewind@xinu.at>
-# Author: Maciej Bliziński, http://automatthias.wordpress.com/
-#----------------------------------------------------
-#
-# Special Thanks to
-# Maciej Bliziński, http://automatthias.wordpress.com/
-#
-# References:
-# http://www.voip-info.org/wiki/view/QoS+Linux+with+HFSC
-# http://www.nslu2-linux.org/wiki/HowTo/EnableTrafficShaping
-# http://www.cs.cmu.edu/~hzhang/HFSC/main.html
-
-########################################################################
-# CONFIGURATION
-########################################################################
-
-# Uplink and downlink speeds
-# Normally use a bit lower values than your real speed, but
-# you should experiment a bit
-# downlink is unused
-#DOWNLINK=75000
-UPLINK=7400
-
-# Device that connects you to the Internet
-DEV="extern0"
-
-# Traffic classes:
-# 1:2 Interactive (SSH, DNS, ACK, Quake)
-# 1:3 Low latency (VoIP)
-# 1:4 Browsing (HTTP, HTTPs)
-# 1:5 Default
-# 1:6 Middle-low priority
-# 1:7 Lowest priority
-
-# Interactive class: SSH Terminal, DNS and gaming (Quake)
-INTERACTIVEPORTS="22 23 53 3389 5900 22222 6667 7000 44400 7776 4949 11030 11239 143 445 25765"
-
-# VoIP telephony
-#VOIPPORTS="5060:5100 10000:11000 5000:5059 8000:8016 5004 1720 1731"
-VOIPPORTS="7977 9987"
-# IP addresses of the VoIP phones,
-# if none, set VOIPIPS=""
-VOIPIPS=""
-
-
-# WWW, jabber and IRC
-BROWSINGPORTS="80 443 8080 993"
-
-# Everything unspecified will be here (inbetween Browsing and Data)
-
-# FTP, Mail...
-DATAPORTS="110 25 21 137:139 4662 4664 "
-
-# The lowest priority traffic: eDonkey, Bittorrent, etc.
-#P2PPORTS="6881:6999 36892 8333"
-P2PPORTS=""
-
-########################################################################
-# CONFIGURATION ENDS HERE
-########################################################################
-
-if [ -z "$DEV" ] ; then
- echo "$0: device not set, aborting."
- exit -1
-fi
-
-function stop() {
- # Reset everything to a known state (cleared)
- tc qdisc del dev $DEV root &> /dev/null
- tc qdisc del dev $DEV ingress &> /dev/null
-
- # Flush and delete tables
- iptables -t mangle --delete POSTROUTING -o $DEV -j THESHAPER &> /dev/null
- iptables -t mangle --flush THESHAPER &> /dev/null
- iptables -t mangle --delete-chain THESHAPER &> /dev/null
-}
-
-function start() {
- #if [ -z "$DOWNLINK" ] ; then
- #echo "$0: start requires a downlink speed, aborting."
- #exit -1
- #fi
- if [ -z "$UPLINK" ] ; then
- echo "$0: start requires an uplink speed, aborting."
- exit -1
- fi
-
- # add HFSC root qdisc
- tc qdisc add dev $DEV root handle 1: hfsc default 5
-
- # add main rate limit class
- tc class add dev $DEV parent 1: classid 1:1 hfsc \
- sc rate ${UPLINK}kbit ul rate ${UPLINK}kbit
-
- # Interactive traffic: guarantee full uplink for 50ms, then
- # 5/10 of the uplink
- tc class add dev $DEV parent 1:1 classid 1:2 hfsc \
- sc m1 ${UPLINK}kbit d 50ms m2 $((5*$UPLINK/10))kbit \
- ul rate ${UPLINK}kbit
-
- # VoIP: guarantee full uplink for 200ms, then 3/10
- tc class add dev $DEV parent 1:1 classid 1:3 hfsc \
- sc m1 ${UPLINK}kbit d 200ms m2 $((3*$UPLINK/10))kbit \
- ul rate ${UPLINK}kbit
-
- # Browsing: guarantee 3/10 uplink for 200ms, then
- # guarantee 1/10
- tc class add dev $DEV parent 1:1 classid 1:4 hfsc \
- sc m1 $((3*$UPLINK/10))kbit d 200ms m2 $((1*$UPLINK/10))kbit \
- ul rate ${UPLINK}kbit
-
- # Default traffic: guarantee 1/10 uplink for 100ms,
- # then guarantee 3/20
- tc class add dev $DEV parent 1:1 classid 1:5 hfsc \
- sc m1 $((1*$UPLINK/10))kbit d 100ms m2 $((3*$UPLINK/20))kbit \
- ul rate ${UPLINK}kbit
-
- # Middle-low taffic: don't guarantee anything for the first 5 seconds,
- # then guarantee 1/10
- tc class add dev $DEV parent 1:1 classid 1:6 hfsc \
- sc m1 0 d 5s m2 $((1*$UPLINK/10))kbit \
- ul rate ${UPLINK}kbit
-
- # Lowest taffic: don't guarantee anything for the first 10 seconds,
- # then guarantee 1/20
- #ls m2 $((1*$UPLINK/200))kbit \
- tc class add dev $DEV parent 1:1 classid 1:7 hfsc \
- sc m1 0 d 5s m2 10kbit \
- ul rate $((UPLINK-200))kbit
-
- # add THESHAPER chain to the mangle table in iptables
- iptables -t mangle --new-chain THESHAPER
- iptables -t mangle --insert POSTROUTING -o $DEV -j THESHAPER
-
- # Type of service filters (see /etc/iproute2/rt_dsfield)
- iptables -t mangle -A THESHAPER \
- -m tos --tos 0x10 \
- -j CLASSIFY --set-class 1:2
-
- iptables -t mangle -A THESHAPER \
- -m tos --tos 0x08 \
- -j CLASSIFY --set-class 1:7
-
- # To speed up downloads while an upload is going on, put short ACK
- # packets in the interactive class
- iptables -t mangle -A THESHAPER \
- -p tcp \
- -m tcp --tcp-flags FIN,SYN,RST,ACK ACK \
- -m length --length :64 \
- -j CLASSIFY --set-class 1:2
-
- # put large (512+) icmp packets in default category
- iptables -t mangle -A THESHAPER \
- -p icmp \
- -m length --length 512: \
- -j CLASSIFY --set-class 1:5
-
- # small ICMP in the interactive class
- iptables -t mangle -A THESHAPER \
- -p icmp \
- -m length --length :512 \
- -j CLASSIFY --set-class 1:2
-
- setclassbyport() {
- port=$1
- CLASS=$2
- iptables -t mangle -A THESHAPER -p udp --sport $port -j CLASSIFY --set-class $CLASS
- iptables -t mangle -A THESHAPER -p udp --dport $port -j CLASSIFY --set-class $CLASS
- iptables -t mangle -A THESHAPER -p tcp --sport $port -j CLASSIFY --set-class $CLASS
- iptables -t mangle -A THESHAPER -p tcp --dport $port -j CLASSIFY --set-class $CLASS
- }
-
- for port in $INTERACTIVEPORTS; do setclassbyport $port 1:2; done
- for port in $VOIPPORTS; do setclassbyport $port 1:3; done
- for port in $BROWSINGPORTS; do setclassbyport $port 1:4; done
- for port in $DATAPORTS; do setclassbyport $port 1:6; done
- for port in $P2PPORTS; do setclassbyport $port 1:7; done
-
- for VOIP in $VOIPIPS; do
- iptables -t mangle -A THESHAPER --src $VOIP -j CLASSIFY --set-class 1:3
- iptables -t mangle -A THESHAPER --dst $VOIP -j CLASSIFY --set-class 1:3
- done
-
- # put large (1024+) https packets in default category
- iptables -t mangle -A THESHAPER \
- -p tcp --dport 443 \
- -m length --length 1024: \
- -j CLASSIFY --set-class 1:6
-
- # put large (1024+) http packets in default category
- iptables -t mangle -A THESHAPER \
- -p tcp --dport 80 \
- -m length --length 1024: \
- -j CLASSIFY --set-class 1:6
-
- # put large (1024+) packets in default category
- #iptables -t mangle -A THESHAPER \
- #-p tcp \
- #-m length --length 1024: \
- #-j CLASSIFY --set-class 1:6
-
- # put large (1024+) ssh packets in default category
- iptables -t mangle -A THESHAPER \
- -p tcp --dport 22 \
- -m length --length 1024: \
- -j CLASSIFY --set-class 1:6
-
- # put all traffic from user torrent into p2p category (only works for the host this script runs on)
- #iptables -t mangle -A THESHAPER \
- #--match owner --uid-owner 169 -j CLASSIFY --set-class 1:7
-
- # Try to control the incoming traffic as well.
- # Set up ingress qdisc
- #tc qdisc add dev $DEV handle ffff: ingress
-
- # Filter everything that is coming in too fast
- # It's mostly HTTP downloads that keep jamming the downlink, so try to restrict
- # them to 95/100 of the downlink.
-
- # FIXME: slows down too much
- #tc filter add dev $DEV parent ffff: protocol ip prio 50 \
- #u32 match ip src 0.0.0.0/0 \
- #match ip protocol 6 0xff \
- #match ip sport 80 0xffff \
- #police rate $((95*${DOWNLINK}/100))kbit \
- #burst 10k drop flowid :1
-
- #tc filter add dev $DEV parent ffff: protocol ip prio 50 \
- #u32 match ip src 0.0.0.0/0 \
- #police rate $((95*${DOWNLINK}/100))kbit \
- #burst $((95*${DOWNLINK}/100*2)) drop flowid :1
-}
-
-function status() {
- echo "[qdisc]"
- tc -s qdisc show dev $DEV
-
- echo ""
- echo "[class]"
- tc -s class show dev $DEV
-
- echo ""
- echo "[filter]"
- tc -s filter show dev $DEV
-
- echo ""
- echo "[iptables]"
- iptables -n -t mangle -L THESHAPER -v -x
-}
-
-case "$1" in
- status)
- status
- ;;
- stop)
- stop
- ;;
- start)
- start
- ;;
- restart)
- stop
- start
- ;;
- *)
- echo "$0 [ACTION] [device]"
- echo "ACTION := { start | stop | status | restart }"
- exit
- ;;
-esac
diff --git a/qos.pl b/qos.pl
deleted file mode 100755
index b953e69..0000000
--- a/qos.pl
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/perl -T
-use warnings;
-use strict;
-
-use v5.10;
-use autodie;
-use File::Slurp;
-use List::Util qw(reduce);
-use POSIX;
-use Time::HiRes qw(sleep time);
-
-=head1 NAME
-
-qos.pl - Show some network QoS statistics
-
-=head1 SYNOPSIS
-
-qos.pl [interval [history_size]]
-
- Options:
- interval: Set the sampling interval in seconds
- history_size: Set the number of samples to produce averages with
-
-=head1 DESCRIPTION
-
-Use with hfsc_shaper.sh.
-
-This programm will output QoS metrics. If an interval is set, it will output
-the metrics roughly once per interval. If a history size N is set, it will
-display the average traffic per second using N samples.
-
-The output can be adjusted in the source code of this script.
-
-=cut
-
-my $device = "extern0";
-my %classes = (
- "1:2" => "interactive",
- "1:3" => "voip",
- "1:4" => "browsing",
- "1:5" => "default",
- "1:6" => "mid-low",
- "1:7" => "low/data",
-);
-
-my $show_debug_info = 0;
-
-my @display_rows = (
- [qw(time space interface-name)],
- #[qw(1:2 1:5 space total-up-tc)],
- #[qw(1:3 1:6 space total-up)],
- #[qw(1:4 1:7 space total-down)],
- [qw(1:2 1:5)],
- [qw(1:3 1:6)],
- [qw(1:4 1:7)],
- [],
- [qw(total-up-tc total-up total-down)],
-);
-
-sub untaint {
- my $data = shift;
- my $regex = shift;
-
- $data =~ m/^($regex)$/ or die "Failed to untaint: $data";
- return $1;
-}
-
-sub format_bytes {
- my $bytes = shift;
- my $boundry = 2048;
- my $format;
- my $unit;
-
- my @suffix = qw(B KiB MiB GiB TiB);
-
- for (@suffix) {
- $unit = $_;
- last if (abs($bytes) < $boundry);
- $bytes /= 1024;
- }
-
- if ($unit eq "B") {
- $format = "%.0f %s";
- } else {
- $format = "%.2f %s";
- }
-
- return sprintf $format, $bytes, $unit;
-}
-
-sub parse_tc_output {
- my $output = shift;
- my $timestamp = shift;
- my $history_values = shift;
- my $history_size_limit = shift;
-
- my $class = undef;
- my %results = ();
-
- for (split /^/, $output) {
- if (m/^class [a-z]+ (?<class>[^ ]+)/) {
- $class = $+{class};
- }
-
- if ($class && defined($classes{$class})) {
- if (m/ Sent (?<sent>[0-9]+) bytes/) {
- $results{$class} = $+{sent};
-
- if ($history_size_limit > 0) {
- # keep history of previous values
- if (!defined($history_values->{$class})) {
- $history_values->{$class} = [];
- push @{$history_values->{$class}}, {
- value => $+{sent},
- value_diff => 0,
- time_diff => 0,
- time => $timestamp,
- };
- } else {
- my $last_time = $history_values->{$class}[-1]{time};
- my $last_value = $history_values->{$class}[-1]{value};
- push @{$history_values->{$class}}, {
- value => $+{sent},
- value_diff => $+{sent} - $last_value,
- time_diff => $timestamp - $last_time,
- time => $timestamp,
- };
- }
-
- # limit history size
- if (0+@{$history_values->{$class}} > $history_size_limit) {
- splice @{$history_values->{$class}}, 0, 1;
- }
- }
- }
- }
-
- if (m/^$/) {
- $class = undef;
- }
- }
-
- return \%results;
-}
-
-sub get_interface_speed {
- my $interface = shift;
- my $history_size_limit = shift;
-
- state $speed_history = {};
-
- my $tx_bytes = read_file("/sys/class/net/$interface/statistics/tx_bytes");
- my $rx_bytes = read_file("/sys/class/net/$interface/statistics/rx_bytes");
- my $timestamp = time;
-
- if (!defined($speed_history->{$interface})) {
- $speed_history->{$interface} = [];
- push @{$speed_history->{$interface}}, {
- rx_value => $rx_bytes,
- tx_value => $tx_bytes,
- rx_diff => 0,
- tx_diff => 0,
- time => $timestamp,
- time_diff => 0,
- };
- } else {
- my $last_time = $speed_history->{$interface}[-1]{time};
- my $last_rx = $speed_history->{$interface}[-1]{rx_value};
- my $last_tx = $speed_history->{$interface}[-1]{tx_value};
- push @{$speed_history->{$interface}}, {
- rx_value => $rx_bytes,
- tx_value => $tx_bytes,
- rx_diff => $rx_bytes - $last_rx,
- tx_diff => $tx_bytes - $last_tx,
- time => $timestamp,
- time_diff => $timestamp - $last_time,
- };
- }
-
- # limit history size
- if (0+@{$speed_history->{$interface}} > $history_size_limit) {
- splice @{$speed_history->{$interface}}, 0, 1;
- }
-
- my $total_time = reduce {$a + $b->{time_diff}} 0, @{$speed_history->{$interface}};
- my $total_rx = reduce {$a + $b->{rx_diff}} 0, @{$speed_history->{$interface}};
- my $total_tx = reduce {$a + $b->{tx_diff}} 0, @{$speed_history->{$interface}};
-
- my $rx_speed = 0;
- my $tx_speed = 0;
-
- $rx_speed = $total_rx/$total_time if $total_time != 0;
- $tx_speed = $total_tx/$total_time if $total_time != 0;
-
- return ($rx_speed, $tx_speed);
-}
-
-sub print_output_table {
- my $results = shift;
- my $history_values = shift;
- my $history_size_limit = shift;
- my $starttime = shift;
- my $after_tc = shift;
- my $interval = shift;
- my $first_run = shift;
-
- my $output_buffer = "";
-
- my $global_speed = 0;
- my ($rx_speed, $tx_speed);
-
- if ($history_size_limit > 0) {
- ($rx_speed, $tx_speed) = get_interface_speed($device, $history_size_limit);
- }
-
- for my $class_id (keys %classes) {
- if ($history_values->{$class_id}) {
- my $total_time = reduce {$a + $b->{time_diff}} 0, @{$history_values->{$class_id}};
- my $total_value = reduce {$a + $b->{value_diff}} 0, @{$history_values->{$class_id}};
- my $speed = 0;
-
- $speed = $total_value / $total_time if $total_time != 0;
- $global_speed += $speed;
- }
- }
-
- for my $row (@display_rows) {
- for my $col (@{$row}) {
- if ($col =~ /^total-.*/) {
- if ($history_size_limit > 0) {
- if ($col eq "total-up") {
- $output_buffer .= sprintf "%11s/s up (tc)", format_bytes($global_speed);
- } elsif ($col eq "total-up-tc") {
- $output_buffer .= sprintf "%11s/s up (interface)", format_bytes($tx_speed);
- } elsif ($col eq "total-down") {
- $output_buffer .= sprintf "%11s/s down (interface)", format_bytes($rx_speed);
- }
- }
- } elsif ($col eq "space") {
- $output_buffer .= " "x4;
- } elsif ($col eq "spaaaaaace") {
- if ($interval) {
- $output_buffer .= " "x81;
- } else {
- $output_buffer .= " "x14;
- }
- } elsif ($col eq "interface-name") {
- $output_buffer .= $device;
- } elsif ($col eq "time") {
- $output_buffer .= POSIX::strftime("%Y-%m-%d %H:%M:%S ", localtime);
- } else {
- my $class_id = $col;
- if ($history_values->{$class_id}) {
- my $total_time = reduce {$a + $b->{time_diff}} 0, @{$history_values->{$class_id}};
- my $total_value = reduce {$a + $b->{value_diff}} 0, @{$history_values->{$class_id}};
- my $speed = 0;
-
- $speed = $total_value / $total_time if $total_time != 0;
-
- $output_buffer .= sprintf "%14s (%s): %11s %11s/s", $classes{$class_id}, $class_id, format_bytes($results->{$class_id}), format_bytes($speed);
- } else {
- $output_buffer .= sprintf "%14s (%s): %11s", $classes{$class_id}, $class_id, format_bytes($results->{$class_id});
- }
- }
- }
- $output_buffer .= "\n";
- }
-
- my $runtime = time - $starttime;
- my $runtime_tc = $after_tc - $starttime;
- printf "WARNING: processing took %0.4fs, skipping sleep. Consider raising interval!\n", $runtime if $runtime > $interval and $interval > 0;
-
- $output_buffer = sprintf "Runtime for this iteration: %0.4fs (tc: %0.4fs = %0.2f%%)\n%s", $runtime, $runtime_tc, $runtime_tc / $runtime * 100, $output_buffer if $show_debug_info;
- if (!$first_run) {
- my $newline_count = (split /^/, $output_buffer);
- # move cursor to start of previous table and clear screen
- printf "[%dF", $newline_count;
- }
- print $output_buffer;
-}
-
-sub main {
- my $interval = 0;
- my %history_values = ();
- my $history_size_limit = 0;
- my $first_run = 1;
-
- if (0+@ARGV >= 1) {
- $interval = $ARGV[0];
- }
-
- if (0+@ARGV >= 2) {
- $history_size_limit = $ARGV[1];
- }
-
- $ENV{PATH} = untaint($ENV{PATH}, qr(.*));
-
- while (1) {
- my $starttime = time;
- my $stats = `tc -s class show dev $device`;
- my $after_tc = time;
-
- my $results = parse_tc_output($stats, $after_tc, \%history_values, $history_size_limit);
-
- print_output_table($results, \%history_values, $history_size_limit, $starttime, $after_tc, $interval, $first_run);
-
- $first_run = 0;
- last unless $interval > 0;
- my $runtime = time - $starttime;
- sleep($interval - $runtime) unless $runtime > $interval;
- }
-}
-
-main();