Created
March 28, 2020 01:22
-
-
Save joshrosso/16ec07cea7483d1e6a277ec5b3bc4cdf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# This script using tc (`man tc`) to shape egress traffic from a host to specific | |
# IP CIDR(s). | |
# RATES Bandwidths or rates. These parameters accept a floating point | |
# number, possibly followed by either a unit (both SI and IEC units supported), | |
# or a float followed by a '%' character to specify the rate as a percentage of | |
# the device's speed (e.g. 5%, 99.5%). Warning: specifying the rate as | |
# a percentage means a fraction of the current speed; if the speed changes, the | |
# value will not be recalculated. | |
# | |
# default Bits per second | |
# | |
# kbit Kilobits per second | |
# | |
# mbit Megabits per second | |
# | |
# gbit Gigabits per second | |
# | |
# tbit Terabits per second | |
# | |
# bps Bytes per second | |
# | |
# kbps Kilobytes per second | |
# | |
# mbps Megabytes per second | |
# | |
# gbps Gigabytes per second | |
# | |
# tbps Terabytes per second | |
# | |
# | |
# Location of tc command | |
TC=/sbin/tc | |
# Network Interface (`ip a`) to shape. | |
IF=ens160 | |
# Egress limit | |
PARENT_LIMIT=300kbit | |
BASE=10kbit | |
CEIL=300kbit | |
# CIDR ranges | |
# There should be 1 per target edge network | |
EDGE_0=192.168.201.1/32 # Edge Site 0 Description | |
EDGE_1=192.168.201.2/32 # Edge Site 1 Description | |
EDGE_2=192.168.201.3/32 # Edge Site 2 Description | |
# Filter options for limiting the intended interface. | |
U32="$TC filter add dev $IF protocol ip parent 1:0 prio 1 u32" | |
create () { | |
echo "===> Setting up shaping" | |
# Hierarchical Token Bucket (HTB) is used as it provides bandwidth-based shaping | |
# HTB The Hierarchy Token Bucket implements a rich linksharing | |
# hierarchy of classes with an emphasis on conforming to existing | |
# practices. HTB facilitates guaranteeing bandwidth to classes, while | |
# also allowing specification of upper limits to inter-class sharing. It | |
# contains shaping elements, based on TBF and can prioritize classes. | |
# root qdisc | |
$TC qdisc add dev $IF root handle 1: htb default 30 | |
echo "===> Setup root qdisc on $IF" | |
# classes | |
# shapers of bandwidth | |
# | |
# These include parent and leaf (child) classes. A parent class can specify a limit | |
# of bandwidth that can be borrowed by all children as they speed up from | |
# their rate ($BASE) to their ceiling ($CEIL). | |
# | |
# root 1: # root qdisc | |
# | | |
# / | |
# 1:1 (parent class (overall QoS)) | |
# / \ | |
# 1:10 1:20 (leaf classes (individual QoS)) | |
# | |
# In the above, a root qdisc (1:) is attached to an interface. Since rate limits | |
# are not set on root, a new class is instantiated (1:1). This class is the | |
# parent of all subsequent classes (1:10 and 1:20). | |
# | |
# With a rate on the parent (1:1) of 300mbits (the ceiling is the rate unless | |
# otherwise specified). Each leaf can set their limit up to 300mbits. Each | |
# child's rate ($BASE) is the starting rate. If 1:10 and 1:20 are transmitting | |
# at maximum speed, assuming their ceilings are set to 300mbits, they will | |
# each be throttled around 150mbits, since 150mbits * 2 = 300mbits. | |
# | |
# | |
# parent class; it's ceiling (set implicitly by rate) is shared across leaves (children) | |
$TC class add dev $IF parent 1: classid 1:1 htb rate $PARENT_LIMIT # parent | |
# leaf classes; 1 per target CIDR. | |
# ceil is the max upload speed this class should ever transmit. | |
# rate is the starting upload speed; it should be much slower than ceiling | |
$TC class add dev $IF parent 1:1 classid 1:10 htb rate $BASE ceil $CEIL # leaf | |
$TC class add dev $IF parent 1:1 classid 1:20 htb rate $BASE ceil $CEIL # leaf | |
$TC class add dev $IF parent 1:1 classid 1:30 htb rate $BASE ceil $CEIL # leaf | |
echo "===> Setup child qdisc(s) on $IF" | |
# filters for child classes | |
# maps a destination IP with the appropriate (bandwidth limiting) class | |
# flowid should map to a classid defined above | |
$U32 match ip dst $EDGE_0 flowid 1:10 | |
$U32 match ip dst $EDGE_1 flowid 1:20 | |
$U32 match ip dst $EDGE_2 flowid 1:30 | |
echo "===> Setup filters" | |
echo "===> Shaping configuration complete" | |
} | |
# clean removes *all* existing qdiscs from the target interface | |
clean () { | |
echo "===> Deleting existing qdiscs on $IF" | |
$TC qdisc del dev $IF root | |
echo "===> Deleted existing qdiscs on $IF" | |
} | |
# run script; always clean then create | |
clean | |
create |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment