Refactor shaping code to minimize duplication

This commit is contained in:
hk 2018-02-02 22:27:47 +01:00
parent 7d391d3be6
commit 8ed4fbaea4
2 changed files with 84 additions and 103 deletions

View File

@ -27,15 +27,15 @@ Remove configuration
# Simple DHCP WAN config # Simple DHCP WAN config
allow-auto eth1 allow-auto eth1
iface eth1 inet dhcp iface eth1 inet dhcp
post-up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0 up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0
# More advanced example with an additional tc filter exclude for # More advanced example with an additional tc filter exclude for
# UDP-encapsulated IPsec ESP-traffic to avoid double counting IPsec data on # UDP-encapsulated IPsec ESP-traffic to avoid double counting IPsec data on
# ingress # ingress
allow-auto bond0.12 allow-auto bond0.12
iface bond0.12 inet dhcp iface bond0.12 inet dhcp
post-up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0 up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0
post-up /sbin/tc filter add dev ${IFACE} parent ffff: protocol ip prio 1 u32 match ip protocol 17 0xff match ip dport 4500 0xffff action pass up /sbin/tc filter add dev ${IFACE} parent ffff: protocol ip prio 1 u32 match ip protocol 17 0xff match ip dport 4500 0xffff action pass
# Example with egress shaping on gre-tunnel # Example with egress shaping on gre-tunnel
allow-auto gre2 allow-auto gre2
@ -46,4 +46,4 @@ Remove configuration
endpoint 10.1.2.2 endpoint 10.1.2.2
mode gre mode gre
mtu 1400 mtu 1400
post-up /usr/local/bin/tc-gen -i ${IFACE} -u 25 up /usr/local/bin/tc-gen -i ${IFACE} -u 25

View File

@ -168,8 +168,11 @@ get_fq_codel_quantum () {
get_ecn () { get_ecn () {
# Takes input rate in kbit/s as parameter # Takes input rate in kbit/s as parameter
local RATE=$1 local RATE=$1
local ECN_MINRATE=$2
if [[ ${RATE} -ge 4000 ]]; then [[ -n ${ECN_MINRATE} ]] || ECN_MINRATE=4000
if [[ ${RATE} -ge ${ECN_MINRATE} ]]; then
echo "ecn" echo "ecn"
else else
echo "noecn" echo "noecn"
@ -251,51 +254,80 @@ add_prio_classes () {
local IF_NAME=$1 local IF_NAME=$1
local CLASS_CONFIG=$2 local CLASS_CONFIG=$2
local MAX_RATE=$3 local MAX_RATE=$3
local DEFAULT_PRIO=$4 local ECN_MINRATE=$4
local CLASSES=( $(echo "${CLASS_CONFIG}" | tr ',' ' ') )
for CLASS in ${CLASSES[@]}; do # Default values
local CONFIG=( $(echo "${CLASS}" | tr ':' ' ') ) local DEFAULT_CLASS=99
local FWMARK=${CONFIG[0]} local DEFAULT_RATE=${MAX_RATE}
local CLASS_RATE=$(convert_rate ${CONFIG[1]}) local DEFAULT_PRIO=4
local CEIL_RATE=${MAX_RATE}
local PRIO=${DEFAULT_PRIO}
local CLASS_ID=${FWMARK}
[[ -n ${CONFIG[2]} ]] && CEIL_RATE=$(convert_rate ${CONFIG[2]}) # Add root handle and set default leaf
[[ -n ${CONFIG[3]} ]] && PRIO=${CONFIG[3]} ${TC} qdisc add dev ${IF_NAME} root handle 1: htb default ${DEFAULT_CLASS}
if [[ ${CEIL_RATE} -gt ${MAX_RATE} ]]; then # Set the overall shaped rate of the interface
>&2 echo "ERROR: ceiling value should not be larger than total max rate" ${TC} class add dev ${IF_NAME} parent 1: classid 1:1 htb \
exit 1 rate ${MAX_RATE}kbit \
fi quantum $(get_htb_quantum ${MAX_RATE})
# Reduce the leftover default rate accordingly for each class' guaranteed rate if [[ -n ${CLASS_CONFIG} ]]; then
# This is used by the calling code, so ensure DEFAULT_RATE is defined there. local CLASSES=( $(echo "${CLASS_CONFIG}" | tr ',' ' ') )
DEFAULT_RATE=$(( ${DEFAULT_RATE} - ${CLASS_RATE} ))
if [[ ${DEFAULT_RATE} -le 0 ]]; then for CLASS in ${CLASSES[@]}; do
echo "ERROR: The aggregated guaranteed rate of the classes needs to be less than the total up rate to leave some room for the default class" local CONFIG=( $(echo "${CLASS}" | tr ':' ' ') )
exit 1 local FWMARK=${CONFIG[0]}
fi local CLASS_RATE=$(convert_rate ${CONFIG[1]})
local CEIL_RATE=${MAX_RATE}
local PRIO=${DEFAULT_PRIO}
local CLASS_ID=${FWMARK}
${TC} class add dev ${IF_NAME} parent 1:1 classid 1:${CLASS_ID} htb \ [[ -n ${CONFIG[2]} ]] && CEIL_RATE=$(convert_rate ${CONFIG[2]})
rate ${CLASS_RATE}kbit ceil ${CEIL_RATE}kbit \ [[ -n ${CONFIG[3]} ]] && PRIO=${CONFIG[3]}
prio ${PRIO} quantum $(get_htb_quantum ${CLASS_RATE})
# Should the class rate or ceil be used for the calculations here?? if [[ ${CEIL_RATE} -gt ${MAX_RATE} ]]; then
# Using ceil as this is probably the rate it is most often running >&2 echo "ERROR: ceiling value should not be larger than total max rate"
# at. exit 1
${TC} qdisc replace dev ${IF_NAME} parent 1:${CLASS_ID} \ fi
handle ${CLASS_ID}: fq_codel \
limit $(get_limit ${CEIL_RATE}) \
target $(get_target ${CEIL_RATE} $(get_mtu ${IF_NAME})) \
$(get_fq_codel_quantum ${CEIL_RATE}) \
$(get_ecn ${CEIL_RATE})
${TC} filter add dev ${IF_NAME} parent 1: protocol all \ # Reduce the leftover default rate accordingly for each class' guaranteed rate
handle ${FWMARK} fw classid 1:${CLASS_ID} # This is used by the calling code, so ensure DEFAULT_RATE is defined there.
done DEFAULT_RATE=$(( ${DEFAULT_RATE} - ${CLASS_RATE} ))
if [[ ${DEFAULT_RATE} -le 0 ]]; then
echo "ERROR: The aggregated guaranteed rate of the classes needs to be less than the total up rate to leave some room for the default class"
exit 1
fi
${TC} class add dev ${IF_NAME} parent 1:1 classid 1:${CLASS_ID} htb \
rate ${CLASS_RATE}kbit ceil ${CEIL_RATE}kbit \
prio ${PRIO} quantum $(get_htb_quantum ${CLASS_RATE})
# Should the class rate or ceil be used for the calculations here??
# Using ceil as this is probably the rate it is most often running
# at.
${TC} qdisc replace dev ${IF_NAME} parent 1:${CLASS_ID} \
handle ${CLASS_ID}: fq_codel \
limit $(get_limit ${CEIL_RATE}) \
target $(get_target ${CEIL_RATE} $(get_mtu ${IF_NAME})) \
$(get_fq_codel_quantum ${CEIL_RATE}) \
$(get_ecn ${CEIL_RATE} ${ECN_MINRATE})
${TC} filter add dev ${IF_NAME} parent 1: protocol all \
handle ${FWMARK} fw classid 1:${CLASS_ID}
done
fi
# Create class for the default priority
${TC} class add dev ${IF_NAME} parent 1:1 classid 1:${DEFAULT_CLASS} htb \
rate ${DEFAULT_RATE}kbit \
ceil ${MAX_RATE}kbit prio ${DEFAULT_PRIO} \
quantum $(get_htb_quantum ${MAX_RATE})
# Set qdisc to fq_codel
${TC} qdisc replace dev ${IF_NAME} parent 1:${DEFAULT_CLASS} handle ${DEFAULT_CLASS}: fq_codel \
limit $(get_limit ${MAX_RATE}) \
target $(get_target ${MAX_RATE} $(get_mtu ${IF_NAME})) \
$(get_fq_codel_quantum ${MAX_RATE}) \
$(get_ecn ${MAX_RATE} ${ECN_MINRATE})
} }
apply_egress_shaping () { apply_egress_shaping () {
@ -303,37 +335,10 @@ apply_egress_shaping () {
${ETHTOOL} --offload ${IF_NAME} $(get_tx_offloads ${UP_RATE}) \ ${ETHTOOL} --offload ${IF_NAME} $(get_tx_offloads ${UP_RATE}) \
> /dev/null 2>&1 || true > /dev/null 2>&1 || true
# Add root handle and set default leaf add_prio_classes \
${TC} qdisc add dev ${IF_NAME} root handle 1: htb default 99 ${IF_NAME} \
"${CLASS_CONFIG}" \
# Set the overall shaped rate of the interface ${UP_RATE}
${TC} class add dev ${IF_NAME} parent 1: classid 1:1 htb \
rate ${UP_RATE}kbit \
quantum $(get_htb_quantum ${UP_RATE})
local DEFAULT_RATE=${UP_RATE}
local DEFAULT_PRIO=4
if [[ -n ${CLASS_CONFIG} ]]; then
add_prio_classes \
${IF_NAME} \
"${CLASS_CONFIG}" \
${UP_RATE} \
${DEFAULT_PRIO}
fi
# Create class for the default priority
${TC} class add dev ${IF_NAME} parent 1:1 classid 1:99 htb \
rate ${DEFAULT_RATE}kbit \
ceil ${UP_RATE}kbit prio ${DEFAULT_PRIO} \
quantum $(get_htb_quantum ${UP_RATE})
# Set qdisc to fq_codel
${TC} qdisc replace dev ${IF_NAME} parent 1:99 handle 99: fq_codel \
limit $(get_limit ${UP_RATE}) \
target $(get_target ${UP_RATE} $(get_mtu ${IF_NAME})) \
$(get_fq_codel_quantum ${UP_RATE}) \
$(get_ecn ${UP_RATE})
} }
apply_ingress_shaping () { apply_ingress_shaping () {
@ -348,36 +353,12 @@ apply_ingress_shaping () {
${MODPROBE} ifb ${MODPROBE} ifb
${IP} link set dev ${IFB_IF_NAME} up ${IP} link set dev ${IFB_IF_NAME} up
# Add root handle and set default leaf # Enabling ECN is recommended for ingress, so ECN_MINRATE is set to 0
${TC} qdisc add dev ${IFB_IF_NAME} root handle 1: htb default 99 add_prio_classes \
${IFB_IF_NAME} \
# Set the overall shaped rate of the interface "${IFB_CLASS_CONFIG}" \
${TC} class add dev ${IFB_IF_NAME} parent 1: classid 1:1 htb \ ${DOWN_RATE} \
rate ${DOWN_RATE}kbit 0
local DEFAULT_RATE=${DOWN_RATE}
local DEFAULT_PRIO=4
if [[ -n ${IFB_CLASS_CONFIG} ]]; then
add_prio_classes \
${IFB_IF_NAME} \
"${IFB_CLASS_CONFIG}" \
${DOWN_RATE} \
${DEFAULT_PRIO}
fi
# Create class for the default priority
${TC} class add dev ${IFB_IF_NAME} parent 1:1 classid 1:99 htb \
rate ${DEFAULT_RATE}kbit \
ceil ${DOWN_RATE}kbit prio ${DEFAULT_PRIO} \
quantum $(get_htb_quantum ${DOWN_RATE})
# Set qdisc to fq_codel. Enabling ECN is recommended for ingress
${TC} qdisc replace dev ${IFB_IF_NAME} parent 1:99 handle 99: fq_codel \
limit $(get_limit ${DOWN_RATE}) \
target $(get_target ${DOWN_RATE} $(get_mtu ${IF_NAME})) \
$(get_fq_codel_quantum ${DOWN_RATE}) \
ecn
# Redirect all ingress traffic to IFB egress. Use prio 99 to make it # Redirect all ingress traffic to IFB egress. Use prio 99 to make it
# possible to insert filters earlier in the chain. # possible to insert filters earlier in the chain.