Example behaviour of typical 3G network

300Kbit 200-100ms avg 2% loss

Setup script – shaper.sh

#!/bin/bash -x
#
# ./shaper.sh \""{{ DELAY  }}";"{{ SPREAD }}"\" \""{{ SPEED }}";"{{ CEIL }}";"{{ BURST }}"\" "{{ LOSS }}"
#

_DELAY=$1
_SPEED=$2
loss=$3

# Info

delay=$(echo ${_DELAY} | cut -f 1 -d ";")
spread=$(echo ${_DELAY} | cut -f 2 -d ";")
speed=$(echo ${_SPEED} | cut -f 1 -d ";")
ceil=$(echo ${_SPEED} | cut -f 2 -d ";")
burst=$(echo ${_SPEED} | cut -f 3 -d ";")

# Reset settings on eth0
tc qdisc del dev eth0 root

# Basic setup
tc qdisc add dev eth0 root handle 1: htb default 10
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit burst 30k

# Use parameters for TC filter setup
tc class add dev eth0 parent 1:1 classid 1:10 htb rate ${speed}kbit ceil ${ceil}kbit burst ${burst}k
tc qdisc add dev eth0 parent 1:10 handle 10: netem delay ${delay}ms ${spread}ms loss ${loss}% distribution normal

# Enable filter
tc filter add dev eth0 protocol ip parent 1:10 prio 3 u32 match ip dst 0.0.0.0/0.0.0.0 flowid 1:1

Simple Ansible playbook

 vars.yml
---
  DELAY: XXDELAYXX
  SPREAD: XXSPREADXX
  SPEED: XXSPEEDXX
  CEIL: XXCEILXX
  BURST: XXBURSTXX
  LOSS: XXLOSSXX
 tc_setup.yml
---
- hosts: any
  gather_facts: no
  sudo: yes
  vars_files:
   - vars.yml

tasks:
- name: "Reset TC settings, safe to ignore errors if there is no previouse setup"
  shell: /sbin/tc qdisc del dev eth0 root
  register: resettc_result
  tags: reset
  ignore_errors: yes

- name: Copy shaping script to node and run
  script: './shaper.sh \""{{ DELAY }}";"{{ SPREAD }}"\" \""{{ SPEED }}";"{{ CEIL }}";"{{ BURST }}"\" "{{ LOSS }}"'
  register: shapper_result
  tags: setup

- name: Show TC settings
  shell: /sbin/tc -s qdisc ls dev eth0
  register: tcresult
  ignore_errors: yes
  tags:
   - always

- name: Debug shaper output
  debug: msg="{{ shapper_result.stdout }}"
  tags: setup

- name: Debug TC shaper setup
  debug: msg="{{ tcresult.stdout }}"
  tags:
   - always