iptablesとnftablesで25万ルール詰め込む場合の話

Posted on 2018/07/10(Tue) 23:45 in technical

さまり

iptablesはAPIが古い設計なので、フィルタルールの追加時には全データをユーザランドにコピーして、再ストアする動きをする。

そのため、ルール数が多くなるとフィルタルールの追加に時間がかかるようになる。

対して、Linuxの次期標準ファイアウォールアプリケーションとして開発されているnftablesはその点が解消されており、フィルタルールの追加が高速に行われるようになっている。

今日は25万個のルールを詰め込んでみて、その差を体感してみようと思う。

環境

環境には、仮想マシンに入れたUbuntu 18.04を準備した。おおよそ以下の通り。

# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
# uname -a
Linux kanade 4.15.0-23-generic #25-Ubuntu SMP Wed May 23 18:02:16 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
# iptables -V
iptables v1.6.1

また、nftablesを実行する環境は、上記から以下の変更を加えたものになる。

# apt update
# apt install -y nftables iptables-nftables-compat
# apt purge -y iptables
# nft -v
nftables v0.8.2 (Joe Btfsplk)

測定方法

適当なコマンドをペタペタ貼り付けたファイルを用意して、これを実行した。

基本的にはiptablesとnftablesでほぼ互換の設定をしているはず。

要点は、以下の通り。

  • 全部で25万個のルールがINPUTチェインに追加される
  • サンプル点は50回に1回の5000点

iptables

#!/bin/bash

RUN_LOG="iptables_rule250k.log"
APPEND_LOG="iptables_rule250k_append.log"
INSERT_LOG="iptables_rule250k_insert.log"

echo "#user,system,elapsed" > ${APPEND_LOG}
echo "#user,system,elapsed" > ${INSERT_LOG}
iptables -F INPUT
iptables -L INPUT > ${RUN_LOG}

for dport in $(seq 60001 65000)
do
    for sport in $(seq 50001 50049)
    do
        iptables -A INPUT -p tcp --sport ${sport} --dport ${dport} -j DROP
    done
    /usr/bin/time -f "%U,%S,%E" iptables -A INPUT -p tcp --sport 50050 --dport ${dport} -j DROP &>> ${APPEND_LOG}
done

iptables -L INPUT | wc -l >> ${RUN_LOG}
iptables -F INPUT
iptables -L INPUT >> ${RUN_LOG}

for dport in $(seq 60001 65000)
do
    for sport in $(seq 50001 50049)
    do
        iptables -I INPUT 1 -p tcp --sport ${sport} --dport ${dport} -j DROP
    done
    /usr/bin/time -f "%U,%S,%E" iptables -I INPUT 1 -p tcp --sport 50050 --dport ${dport} -j DROP &>> ${INSERT_LOG}
done

iptables -L INPUT | wc -l >> ${RUN_LOG}
iptables -F INPUT
iptables -L INPUT >> ${RUN_LOG}

nftables

#!/bin/bash

RUN_LOG="nftables_rule250k.log"
APPEND_LOG="nftables_rule250k_append.log"
INSERT_LOG="nftables_rule250k_insert.log"

echo "#user,system,elapsed" > ${APPEND_LOG}
echo "#user,system,elapsed" > ${INSERT_LOG}
nft flush chain inet filter input
nft list ruleset > ${RUN_LOG}

for dport in $(seq 60001 65000)
do
    for sport in $(seq 50001 50049)
    do
        nft add rule inet filter input tcp sport ${sport} tcp dport ${dport} counter drop
    done
    /usr/bin/time -f "%U,%S,%E" nft add rule inet filter input tcp sport 50050 tcp dport ${dport} counter drop &>> ${APPEND_LOG}
done

nft list ruleset | wc -l >> ${RUN_LOG}
nft flush chain inet filter input
nft list ruleset >> ${RUN_LOG}

for dport in $(seq 60001 65000)
do
    for sport in $(seq 50001 50049)
    do
        nft insert rule inet filter input tcp sport ${sport} tcp dport ${dport} counter drop
    done
    /usr/bin/time -f "%U,%S,%E" nft add rule inet filter input tcp sport 50050 tcp dport ${dport} counter drop &>> ${INSERT_LOG}
done

nft list ruleset | wc -l >> ${RUN_LOG}
nft flush chain inet filter input
nft list ruleset >> ${RUN_LOG}

結果

結果のグラフは以下のようになった。(点線はExcelによる近似曲線)

とりあえずiptablesは設計通りの単調増加。nftablesはその点が解消されて常に一定で設定速度も十分高速。

iptables -A(追加)の場合

0710a_iptables_nftables_250k_rules_001.png

iptables -I(挿入)の場合

0710a_iptables_nftables_250k_rules_002.png

nft add rule(追加)の場合

0710a_iptables_nftables_250k_rules_003.png

nft insert rule(挿入)の場合

0710a_iptables_nftables_250k_rules_004.png

終わり

iptablesがルール数の増大によって設定時間が増加するということを知っていないと、 iptablesでは大量のフィルタルールを設定するケースで、想定していない設定エラーなどに遭遇するかもしれない。

nftablesに切り替えればいいというのは事実かもしれないけど、既にiptablesが前提になっているOpenStackとかDockerなんかもいたりするので、上手に付き合っていけるように特性を踏まえておくと良いと思います。