├── LICENCE ├── README.md └── src └── tc-gen /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 hkbakke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DEPRECATED 2 | The functionality in this script is targeted towards fq_codel/htb. However, 3 | time has passed and today the simpler to use `tc-cake` is the better 4 | alternative in most cases. 5 | 6 | This script will probably still work for a long time, but will not receive any 7 | updates. 8 | 9 | # tc-gen 10 | tc-gen is a wrapper around all the complexity of modern traffic shaping and 11 | policing on linux. It tries to use best practices whenever possible while still 12 | being generic and easy to use. The script is using HTB with fq_codel to do 13 | the heavy lifting. 14 | 15 | Run tc-gen without parameters to see more details. 16 | 17 | ## Examples of common use 18 | Shape egress to 25 mbit/s 19 | 20 | tc-gen -i eth0 -u 25 21 | Shape egress to 5 mbit/s and ingress to 10 mbit/s using IFB-interface 22 | 23 | tc-gen -i eth0 -u 5 -d 10 -f ifb0 24 | Shape egress to 1500 kbit/s and police ingress to 20 mbit/s 25 | 26 | tc-gen -i eth0 -u 1500k -d 20M 27 | Display current configuration 28 | 29 | tc-gen -i eth0 30 | Remove configuration 31 | 32 | tc-gen -i eth0 -x 33 | 34 | ## /etc/network/interfaces examples 35 | # Simple DHCP WAN config 36 | allow-auto eth1 37 | iface eth1 inet dhcp 38 | up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0 39 | 40 | # More advanced example with an additional tc filter exclude for 41 | # UDP-encapsulated IPsec ESP-traffic to avoid double counting IPsec data on 42 | # ingress 43 | allow-auto bond0.12 44 | iface bond0.12 inet dhcp 45 | up /usr/local/bin/tc-gen -i ${IFACE} -u 10 -d 100 -f ifb0 46 | 47 | # Add additional rules to the post-commands file (location can be overridden by -p) 48 | echo '${TC} filter add dev ${IF_NAME} parent ffff: protocol ip prio 1 u32 match ip protocol 17 0xff match ip dport 4500 0xffff action pass' >> /etc/tc-gen/post-commands.bond0.12 49 | 50 | # Example with egress shaping on gre-tunnel 51 | allow-auto gre2 52 | iface gre2 inet tunnel 53 | address 10.0.1.0 54 | netmask 255.255.255.254 55 | local 10.0.2.2 56 | endpoint 10.1.2.2 57 | mode gre 58 | mtu 1400 59 | up /usr/local/bin/tc-gen -i ${IFACE} -u 25 60 | -------------------------------------------------------------------------------- /src/tc-gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | VERSION="1.3.0" 5 | TC=$(command -v tc) 6 | ETHTOOL=$(command -v ethtool) 7 | IP=$(command -v ip) 8 | MODPROBE=$(command -v modprobe) 9 | 10 | 11 | error_handler () { 12 | local SCRIPT_NAME="$0" 13 | local LINE="$1" 14 | local EXIT_CODE="$2" 15 | >&2 echo "${SCRIPT_NAME}: Error in line ${LINE} (exit code ${EXIT_CODE})" 16 | exit ${EXIT_CODE} 17 | } 18 | 19 | trap 'error_handler ${LINENO} $?' ERR INT TERM 20 | set -o errtrace -o pipefail 21 | 22 | 23 | print_usage () { 24 | cat << EOF 25 | tc-gen -i IF_NAME [OPTIONS] 26 | 27 | -i IF_NAME 28 | If this is the only option, the current filter, qdisc and class 29 | configuration on the interface is displayed. 30 | 31 | OPTIONS 32 | Valid units for rates are k (kbit/s) and M (Mbit/s). If no unit are given 33 | with the rate Mbit/s is used. 34 | 35 | -f IFB_IF_NAME 36 | If ingress shaping should be used instead of policing define a valid 37 | ifb interface. Normally ifb0 and ifb1 are available if nothing is 38 | configured beyond loading the ifb kernel module. 39 | -b BURST_SIZE 40 | Only used when ingress policing is used. For ingress shaping this is 41 | ignored. 42 | -c ":::,:::,..." 43 | Define extra leaf classes if you want to slice up and guarantee 44 | bandwith between different kinds of traffic, for exeample by using 45 | fw marks on egress. If the fw mark matches the handle the traffic 46 | will match. 47 | The default class has a priority of 4. If this is not set all the 48 | bandwith is given to the default class which is sufficient for most 49 | use cases. If ceil is not set it will default to UP_RATE. If prio is 50 | not set, it will default to the same priority as the default class. 51 | 52 | Example: 53 | -c "107:50::,109:1400k:7M:2" 54 | 55 | The example above creates a leaf class which get all egress traffic 56 | with handle 107, shaped to a rate of 50 mbit/s with no ceiling and 57 | priority, which means that it may use all the available bandwith if 58 | available in the root class and has the same priority as the default 59 | class. The next leaf class has a handle of 109, a rate of 1400 kbit/s, 60 | a ceil of 7 mbit/s and a priority of 2. 61 | -C ":::,:::,..." 62 | Same as -c but for ingress on IFB interface. Note that it is not 63 | possible to use fw marks to assign traffic to IFB interface classes, 64 | as it is not hooked into netfilter. Instead you need to use tc filter 65 | rules, which you normally would add to the post-commands file. 66 | 67 | Example: 68 | tc filter add dev ifb0 parent 1: protocol ip prio 20 \ 69 | u32 \ 70 | match ip protocol 6 0xff \ 71 | match ip dport 22 0xffff \ 72 | classid 1: 73 | 74 | The example above sends TCP port 22 traffic to the 1: class. 75 | The filter priority is used to define filter processing order, and 76 | must not be confused with the class priority, which defines the class' 77 | relative priority to other classes when there is a need to prioritize 78 | traffic. 79 | -d DOWN_RATE 80 | -p CONFIG_DIR 81 | By default tc-gen checks if "/etc/tc-gen/post-commands." exists and 82 | if so, sources that file after tc-gen have finished setting up its 83 | ordinary configuration. Some nice to have environment variables 84 | available for those files are: 85 | 86 | TC, IF_NAME, IFB_IF_NAME, UP_RATE, DOWN_RATE and BURST_SIZE 87 | 88 | Use this option to look in another dir for these files. 89 | -u UP_RATE 90 | -x 91 | Clear all traffic control config on interface. 92 | -V 93 | Print version and exit. 94 | 95 | EXAMPLES OF COMMON USE 96 | Shape egress to 25 mbit/s 97 | tc-gen -i eth0 -u 25 98 | 99 | Shape egress to 5 mbit/s and ingress to 10 mbit/s using IFB-interface 100 | tc-gen -i eth0 -u 5 -d 10 -f ifb0 101 | 102 | Shape egress to 1500 kbit/s and police ingress to 20 mbit/s 103 | tc-gen -i eth0 -u 1500k -d 20M 104 | 105 | Display current configuration 106 | tc-gen -i eth0 107 | 108 | Remove configuration 109 | tc-gen -i eth0 -x 110 | 111 | Always use ingress shaping vs policing if you want the best results. An 112 | additional bonus is that GRO normally can be left on when not using 113 | policing with good results. 114 | 115 | EGRESS TRAFFIC SHAPING 116 | UP_RATE uses HTB and fq_codel to efficiently shape upload 117 | traffic. 118 | 119 | INGRESS TRAFFIC SHAPING 120 | If DOWN_RATE and IFB_IF_NAME is set, ingress traffic shaping using 121 | an IFB-interface, HTB and fq_codel, is used for incoming traffic. 122 | 123 | INGRESS TRAFFIC POLICING 124 | BURST_SIZE is only used for ingress policing. 125 | Ingress policing is used if IFB_IF_NAME is not defined and DOWN_RATE 126 | is set. A good starting point for the burst size is 127 | 128 | phy_line_rate_in_bps * burst_time_seconds / 8 = burst_size_in_bytes 129 | 130 | with a burst_time_seconds value of 0.005s, or 5ms. 131 | 132 | The minimum recommended burst size is 133 | 134 | MTU * 10 = burst_size_in_bytes 135 | 136 | tc-gen tries to automatically calculate this for you, but in several 137 | cases it is hard to determine the actual physical line rate for the 138 | interface, so you may need to set BURST_SIZE manually for optimal 139 | results. 140 | 141 | Ingress policing is very unreliable unless generic receive offload is 142 | disabled for the interface. For bonds and VLAN interfaces you have to 143 | disable GRO for the actual physical NICs manually as the script does 144 | not know the interface names of those. Disabling GRO usually leads to a 145 | massive increase in CPU-usage for high bandwith and might not be an option 146 | in many systems. 147 | 148 | EXCLUDE TRAFFIC FROM INGRESS FILTERING 149 | The catch all filter for ingress has a priority of 99. This means that it 150 | is possible to manually add lower priority filter rules e.g. to exclude 151 | traffic from rate limiting. This is typically used for IPsec ESP-packets 152 | as they are seen both in its encrypted and decrypted form on the ingress 153 | interface if the tunnels are terminated locally, resulting in double 154 | counting of the traffic. 155 | EOF 156 | } 157 | 158 | print_version () { 159 | echo "tc-gen v${VERSION}" 160 | } 161 | 162 | get_htb_quantum () { 163 | # Takes input rate in kbit/s as parameter 164 | local RATE=$1 165 | local QUANTUM=8000 166 | 167 | if [[ ${RATE} -lt 40000 ]]; then 168 | QUANTUM=1514 169 | fi 170 | 171 | echo ${QUANTUM} 172 | } 173 | 174 | get_target () { 175 | # Takes input rate in kbit/s and mtu as parameter 176 | local RATE=$1 177 | local MTU=$2 178 | local KBYTES=$(( ${RATE} / 8 )) 179 | local MS=$(( ${MTU} / ${KBYTES} )) 180 | local TARGET=5 181 | 182 | if [[ ${MS} -gt 5 ]]; then 183 | TARGET=$(( ${MS} + 1 )) 184 | fi 185 | 186 | echo "${TARGET}.0ms" 187 | } 188 | 189 | get_fq_codel_quantum () { 190 | # Takes input rate in kbit/s as parameter 191 | local RATE=$1 192 | 193 | if [[ ${RATE} -lt 100000 ]]; then 194 | echo "quantum 300" 195 | fi 196 | } 197 | 198 | get_ecn () { 199 | # Takes input rate in kbit/s as parameter 200 | local RATE=$1 201 | local ECN_MINRATE=$2 202 | 203 | [[ -n ${ECN_MINRATE} ]] || ECN_MINRATE=0 204 | 205 | if [[ ${RATE} -ge ${ECN_MINRATE} ]]; then 206 | echo "ecn" 207 | else 208 | echo "noecn" 209 | fi 210 | } 211 | 212 | get_speed () { 213 | # Takes interface as parameter 214 | if [[ -r /sys/class/net/${1}/speed ]]; then 215 | cat /sys/class/net/${1}/speed 216 | else 217 | echo 0 218 | fi 219 | } 220 | 221 | get_mtu () { 222 | # Takes interface as parameter 223 | cat /sys/class/net/${1}/mtu 224 | } 225 | 226 | get_tx_offloads () { 227 | # Takes rate in kbit/s as parameter 228 | local RATE=$1 229 | 230 | if [[ ${RATE} -lt 40000 ]]; then 231 | echo "tso off gso off" 232 | else 233 | echo "tso on gso on" 234 | fi 235 | } 236 | 237 | get_rx_offloads () { 238 | # Takes rate in kbit/s as parameter 239 | local RATE=$1 240 | 241 | if [[ ${RATE} -lt 40000 ]]; then 242 | echo "gro off" 243 | else 244 | echo "gro on" 245 | fi 246 | } 247 | 248 | get_limit () { 249 | # Takes rate in kbit/s as parameter 250 | local RATE=$1 251 | local LIMIT=10000 252 | 253 | if [[ ${RATE} -le 10000 ]]; then 254 | LIMIT=600 255 | elif [[ ${RATE} -le 100000 ]]; then 256 | LIMIT=800 257 | elif [[ ${RATE} -le 1000000 ]]; then 258 | LIMIT=1200 259 | fi 260 | 261 | echo ${LIMIT} 262 | } 263 | 264 | clear_all () { 265 | ${TC} qdisc del dev ${IF_NAME} root > /dev/null 2>&1 || true 266 | ${TC} qdisc del dev ${IF_NAME} ingress > /dev/null 2>&1 || true 267 | 268 | if [[ -n ${IFB_IF_NAME} ]]; then 269 | ${TC} qdisc del dev ${IFB_IF_NAME} root > /dev/null 2>&1 || true 270 | fi 271 | 272 | ${ETHTOOL} --offload ${IF_NAME} gro on tso on gso on \ 273 | > /dev/null 2>&1 || true 274 | } 275 | 276 | print_config () { 277 | local IF_NAME="$1" 278 | 279 | echo -e "### INTERFACE: ${IF_NAME} ###\n" 280 | echo "=== Filters ===" 281 | ${TC} -s -d filter show dev ${IF_NAME} 282 | ${TC} -s -d filter show dev ${IF_NAME} parent ffff: 283 | 284 | echo -e "\n=== Classes ===" 285 | ${TC} -s -d class show dev ${IF_NAME} 286 | 287 | echo -e "\n=== Qdiscs ===" 288 | ${TC} -s -d qdisc show dev ${IF_NAME} 289 | echo "" 290 | } 291 | 292 | add_prio_classes () { 293 | local IF_NAME=$1 294 | local MAX_RATE=$2 295 | local ECN_MINRATE=$3 296 | local CLASS_CONFIG=$4 297 | 298 | # Default values 299 | local DEFAULT_CLASS=99 300 | local DEFAULT_RATE=${MAX_RATE} 301 | local DEFAULT_PRIO=4 302 | 303 | # Add root handle and set default leaf 304 | ${TC} qdisc add dev ${IF_NAME} root handle 1: htb default ${DEFAULT_CLASS} 305 | 306 | # Set the overall shaped rate of the interface 307 | ${TC} class add dev ${IF_NAME} parent 1: classid 1:1 htb \ 308 | rate ${MAX_RATE}kbit \ 309 | quantum $(get_htb_quantum ${MAX_RATE}) 310 | 311 | if [[ -n ${CLASS_CONFIG} ]]; then 312 | local CLASSES=( $(echo "${CLASS_CONFIG}" | tr ',' ' ') ) 313 | 314 | for CLASS in ${CLASSES[@]}; do 315 | local CONFIG 316 | IFS=':' read -r -a CONFIG <<< "${CLASS}" 317 | local HANDLE=${CONFIG[0]} 318 | local CLASS_RATE=$(convert_rate ${CONFIG[1]}) 319 | local CEIL_RATE=${MAX_RATE} 320 | local PRIO=${DEFAULT_PRIO} 321 | local CLASS_ID=${HANDLE} 322 | 323 | [[ -n ${CONFIG[2]} ]] && CEIL_RATE=$(convert_rate ${CONFIG[2]}) 324 | [[ -n ${CONFIG[3]} ]] && PRIO=${CONFIG[3]} 325 | 326 | if [[ ${CEIL_RATE} -gt ${MAX_RATE} ]]; then 327 | >&2 echo "ERROR: ceiling value should not be larger than total max rate" 328 | exit 1 329 | fi 330 | 331 | # Reduce the leftover default rate accordingly for each class' guaranteed rate 332 | # This is used by the calling code, so ensure DEFAULT_RATE is defined there. 333 | DEFAULT_RATE=$(( ${DEFAULT_RATE} - ${CLASS_RATE} )) 334 | 335 | if [[ ${DEFAULT_RATE} -le 0 ]]; then 336 | 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" 337 | exit 1 338 | fi 339 | 340 | ${TC} class add dev ${IF_NAME} parent 1:1 classid 1:${CLASS_ID} htb \ 341 | rate ${CLASS_RATE}kbit ceil ${CEIL_RATE}kbit \ 342 | prio ${PRIO} quantum $(get_htb_quantum ${CLASS_RATE}) 343 | 344 | # Should the class rate or ceil be used for the calculations here?? 345 | # Using ceil as this is probably the rate it is most often running 346 | # at. 347 | ${TC} qdisc replace dev ${IF_NAME} parent 1:${CLASS_ID} \ 348 | handle ${CLASS_ID}: fq_codel \ 349 | limit $(get_limit ${CEIL_RATE}) \ 350 | target $(get_target ${CEIL_RATE} $(get_mtu ${IF_NAME})) \ 351 | $(get_fq_codel_quantum ${CEIL_RATE}) \ 352 | $(get_ecn ${CEIL_RATE} ${ECN_MINRATE}) 353 | 354 | ${TC} filter add dev ${IF_NAME} parent 1: protocol all handle ${HANDLE} \ 355 | fw classid 1:${CLASS_ID} 356 | done 357 | fi 358 | 359 | # Create class for the default priority 360 | ${TC} class add dev ${IF_NAME} parent 1:1 classid 1:${DEFAULT_CLASS} htb \ 361 | rate ${DEFAULT_RATE}kbit \ 362 | ceil ${MAX_RATE}kbit prio ${DEFAULT_PRIO} \ 363 | quantum $(get_htb_quantum ${MAX_RATE}) 364 | 365 | # Set qdisc to fq_codel 366 | ${TC} qdisc replace dev ${IF_NAME} parent 1:${DEFAULT_CLASS} handle ${DEFAULT_CLASS}: fq_codel \ 367 | limit $(get_limit ${MAX_RATE}) \ 368 | target $(get_target ${MAX_RATE} $(get_mtu ${IF_NAME})) \ 369 | $(get_fq_codel_quantum ${MAX_RATE}) \ 370 | $(get_ecn ${MAX_RATE} ${ECN_MINRATE}) 371 | } 372 | 373 | apply_egress_shaping () { 374 | # Disable tso and gso for lower bandwiths 375 | ${ETHTOOL} --offload ${IF_NAME} $(get_tx_offloads ${UP_RATE}) \ 376 | > /dev/null 2>&1 || true 377 | 378 | add_prio_classes \ 379 | ${IF_NAME} \ 380 | ${UP_RATE} \ 381 | 4000 \ 382 | "${CLASS_CONFIG}" 383 | } 384 | 385 | apply_ingress_shaping () { 386 | # Disable gro for lower bandwiths 387 | ${ETHTOOL} --offload ${IF_NAME} $(get_rx_offloads ${DOWN_RATE}) \ 388 | > /dev/null 2>&1 || true 389 | 390 | # Create ingress on interface 391 | ${TC} qdisc add dev ${IF_NAME} handle ffff: ingress 392 | 393 | # Ensure the ifb interface is up 394 | ${MODPROBE} ifb 395 | ${IP} link set dev ${IFB_IF_NAME} up 396 | 397 | # Enabling ECN is recommended for ingress, so ECN_MINRATE is set to 0 398 | add_prio_classes \ 399 | ${IFB_IF_NAME} \ 400 | ${DOWN_RATE} \ 401 | 0 \ 402 | "${IFB_CLASS_CONFIG}" 403 | 404 | # Redirect all ingress traffic to IFB egress. Use prio 99 to make it 405 | # possible to insert filters earlier in the chain. 406 | ${TC} filter add dev ${IF_NAME} parent ffff: protocol all prio 99 \ 407 | u32 \ 408 | match u32 0 0 \ 409 | action mirred egress redirect dev ${IFB_IF_NAME} 410 | } 411 | 412 | apply_ingress_policing () { 413 | # Ingress policing is very unreliable unless generic receive offload is 414 | # disabled for the interface. Note that for bonds and VLAN interfaces 415 | # you have to disable gro for the actual physical NICs manually. This 416 | # greatly increases CPU-usage in most systems for higher bandwiths. 417 | ${ETHTOOL} --offload ${IF_NAME} gro off \ 418 | > /dev/null 2>&1 || true 419 | 420 | # Create ingress on interface 421 | ${TC} qdisc add dev ${IF_NAME} handle ffff: ingress 422 | 423 | local MTU=$(get_mtu ${IF_NAME}) 424 | local PHY_SPEED_MBITS=$(get_speed ${IF_NAME}) 425 | local BURST_TIME_MS=5 426 | 427 | if [[ -z ${BURST_SIZE} ]]; then 428 | BURST_SIZE_MIN=$(( ${MTU} * 10 )) 429 | BURST_SIZE=$(( ${PHY_SPEED_MBITS} * 1000 * ${BURST_TIME_MS} / 8 )) 430 | 431 | if [[ ${BURST_SIZE} -lt ${BURST_SIZE_MIN} ]]; then 432 | BURST_SIZE=${BURST_SIZE_MIN} 433 | fi 434 | fi 435 | 436 | # Police all ingress traffic. Use prio 99 to make it possible to insert 437 | # filters earlier in the chain. 438 | ${TC} filter add dev ${IF_NAME} parent ffff: protocol all prio 99 \ 439 | u32 \ 440 | match u32 0 0 \ 441 | police rate ${DOWN_RATE}kbit burst ${BURST_SIZE} mtu ${MTU} drop 442 | } 443 | 444 | convert_rate () { 445 | # Takes command line input rate as argument. 446 | # Converts rates to kbit/s. 447 | local IN_RATE=$1 448 | local RATE=0 449 | local DEFAULT_REGEX="^([0-9]+)$" 450 | local KBIT_REGEX="^([0-9]+)k$" 451 | local MBIT_REGEX="^([0-9]+)M$" 452 | 453 | if [[ ${IN_RATE} =~ ${MBIT_REGEX} ]]; then 454 | RATE=$(( ${BASH_REMATCH[1]} * 1000 )) 455 | elif [[ ${IN_RATE} =~ ${KBIT_REGEX} ]]; then 456 | RATE=${BASH_REMATCH[1]} 457 | elif [[ ${IN_RATE} =~ ${DEFAULT_REGEX} ]]; then 458 | RATE=$(( ${BASH_REMATCH[1]} * 1000 )) 459 | else 460 | echo "${IN_RATE} is not a valid rate" 461 | false 462 | fi 463 | 464 | echo ${RATE} 465 | } 466 | 467 | 468 | # Defaults 469 | CONFIG_DIR="/etc/tc-gen" 470 | 471 | while getopts ":i:u:d:b:f:q:c:C:p:xV" OPT; do 472 | case ${OPT} in 473 | i) 474 | IF_NAME="${OPTARG}" 475 | ;; 476 | u) 477 | UP_RATE=$(convert_rate ${OPTARG}) 478 | ;; 479 | d) 480 | DOWN_RATE=$(convert_rate ${OPTARG}) 481 | ;; 482 | b) 483 | BURST_SIZE="${OPTARG}" 484 | ;; 485 | f) 486 | IFB_IF_NAME="${OPTARG}" 487 | ;; 488 | c) 489 | CLASS_CONFIG="${OPTARG}" 490 | ;; 491 | C) 492 | IFB_CLASS_CONFIG="${OPTARG}" 493 | ;; 494 | p) 495 | CONFIG_DIR="${OPTARG}" 496 | ;; 497 | x) 498 | CLEAR_CONFIG=1 499 | ;; 500 | V) 501 | print_version 502 | exit 0 503 | ;; 504 | *) 505 | print_usage 506 | exit 1 507 | ;; 508 | esac 509 | done 510 | 511 | if [[ -z ${IF_NAME} ]]; then 512 | print_usage 513 | exit 1 514 | fi 515 | 516 | if [[ -n ${IFB_CLASS_CONFIG} && -z ${IFB_IF_NAME} ]]; then 517 | >&2 echo "ERROR: you must define an IFB interface to use IFB priority classes" 518 | exit 1 519 | fi 520 | 521 | if [[ -n ${CLEAR_CONFIG} ]]; then 522 | clear_all 523 | echo "Config cleared" 524 | exit 0 525 | fi 526 | 527 | if [[ -z ${UP_RATE} && -z ${DOWN_RATE} ]]; then 528 | print_config "${IF_NAME}" 529 | exit 0 530 | fi 531 | 532 | clear_all 533 | 534 | if [[ -n ${UP_RATE} ]]; then 535 | apply_egress_shaping 536 | fi 537 | 538 | if [[ -n ${DOWN_RATE} ]]; then 539 | if [[ -n ${IFB_IF_NAME} ]]; then 540 | apply_ingress_shaping 541 | else 542 | apply_ingress_policing 543 | fi 544 | fi 545 | 546 | # Execute post commands 547 | IF_POST_COMMANDS="${CONFIG_DIR}/post-commands.${IF_NAME}" 548 | IFB_POST_COMMANDS="${CONFIG_DIR}/post-commands.${IFB_IF_NAME}" 549 | 550 | for f in "${IF_POST_COMMANDS}" "${IFB_POST_COMMANDS}"; do 551 | [[ -r $f ]] && . "$f" 552 | done 553 | 554 | trap - ERR INT TERM 555 | --------------------------------------------------------------------------------