├── .gitignore ├── LICENSE ├── README.md └── lossy /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Dmitry Murashenkov 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 | # lossy 2 | Wrapper for linux tc and netem tools. Simulate lossy/shaped networks the easy way. 3 | 4 | Lossy uses tc (traffic control) to build a chain of qdiscs (queues for packets) and simulate packet loss, delay 5 | or limited network bandwidth. It uses standard netem (network emulator) and tbf (token bucket filter) qdiscs for 6 | that purpose. 7 | 8 | However using tc directly can be tricky because of several known issues, so this tool is made to simplify usage and 9 | provide built-in detection/workarounds for some problems. 10 | 11 | Lossy sets rules that match incoming/outgoing traffic and applies policies to these packets: 12 | * To enabled packet loss/delay specify netem settings (it is better to check 'man netem' for detailed description. 13 | * To limit network bandwidth specify tbf settings (see 'man tbf') 14 | 15 | #Usage 16 | 17 | ``` 18 | Usage: sudo lossy -n 'delay 100ms 10ms 25% loss 0.1%' \ 19 | -t 'rate 0.5mbit burst 10kb limit 10k' \ 20 | --from 127.0.0.1:* \ 21 | --to *:80 22 | ``` 23 | 24 | Options: 25 | 26 | ``` 27 | -s 28 | Print status. 29 | 30 | -c 31 | Clear all rules. 32 | 33 | -t|--tbf 34 | Set network shaping setting that are passed to token bucket filter. 35 | Example 'rate 0.5mbit burst 10kb limit 10k'. 36 | See 'man tbf' for details. Default ''. 37 | 38 | -n|--netem 39 | Set delay/loss settings that are passed to netem. 40 | Example 'delay 100ms 10ms 25% loss 0.1%'. 41 | See 'man netem' for details. Default ''. 42 | 43 | --from 44 | Match only packets from this address. 45 | Example '127.0.0.1:80', '*:80', '127.0.0.1/24:*', '*:*'. 46 | Special value 'none' - match none. 47 | Default 'none'. 48 | Host with mask can be specified. 49 | 50 | --to 51 | Match only packets from to this address. 52 | Example '127.0.0.1:80', '*:80', '127.0.0.1/24:*', '*:*'. 53 | Special value 'none' - match none. 54 | Default 'none'. 55 | Host with mask can be specified. 56 | 57 | -i|--interface 58 | Matches only on this interface. 59 | Example 'eth0', 'lo'. 60 | Default 'eth0'. 61 | 62 | -r|--reorder-if-jitter 63 | If jitter is specified for netem then should it reorder packets or send them in order. 64 | Default 'false' - send in order. 65 | 66 | -e|--exclude-ports 67 | Exclude traffic to/from this port from any host from matching. 68 | Used to prevent setting up rule that affects ssh session you run lossy in. 69 | Example '22,80'. 70 | Several port can be specified separated by comma. 71 | Default '22'. 72 | ``` 73 | 74 | # Important notes 75 | 76 | * Must be run as root. 77 | 78 | * All changes are cleared after reboot 79 | 80 | * Clears existing rules on specified interface before adding new rules, so if you launched it with '-i eth0' and then '-i lo' 81 | then rules on eth0 will remain. When invoking lossy with -c you can also add -i to specify interface to clear. 82 | 83 | * Options --from and --to each is applied both to incoming and outgoing traffic. Example: -netem 'delay 100ms' --to '*:*', 84 | we ping this machine and get 200ms roundtrip time because incoming packets matches *:* and reply packet also matches rule. 85 | If you want to affect only upstream/downstream you will have to specify ip or mask so that packets to/from this machine 86 | are not matched. Example: this machine has ip 192.168.1.1 and we add rule --to 192.168.1.1 this will result in 100ms 87 | rountrip, incoming packets will have 100ms delay while outgoing will have 0ms delay. 88 | 89 | * Lossy uses ethtool to verify environment correctness, it is not required to run, but may tell you about some problems 90 | that can cause incorrect behavior. 91 | 92 | * All settings are applied both to outgoing traffic and incoming traffic, so if you specify delay 100ms then roundtrip 93 | time will be 200ms. Use --from and --to to match packets more granularly. 94 | 95 | * Remember that your ssh session is affected by lossy also (if you alter -e option at least), so if you specify large 96 | delay, jitter, packet loss you may not be able to disable it via ssh. However all settings are reset after system reboot. 97 | 98 | * If both tbf and netem enabled then netem goes after tbf. 99 | 100 | * No need to specify 'limit' in tbf settings if netem is enabled, because netem also has 'limit' option and internal 101 | pfifo qdisc, so traffic will mainly be affected by this setting which we set to 1000 (packets) by default. 102 | 103 | * If 'large segment offload' option (also known as TSO/GSO) is enabled in kernel (check with 'ethtool -k eth0') then 104 | inside kernel packets can be larger than MTU and be broken into MTU-size chunks only by network interface. This leads 105 | to tbf limiting speed to very low value (10-20Kb/sec) despite of settings. If this is the case recommended approach 106 | is to disable TSO/GSO, this doesn't affect functionality, but may slightly increase CPU usage in case of large amounts 107 | of traffic. 108 | 109 | * Netem has a reordering bug/feature - if jitter is specified like 'delay 100ms 50ms' then packets will be reordered. Docs 110 | suggest adding child pfifo qdisc, but it doesn't work in 3.2-4.2 kernels, but there is undocumented behavior that if 111 | 'rate' netem option is specified then no reordering occurs. Option was added in attempt to bring tbf functionality into 112 | netem but has this side effect. So we simply have -r flag to prevent reordering, it results in adding large 'rate' value. 113 | Seems several rates can be specified and the last one takes effect so we prepend our value to allow overriding. 114 | 115 | * When configuring tbf set burst and limit high enough. Min burst is rate/250 (HZ=250 in many linux kernels) so 40k is 116 | required to reach 10Mb/sec speed. Sometimes packets can even fail to queue at all if limit is low (-s shows drops 117 | increasing, but sent bytes stays the same) so always verify your configuration with iperf and ping tools. 118 | -------------------------------------------------------------------------------- /lossy: -------------------------------------------------------------------------------- 1 | #!/bin/bash +x 2 | 3 | #netem has inner queue if packets (implemented as a pfifo qdisc) so if both netem and tbf are enabled 4 | #and netem goes after tbf then total traffic will be limited by netem's "limit" option and tbf's "limit" 5 | #won't have any effect 6 | #netem "limit" option has same meaning as tbf "limit" option so in typical case of mss=1.5Kb 7 | #10 pkts will mean 15Kb 8 | TBF_BUFFER_SIZE_PKTS=1000 9 | 10 | INTERFACE="eth0" 11 | FROM='none' 12 | TO='none' 13 | TBF_SETTINGS='' 14 | NETEM_SETTINGS='' 15 | NETEM_REORDER_IF_JITTER='false' 16 | ACTION="enable" 17 | EXCLUDE_PORTS="22" 18 | 19 | usage() 20 | { 21 | echo " 22 | Usage: sudo lossy -n 'delay 100ms 10ms 25% loss 0.1%' \ 23 | -t 'rate 0.5mbit burst 10kb limit 10k' \ 24 | --from 127.0.0.1:* \ 25 | --to *:80 26 | 27 | Wrapper for linux tc and netem tools. Simulate lossy/shaped networks the easy way. 28 | 29 | Lossy uses tc (traffic control) to build a chain of qdiscs (queues for packets) and simulate packet loss, delay 30 | or limited network bandwidth. It uses standard netem (network emulator) and tbf (token bucket filter) qdiscs for 31 | that purpose. 32 | 33 | However using tc directly can be tricky because of several known issues, so this tool is made to simplify usage and 34 | provide built-in detection/workarounds for some problems. 35 | 36 | Lossy sets rules that match incoming/outgoing traffic and applies policies to these packets: 37 | * To enabled packet loss/delay specify netem settings (it is better to check 'man netem' for detailed description. 38 | * To limit network bandwidth specify tbf settings (see 'man tbf') 39 | 40 | Options: 41 | 42 | -s 43 | Print status. 44 | 45 | -c 46 | Clear all rules. 47 | 48 | -t|--tbf 49 | Set network shaping setting that are passed to token bucket filter. 50 | Example 'rate 0.5mbit burst 10kb limit 10k'. 51 | See 'man tbf' for details. Default ''. 52 | 53 | -n|--netem 54 | Set delay/loss settings that are passed to netem. 55 | Example 'delay 100ms 10ms 25% loss 0.1%'. 56 | See 'man netem' for details. Default ''. 57 | 58 | --from 59 | Match only packets from this address. 60 | Example '127.0.0.1:80', '*:80', '127.0.0.1/24:*', '*:*'. 61 | Special value 'none' - match none. 62 | Default 'none'. 63 | Host with mask can be specified. 64 | 65 | --to 66 | Match only packets from to this address. 67 | Example '127.0.0.1:80', '*:80', '127.0.0.1/24:*', '*:*'. 68 | Special value 'none' - match none. 69 | Default 'none'. 70 | Host with mask can be specified. 71 | 72 | -i|--interface 73 | Matches only on this interface. 74 | Example 'eth0', 'lo'. 75 | Default 'eth0'. 76 | 77 | -r|--reorder-if-jitter 78 | If jitter is specified for netem then should it reorder packets or send them in order. 79 | Default 'false' - send in order. 80 | 81 | -e|--exclude-ports 82 | Exclude traffic to/from this port from any host from matching. 83 | Used to prevent setting up rule that affects ssh session you run lossy in. 84 | Example '22,80'. 85 | Several port can be specified separated by comma. 86 | Default '22'. 87 | 88 | Important notes: 89 | 90 | * Must be run as root. 91 | 92 | * All changes are cleared after reboot 93 | 94 | * Clears existing rules on specified interface before adding new rules, so if you launched it with '-i eth0' and then '-i lo' 95 | then rules on eth0 will remain. When invoking lossy with -c you can also add -i to specify interface to clear. 96 | 97 | * Options --from and --to each is applied both to incoming and outgoing traffic. Example: -netem 'delay 100ms' --to '*:*', 98 | we ping this machine and get 200ms roundtrip time because incoming packets matches *:* and reply packet also matches rule. 99 | If you want to affect only upstream/downstream you will have to specify ip or mask so that packets to/from this machine 100 | are not matched. Example: this machine has ip 192.168.1.1 and we add rule --to 192.168.1.1 this will result in 100ms 101 | rountrip, incoming packets will have 100ms delay while outgoing will have 0ms delay. 102 | 103 | * Lossy uses ethtool to verify environment correctness, it is not required to run, but may tell you about some problems 104 | that can cause incorrect behavior. 105 | 106 | * All settings are applied both to outgoing traffic and incoming traffic, so if you specify delay 100ms then roundtrip 107 | time will be 200ms. Use --from and --to to match packets more granularly. 108 | 109 | * Remember that your ssh session is affected by lossy also (if you alter -e option at least), so if you specify large 110 | delay, jitter, packet loss you may not be able to disable it via ssh. However all settings are reset after system reboot. 111 | 112 | * If both tbf and netem enabled then netem goes after tbf. 113 | 114 | * No need to specify 'limit' in tbf settings if netem is enabled, because netem also has 'limit' option and internal 115 | pfifo qdisc, so traffic will mainly be affected by this setting which we set to 1000 (packets) by default. 116 | 117 | * If 'large segment offload' option (also known as TSO/GSO) is enabled in kernel (check with 'ethtool -k eth0') then 118 | inside kernel packets can be larger than MTU and be broken into MTU-size chunks only by network interface. This leads 119 | to tbf limiting speed to very low value (10-20Kb/sec) despite of settings. If this is the case recommended approach 120 | is to disable TSO/GSO, this doesn't affect functionality, but may slightly increase CPU usage in case of large amounts 121 | of traffic. 122 | 123 | * Netem has a reordering bug/feature - if jitter is specified like 'delay 100ms 50ms' then packets will be reordered. Docs 124 | suggest adding child pfifo qdisc, but it doesn't work in 3.2-4.2 kernels, but there is undocumented behavior that if 125 | 'rate' netem option is specified then no reordering occurs. Option was added in attempt to bring tbf functionality into 126 | netem but has this side effect. So we simply have -r flag to prevent reordering, it results in adding large 'rate' value. 127 | Seems several rates can be specified and the last one takes effect so we prepend our value to allow overriding. 128 | 129 | * When configuring tbf set burst and limit high enough. Min burst is rate/250 (HZ=250 in many linux kernels) so 40k is 130 | required to reach 10Mb/sec speed. Sometimes packets can even fail to queue at all if limit is low (-s shows drops 131 | increasing, but sent bytes stays the same) so always verify your configuration with iperf and ping tools. 132 | " 133 | } 134 | 135 | status() 136 | { 137 | echo "Outgoing traffic settings for interface $INTERFACE" 138 | tc qdisc show dev $INTERFACE 139 | tc -s filter show dev $INTERFACE 140 | echo 141 | echo "Incoming traffic settings for interface $INTERFACE" 142 | tc qdisc show dev ifb0 143 | tc -s filter show dev ifb0 144 | echo 145 | echo "Statistics for interface $INTERFACE" 146 | tc -s qdisc ls 147 | } 148 | 149 | clear() 150 | { 151 | echo "Clearing rules for interface $INTERFACE" 152 | tc qdisc del dev $INTERFACE root 153 | tc qdisc del dev $INTERFACE ingress 154 | tc qdisc del dev ifb0 root 155 | } 156 | 157 | checkTSO() 158 | { 159 | if ! hash ethtool 2>/dev/null; then 160 | echo "Recommend installing ethtool so we can verify environment correctness and report possible problems (not required)" 161 | return 162 | fi 163 | 164 | if [ "x" != "x$TBF_SETTINGS" ]; then 165 | #If "Large segment offload" (also called TSO/GSO) kernel option is enabled 166 | #then kernel may operate large packets (like MTU is 16K for example) internally 167 | #and only when packet reaches network interface it is broken into network-MTU-size 168 | #chunks. 169 | #In this options is on and TBF enabled then it will limit speed to very low value (10-20Kb/sec) 170 | #despite of applied settings. Disabling TSO/GSO doesn't affect functionality but 171 | #may cause some CPU overhead (not a problem unless you have really much traffic). 172 | if ethtool -k $INTERFACE | egrep 'tcp-segmentation-offload: on|generic-segmentation-offload: on' > /dev/null ; then 173 | echo "TSO/GSO must be disabled for network interface with following command (otherwise TBF works incorrectly): ethtool -K $INTERFACE tso off gso off" 174 | exit 1 175 | fi 176 | fi 177 | } 178 | 179 | checkRoot() 180 | { 181 | if [[ $EUID -ne 0 ]]; then 182 | echo "This script must be run as root" 183 | exit 1 184 | fi 185 | } 186 | 187 | buildFromFilter() 188 | { 189 | FILTER="" 190 | if [ "none" == "$FROM" ]; then 191 | return 192 | elif [ "x" != "x$FROM" ]; then 193 | IP=`getIp "$FROM"` 194 | PORT=`getPort "$FROM"` 195 | if [ "x" != "x$IP" ]; then 196 | FILTER="$FILTER match ip src $IP" 197 | else 198 | #if ip not specified then we need to match all packets 199 | FILTER="$FILTER match ip src 0/0" 200 | fi 201 | 202 | if [ "x" != "x$PORT" ]; then 203 | FILTER="$FILTER match ip sport $PORT 0xffff" 204 | fi 205 | fi 206 | 207 | echo $FILTER 208 | } 209 | 210 | buildToFilter() 211 | { 212 | FILTER="" 213 | if [ "none" == "$TO" ]; then 214 | return 215 | elif [ "x" != "x$TO" ]; then 216 | IP=`getIp "$TO"` 217 | PORT=`getPort "$TO"` 218 | if [ "x" != "x$IP" ]; then 219 | FILTER="$FILTER match ip dst $IP" 220 | else 221 | #if ip not specified then we need to match all packets 222 | FILTER="$FILTER match ip dst 0/0" 223 | fi 224 | 225 | if [ "x" != "x$PORT" ]; then 226 | FILTER="$FILTER match ip dport $PORT 0xffff" 227 | fi 228 | fi 229 | 230 | echo $FILTER 231 | } 232 | 233 | 234 | addExcludePortFilter() 235 | { 236 | if [ "x" != "x$EXCLUDE_PORTS" ]; then 237 | IFS=',' read -r -a PORTS <<< "$EXCLUDE_PORTS" 238 | for PORT in "${PORTS[@]}" 239 | do 240 | eval "tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip src 0/0 match ip sport $PORT 0xffff flowid 1:1" 241 | eval "tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip src 0/0 match ip dport $PORT 0xffff flowid 1:1" 242 | eval "tc filter add dev ifb0 protocol ip parent 2:0 prio 1 u32 match ip src 0/0 match ip dport $PORT 0xffff flowid 2:1" 243 | eval "tc filter add dev ifb0 protocol ip parent 2:0 prio 1 u32 match ip src 0/0 match ip dport $PORT 0xffff flowid 2:1" 244 | done 245 | fi 246 | } 247 | 248 | enableEgress() 249 | { 250 | #first add prio queue to split traffic - with it we can apply limits to single band 251 | tc qdisc add dev $INTERFACE root handle 1: prio 252 | PARENT_QDISC_HANDLE="1:3" 253 | 254 | if [ "x" != "x$TBF_SETTINGS" ]; then 255 | eval "tc qdisc add dev $INTERFACE parent $PARENT_QDISC_HANDLE handle 10: tbf $TBF_SETTINGS" 256 | PARENT_QDISC_HANDLE="10:0" 257 | fi 258 | 259 | if [ "x" != "x$NETEM_SETTINGS" ]; then 260 | eval "tc qdisc add dev $INTERFACE parent $PARENT_QDISC_HANDLE handle 11: netem $NETEM_SETTINGS limit $TBF_BUFFER_SIZE_PKTS" 261 | fi; 262 | 263 | FROM_FILTER=`buildFromFilter` 264 | TO_FILTER=`buildToFilter` 265 | if [ "x" != "x$FROM_FILTER" ]; then 266 | eval "tc filter add dev $INTERFACE protocol ip parent 1:0 prio 3 u32 $FROM_FILTER flowid 1:3" 267 | fi; 268 | if [ "x" != "x$TO_FILTER" ]; then 269 | eval "tc filter add dev $INTERFACE protocol ip parent 1:0 prio 3 u32 $TO_FILTER flowid 1:3" 270 | fi; 271 | } 272 | 273 | enableIngress() 274 | { 275 | #tc exists to control how we send (egress) traffic and it is expected that we want 276 | #to process received (ingress) traffic without introducing any queues however for test 277 | #purposes we may want to shape incoming traffic so we have to redirect it via virtual interface 278 | #and handle it like it is egress traffic 279 | modprobe ifb 280 | ip link set dev ifb0 up 281 | tc qdisc add dev $INTERFACE ingress 282 | tc filter add dev $INTERFACE parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0 283 | 284 | tc qdisc add dev ifb0 root handle 2: prio 285 | PARENT_QDISC_HANDLE="2:3" 286 | 287 | if [ "x" != "x$TBF_SETTINGS" ]; then 288 | eval "tc qdisc add dev ifb0 parent $PARENT_QDISC_HANDLE handle 20: tbf $TBF_SETTINGS" 289 | PARENT_QDISC_HANDLE="20:0" 290 | fi 291 | 292 | if [ "x" != "x$NETEM_SETTINGS" ]; then 293 | eval "tc qdisc add dev ifb0 parent $PARENT_QDISC_HANDLE handle 21: netem $NETEM_SETTINGS limit $TBF_BUFFER_SIZE_PKTS" 294 | fi; 295 | 296 | FROM_FILTER=`buildFromFilter` 297 | TO_FILTER=`buildToFilter` 298 | if [ "x" != "x$FROM_FILTER" ]; then 299 | eval "tc filter add dev ifb0 protocol ip parent 2:0 prio 3 u32 $FROM_FILTER flowid 1:3" 300 | fi; 301 | if [ "x" != "x$TO_FILTER" ]; then 302 | eval "tc filter add dev ifb0 protocol ip parent 2:0 prio 3 u32 $TO_FILTER flowid 1:3" 303 | fi; 304 | } 305 | 306 | enable() 307 | { 308 | checkTSO 309 | enableEgress 310 | enableIngress 311 | addExcludePortFilter 312 | echo 'New settings applied' 313 | } 314 | 315 | getIp() 316 | { 317 | OIFS="$IFS" 318 | IFS=':' 319 | read -a IP_PORT <<< "$1" 320 | IFS="$OIFS" 321 | #if wildcard is given output empty string to match everything 322 | echo "${IP_PORT[0]}" | tr -d '*' 323 | } 324 | 325 | getPort() 326 | { 327 | OIFS="$IFS" 328 | IFS=':' 329 | read -a IP_PORT <<< "$1" 330 | IFS="$OIFS" 331 | shift 332 | #if wildcard is given output empty string to match everything 333 | echo "${IP_PORT[1]}" | tr -d '*' 334 | } 335 | 336 | printArgs() 337 | { 338 | echo "Interface: $INTERFACE" 339 | echo "From: ${FROM:-*:*}" 340 | echo "To: ${TO:-*:*}" 341 | echo "Exclude ports: $EXCLUDE_PORTS" 342 | echo "TBF settings: $TBF_SETTINGS" 343 | echo "Netem settings: $NETEM_SETTINGS" 344 | echo "Reorder packets during jitter: $NETEM_REORDER_IF_JITTER" 345 | } 346 | 347 | if [ "$#" == 0 ]; then 348 | usage 349 | exit 0 350 | fi 351 | 352 | while [[ $# -gt 0 ]] 353 | do 354 | key="$1" 355 | 356 | case $key in 357 | 358 | -h|--help|'-?') 359 | usage 360 | exit 0 361 | ;; 362 | 363 | -s|--status) 364 | ACTION="status" 365 | ;; 366 | 367 | -t|--tbf) 368 | shift 369 | TBF_SETTINGS=$1 370 | ;; 371 | 372 | -n|--netem) 373 | shift 374 | NETEM_SETTINGS=$1 375 | ;; 376 | 377 | --from) 378 | shift 379 | FROM=$1 380 | ;; 381 | 382 | --to) 383 | shift 384 | TO=$1 385 | ;; 386 | 387 | -i|--interface) 388 | shift 389 | INTERFACE=$1 390 | ;; 391 | 392 | -r|--reorder-if-jitter) 393 | shift 394 | NETEM_REORDER_IF_JITTER=$1 395 | ;; 396 | 397 | -c|--clear) 398 | ACTION="clear" 399 | ;; 400 | 401 | -e|--exclude-port) 402 | shift 403 | EXCLUDE_PORTS=$1 404 | ;; 405 | 406 | *) 407 | echo "Unknown option $key" 408 | exit 1 409 | ;; 410 | 411 | esac 412 | shift 413 | done 414 | 415 | if [ "clear" == "$ACTION" ]; then 416 | checkRoot 417 | clear 418 | exit 0 419 | elif [ "status" == "$ACTION" ]; then 420 | status 421 | exit 0 422 | elif [ "enable" == "$ACTION" ]; then 423 | if [ "false" == "$NETEM_REORDER_IF_JITTER" ] && [ "x" != "x$NETEM_SETTINGS" ]; then 424 | #latest version of netem only prevents reorder if rate is added 425 | NETEM_SETTINGS="rate 10Gbit $NETEM_SETTINGS" 426 | fi 427 | 428 | checkRoot 429 | printArgs 430 | clear 431 | enable 432 | 433 | if [ "false" == "$NETEM_REORDER_IF_JITTER" ] && [ "x" != "x$NETEM_SETTINGS" ]; then 434 | #check that 'rate' param is supported and was set 435 | if ! tc -s qdisc ls | grep netem | grep rate &>/dev/null; then 436 | echo "This netem version always reorders packets based on jitter, -r option omitted" 437 | fi 438 | fi 439 | fi 440 | --------------------------------------------------------------------------------