はじめに
以前の記事では、IxNetworkとixia-cのGUI/API対応の説明とPort Endpointを利用したTraffic生成を1本の記事にまとめていたが、内容を整理し、シリーズとして読みやすくするために分割した。本記事ではPort Endpointを利用した最小構成によるTraffic生成に焦点を当てて解説する。
Port Endpointを利用した最小構成
今回は以下のような構成で双方向UDPトラフィックを60秒間印加する設定を作成する。
veth-a <-----> veth-z
Header:UDP
FrameSize:512Byte
LineRate:10%
Duration:60秒
なお、今回はPort Endpointを利用してTrafficを生成する。Topology(Device)やIPv4 Interfaceは作成せず、Flow内でEthernet/IPv4/UDPヘッダを定義する最もシンプルな構成である。IxNetworkでいうProtocol Interfaceを起動する構成ではなく、Portを送受信端点としてTraffic Item相当のFlowを作成し、Ethernet/IPv4/UDPヘッダを持つトラフィックを直接送信する例である。
Step1 Controller接続
api = snappi.api(
location="https://localhost:8443",
verify=False
)
cfg = api.config()
Step2 使用するPort作成(PortのAssign)
p1 = cfg.ports.add(
name="p1",
location="veth-a"
)
p2 = cfg.ports.add(
name="p2",
location="veth-z"
)
Step3 Port Endpoint用のFlowを作成する
flow1 = cfg.flows.add(
name="p1_to_p2"
)
flow2 = cfg.flows.add(
name="p2_to_p1"
)
ixia-cでは双方向通信を1つのFlowで指定するのではなく、送信方向ごとにFlowを作成する。前回の記事では片方向通信で試験。本例では p1_to_p2 と p2_to_p1 の2本のFlowを作成する。
Step4 Tx/Rxを設定
flow1.tx_rx.port.tx_name = p1.name
flow1.tx_rx.port.rx_names = [p2.name]
flow2.tx_rx.port.tx_name = p2.name
flow2.tx_rx.port.rx_names = [p1.name]
IxNetworkではTraffic ItemのSource/Destinationを指定する操作に相当する。
※本記事の検証環境では rx_name は非推奨(Deprecated)として警告が表示されたため、rx_names を使用している。
Step5 Packet Header(Ethernet/IPv4/UDP)を定義する
※Port EndpointではFlow内でPacket Headerを明示的に定義する。Device EndpointでもPacket Headerを定義できるが、Endpointの指定方法やPacket Headerとの関係が異なる。
flow1.packet.ethernet()
flow1.packet.ipv4()
flow1.packet.udp()
flow2.packet.ethernet()
flow2.packet.ipv4()
flow2.packet.udp()
IxNetworkではFrameの中身を編集する操作に相当する。
Step6 Frame Size設定
flow1.size.fixed = 512
flow2.size.fixed = 512
Step7 LineRate設定
flow1.rate.percentage = 10
flow2.rate.percentage = 10
Step8 Duration設定
flow1.duration.fixed_seconds.seconds = 60
flow2.duration.fixed_seconds.seconds = 60
Step9 Metrics設定
flow1.metrics.enable = True
flow2.metrics.enable = True
IxNetworkではTracking条件を柔軟に設定してさまざまな粒度で統計情報を取得できるが、ixia-cでは取得できる統計情報が比較的シンプルである点には留意したい。
Metricsを有効化しなくてもFlowは送信される。ただし、Flowごとの送信・受信フレーム数やバイト数などの統計情報を取得するためには、flow.metrics.enable = True を設定する必要がある。
Step10 Config反映
api.set_config(cfg)
Step11 試験開始(この設定では60秒で試験終了)
state = api.control_state()
state.traffic.flow_transmit.state = state.traffic.flow_transmit.START
api.set_control_state(state)
print("Traffic Started")
※本コードでは Duration を60秒に設定しているため、トラフィックは60秒間送信される。完成版では time.sleep(60) 後に STOP を実行して送信を終了している。
※本記事の検証環境(2026年6月時点)ではtransmit_state() は利用できず、control_state() を使用した。
完成版サンプルコード(双方向UDPトラフィックを60秒印加するサンプルコード)
ここまで説明した内容をまとめると、最終的なサンプルコードは以下のようになる。
# Python標準ライブラリ(試験時間の待機処理に使用)
import time
# OTG APIを操作するPython SDK
import snappi
# ------------------------------------------------------------------
# Controllerへ接続
# ------------------------------------------------------------------
api = snappi.api(
location="https://localhost:8443",
verify=False
)
# ------------------------------------------------------------------
# Config作成
# ------------------------------------------------------------------
cfg = api.config()
# ------------------------------------------------------------------
# Port作成
# ------------------------------------------------------------------
p1 = cfg.ports.add(
name="p1",
location="veth-a"
)
p2 = cfg.ports.add(
name="p2",
location="veth-z"
)
# ------------------------------------------------------------------
# Flow① p1 → p2
# ------------------------------------------------------------------
flow1 = cfg.flows.add(name="p1_to_p2")
# Tx/Rx Port
flow1.tx_rx.port.tx_name = p1.name
flow1.tx_rx.port.rx_names = [p2.name]
# Packet Header
flow1.packet.ethernet()
flow1.packet.ipv4()
flow1.packet.udp()
# Frame Size
flow1.size.fixed = 512
# Rate
flow1.rate.percentage = 10
# Duration
flow1.duration.fixed_seconds.seconds = 60
# Metrics
flow1.metrics.enable = True
# ------------------------------------------------------------------
# Flow② p2 → p1
# ------------------------------------------------------------------
flow2 = cfg.flows.add(name="p2_to_p1")
# Tx/Rx Port
flow2.tx_rx.port.tx_name = p2.name
flow2.tx_rx.port.rx_names = [p1.name]
# Packet Header
flow2.packet.ethernet()
flow2.packet.ipv4()
flow2.packet.udp()
# Frame Size
flow2.size.fixed = 512
# Rate
flow2.rate.percentage = 10
# Duration
flow2.duration.fixed_seconds.seconds = 60
# Metrics
flow2.metrics.enable = True
# ------------------------------------------------------------------
# Config反映
# ------------------------------------------------------------------
api.set_config(cfg)
# ------------------------------------------------------------------
# Traffic印加開始
# ------------------------------------------------------------------
state = api.control_state()
state.traffic.flow_transmit.state = state.traffic.flow_transmit.START
api.set_control_state(state)
print("Traffic Started")
# 60秒待機
time.sleep(60)
# ------------------------------------------------------------------
# Traffic印加停止
# ------------------------------------------------------------------
state = api.control_state()
state.traffic.flow_transmit.state = state.traffic.flow_transmit.STOP
api.set_control_state(state)
print("Traffic Stopped")
# ------------------------------------------------------------------
# Metrics取得
# ------------------------------------------------------------------
request = api.metrics_request()
request.flow.flow_names = [flow1.name, flow2.name]
metrics = api.get_metrics(request)
print(metrics)
動作確認(デフォルト値)
cd ~/ixia-c/conformance
./do.sh pytest examples/test-bydirectional-config.py -s
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-7.1.1, pluggy-1.6.0 -- /home/test/ixia-c/conformance/.env/bin/python
cachedir: .pytest_cache
rootdir: /home/test/ixia-c/conformance, configfile: pytest.ini
plugins: html-4.2.0
collecting ... 2026-06-27 09:23:26.005 [snappi] [WARNING] Version check is disabled
----------------------------- live log collection ------------------------------
WARNING snappi:snappi.py:106 Version check is disabled
2026-06-27 09:23:26.006 [snappi] [WARNING] Certificate verification is disabled
WARNING snappi:snappi.py:164 Certificate verification is disabled
Traffic Started
Traffic Stopped
choice: flow_metrics
flow_metrics:
- bytes_rx: '7619984384'
bytes_tx: '7619984384'
frames_rx: '14882782'
frames_rx_rate: 0
frames_tx: '14882782'
frames_tx_rate: 0
name: p1_to_p2
rx_rate_bps: 0
transmit: stopped
tx_rate_bps: 0
- bytes_rx: '7609734144'
bytes_tx: '7609734144'
frames_rx: '14862762'
frames_rx_rate: 0
frames_tx: '14862762'
frames_tx_rate: 0
name: p2_to_p1
rx_rate_bps: 0
transmit: stopped
tx_rate_bps: 0
collected 0 items
======================= no tests ran in 62.53s (0:01:02) =======================
DurationによりFlowは60秒で停止するが、ここでは後続処理を明確にするため、待機後にSTOPも実行している。
Metrics取得結果
上記ログのうちMetrics部分を抜粋すると以下のとおり
flow_metrics:
- name: p1_to_p2
bytes_tx: 7619984384
bytes_rx: 7619984384
frames_tx: 14882782
frames_rx: 14882782
tx_rate_bps: 0
rx_rate_bps: 0
tx_rate_bps / rx_rate_bps が 0 なのはTraffic停止後にMetricsを取得しているためで、異常ではない。frames_tx / frames_rx の累積値で送受信フレーム数を確認できる。
補足情報
今回流したパケットをWiresharkで確認すると、Ethernet/IPv4/UDPヘッダは付与されているものの、送信元・宛先MACアドレスはいずれも 00:00:00:00:00:00、送信元・宛先IPアドレスはいずれも 0.0.0.0 となっていた。また、UDPのSrc/Dst Portも0となっている。
Packet Header(Ethernet/IPv4/UDP)自体は生成されるものの、各フィールドの値を設定していないため、MACアドレス・IPアドレス・UDP Portはいずれもデフォルト値(0)となる。

※今回 flow.size.fixed = 512 の設定でトラフィックを印加しているが、
これはL2フレームサイズ(FCSを含む)を指定しており、LinuxでキャプチャするとFCS(4Byte)は取得されないため、Wiresharkでは508Byteと表示される。
Packet Headerへ各フィールド値を設定する
IPアドレス/MACアドレス/Port番号を入れる場合の設定例は以下になる。
※Topology(Device)は使用せず、FlowのPacket Headerに直接値を設定する方法
# Python標準ライブラリ(試験時間の待機処理に使用)
import time
# OTG APIを操作するPython SDK
import snappi
# ------------------------------------------------------------------
# Controllerへ接続
# ------------------------------------------------------------------
api = snappi.api(
location="https://localhost:8443",
verify=False
)
# ------------------------------------------------------------------
# Config作成
# ------------------------------------------------------------------
cfg = api.config()
# ------------------------------------------------------------------
# Port作成
# ------------------------------------------------------------------
p1 = cfg.ports.add(
name="p1",
location="veth-a"
)
p2 = cfg.ports.add(
name="p2",
location="veth-z"
)
# ------------------------------------------------------------------
# Flow① p1 → p2
# ------------------------------------------------------------------
flow1 = cfg.flows.add(name="p1_to_p2")
# Tx/Rx Port
flow1.tx_rx.port.tx_name = p1.name
flow1.tx_rx.port.rx_names = [p2.name]
# Packet Header
eth1, ipv4_1, udp1 = flow1.packet.ethernet().ipv4().udp()
# MAC Address
eth1.src.value = "00:00:00:00:00:01"
eth1.dst.value = "00:00:00:00:00:02"
# IPv4 Address
ipv4_1.src.value = "10.1.0.1"
ipv4_1.dst.value = "10.1.0.2"
# UDP Port
udp1.src_port.value = 5000
udp1.dst_port.value = 6000
# Frame Size
flow1.size.fixed = 512
# Rate
flow1.rate.percentage = 10
# Duration
flow1.duration.fixed_seconds.seconds = 60
# Metrics
flow1.metrics.enable = True
# ------------------------------------------------------------------
# Flow② p2 → p1
# ------------------------------------------------------------------
flow2 = cfg.flows.add(name="p2_to_p1")
# Tx/Rx Port
flow2.tx_rx.port.tx_name = p2.name
flow2.tx_rx.port.rx_names = [p1.name]
# Packet Header
eth2, ipv4_2, udp2 = flow2.packet.ethernet().ipv4().udp()
# MAC Address
eth2.src.value = "00:00:00:00:00:02"
eth2.dst.value = "00:00:00:00:00:01"
# IPv4 Address
ipv4_2.src.value = "10.1.0.2"
ipv4_2.dst.value = "10.1.0.1"
# UDP Port
udp2.src_port.value = 6000
udp2.dst_port.value = 5000
# Frame Size
flow2.size.fixed = 512
# Rate
flow2.rate.percentage = 10
# Duration
flow2.duration.fixed_seconds.seconds = 60
# Metrics
flow2.metrics.enable = True
# ------------------------------------------------------------------
# Config反映
# ------------------------------------------------------------------
api.set_config(cfg)
# ------------------------------------------------------------------
# Traffic印加開始
# ------------------------------------------------------------------
state = api.control_state()
state.traffic.flow_transmit.state = state.traffic.flow_transmit.START
api.set_control_state(state)
print("Traffic Started")
# 60秒待機
time.sleep(60)
# ------------------------------------------------------------------
# Traffic印加停止
# ------------------------------------------------------------------
state = api.control_state()
state.traffic.flow_transmit.state = state.traffic.flow_transmit.STOP
api.set_control_state(state)
print("Traffic Stopped")
# ------------------------------------------------------------------
# Metrics取得
# ------------------------------------------------------------------
request = api.metrics_request()
request.flow.flow_names = [flow1.name, flow2.name]
metrics = api.get_metrics(request)
print(metrics)
動作確認(フィールド値設定後)
./do.sh pytest examples/test2-bydirectional-config.py
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-7.1.1, pluggy-1.6.0 -- /home/test/lab/ixia-c/conformance/.env/bin/python
cachedir: .pytest_cache
rootdir: /home/test/lab/ixia-c/conformance, configfile: pytest.ini
plugins: html-4.2.0
collecting ... 2026-07-02 13:08:07.421 [snappi] [WARNING] Version check is disabled
----------------------------- live log collection ------------------------------
WARNING snappi:snappi.py:106 Version check is disabled
2026-07-02 13:08:07.421 [snappi] [WARNING] Certificate verification is disabled
WARNING snappi:snappi.py:164 Certificate verification is disabled
Traffic Started
Traffic Stopped
choice: flow_metrics
flow_metrics:
- bytes_rx: '7255256064'
bytes_tx: '7255256064'
frames_rx: '14170422'
frames_rx_rate: 0
frames_tx: '14170422'
frames_tx_rate: 0
name: p1_to_p2
rx_rate_bps: 0
transmit: stopped
tx_rate_bps: 0
- bytes_rx: '7256308224'
bytes_tx: '7256308224'
frames_rx: '14172477'
frames_rx_rate: 0
frames_tx: '14172477'
frames_tx_rate: 0
name: p2_to_p1
rx_rate_bps: 0
transmit: stopped
tx_rate_bps: 0
collected 0 items
======================= no tests ran in 61.83s (0:01:01) =======================
Wiresharkで再度確認。IPアドレス/MACアドレスおよび任意に設定したUDPポート番号が付与されている。
まとめ
今回はPort Endpointを利用し、Flow内でPacket Header(Ethernet/IPv4/UDP)を定義する方法を確認した。
Port Endpointでは、Flow内でPacket Headerを定義し、その中でMACアドレスやIPアドレス、UDP Portなどを直接設定してTrafficを生成する。
一方、Device EndpointではTopology(Device)配下のInterfaceをEndpointとして利用する。Packet HeaderもFlow内で定義できるが、Port Endpointとは役割や設定方法が異なる。この違いについては別記事で解説する。
