Adaptive Quality of Service using Zyxel VMG5313-B30 and OpenWRT

The title is not really descriptive, but I hope someone will find this useful.

This is the setup – I currently get my broadband service from Croatia’s Iskon, their 30/5 mbit package (which my line, sadly, doesn’t provide fully). In addition to this, I also have their IPTV service, so in order for me to make the best use of the broadband speed available, when I shut down my IPTV STB, I can use all of the bandwidth.

My setup also includes a TP-LINK TL-WDR3600  router, in charge of the PPPoE connection and WIFI at 2.5 and 5 GHz. The router is running  OpenWRT Barrier Breaker. One of the nifty things OpenWRT does well is Quality of Service, which distributes the bandwidth according to a set of rules (lowering priority to, for instance, P2P which tends to hog the bandwidth). However, in order for QoS to work properly, you need to set its maximum speed properly, and therein lies the problem – if I set it to the lower speed, I won’t be able to use the speed boost I get with the STB off. If I set ti to a higher speed, QoS loses its purpose and doesn’t do its job.

So what I needed was to automatically adjust the maximum download speed set in the QoS service, depending on whether the STB is on or off.

Iskon’s VDSl2 service comes with Zyxel VMG5313-B30 router which is a real powerhouse in terms of everything it offers, but most of the WebUI is hidden away from regular users. One can gain access to all of its options (including its own QoS and 3G WAN backup), but I needed a solution which worked with the standard level of access (which is basically: look, don’t touch).

The solution I came up with was this:

1) Since the VDSL2 router is running in bridge mode and connected to the WAN port on the WDR3600, I had to ensure access to its Web UI from the LAN side. I did this by setting up another fixed IP interface in the modem’s subnet (Iskon uses 192.168.5.x).

So basically, I added the following to /etc/config/interfaces:

config interface 'modem'
        option proto 'static'
        option netmask '255.255.255.0'
        option ifname 'eth0.2'
        option ipaddr '192.168.5.254'

(and checked the “Bring up on boot” option).

2) Now that I can access the modem from the LAN side, I need to log in via the web UI (telnet/ssh access is, of course, disabled by my broadband provider) and find a way of identifying if the IPTV STB is on.

The first step is simple, I used cURL to do a POST request to Zyxel’s login page and save the cookies.

curl -s -l -b /tmp/cookie -c /tmp/cookie http://192.168.5.1/login/login-page.cgi -d "AuthName=Administrator&Display=Administrator&AuthPassword=Administrator"

Step two was a slightly harder. The only way I was able to identify if the STB is running was under System Monitor – Traffic Status which shows the upload/download traffic by interface (VDSL_VoIP, VDSL_IPTV, VDSL_Management). So what I needed to do was to poll the figures twice and see if they change and how much they change. I ended up with this:

curl -s -b /tmp/cookie -c /tmp/cookie  http://192.168.5.1/pages/systemMonitoring/trafficStatus/wan.html | sed -nr 's/.*VDSL_IPTV\|ptm0\.3\|(.*)@1\|VDSL_Management.*/\1/p' | cut -d, -f4

If I repeat this after 10 seconds and the packet count is significant, the STB is probably on (even when the STB is off, there is some traffic, but not more than 15 packets per 10 seconds in my case)

3) The rest was easy – use the UCI to set appropriate speed limits and reload the QoS service.

uci set qos.wan.download=VALUE
uci commit qos
/etc/init.d/qos reload

And this is the whole bash script (sorry, some of the variable names are in Croatian). Name the file /etc/qostuner.sh and make it executable (chmod +x /etc/qostuner.sh)

#!/bin/sh
logger="logger -p daemon.info $0 $@"
WAIT="30"
HIGHER="24000"
LOWER="20500"
TRENUTNO=$(uci get qos.wan.download)
if [ "$TRENUTNO" == "$HIGHER" ]; then
IPTVON="0"
else
IPTVON="1"
fi
$logger "Starting up. Current speed limit is $TRENUTNO, Receiver: $IPTVON"
if [[ -s /tmp/cookie ]]
then
LOGIN="1"
else
LOGIN="0"
fi
while [ 1 ]; do
if [ "$LOGIN" == "0" ]; then
RESPONSE=$(curl -s -l -b /tmp/cookie -c /tmp/cookie http://192.168.5.1/login/login-page.cgi -d "AuthName=Administrator&Display=Administrator&AuthPassword=Administrator" | awk 'NR==4' | sed -e "s/\(.*'\)\(.*\)\('.*\)/\\2/")
if [[ $RESPONSE == "/index.html" ]]; then
LOGIN="1"
fi
fi

TRAFFIC=$(curl -s -b /tmp/cookie -c /tmp/cookie  http://192.168.5.1/pages/systemMonitoring/trafficStatus/wan.html | sed -nr 's/.*VDSL_IPTV\|ptm0\.3\|(.*)@1\|VDSL_Management.*/\1/p' | cut -d, -f4)
if [ $TRAFFIC != "" ]; then
sleep 10
TRAFFIC2=$(curl -s -b /tmp/cookie -c /tmp/cookie  http://192.168.5.1/pages/systemMonitoring/trafficStatus/wan.html | sed -nr 's/.*VDSL_IPTV\|ptm0\.3\|(.*)@1\|VDSL_Management.*/\1/p' | cut -d, -f4)
RAZLIKA=`expr $TRAFFIC2 - $TRAFFIC`
if [ "$RAZLIKA" -gt "50" ]; then
if [ "$IPTVON" == "0" ]; then
IPTVON="1"
$logger "IPTV Receiver on. Lowering QOS maximum speed to $LOWER."
uci set qos.wan.download=$LOWER
uci commit qos
/etc/init.d/qos reload
fi
else
if [ "$IPTVON" == "1" ]; then
$logger "IPTV Receiver is off. QOS maximum speed set to $HIGHER."
uci set qos.wan.download=$HIGHER
uci commit qos
IPTVON="0"
/etc/init.d/qos reload
fi
fi
else
LOGIN="0"
rm /tmp/cookie
fi
sleep $WAIT
done

We’ll also need a startup script (/etc/init.d/qostuner)

#!/bin/sh /etc/rc.common
 START=90
 start() {
 /etc/qostuner.sh &
 }

stop() {
 killall -9 qostuner.sh
 }

Don’t forget to set your two speeds at the beginning of the script and make it run on startup.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.