Throttling Internet on Linux

     Throttling your internet might seem crazy, I mean why would you ever want to have slow internet? Well consider this, you have multiple machines on the same network, a couple laptops, a few desktops, cell phones, tablets, you get the idea. Say you decide you want to upload a video to youtube, but don't want to eat up all your upload speeds doing that, now if you had a nice router you could probably limit the upload speeds on a device basis, but for those of us that are stuck with garbage routers that isn't an option. Introducing TC, this has been around for years I'm sure, and I honestly don't know too much about it, I do know that it can be used to limit how fast you can download or upload, I'm not sure if you can set different speeds for up and downloads, 'cause I can't seem to find a means to do that, but you can read the manpage yourself to find more information.
     In my use case I upload youtube videos all the time, sometimes I don't have optimal uploading time, and don't want to slow the internet down for all the other users so I like to scale back my upload speeds, obviously this makes the uploads take longer, but there is less noticeable effect for everybody else. For a while I've been using the terminal and just punching in code manually, but this past weekend I decided that I was through with that and was going to write up a bash script that would take input and take care of everything for me, so I just have to run the script and define the speed I want to throttle too. You can just copy this text, or grab it off of Github.

#!/bin/bash
# Change the network speed with ease.
# Find the name of your network adapters with ifconfig and change wlp3s0 and enp2s0 accordingly.

read -p '(T)hrottle or (U)n-throttle? ' state

if [ $state == "t" ]; then
   read -p "Max transfer speed? " speed
   read -p "Interface to throttle, (1)wlp3s0 or (2)enp2s0? " interface
    if [ $interface == '1' ]; then
        NET='wlp3s0'
    elif [ $interface == '2' ]; then
        NET='enp2s0'
    fi
   tc qdisc add dev $NET handle 1: root htb default 11
   tc class add dev $NET parent 1: classid 1:1 htb rate "$speed"kbps
   tc class add dev $NET parent 1:1 classid 1:11 htb rate "$speed"kbps
   echo Speed throttled to $speed kbps on $NET interface.
   exit 1

elif [ $state == "u" ]; then
   tc qdisc del dev wlp3s0 root
   tc qdisc del dev enp2s0 root
   exit 1
   fi
fi

     It's a rather basic script, but let me explain what is going on. We start with a prompt, this is how we find out of the user wants to throttle the speeds, or clear the throttling. the -p following the read command lets the system know that the input should be on the same line, and the trailing state lets the read command know what variable to store the result as. I don't have any error catching built in, so if you type any non-defined options you'll probably just crash the script, but I'm not too worried about that, because I'm smart enough to use the correct inputs.
     If the user wants to throttle their speed we get some more inputs, what speed that want to throttle too, and on which interface that want the throttling to happen. We then display the input back to the user, though it's rather pointless to do so as we don't allow any changes, and its unlikely that they would have forgotten what they just inputted a few seconds ago....
     The magic happens in the next three lines where we define the tc qdisc and classes. Here we use the interface and speed variables that we asked the user for, qdisc does need to run as root, so the script must be executed with elevated privileges, or it will throw an error at this point. Again, to learn more about qdisc please read the manpage, I don't know much about it other than it can be used to throttle network speeds. You'll notice we use our speed variable by calling "$speed" in the command. There is no error catching here, so if somebody inputs anything that isn't a number the script will abort.

     If we've throttled the internet we'll probably want to open it back up at some point, which is where the unthrottle option comes in to play, on my laptop I have wlan0 and eth0 so I just remove rules from both of those, though I could take user input again to only remove the rules from a certain interface. In life fashion if you were only going to be throttling on a certain interface you could change the code of the script to run on that interface and not ask for that input, you could do the same thing for the speed if you always wanted to use a predefined speed.


     That's about it for this post, to use this script just copy and save it as a .sh file and make it executable then run as sudo or su via a terminal and answer the prompts.

Happy Hacking!

Updated Oct 9th 2016:
     Updated script to eliminate the need to type the network adapter name every time the script is run. Also linked to the git repository.

Add new comment