macOS X has many FreeBSD-based subsystems and packet filtering is not an exception. Currently macOS X has pf which is originally from OpenBSD and also in FreeBSD.

macOS X는 많은 부분이 FreeBSD 기반인데 패킷 필터링 시스템도 그렇습니다. 현재 macOS의 패킷 필터는 pf 라고 하는데 원래 OpenBSD 에서 개발되어 FreeBSD 로 포팅된 것입니다.

For traffic shaping, FreeBSD has dummynet and macOS X has dummynet as well with use of pf. You may use Network Link Conditioner UI but sometimes you want to control via a command line interface. Here is how to configure dummynet on macOS X for the command line use. I tested on Mojave but it seems to work in Catalina too.

트래픽 제어를 위해서 FreeBSD에는 dummynet이 있고 macOS X에도 pf와 사용할 수 있도록 dummynet이 있습니다. Network Link Conditioner의 UI를 사용해도 가능 합니다만 명령행 인터페이스로 제어하는 것이 더 나을 때도 있습니다. 다음은 macOS X 명령행에서 dummynet을 이용한 트래픽 제어를 설정하는 방법입니다. Mojave에서 주로 테스트 되었습니다만 Catalina 에서도 되는 것으로 보입니다.

Prerequisite

Nothing if you have a running macOS X. To enable pf, you need to run the following:

macOS X가 있다면 추가로 필요한 것은 없습니다. 다음 명령을 실행해서 pf 패킷 필터를 활성화해 줍니다:

% sudo pfctl -E
No ALTQ support in kernel
ALTQ related functions disabled
pf enabled
Token : 11635722348223850675

dummynet

To demonstrate, let’s say I have a VMware guest VM (or container) running linux and want to set up a traffic shaping between your host macOS and a guest VM, and you want to limit the network as follows:

  • 20ms RTT, 20Mbit/sec download and upload
  • No packet loss

예를 들어 리눅스가 돌고 있는 VMWare 게스트 VM (또는 컨테이너)이 있다고 하고 호스트 macOS와 이 VM 사이에서 트래픽 속도 제어를 하고 싶다고 해 봅시다. 다음 조건으로 생각해 봅니다:

  • 20ms RTT, 업로드/다운로드 모두 20Mbit/초
  • 패킷 손실 없음

At first you want to create a dummynet config, as follows. Note that this is a shell command, not a configuration file.

먼저 dummynet 설정을 만들어야 합니다. 아래는 쉘에서 실행하는 명령이라는 점에 유의 하세요.

% dnctl pipe delete 1
% dnctl pipe delete 2
% dnctl pipe 1 config bw 20Mbit/s delay 10
% dnctl pipe 2 config bw 20Mbit/s delay 10

dnctl is a command line utility for dummynet. It doesn’t exist in FreeBSD because dummynet was integrated with ipfw directly, but macOS X has a separate command line utility.

Here I create 2 pipes, one for upstream and one for downstream. bw 20Mbit/sec is a bandwidth config and delay 10 is one way latency which is 10ms. We have a 2 pipes in each direction so the round trip time is 20ms.

dnctl은 dummynet 설정용 명령행 유틸리티입니다. FreeBSD는 ipfw 설정에서 바로 dummynet 설정이 가능한 관계로 이 유틸리티가 없습니다만 macOS X에서는 별도의 프로그램으로 존재합니다.

여기서는 두개의 파이프를 만드는데 업로드용과 다운로드용입니다. bw 20Mbit/sec은 대역폭을 지정하는 것이고 delay 10은 단방향 지연 시간을 10ms로 지정하는 것입니다. 파이프가 두 방향으로 하나씩 존재하므로 왕복 지연 시간 (RTT)는 20ms가 됩니다.

PF config

Now we need to apply this config to a connection. Let’s say the VM network interface is vmnet8 and you only want to apply to port 80/tcp, then you can add the following to /etc/pf.conf, or you can have a separate file.

이제 이 설정을 적용할 것입니다. VM의 네트워크 인터페이스 (호스트 측)이 vmnet8이고 TCP 80번 포트에만 적용하고 싶다면 다음과 같은 내용으로 설정 파일을 만듭니다. /etc/pf.conf에 추가해도 되고 별도의 파일을 만들어도 됩니다.

dummynet out proto tcp from any port 80 to any pipe 1
dummynet out proto tcp from any to any port 80 pipe 2

This will apply dummynet pipe 1 config from 80/tcp to outgoing, and pipe 2 to the traffic incoming to 80/tcp. You can make an asymmetric network (e.g. Cable network) by using a different dummynet config for each pipe.

이는 pipe 1을 80번 포트에서 나가는 트래픽에 적용하고 pipe 2를 80번 포트로 들어오는 트래픽에 적용 합니다. 네트워크가 비대칭인 경우 (e.g. 케이블 네트워크) 각 pipe 에 서로 다른 dummynet 설정을 적용할 수 있습니다.

Applying the change

Now you have dummynet and pf config, update pf with the change:

dummynetpf설정이 다 되었으므로 실제로 적용해 봅니다:

% sudo pfctl -F dummynet
% sudo pfctl -i vmnet8 -f /etc/pf.conf

-F dummynet will flush the current dummynet config.

-F dummynet 은 기존의 dummynet 설정을 초기화합니다.

-i vmnet8 is for specifying a network interface to apply the config. If missing it will apply to every interface so better to specify which one to use. You can specify the IP block in pf config too.

-i vmnet8은 설정을 적용할 네트워크 인터페이스 이름입니다. 만약 지정하지 않으면 전체 인터페이스에 적용 되므로 사용할 인터페이스명을 지정하는 것이 좋습니다. pf 설정시에는 IP 대역을 지정하는 것도 가능 합니다.

Verify the change

Let’s use iperf (v2) to verify the change:

iperf (버전 2)를 사용해서 실제 적용 여부를 확인해 봅시다.

Linux VM Guest

In a guest VM, run iperf as a server mode at 80/tcp.

게스트 VM 안에서 서버 모드로 TCP 포트 80에 iperf 를 실행 합니다.

% iperf -s -p 80
Hostname is vm (for client connection below).

macOS X Host - Before dummynet

This is a raw speed between macOS host and linux guest before dummynet change.

dummynet설정을 적용하기 전에 호스트와 게스트 간의 최대 속도를 측정해 봅니다.

$ iperf -c vm -p 80
------------------------------------------------------------
Client connecting to nginx-ssl, TCP port 80
TCP window size: 185 KByte (default)
------------------------------------------------------------
[ 6] local 172.16.127.1 port 61434 connected with 172.16.127.140 port 80
[ ID] Interval    Transfer   Bandwidth
[ 6] 0.0-10.1 sec 2.22 GBytes 1.89 Gbits/sec

macOS X Host - After dummynet

This is after we applied the dummynet config (20Mbit/sec) above:

이제 위에서 한 대로 dummynet설정 (20Mbit/sec) 을 적용해 보고 다시 측정해 봅니다.

$ iperf -c vm -p 8444
------------------------------------------------------------
Client connecting to nginx-ssl, TCP port 80
TCP window size: 129 KByte (default)
------------------------------------------------------------
[ 6] local 172.16.127.1 port 61449 connected with 172.16.127.140 port 80
[ ID] Interval    Transfer   Bandwidth
[ 6] 0.0-10.1 sec 23.2 MBytes 19.4 Mbits/sec

It works!

잘 되는군요!

Reset the change

You can simply clear the dummynet config by:

dummynet설정은 다음 명령으로 삭제할 수 있습니다.

$ sudo pfctl -F dummynet
No ALTQ support in kernel
ALTQ related functions disabled
dummynet cleared

Or disable pf if you don’t use it at all:

pf를 더 이상 사용하지 않겠다면 비활성화시키는 것이 좋습니다.

$ sudo pfctl -d
No ALTQ support in kernel
ALTQ related functions disabled
pf disabled

Conclusion

You can use dummynet in macOS X for configuring a traffic shaper if you need to run some test locally but want to simulate some network. In this case you can also configure tc on the linux VM side, but if you don’t have a VM or don’t want to change VM (or a container) config, this way will work great.

테스트를 PC 안에서 할 때 네트워크 상황을 시뮬레이션하고 싶은 경우를 위해서 macOS X의 dummynet을 이용한 트래픽 속도 제어 기능을 사용할 수 있습니다. 물론 linux 쪽에서 tc를 사용하는 방법도 있습니다만 VM이 아니거나 VM/컨테이너 설정을 바꾸고 싶지 않을 때 이 방법이 유용합니다.

Note that dummynet has many parameters to config; you can add a packet loss by plr (e.g. plr 0.01 will make a 1% packet loss) and tune queue value if you want to simulate a high BDP network.

dummynet에는 설명하지 않은 많은 기능이 더 있습니다. 가령 plr 로 패킷 손실율을 지정할 수도 있고 (plr 0.01 이라고 지정하면 1% 의 패킷 손실을 발생합니다) queue값을 조정해서 BDP값이 큰 네트워크에 알맞은 큐 크기를 지정할 수도 있습니다.

For more information, please see dnctl, dummynet and pfctl man page in your macOS X.

자세한 내용은 macOS X의 dnctl, dummynet, pfctl 매뉴얼 페이지를 참조하세요.

Also, recently I have found an interesting tool named throttle working both on macOS and Linux, doing the steps in the blog automatically in one command. You may try this as well.

또한 최근에 throttle 이라는 도구를 알게 되었는데 이건 macOS 와 Linux 에서 모두 동작 하고 위에서 설명한 내용을 자동적으로 설정해 주는 것으로 보입니다. 대신 해 보셔도 좋을것 같네요.