Ethernet PSFPのstream gateと1ps境界¶
文書バージョン:1.2.0
対象GitHubバージョン:v1.2.0
文書ID:guide-psfp-gate-boundary
文書状態:公開用完成稿
更新履歴¶
| 文書バージョン | 更新日 | 更新内容 |
|---|---|---|
1.2.0 |
2026-10-22 |
v1.2.0の対象タグ・文書版を確定。過去の測定基準と公開済み履歴を保持 |
1.1.0 |
2026-10-19 |
初版:stream gateのbase_time_psだけを1ps変える2条件、正式版CLI実測と実Viewerの到着境界を追加 |
目的:同じ送信が受信側で通過・拒否に分かれる境界を調べる¶
PSFP(Per-Stream Filtering and Policing)は、受信した通信をstreamごとの条件で受け入れるか判断する仕組みです。ここではstream gate、つまり「受信を許す時間帯」だけを変えます。同じ1フレームが同じ時刻に届いても、到着時にgateが閉じていれば受信側で拒否されます。
比較する要求は、生成0psの空payload・tagなし・priority7の1フレームです。gateの開始時刻を76000psから76001psへ1psずらし、送信copyが同じままで受信結果だけが変わることを確かめます。色判定の設定を変えるPSFP meterの実習とは別の実験です。
profileはethernet.tsn.v1です。以下の数値と画像は正式v1.1.6 Release、source 397900451015c9bca6a33d24feac0a88b9b7b8feからビルドした同一CLIで取得しました。企画の調査基準main 28ad65c992af80f4f3db681930daa0756546294fと、実測に使った正式タグのsourceを区別しています。
全体の構成・責務・適用範囲¶
workloadの生成 → Net.aのP7出力FIFO → Net.a.tx
│ 1Gbps・伝搬0ps
↓
Net.b.rx → VLAN分類 → stream照合 → SDU上限 → stream gate → meter → 受信完了
│ │
└── 拒否 ─────┘
この実習の流れは、INIでNED・モデル設定・workloadを結び、validateで入力を検証し、runで通信を実行し、viewで保存済み結果を読む、という順序です。Viewerは再シミュレーションをせず、保存された時刻・状態・理由を再生します。
| 構成要素 | 責務と、この実習で固定する条件 |
|---|---|
| NED | a/bのEndpointと往復2方向のLinkを接続。1Gbps、伝搬0ps、TX/RX処理0ps、総queue容量64を定義 |
| INI | network、NED探索先、profile、model-config、workloadを接続。終了・集計の終端120000000psを指定 |
| workload | Net.aからNet.bのMACへ1個。生成0ps、空payload、untagged、P7、deadlineなし |
| baseのVLAN・queue設定 | PVID10、default_priority7、VID10のuntagged membership、admit all。8classのstrict priority。Linkはup |
| stream s0 | ingress=Net.b.rx、宛先MAC=02:00:00:00:00:02、VID10、priority7の完全一致。flow_idは照合キーに使わない |
| SDU上限 | max_sdu_bytes=64。このprofileではheader・padding・FCSを含むMAC長を比較する。今回の64byteは等号で通過 |
| stream gate | 周期1000000ps、open500000ps・closed500000ps。開始時刻base_time_psだけを76000/76001へ変更 |
| meter | committed 8Mbps/64byte、peak 16Mbps/128byte、初期満杯。yellow_actionはpass。gateを通った場合に評価 |
| Viewer | copyの送信状態、受信状態、policing記録とmeterの保持値を表示。実績と予定値を区別 |
出力TASはnull、CBSは空列、途中のcontrolsとGCL更新も空列です。Switchはありません。逆方向のb.tx→a.rxは接続に残しますが、逆向き負荷は生成しません。理想共通時計ideal_sharedを使う、この2 Endpoint・単一stream・1フレームだけの比較です。
TASの実習は、送信を開始する前に出力窓へ収まるかを確認して待たせます。今回のPSFP stream gateは、フレームがbへ実到着した時刻に受理・拒否を判断します。閉じていても、このフレームを受信待ちとして保持して次のopenまで遅延させるわけではありません。
到着時刻と半開区間を計算する¶
空payloadでも、untagged Ethernet MACにはheader14byte、padding46byte、FCS4byteがあり、合計64byteになります。直列化にはpreamble/SFD相当8byteも含めます。SOF=0ps、伝搬・処理0psなので次の計算になります。
直列化 = (64 + 8) × 8 × 10^12 / 10^9 = 576000ps
EOF = arrival = 0 + 576000 = 576000ps
release = EOF + IFG12 × 8 × 10^12 / 10^9 = 672000ps
EOFは送信フレームの直列化が終わる時刻、arrivalは相手に到着する時刻です。今回は伝搬0psなので一致します。releaseはIFGも終わって次の送信へ出力資源を渡せる時刻であり、今回の受信gateの判定時刻には使いません。
openの時間帯は、左端を含み右端を含まない半開区間です。到着時の位相は(arrival - base_time_ps) mod cycle_time_psで、今回は500000ps未満ならopenです。
| base_time_ps | 最初のopen区間 | arrivalでの位相 | 576000psの判定 |
|---|---|---|---|
| 76000 | [76000, 576000) | 500000 | 右端に到着するためclosed |
| 76001 | [76001, 576001) | 499999 | 右端の1ps前なのでopen |
この計算を仮説にして、次の正式CLI実測で照合します。開始を1ps後ろへずらすと右端も1ps後ろへ動くため、今回は76001条件のほうが通過します。
独立入力ZIPと正式CLIを用意する¶
独立7ファイルZIPを展開するとexamples/guide/ethernet-psfp-gateができます。このガイドを含むcheckoutの同じフォルダも使えます。正式v1.1.6のsourceを取得しただけでは、この新しい実習フォルダは含まれないため、ZIPも用意してください。
| ファイル | 内容 |
|---|---|
models/ethtsn/Main.ned |
正式版の公開PSFP gateサンプルと同じ接続・速度・遅延 |
workload.json |
公開psfp-gate-workload.jsonと同一の1フレーム |
gate-76000.json / gate-76001.json |
公開psfp-gate-model.jsonからgate開始時刻を設定。2条件のJSON差分はtsn.streams[0].gate.base_time_psのみ |
gate-76000.ini / gate-76001.ini |
model-configの参照名だけが異なる共通INI |
README.md |
入力の版・用途・由来 |
以下はGitとrustup/Cargoを準備済みのWSL Ubuntu 24.04 LTS x86_64、Rust1.85.0の手順です。新しいフォルダ名を使い、正式タグのcommitが一致した場合だけbuildへ進めます。
git -c core.autocrlf=false clone --depth 1 --branch v1.1.6 --single-branch \
https://github.com/hideki-ozu/DIR-Simulator.git dir-v116-cli &&
cd dir-v116-cli &&
test "$(git rev-parse HEAD)" = 397900451015c9bca6a33d24feac0a88b9b7b8fe &&
cargo build --locked --release -j 1 --target-dir target -p dir-simulator &&
export PATH="$PWD/target/release:$PATH" &&
command -v dir-simulator
同じシェルで、ZIPを展開した場所へ移動します。examples/guide/ethernet-psfp-gateが見える場所で、新しい出力先を指定してください。
mkdir psfp-gate-results
for base in 76000 76001; do
dir-simulator validate \
--config examples/guide/ethernet-psfp-gate/gate-$base.ini &&
dir-simulator run \
--config examples/guide/ethernet-psfp-gate/gate-$base.ini \
--output psfp-gate-results/gate-$base &&
dir-simulator view \
--input psfp-gate-results/gate-$base/results.json \
--output psfp-gate-results/gate-$base-viewer.html || break
done
実測では、リポジトリ内の入力とZIPを新しい場所へ展開した入力について、2条件のvalidate/run/view、計12操作が終了0でした。manifestはcomplete・partial:false、diagnosticsは空、結果はevents_exhausted・pending0です。両経路のsimulationも一致しました。以下はその結果であり、既存のPSFP meter記事の測定値を流用していません。
実測:送信copyは一致し、受信判定が変わる¶
| 記録・時刻 | base76000 | base76001 |
|---|---|---|
| generated / source ready / queued / SOF(ps) | 0 / 0 / 0 / 0 | 0 / 0 / 0 / 0 |
| EOF / arrival(ps) | 576000 / 576000 | 576000 / 576000 |
| IFG込みrelease(ps) | 672000 | 672000 |
| copyの最終status / drop_reason | serialized / null | serialized / null |
| reception observed / ready(ps) | 576000 / 576000 | 576000 / 576000 |
| reception status / reason | filtered / psfp_gate_closed | received / null |
| policing verdict / color | psfp_gate_closed / null | pass / green |
| meter committed before → after | null → null | 512000000000000 → 0 |
| meter peak before → after | null → null | 1024000000000000 → 512000000000000 |
| consumed_bits | 0 | 1024 |
2条件のtransferデータはwireを含めて同一です。閉鎖側は、送信元のqueue fullやLinkでのcopy破棄ではありません。bまで到着したcopyに対し、受信側のstream gateがpsfp_gate_closedを記録し、receptionがfilteredになります。両条件とも出力copyのdroppedは0です。この実験では拒否したframeを自動再送しません。
gateはmeterより前に評価されます。76000側でcolorと4つのtoken欄がnull、consumed_bits=0であることは、この到着でmeterを評価・消費していないことを示します。76001側はstream照合とSDU上限64byteの等号を通り、gateもopenなのでmeterへ進みます。
tokenの保存値はbit×10^12の整数です。76001側の評価前はcommitted512bit・peak1024bitで、greenとして両bucketから512bitずつ消費し、評価後は0bit・512bitです。consumed_bits=1024は2つのbucketから引いた合計です。MAC64byteのcostは512bit、preamble/SFDを含むwire直列化は576bitのままであり、1024bitのフレームを送ったという意味ではありません。
実Viewerを同じ576000psで比較する¶
2つのgate-*-viewer.htmlをブラウザで開き、時刻入力に576000を入れて「移動」を押します。まず転送行psfp_gate:0を選び、copyのEOF・arrival576000psとdrop_reasonがないことを確認します。「このフレームの受信記録」は76000側でフィルタ拒否、76001側で受信完了になります。詳細の生JSONはrun全体の最終保存記録なので、cursor時点の状態表示と読み分けます。
デスクトップ1440pxで取得した実画面全体は、76000条件と76001条件で確認できます。同じ576000psに、上部は両方EOF到達1・copy破棄0、受信完了だけが0/1です。画面下の「TSN gate・credit・meter」でstreamカードs0を見ます。


上のカードは390pxの実画面から取得しています。閉鎖側でも、カードのcommitted/peakはnull表示にはなりません。 正式v1.1.6のViewerは初期満杯の保持値を示し、「最後のmeter評価」は0psのままです。新しいpolicingのnull欄はresults JSONで確認します。画面の「潜在refill(未消費)」も、meterの新しい評価・token消費ではありません。通過側では実際に評価した576000psと消費後の0・512000000000000が表示されます。
同じ欄のNet.a.tx・Net.b.txに出る「Gate 常時open」は出力TASの表示です。受信stream gateの通過・拒否はs0のverdictと受信記録で読みます。
次に両条件を575999psへ戻します。この時点はまだ到着前で、streamカードは「未到着」、上部は送信中1・EOF到達0・受信完了0です。576000psへ進むと上記の結果へ切り替わります。検証ではさらに672000psへ進み、575999psへ巻き戻してから576000psへ戻し、件数・カード・選択詳細・転送行が同時刻の状態に一致することも確認しました。gateの未来予定だけで受信を完了済みにしているわけではありません。
JSONと証跡を照合する¶
policingには評価時刻、stream_id、reception_id、verdict、color、token、consumed_bitsがあります。receptionには同じcopyに対するobserved/ready、status/reasonがあります。配列の格納順から判定せず、schemaと参照IDで結びます。
python3 - <<'PY'
import json
from pathlib import Path
for base in (76000, 76001):
rows = json.loads(Path(f'psfp-gate-results/gate-{base}/results.json').read_text())['simulation']['model_records']
print(base)
for schema in ('ethernet.dynamic.transfer', 'ethernet.dynamic.reception', 'ethernet.tsn.policing'):
for row in rows:
if row['schema_name'] == schema:
print(schema, row['record_id'], row['time_ps'], row['data'])
PY
CLI測定証跡には、正式source commit、binaryとbuild sourceのSHA-256、各入力のSHA-256、両条件の実記録、ZIPからの再現結果を保存しています。Viewer検証証跡には、使用したHTML・結果・画像のSHA-256、ブラウザ版、575999/576000psと巻き戻しの確認を保存しています。元の結果・manifest・Viewer HTMLは変更せず、実際に正式CLIが出力したHTMLを使いました。4つのHTML(2条件×リポジトリ/ZIP)でpage error、console error、request failure、外部通信は0でした。
制約と関連する実習¶
1psはこのモデルの整数時刻で条件を分けるための差です。実機の1ps精度、PTP同期精度、IEEE Qciへの完全適合を検証したものではありません。複数streamや複数hop、gateとmeterの複合負荷、TAS/CBSとの組合せ、時計ずれは今回の測定範囲に含めません。
判断順と設定の契約は正式版のEthernet TSN仕様を参照してください。送信側で待たせるTAS・CBS、受信meterの色判定とyellow破棄を並べると、どの段階のどの時刻を変えたかを追えます。