All Articles

Traffic Control

사내 프로젝트 진행 중 네트워크 트래픽을 제한해야할 일이 생겨 Traffic Control을 사용해보고, 해당 내용을 정리하였다.

Traffic Control?

  • 언제 사용할까?

    • 네트워크 사용량이 정해져 있을 때( 호스팅을 사용할 때 ) upload / download throughput을 제한할 때 사용.
    • latency 추가 등 기타 네트워크 에뮬레이션 기능이 필요할 때
  • traffic shaping
  • qdisc, class, filter

    • qdisc : qdisc로 classfy된 트래픽들이 해야할 행동 같은것을 정의. 다양한게 있지만, tc-net-emul 모듈을 이용하여 딜레이를 줘보자.
    • class : 생성된 qdisc를 거쳐가는 트래픽을 분류하여 classfying 한다.
    • filter : filter를 통해 트래픽을 분류하여 class로 보냄
  • 간략히 분류 한것이지만, 실제로는 더 많은 내용을 가지고 있다.

Script 작성해보기

요구사항

  • web-service에 band-width를 256kbps로 제한한다.
  • web-service에 latency 200ms 딜레이를 추가한다.
  • ssh는 느려지지 않았으면 좋겠다.

How to?

  • 클래스를 2개 생성한다.

    • WebService 클래스
    • SSH 클래스
  • WebService 클래스에 256KBps 제한, 200ms 딜레이 추가
  • SSH 클래스는 제한 없음.
  • filter를 정의할 때 들어온 포트로 해당 클래스를 분기한다.

스크립트

아래 Reference script 참고.

#!/bin/bash

IF=eth0
SPEED=256
PORT=8080

start() {
  echo "==================================================="
  echo "Start Traffic control script"
  echo "==================================================="

  #
  # qdisc
  #

  ### define root qdisc
  tc qdisc add dev $IF root handle 1:0 htb default 10

  #
  # class
  #

  # define default class bitrate 1Gbit
  tc class add dev $IF parent 1:0 classid 1:10 htb rate 1024mbit burst 15k

  # define ssh class bitrate 1Mbit
  tc class add dev $IF parent 1:0 classid 1:20 htb rate 1mbit burst 15k

  # define web-service class bitrate 256Kbit and add latency delay 200ms
  tc class add dev $IF parent 1:0 classid 1:30 htb rate 256kbit burst 10k
  tc qdisc add dev $IF parent 1:30 handle 30: netem delay 200ms

  #
  # filter
  #
  ### filter ssh
  tc filter add dev $IF protocol ip parent 1:0 prio 1 u32 match ip sport 22 0xffff flowid 1:20
  ### filter 8080 for web service
  tc filter add dev $IF protocol ip parent 1:0 prio 1 u32 match ip sport 8080 0xffff flowid 1:30
}

stop() {
  echo "==================================================="
  echo "Stop Traffic control script"
  echo "==================================================="

  tc qdisc del dev $IF root
}

status() {
  printf "\n--------------------------------------------------"
  printf "\n[ qdisc  ] : \n"
  tc qdisc show dev $IF
  printf "\n[ class  ] : \n"
  tc class show dev $IF
  printf "\n[ filter ] : \n"
  tc filter show dev $IF
  printf "\n--------------------------------------------------\n"
}

restart() {
  stop
  sleep 1
  start
}

case "$1" in

  start)
    start
    status
    ;;

  stop)
    stop
    status
    ;;

  status)
    status
    ;;

  *)
    pwd=$(pwd)
    echo "Usage: ./ctl {start|stop|restart|status}"
    ;;

esac

exit 0

Reference script

#!/bin/bash
#
# Copyright LMAX
#
# chkconfig: 345 99 01
# description: Add routing and traffic control rules so that we can
#              add latency and bandwidth limitations to performance tests.
# processname: latency
#
# To understand traffic control see the linux advanced routing and traffic
# control how to http://www.lartc.org/
#

export PATH=/sbin:$PATH

## configuration.
SEASIAIP=172.16.10.10
SEASIAPORT=9091
EUIP=172.16.10.10
EUPORT=9092
INTERFACE=bond0.30
LOCKFILE="/var/lock/subsys/latency"
## end of configuration

function start()
{
  ## outbound.

  tc qdisc add dev $INTERFACE root handle 1:0 htb default 10
  # default class
  tc class add dev $INTERFACE parent 1:0 classid 1:10 htb rate 1024mbit

  # "europe" traffic class - outbound bandwidth limit
  tc class add dev $INTERFACE parent 1:0 classid 1:11 htb rate 512kbit

  # "se asia" traffic class - outbound bandwidth limit
  tc class add dev $INTERFACE parent 1:0 classid 1:12 htb rate 128kbit

  # network emulation - add latency.
  tc qdisc add dev $INTERFACE parent 1:11 handle 11:0 netem delay 20ms 5ms 25% distribution normal
  tc qdisc add dev $INTERFACE parent 1:12 handle 12:0 netem delay 330ms 10ms 25% distribution normal

  # filter packets into appropriate traffic classes.
  tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dst $SEASIAIP match ip dport $SEASIAPORT 0xffff flowid 1:12
  tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dst $EUIP match ip dport $EUPORT 0xffff flowid 1:11

  ## inbound

  # inbound qdisc.
  tc qdisc add dev $INTERFACE handle ffff: ingress

  # attach a policer for "se asia" class.
  tc filter add dev $INTERFACE protocol ip parent ffff: prio 1 u32 match ip src $SEASIAIP  match ip sport $SEASIAPORT 0xffff \
   police rate 128kbit burst 10k drop flowid :1

  # attach a policer for "europe" traffic class.
  tc filter add dev $INTERFACE protocol ip parent ffff: prio 1 u32 match ip src $EUIP match ip sport $EUPORT 0xffff \
   police rate 512kbit burst 10k drop flowid :2

  #
  touch $LOCKFILE
}

function stop ()
{
  # remove any existing ingress qdisc.
  tc qdisc del dev $INTERFACE ingress
  ## remove any existing egress qdiscs
  tc qdisc del dev $INTERFACE root

  rm -f $LOCKFILE
}

function status ()
{
  echo " [1m Active Queue Disciplines for $INTERFACE  [m"
  tc -s qdisc show dev $INTERFACE
  echo
  echo " [1m Active Queueing Classes for $INTERFACE  [m"
  tc -s class show dev $INTERFACE
  echo
  echo " [1m Active Traffic Control Filters for $INTERFACE  [m"
  tc -s filter show dev $INTERFACE
}

# main

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart|reload)
    stop
    start
    ;;
  condrestart)
    if [ -f $LOCKFILE ]; then
     stop
     start
    fi
    ;;
  status)
    status
    ;;
  *)
    echo $"Usage: $0 {start|stop|restart|condrestart|status}"
    exit 1
esac

exit 0;