この記事はBBSakuraNetworksアドベントカレンダー2025の23日目の記事です。
はじめに
BBSakura Networksでアルバイトとして勤務をしている池田です。
日々の業務として、ネットワーク機器の評価・検証を行っています。
本記事では、検証業務で用いているTRexを使って、ルータのNAT機能をどのように検証しているかを紹介します。特に、ソフトウェアルータを対象としたNAT性能検証の一例として、具体的な構成や設定、注意点をまとめています。
TRexとは
Cisco TRexは、Ciscoが提供している高性能なトラフィックジェネレーターです。
ネットワーク機器やサーバーに対して大量の通信を生成し、性能検証や負荷テストを行うために使われます。
ソフトウェアベースで動作し、汎用的なハードウェアでも高速・大容量のトラフィック生成が可能なのが特徴です。
L2〜L7まで幅広い通信に対応しており、実運用に近いテストを行うことができます。
検証構成
今回の構成では、ソフトウェアルータとしてOSSであるVyOSを試験対象としています。TRexから生成したトラフィックをVyOSに通過させ、NAT処理を行った上で、受信側のTRexへ転送する構成です。
本記事で紹介する手法は、VyOSに限らず、他のソフトウェアルータや物理ルータに対しても同様に適用することが可能です。図中のVyOSを、NAT処理を行う試験対象のルータに置き換えることで、さまざまな機器のNAT性能評価に応用できます。
使用機材・ソフトウェア
TRex側とDUT(VyOS)側で役割が異なるため、環境を分けて整理します。
TRex(トラフィック生成側)
| 項目 | 内容 |
|---|---|
| ソフトウェア | TRex v3.06 |
| 実行環境 | 仮想マシン(VM) |
| CPU | 32vCPU |
| メモリ | 16GiB |
| Host OS | Ubuntu 22.04.5 LTS |
秒間に多数の新規セッションを生成するため、CPUコア数を多めに割り当てています。
ASTFモードではメモリ使用量も増加するため、16GiBのメモリを確保しています。
VyOS(DUT)
| 項目 | 内容 |
|---|---|
| ソフトウェア | VyOS 1.4.1 |
| 実行環境 | 仮想マシン(VM) |
| CPU | 2vCPU |
| メモリ | 4GiB |
VyOSはNAT処理性能の評価対象であるため、最小限のリソース構成としています。
TRexを利用する際は、OSとPythonのバージョン整合性に注意が必要です。TRexはHost OSのPython環境に依存するため、バージョン差異によるエラーが発生しやすいためです。
-
Ubuntu 22.04以前を使用する場合: 多くのリリースで動作が安定しており、最も無難な選択肢です。
-
Ubuntu 24.04を使用する場合: 標準のPython 3.12に対応した TRex v3.08以降 を使用することが必須となります。
2025年12月時点の最新バージョンは v3.08 ですが、検証環境のOSに合わせて適切なバージョンを選択してください。
TRexのバージョンと対応環境については、以下の公式リリースノートを参照してください。
Router側のNAT設定
VyOSの設定例を以下に示します。内部ネットワークから外部ネットワークへの通信に対して、Source NAT(masquerade)を行うシンプルな構成です。
interfaces {
ethernet eth3 {
address 192.168.1.82/24
hw-id 52:54:00:b0:1e:15
}
ethernet eth4 {
address 16.1.0.1/15
hw-id 52:54:00:31:44:ce
}
ethernet eth5 {
address 48.0.1.1/23
hw-id 52:54:00:c4:a5:8b
}
loopback lo {
}
}
nat {
source {
rule 100 {
description "src-nat inside->outside"
destination {
address 48.0.0.0/24
}
outbound-interface {
name eth5
}
source {
address 16.0.0.0/16
}
translation {
address masquerade
}
}
}
}
protocols {
static {
route 0.0.0.0/0 {
next-hop 192.168.1.1 {
}
}
route 16.0.0.0/16 {
next-hop 16.1.0.2 {
}
}
route 48.0.0.0/24 {
next-hop 48.0.1.2 {
}
}
}
}
また、NATセッション数を十分に確保するため、VyOS側で以下のsysctl設定を行っています。
sudo sysctl -w net.netfilter.nf_conntrack_max=1048576
sudo sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
なお、これらのパラメータは、VyOSにおいてはset system sysctl 配下でコンフィグとして設定できるようです。
TRex設定
TRex インストール
sudo apt-get update
sudo apt-get install -y python3 python3-pip pciutils ethtool tmux screen \
make gcc unzip tar linux-headers-$(uname -r)
sudo modprobe vfio-pci
sudo mkdir -p /opt/trex
cd /opt/trex
sudo wget --no-cache https://trex-tgn.cisco.com/trex/release/latest --no-check-certificate
sudo tar -xzvf latest
HugePagesの設定
TRexは内部でDPDK (Data Plane Development Kit) を利用して高速なパケット処理を行います。DPDK では、ユーザ空間からNICを直接操作するため、
- ページフォルトの発生を抑える
- TLB ミスを減らす
- メモリ連続性を確保する
といった目的で HugePages を利用します。
HugePagesを事前に確保しておかないと、TRex起動時にエラーとなったり、十分なスループットが出ない原因となるため、必ず設定しておきます。
echo 4096 | sudo tee /proc/sys/vm/nr_hugepages
echo 'vm.nr_hugepages=1024' | sudo tee /etc/sysctl.d/80-trex-hugepages.conf
sudo sysctl --system
sudo mkdir -p /mnt/huge
sudo mount -t hugetlbfs nodev /mnt/huge
DPDK ドライバへのバインド
TRexはDPDKを用いてNICを直接制御します。
そのため、通常Linuxが使用するカーネル標準ドライバ (virtio-net / ixgbe など) から、
DPDK 用の PMD (Poll Mode Driver) へNICをバインドし直す必要があります。
dpdk_setup_ports.py は以下を自動で行うユーティリティです。
- 使用可能な NIC(PCI アドレス)の一覧表示
- 対象 NIC を vfio-pci ドライバへバインド
- TRex 用設定ファイル(trex_cfg.yaml)の雛形生成
cd /opt/trex/v3.06
sudo ./dpdk_setup_ports.py -s # NIC と現在のドライバを確認
sudo ./dpdk_setup_ports.py -i # vfio-pci へバインド & 設定ファイル生成
この操作により、NICはLinux ネットワークインタフェースとしては見えなくなり、
TRex(DPDK)が専有する形になります。
設定ファイルのチューニング
dpdk_setup_ports.py により生成される trex_cfg.yaml は最低限動作する設定ですが、NAT 性能検証では NAT セッション数を意図的に増やすための調整を行っています。
virtual_ip:
start_ip: 48.0.0.0
end_ip: 48.0.0.255
この設定により、TRex が使用する送信元/宛先 IP アドレスを動的に変化させ、多数の異なるフローを生成します。
これによって VyOS 側では新規 NAT セッションが継続的に作成され、conntrack テーブルを十分に消費する状態を作り出すことができます。
本検証では、スループットだけでなく NAT セッション処理能力 を評価することを目的としているため、この設定を有効にしています。
追加した設定を含めた/etc/trex_cfg.yamlは以下の通りです。
### Config file generated by dpdk_setup_ports.py ###
- version: 2
interfaces: ['07:00.0', '08:00.0']
port_info:
- ip: 16.1.0.2
default_gw: 16.1.0.1
dest_mac: 52:54:00:51:bd:1e
- ip: 48.0.1.2
default_gw: 48.0.1.1
dest_mac: 52:54:00:66:13:38
virtual_ip :
start_ip : 48.0.0.0
end_ip : 48.0.0.255
platform:
master_thread_id: 0
latency_thread_id: 1
dual_if:
- socket: 0
threads: [2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]
TRex 実行
TRex 実行前の MACアドレス解決について
TRex でトラフィックを生成する前に、対向機器(DUT)との MACアドレス解決を完了させておく必要があります。
ASTF プロファイル内で ARP 処理を実装している場合は不要ですが、本検証では TRex の サービスモード を用いて事前に ARPによるMACアドレス解決を行います。
service mode では、TRex のポートが ARP や ICMP(PING)に応答する状態となり、 トラフィック送信前の疎通確認や MACアドレス解決に利用できます。
TRex 起動と MACアドレス解決手順
まず、ASTF モードで TRex サーバを起動します。
sudo ./t-rex-64 --astf -c 16 -i
また、CPUコア数(-c オプション)を2以上指定する場合、KVMにおいては以下の操作を行う必要があります。
KVMでのTRexマルチコア動作設定
TRexが入っているVMを一度shutdownするsudo virsh dumpxml [VM名] > [VM名].xml
interfaceの部分に追加する
<interface type='bridge'>
<mac address='52:54:00:d2:7f:4e'/>
<source bridge='virbr1'/>
<model type='virtio'/>
<driver name='vhost' queues='16'/>
<address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
</interface>
<interface type='bridge'>
<mac address='52:54:00:fb:a5:f3'/>
<source bridge='virbr3'/>
<model type='virtio'/>
<driver name='vhost' queues='16'/>
<address type='pci' domain='0x0000' bus='0x08' slot='0x00' function='0x0'/>
</interface>
sudo virsh define [VM名].xml
これで再度起動する
別ターミナルから TRex コンソールへ接続します。
./trex-console
次に service mode を有効化し、MACアドレス解決を実行します。
trex> service
trex(service)> arp
trex(service)> service --off
MACアドレス解決が完了したら service mode を終了し、トラフィック生成を開始します。
trex> start -m 55000 -f imix_astf.py
実行中の確認と停止
実行中は TUI 画面で Global Statistics や Port Statistics を確認できます。
trex> tui
検証を終了する場合は、以下のコマンドでトラフィックを停止します。
trex> stop
実行ファイル
TRexの実行は3つのモードが存在します。
今回はそのうち、ASTFモードで実行可能なshortパケット検証用コードとimixパケット検証用コードを以下に提示します。
環境に合わせて適宜修正し、使用してください。
| モード名 | ファイル種別 | 内容 |
|---|---|---|
| STLモード | Python | パケットを一方的に送信するパケットベースのトラフィック生成モードです。L2/L3スイッチやルータに対する帯域・パケット転送性能の評価に向いています。ストリーミングトラフィックなど、セッション管理を伴わない通信の検証に利用します。 |
| STFモード | YAML | TCP/UDPのフローを再現するフローベースのトラフィック生成モードです。DUTにおいてL7までのパケット内容を確認できますが、TCPフラグやオプションなど、プロトコル動作そのものの制御は行えません。 |
| ASTFモード | Python | STFモードを拡張し、TCPセッションの確立・終了やSSL通信を含むアプリケーションレベルのトラフィックを再現できます。 |
short_astf.py
# short_astf.py
from trex.astf.api import *
from scapy.all import *
import argparse
import os
class ProfShort():
def __init__(self):
pass
def get_profile(self, tunables, **kwargs):
parser = argparse.ArgumentParser(
description='Argparser for {}'.format(os.path.basename(__file__)),
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
args = parser.parse_args(tunables)
# IPレンジ設定
ip_gen_c = ASTFIPGenDist(ip_range=["16.0.0.1", "16.0.0.254"], distribution="seq")
ip_gen_s = ASTFIPGenDist(ip_range=["48.0.0.1", "48.0.0.254"], distribution="seq")
ip_gen = ASTFIPGen(
glob=ASTFIPGenGlobal(ip_offset="1.0.0.0"),
dist_client=ip_gen_c,
dist_server=ip_gen_s
)
# UDPパケット作成
base_pkt = Ether()/IP()/UDP(sport=1234, dport=4321)
payload_len = max(0, 64 - len(base_pkt))
payload = b'x' * payload_len
# クライアント:UDP送信
prog_c = ASTFProgram()
prog_c.send(payload)
# サーバ:UDP受信
prog_s = ASTFProgram()
prog_s.recv(len(payload))
# clusterは引数なしで生成(TRex 3.06~3.08対応)
cluster = ASTFCluster()
# Client/Server Template(ip_genをキーワードで渡す)
client = ASTFTCPClientTemplate(cluster=cluster, ip_gen=ip_gen, program=prog_c)
server = ASTFTCPServerTemplate(program=prog_s)
template = ASTFTemplate(client_template=client,
server_template=server)
# ASTFProfile生成
profile = ASTFProfile(default_ip_gen=ip_gen, templates=[template])
return profile
def register():
return ProfShort()
imix_astf.py
# imix_astf.py
from trex.astf.api import *
from scapy.all import *
import argparse
import os
class ProfImix():
def __init__(self):
# IMIXテーブル
self.imix_table = [
{'size': 60, 'pps': 28, 'isg': 0},
{'size': 590, 'pps': 16, 'isg': 0.1},
{'size': 1514, 'pps': 4, 'isg': 0.2}
]
# IPレンジ
self.ip_range = {
'src': ["16.0.0.1", "16.0.0.254"],
'dst': ["48.0.0.1", "48.0.0.254"]
}
def get_profile(self, tunables, **kwargs):
parser = argparse.ArgumentParser(
description='Argparser for {}'.format(os.path.basename(__file__)),
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
args = parser.parse_args(tunables)
# IPレンジ設定
ip_gen_c = ASTFIPGenDist(ip_range=self.ip_range['src'], distribution="seq")
ip_gen_s = ASTFIPGenDist(ip_range=self.ip_range['dst'], distribution="seq")
ip_gen = ASTFIPGen(
glob=ASTFIPGenGlobal(ip_offset="1.0.0.0"),
dist_client=ip_gen_c,
dist_server=ip_gen_s
)
# ASTFCluster生成
cluster = ASTFCluster()
# プログラム作成(クライアント送信 / サーバ受信)
prog_c = ASTFProgram()
prog_s = ASTFProgram()
for entry in self.imix_table:
size = entry['size']
payload_len = max(0, size - len(Ether()/IP()/UDP()))
payload = b'x' * payload_len
# 送信
prog_c.send(payload)
# 受信
prog_s.recv(len(payload))
# Template生成
client = ASTFTCPClientTemplate(cluster=cluster, ip_gen=ip_gen, program=prog_c)
server = ASTFTCPServerTemplate(program=prog_s)
template = ASTFTemplate(client_template=client, server_template=server)
# ASTFProfile生成
profile = ASTFProfile(default_ip_gen=ip_gen, templates=[template])
return profile
def register():
return ProfImix()
imix_astf.pyはTRexに付随している検証用ファイル(imix.py)を参考に作成しています
実行結果
この環境では、以下の結果になりました。
| shortパケット | IMIXパケット | |
|---|---|---|
| bps | 150 Mbps | 300 Mbps |
| pps | 250 kpps | 300 kpps |
補足
TRexでNAT検証を行う場合は、ASTF(Advanced Stateful Traffic)モード を使用します。
過去にはSTFモードにおける --learn-mode オプションを用いてNAT検証を行う方法も紹介されていましたが、今回検証した限りでは期待した動作を確認できませんでした。そのため、現在はASTFモードを用いた検証を推奨します。
詳細は以下の公式ドキュメントをご参照ください。
まとめ
本記事では、TRexを用いてVyOSのNAT機能を検証する方法について紹介しました。TRexを活用することで、高価な専用機材を用いずとも、NATセッション数やスループットといった重要な指標を実践的に検証することが可能です。
TRexやVyOSのバージョン、host OSの違いによって挙動が変わる点には注意が必要ですが、検証環境を正しく構築することで、再現性の高いNAT性能評価を行うことができます。今後、ソフトウェアルータや物理ルータのNAT性能検証を行う際の参考になれば幸いです。
参考記事
https://qiita.com/Shakapon/items/128f8d39cdacb8f1fc0a
https://metonymical.hatenablog.com/entry/2020/07/24/204413
https://www.youtube.com/watch?v=u7YV-53VxEU
https://trex-tgn.cisco.com/trex/doc/trex_astf.html
