NetEM(Network Emulation)기능을 활용한 패킷의 지연, 중복, 유실 등을 테스트해보자. 에뮬레이션은 다양한 관점에서 활용될 수 있다. 애플리케이션의 벤치마크라든지 제품의 테스트 또는 대역폭의 제한으로까지 이용할 수 있다.
NetEM 은 크게 2개의 컴포넌트로 구성되어 있다. 큐를 위한 커널 모듈과 설정을 위한 커맨드라인 도구인 tc 가 있다. 커널모듈은 2.6.8 이후부터 통합되었고, iproute2 패키지의 한 부분이다. 여기서는 Traffic Shaping 과 관련하여 소개를 해 보고자 한다. Traffic Shaping 은 네트워크 트래픽을 제한하여 자원에 대한 우선순위를 조정한다. 사전에 정의된 분류, 정책, 큐 등을 이용하여 네트워크 자원을 필요에 따라 효과적으로 정의하는 것이다. 이것을 통해 여러분들은
- 네트워크 서비스 조절
- 대역폭의 제한
- 서비스에 대한 QoS(Quality of Service) 보장
을 통해 네트워크의 안정적인 운영, 서비스 가용성등을 확보할 수도 있다.
기본적으로 큐는 FIFO 패킷 큐 형태로 동작한다. 학교 수업때 한번쯤 들어보았을 만한 이 것은 먼저 들어온 것이 먼저 나간다는 First In First Out 개념이다.
이제 몇 가지 사용 예제를 알아볼 것인데, 여러분들이 사용하는 커널이 2.6.8 이상 이라면 특별한 설치는 필요하지 않다. 아마 대부분의 경우 사용할 수 있을 것이다.
해당 기능은 커널 컴파일 옵션시 다음 그림과 같이 선택되어 있으면 된다.
예제를 설명하기 전에 주로 'tc' 커맨드 도구를 이용하여 설명을 할 것이다. tc 의 기본적인 사용방법은 아래와 같다:
tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id |
root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]
tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid
class-id ] qdisc [ qdisc specific parameters ]
tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ]
protocol protocol prio priority filtertype [ filtertype specific param‐
eters ] flowid flow-id
tc [ FORMAT ] qdisc show [ dev DEV ]
tc [ FORMAT ] class show dev DEV
qdisc 는 Queue Discipline (qdisc) 로 패킷을 받고 서비스하기 위한 순서를 정하기 위한 어떤 룰들의 집합이라고 보면 된다. 즉, 이것은 패킷 큐로 패킷을 전송할때 어떤 알고리즘을 사용해 패킷을 보낼지 정하는 것이다. qdisc 는 Classless, Classful, Root, egress, ingress 등이 있다. Root 는 classful/classless 랑 상관없이 각 네트워크 인터페이스의 상위 qdisc 이고 egress 는 밖으로 나가는 패킷에 대해서만 동작하고 ingress 는 내부로 들어오는 트래픽에 대해서 동작한다.
- 패킷 80ms 지연하기
# tc qdisc add dev eth0 root netem delay 80ms
add 를 통해 dev 로 네트워크 인터페이스를 정의해 주고 qdisc 를 처리하기 위한 이름을 netem 로 지정하였다. 그리고 마지막으로 delay 를 80ms 주었다.
일단 정상적인 지연을 적용하기 전에 Ping 을 해 보았다. 평균적으로 0-1ms 속도가 나왔다. 하지만, 지연을 적용하고서는 다음과 같이 81ms 정도로 지연되었다.
# ping 203.255.xxx.xxx
PING 203.255.xxx.xxx (203.255.xxx.xxx) 56(84) bytes of data.
64 bytes from 203.255.xxx.xxx: icmp_req=1 ttl=244 time=81.0 ms
64 bytes from 203.255.xxx.xxx: icmp_req=2 ttl=244 time=81.0 ms
64 bytes from 203.255.xxx.xxx: icmp_req=3 ttl=244 time=81.2 ms
^C
--- 203.255.xxx.xxx ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 81.067/81.117/81.208/0.064 ms
- 패킷을 랜덤하게 지연시키기 (30ms ~ 80ms)
특정 값으로 정하기 보다는 지정된 범위안에서 랜덤하게 지연하는 것이다. 명령어 마지막에 추가적으로 값을 하나 더 지정해 주면 된다.
# tc qdisc change dev eth0 root netem delay 80ms 30ms
# ping 203.255.xxx.xxx
PING 203.255.xxx.xxx (203.255.xxx.xxx) 56(84) bytes of data.
64 bytes from 203.255.xxx.xxx: icmp_req=1 ttl=244 time=77.1 ms
64 bytes from 203.255.xxx.xxx: icmp_req=2 ttl=244 time=93.7 ms
64 bytes from 203.255.xxx.xxx: icmp_req=3 ttl=244 time=78.8 ms
64 bytes from 203.255.xxx.xxx: icmp_req=4 ttl=244 time=100 ms
^C
--- 203.255.xxx.xxx ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 77.131/87.483/100.138/9.756 ms
- 기존에 정의된 지연을 다른 값으로 변경
처음 add 를 사용한 것과 달리 change 라고만 바꿔주고 delay 시킬 값을 지정해 주면된다.
# tc qdisc change dev eth0 root netem delay 30ms
# ping 203.255.xxx.xxx
PING 203.255.xxx.xxx (203.255.xxx.xxx) 56(84) bytes of data.
64 bytes from 203.255.xxx.xxx: icmp_req=1 ttl=244 time=31.0 ms
64 bytes from 203.255.xxx.xxx: icmp_req=2 ttl=244 time=31.0 ms
64 bytes from 203.255.xxx.xxx: icmp_req=3 ttl=244 time=31.0 ms
^C
--- 203.255.xxx.xxx ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 31.024/31.062/31.090/0.205 ms
- 현재 정의된 네트워크 인터페이스의 설정 값 확인
# tc qdisc show dev eth0
qdisc netem 8001: root refcnt 2 limit 1000 delay 30.0ms
- 패킷 유실 15% 설정하기
loss 라는 파리미터를 주고 값을 입력한다. 여기서는 약 15% 정도 유실을 설정하였다.
# tc qdisc change dev eth0 root netem loss 15%
# tc qdisc show dev eth0
qdisc netem 8001: root refcnt 2 limit 1000 loss 15%
# ping 203.255.xxx.xxx
PING 203.255.xxx.xxx (203.255.xxx.xxx) 56(84) bytes of data.
64 bytes from 203.255.xxx.xxx: icmp_req=1 ttl=244 time=0.935 ms
64 bytes from 203.255.xxx.xxx: icmp_req=3 ttl=244 time=1.36 ms
64 bytes from 203.255.xxx.xxx: icmp_req=4 ttl=244 time=1.10 ms
64 bytes from 203.255.xxx.xxx: icmp_req=6 ttl=244 time=1.01 ms
64 bytes from 203.255.xxx.xxx: icmp_req=7 ttl=244 time=1.00 ms
64 bytes from 203.255.xxx.xxx: icmp_req=8 ttl=244 time=1.57 ms
^C
--- 203.255.xxx.xxx ping statistics ---
8 packets transmitted, 6 received, 25% packet loss, time 7011ms
rtt min/avg/max/mdev = 0.935/1.164/1.570/0.227 ms
ping 을 해보면 패킷이 유실되는 것 같이 지연이 발생한다.
예를들어 0.1% 라면 대략 1000개중에 1개 정도가 랜덤하게 Drop 된다고 볼 수 있다.
- 패킷 중복
# tc qdisc change dev eth0 root netem duplicate 1%
duplicate 를 이용하여 정의하면 된다.
- 패킷 깨트리기
# tc qdisc change dev eth0 root netem corrupt 0.1%
- 정의된 설정정보 제거하기
# tc qdisc del dev eth0 root
# tc qdisc show dev eth0
qdisc pfifo_fast 0: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
- 특정 IP 목적지 우선순위 조정
203.255.xxx.xxx 로 나가는 것은 Priority 를 3으로 조정하는 것이다.
# tc qdisc add dev eth0 root handle 1: prio
# tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dst 203.255.xxx.xxx/32 flowid 1:3
# tc qdisc show dev eth0
qdisc prio 1: root refcnt 2 bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
- 패킷 대역폭 정의하기
# tc qdisc add dev eth0 root handle 1:0 netem delay 100ms
# tc qdisc add dev eth0 parent 1:1 handle 10: tbf rate 256kbit buffer 1600 limit 3000
# tc -s qdisc ls dev eth0
qdisc netem 1: root refcnt 2 limit 1000 delay 100.0ms
Sent 306774 bytes 4269 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 5p requeues 0
qdisc tbf 10: parent 1:1 rate 256000bit burst 1600b lat 43.8ms
Sent 305784 bytes 4254 pkt (dropped 0, overlimits 3 requeues 0)
backlog 0b 5p requeues 0
지연을 100ms 로 지정하였고, 대역폭을 256Kbit 로 설정하였다.
이상 여기까지 간단히 NetEM 을 이용한 트래픽 제어를 살펴보았다. 간단하게만 언급하였으니 세부적인 것은 Man Page 등을 살펴보길 바란다.
[참고]
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem