Slide 1

Slide 1 text

1 自作パケット処理系の 性能測定と可視化&改善のPDCAを回して 最強のパケット処理系の作り方を学ぼう Let's Measure the Performance of Packet Processing System with Python Tools. Hayasaka Takeru Pycon APEC 2023 2023/10/28

Slide 2

Slide 2 text

自己紹介 - 早坂 彪流 (Hayasaka Takeru|@takemioIO) - 仙台市出身, 京都市在住 - Pycon初参加🐍 - 社会人3年目(25歳) - 今月誕生日でした。四捨五入したら30歳でつらいです。 - さくらインターネット に所属して、現職(BBSakura)へ出向中 - 10月で転職して1年🎊 前職は京都にあるゲーム会社 - 仕事の中身がSwitchからSwitchにSwitchすることになりネットワークに関する開発へ... - 好きな技術: eBPF, Go,Python - 趣味はSFアニメ・漫画、散財とか - ふるさと納税駆け込んだら赤字になってしまった。 - 最近今更「魔法少女リリカルなのは」を見終わった。 2 https://fr.m.wikipedia.org/wiki/Fichier:Go_gopher_mascot_bw.png

Slide 3

Slide 3 text

なぜこの題材で喋るのか - 自作パケット処理系が最近流行っててみんな(?)やってるイメージ - 最近はいい資料もたくさんあるイメージ - 自作パケット処理系をより良いものにするためには?という情報は少ない - なので一歩目ではなく二歩目を踏み出すための資料を作りたいと思った - なので後から見返すと嬉しくなるように書いてみました。 よって今回の発表スタイルは、書いてあるけど説明しない事もあります。 - 普段Python🐍にお世話になってるのでコミュニティにぜひ還元したかった - Goにもお世話になってます 3 https://twitter.com/pandax381/status/1547489422954070021 最近は若者向けにTCPを作ろうインターンみたいなのがあったり 
 https://github.com/xdp-project/xdp-tutorial XDPを利用した開発のためのワークショップが行われたり 


Slide 4

Slide 4 text

Agenda - 背景事情と背景技術 - 高速なパケット処理系を作るとは? - 処理系に関する実装の基本的な考え方を速習 - PGW-Uの性能評価実験 - 実際のパケット処理系をPython製のツールで測定・評価をした話 - PGW-Uのチューニングと改善 - 自作パケット処理系を測定していく中で行った三つの改善の紹介 - 今後の展望とまとめ 4

Slide 5

Slide 5 text

背景事情 5

Slide 6

Slide 6 text

● BBIXとさくらインターネットの合弁会社 ● 2019年8月1日設立 ● ネットワークサービスのソフトウェア開発 ● 親会社を通じてソフトウェアを世に出している ● すべての「モノ」がつながる社会の実現に向け、プラットフォーム(OCX) 提供を通じてネットワークサービスのクラウド化を進めてます 開発や運用をしているサービス ● さくらのセキュアモバイルコネクト ● さくらのショートメッセージサービス ● BBIXお客様向けポータル ● OCX (Open Connectivity eXchange)

Slide 7

Slide 7 text

モバイルをやってます 7

Slide 8

Slide 8 text

フルMVNO事業者として モバイルコアの 開発・運用までをやってます 8

Slide 9

Slide 9 text

今日はそこで得た知見を元に 皆様にお話しします 9

Slide 10

Slide 10 text

背景技術 10

Slide 11

Slide 11 text

基本的なLTEアーキテクチャ 11 UE eNB HSS MME PGW SGW S1-U S5 SGi S6a LTE-Uu S1-MME UE: User Equipment eNB: eNodeB, evolved Node B MME: Mobility Management Entity HSS: Home Subscriber Server SGW: Serving-Gateway PGW: Packet Data Network-Gateway The Internet & Cloud (& Operator network S11 この辺でSIMの 認証や位置登録 この辺でモバイル網の 終端とか制御 基地局 スマホとか

Slide 12

Slide 12 text

フルMVNOの構成 12 UE eNB HSS MME PGW SGW S1-U S8 SGi S6a LTE-Uu S1-MME UE: User Equipment eNB: eNodeB, evolved Node B MME: Mobility Management Entity HSS: Home Subscriber Server SGW: Serving-Gateway PGW: Packet Data Network-Gateway The Internet & Cloud (& Operator network S11 MVNOが 面倒を見てる 範囲 実際にはかなり複雑ことをしています。 詳しくは3GPP TS23.401とGSMA IR88を参照 MNOが 面倒を見てる 範囲 MNO MVNO

Slide 13

Slide 13 text

PGWとは? - PGWはインターネットやクラウド等の網に通信するためのゲートウェイ - PGWはGTPというトンネリングプロトコルを使って、モバイルユーザが移動しても通 信が途切れないようにするための仕組みを実現しています - ハンドオーバーはこの仕組みの上に成り立っています - トンネリングというのはVPNの様なモノです - GTPはTEIDと呼ばれるIDを利用してユーザー通信を識別することができます - これを利用してトラヒック計測による課金(いわゆるギガがない😇)などを実現できます 13

Slide 14

Slide 14 text

LTEアーキテクチャでGTPを見ると... 14 UE eNB HSS MME PGW SGW S1-U S5 SGi S6a LTE-Uu S1-MME UE: User Equipment eNB: eNodeB, evolved Node B MME: Mobility Management Entity HSS: Home Subscriber Server SGW: Serving-Gateway PGW: Packet Data Network-Gateway GTPトンネル: The Internet & Cloud (& Operator network S11 GTPに含まれるTEIDと呼 ばれるIDでUEからの通 信を識別します

Slide 15

Slide 15 text

PGWの性能問題 - PGWはインターネット等に繋ぐときに負荷が掛かりやすいところの一つです - ユーザーのパケットは全てここを通ります - 言い換えればここの性能をちゃんと引き出すことで、利用者に快適な接続性 を提供できるようになります 15

Slide 16

Slide 16 text

PGWのC/U分離ついて - PGWはコントロールプレーンと呼ばれる制御信号を処理する仕組みと ユーザープレーンと呼ばれる利用者信号だけを処理する仕組みに分割できる - このような分割をC/U分離(CUPS)と呼ぶ - 詳しくは3GPP TS 23.214に定義する - PGWでは特に PGW-C, PGW-U と呼びます - 分割することで - キャパシティ増強が簡単で障害時も嬉しい - 機能の単純化によって、性能の最適化も実施しやすい 16

Slide 17

Slide 17 text

LTEアーキテクチャでPGWをC/U分離すると 17 UE eNB HSS MME PGW-U SGW S1-U S5 SGi S6a LTE-Uu S1-MME UE: User Equipment eNB: eNodeB, evolved Node B MME: Mobility Management Entity HSS: Home Subscriber Server SGW: Serving-Gateway PGW-C: Packet Data Network-Gateway Controlplane PGW-U: Packet Data Network-Gateway Userplane The Internet & Cloud (& Operator network S11 PGW-C GTPv1-Uトンネル: GTPv2-Cトンネル:

Slide 18

Slide 18 text

PGW-Uの処理動作 - 今回紹介するPGW-Uは以下のような動きをします - Uplink: SGWから受信したGTPパケットをDecapしてInternet等の方面に送信 - Downlink: Internet等の方面から受信したパケットをGTPヘッダーでEncapし、SGW に対して送信してUEに届ける - 他にもUEに合わせて(==TEIDをみて) どこに送信するか・ポリシーを適用するかを決定 する 18 The Internet & Cloud (& Operator network SGW PGW-U IP TCP IP ETH GTP/ UDP IP TCP ETH Uplink => <=Downlink Encap Decap Dot1q Dot1q

Slide 19

Slide 19 text

ここまでのまとめ - MVNOの事業をやってるよ! - MVNOはPGW, HSSの面倒を見てるよ! - PGWは... - 利用者がインターネットやクラウドに出るためのパケット交換機です - GTPというトンネリングプロトコルを終端してて、ハンドオーバーを実現 - ユーザーの通信はGTPに含まれるTEIDというID単位で識別されます - C/U分離が可能で、分割するとメンテやキャパの観点からいい事がある - PGW-Uのお仕事はGTPをEncap/Decapしてあげて携帯等の通信を外部まで届けること 19

Slide 20

Slide 20 text

自作PGW-Uの紹介 - eBPF/XDP製のPGW-U - PGW-Cからのトンネル作成リクエストをハンドルしてeBPF Mapsと呼ばれるTableに セッションデータを書き込むことでeBPFのコード上で利用可能になる - XDPを採用することで既存のLinux Protocal Stackと協調動作しつつ実装可能 - ARPやICMP等をカーネルにフォワードできるので本質的な必須実装だけに注力可能 - なおこのCplaneやハンドラはGo製...... - 詳しくは以下のENOG 63 の資料が参考になるので興味あればご覧ください ENOG63 モバイルネットワークのデータプレーンを XDPで作る話 https://fr.m.wikipedia.org/wiki/Fichier:Go_gopher_mascot_bw.png

Slide 21

Slide 21 text

このセッションで話す・話さないこと - 話すこと🙆 - 私たちのXDP製自作PGW-Uを題材に、高速パケット処理系をどう測定評価するか - 高速パケット処理系の手法と定石の説明 - 特にソフトウェア上で実装されるモノにフォーカスする - 自作パケット処理系を磨く(測定・検証)ためにPythonをどのように利活用しているか - 話さないこと󰢄 - PGW-Uやモバイル網のアーキテクチャの詳細 - どういうサービスでどういう実装やアーキテクチャになっているか - eBPF/XDPに関する細かい話 21

Slide 22

Slide 22 text

高速なパケット処理系を作るとは? 22

Slide 23

Slide 23 text

なるべく(余計な)処理をしない事である - 高速パケット処理系というとHWベース, SWベースがある - HWベースの実装: ASIC, P4, openflow, SmartNIC…etc - SWベースの実装: eBPF/XDP, DPDK…etc <- 今日はこの話 - 基本的にはソフトウェアの高速化と何も変わらない - 単一コアで処理をせず(並列化)、単一コアの処理時間を短くする(高速化)が肝である - 今どきのパケット処理系では、コストや性能の観点から HWとSWを組み合わせたハイブリットな実装が主流 - HWだけならコストが高すぎて、BigTechクラスの会社じゃないとコスパが悪すぎる 一方SWだけなら思ったほど性能が出ない...😇 23 https://developer.nvidia.com/blog/choosing-the-best-dpu-based-smartnic 今日はこっちの話

Slide 24

Slide 24 text

パケット処理の並列化技術 24 処理箇所 分散方法 利用シーン RSS: Receive Side Scaling NICレベルの処理 Hashを取りNIC Queueに振り 分けてCPUコア へ均等に負荷分散する パケット処理の並列化 RPS: Receive Packet Steering CPUレベルでの処理 単一CPUコアで パケットに対して特定 パラメータでhashを取ってCPU コアに分散する NICでRSSに対応して ないFlowをCPUで処理 できる様に変更した パケット処理の並列化 RFS: Receive Flow Steering NICレベルでの処理 ルールにマッチした特定の パケットが任意のCPUに渡すこ とができる Cplane向けのパケットは 専用に割り当てたCPUコアで 処理することで 特別な処理を分離出来る 処理の安定化を行える - 詳しくはLinux kernelのドキュメント見てください - https://www.kernel.org/doc/Documentation/networking/scaling.txt

Slide 25

Slide 25 text

パケット処理の並列化技術 25 処理箇所 分散方法 利用シーン RSS: Receive Side Scaling NICレベルの処理 Hashを取りNIC Queueに振り 分けてCPUコア へ均等に負荷分散する パケット処理の並列化 RPS: Receive Packet Steering CPUレベルでの処理 単一CPUコアで パケットに対して特定 パラメータでhashを取ってCPU コアに分散する NICでRSSに対応して ないFlowをCPUで処理 できる様に変更した パケット処理の並列化 RFS: Receive Flow Steering NICレベルでの処理 ルールにマッチした特定の パケットが任意のCPUに渡すこ とができる Cplane向けのパケットは 専用に割り当てたCPUコアで 処理することで 特別な処理を分離出来る 処理の安定化を行える - 詳しくはLinux kernelのドキュメント見てください - https://www.kernel.org/doc/Documentation/networking/scaling.txt 今回はRSSだけを メインとして話します

Slide 26

Slide 26 text

NIC RSS: Receive Side Scaling - packetのHashを取りNIC Queueに振り分け てCPUコア へ均等に負荷分散する技術 - packetに含まれる要素N個のTupleで 一つのFlowは定義される - このFlowごとに各CPUに負荷分散することで マルチコア処理が可能になる - 動作原理はざっくり図の通り - 詳しくはLinux kernelのドキュメント見てくださ い - https://www.kernel.org/doc/Documentation/net working/scaling.txt 26 cpu0 cpu1 cpu2 cpu3 RX Queue 00 RX Queue 01 RX Queue 02 RX Queue 03 HashMask
 pkt..
 Indirection Table 0
 HashFunc
 1
 2
 …
 MSX割り込み

Slide 27

Slide 27 text

Q.round robinにせず, なぜHashを取るの? - A. PerFlowでパケット処理をしたいから - PerFlowで処理をしないとパケットのリオーダーが起きてしまう - 例えば TCPには順序保証があるので、雑に並列に処理をすると 並べ直しが必要になり困ってしまう - リオーダーが起きてしまうとパフォーマンス劣化が起きてしまったり、 HoLブロッキングとか...輻輳させてしまう原因に😇 27 UE PGW-U Uplink => <=Downlink サーバー 1 2 3 4 1 2 4 3 ほな今から音楽 データ送るで! TCPで順序保証されて 流れてくる 雑な実装のPGW-Uのせいで 途中経路でバラバラにされてし まった データ並びなおさないと 中身わからんわ! 賢くないと 「データ壊れてる! もう一回送って〜」 とか...

Slide 28

Slide 28 text

- 従来ソフトウェアにおいてのパケット処理高速化の定石は大きく分けて二つ - ProtocolStack/OSのオーバーヘッド回避のためのKernelByPass - 高いパケットレートを保つためのCPU占有のBusyPolling - 大体そこを作るのはだるいので、ほぼパケット処理フレームワークの上に作って終わり(完) - DPDK, netmap, XDPが大体それに当たる - ちなみにXDPは? - KernelByPassはせず、プロトコルスタックに渡す前にドライバーレベルで動作させることでオーバー ヘッドを削減している - BusyPollingは NAPI を利用して実現している - NAPIとはLinuxにおいてパケット流量のレートが上がると自動でポーリングする機能 パケット処理系の高速化技法 28

Slide 29

Slide 29 text

XDPの処理のケースを図にすると... - 水色:XDPで処理するパス - NICドライバー上で実行されkernel内 部で処理 - 橙色:通常の処理するパス - NICドライバーを通じて整形されてプロ トコルスタックに渡している - コンポーネントの論理関係から XDPの方が早いことがわかる 29 Application XDP Driver NIC Protocol stack/ socket Kernel land User land Hardware

Slide 30

Slide 30 text

基本的な実装方針はざっくりこの辺を考えたりする - テーブル参照の数を減らす - 参照するテーブルの数をなるべく減らす&まとめる。 - テーブルの構造の最適化 - HashMapなどを利用する分にはそれなりにパフォーマンスは良い - Per-CPUなテーブルを積極的に利用する - CPUで共通のテーブルだとRead/Writeでロックがかかって遅くなってしまうので、 コア単位でテーブルのレプリカを分けましょう - LPM(Longest Prefix Match)などは処理が重いのでできれば使わないでおく - ちゃんとしてるところはLPMやルーティングテーブルを最適化してたり... - e.g. NTTCom Kamuee の Poptrie 余談: パケット処理系のあるあるな高速化技法 30

Slide 31

Slide 31 text

- ハードウェアで並列化し、必要なところを可能な限り高速にCPUで処理する - 具体的には - ハードウェアベースなところでRSSを処理しておく - CPUのAffinity、Multi NIC Queueも調整しておく - PerFlowパケットをなるべくデータのバケツリレーされるところの最初の方で処理を行う - 細かい話をするともっと色々あるがそれはまた別の話 - CPUの性能を引き出すあれこれ - HW的にはSMTを無効にする - VPPのようにL1のIキャッシュミスを減らすとか... - NICはRSS以外に高速化でも役立つ話とか - Csumオフロード(処理系依存) - VlanのDecapなどもできるので有効化するとか... - 出てきたIFから出す方が処理が早いとか - そんなこんなを上手い事ことするといい感じのオレオレ処理系ができます。 みんなパケットの通る気持ちよさを味わおうね! つまりSW Basedな高速パケット処理系とは 31

Slide 32

Slide 32 text

PGW-Uの性能評価実験 32

Slide 33

Slide 33 text

自作PGW-Uの紹介 - eBPF/XDP製のPGW-U - PGW-Cからのトンネル作成リクエストをハンドルしてeBPF Mapsと呼ばれるTableに セッションデータを書き込むことでeBPFのコード上で利用可能になる - XDPを採用することで既存のLinux Protocal Stackと協調動作しつつ実装可能 - ARPやICMP等をカーネルにフォワードできるので本質的な必須実装だけに注力可能 - なおこのCplaneやハンドラはGo製...... - 詳しくは以下のENOG 63 の資料が参考になります。興味あれば参照して下さい ENOG63 モバイルネットワークのデータプレーンを XDPで作る話 https://fr.m.wikipedia.org/wiki/Fichier:Go_gopher_mascot_bw.png 再掲


Slide 34

Slide 34 text

PGW-Uがどんなことしてるのかおさらい - PGW-Uとはインターネット等に出るためのゲートウェイ - UL: GTPv1-UをUE方面から受信し、DecapしてInternet等に投げる - DL: EthernetをInternet等から受信し、GTPv1-UでEncapしてSGWに投げる - UEの識別にGTPv1-Uに含むTEIDを利用している 34 The Internet & Cloud (& Operator network SGW PGW-U Uplink => <=Downlink Encap Decap IP TCP IP ETH GTP/ UDP IP TCP ETH Dot1q Dot1q

Slide 35

Slide 35 text

性能測定の環境とPGW-Uの設定 35 TrafficGen PGW-U(DUT) L3SW MetricServer 100G 1G - Commons - Xeon Platinum 8362 32C/64T/64G - Intel E810-CQDA2 100GbE 2port - Ubuntu Server - Traffic Generator - TRex v2.50 - Linux 6.1.0-1008-oem - PGW-U - Linux 6.6.0-rc4 - L3SW - Dell S5248F-ON - SONiC v4.1.0 - MetricServer - Grafana v9.5.13 - Prometheus v2.47.2 - Pushgateway v1.6.2

Slide 36

Slide 36 text

性能測定のプロセス 36 TrafficGen PGW-U(DUT) L3SW MetricServer 100G 1G 1. TrafficGen(TRex)からUL/DLパケットをPGW-Uに 送り、PGW-Uで(Encap/Decapの)処理されたパ ケットをTRexで受け取る 2. TrafficGenで計測結果(rx_bps等)の結果を PushGateway に送る 3. PGW-Uにはnode exporterを導入し、処理系 自身のCPU利用率等のメトリックを収集 4. メトリックをgrafana経由で CSV形式でダウンロードし、 matplotlibとsklearnを駆使してグラフ化📈 5. グラフを眺めてみる🤔

Slide 37

Slide 37 text

性能測定のためのパケット生成 - TrafficGeneratorのTRexはバックエンドにDPDK製ソフトウェアを、 フロントエンドにPythonを利用しているOSS - Scapy を使って任意のパケットを生成して負荷をかけることができる - DPDKはCを書かないといけないが、Pythonでラップされててお手軽簡単で 37 IP TCP IP ETH GTP/ UDP Dot1q IP TCP ETH Dot1q Uplink:ローミング網からインターネット等へ Downlink:インターネット等からローミング網へ hdr = Ether()/ \ Dot1Q(vlan=t_global.args.vlan_id)/ \ IP(src=t_global.args.src, dst=t_global.args.dst)/ \ UDP(dport=2152, sport=2152, chksum=0)/ \ GTP_U_Header(gtp_type="g_pdu", teid=200) hdr = Ether()/ \ Dot1Q(vlan=t_global.args.vlan_id)/ \ IP(src=t_global.args.src, dst=t_global.args.dst)/ \ TCP(sport=8080, dport=80) Uplinkでのパケット生成例 Downlinkでのパケット生成例

Slide 38

Slide 38 text

MultiFlowを実現するためのFlow変数 - この機能でパケットをMultiFlowにすることができる - TRexはパケットの一部をランダムやインクリメンタルに変化させられる - これを応用して送信元IPを変化させることで複数クライアントを模した環境 を再現することができる 38 IP TCP IP ETH GTP/ UDP Dot1q IP TCP ETH Dot1q Uplink:ローミング網からインターネット等へ Downlink:インターネット等からローミング網へ # SrcIP STLVmFlowVar( name="ip_src",size=4, op="random", min_value=t_global.args.src_min, max_value=t_global.args.src_max, ) STLVmWrFlowVar(fv_name="ip_src",pkt_offset= "IP.src"), # TEID STLVmFlowVar( name="teid",size=4, op="random", min_value=t_global.args.teid_min, max_value=t_global.args.teid_max, ) STLVmWrFlowVar(fv_name="teid",pkt_offset= "GTP_U_Header.teid") SrcIP, TEIDを 変化させてmulti flowに VID, SrcIP,DstIPを 変化させてmulti flowに Uplinkでのmulti flow化の例

Slide 39

Slide 39 text

生成したパケットで性能測定をしてみる - 実際にTRexを利用してパケットを投げ る時にはこのような設定を 入れます - Interface portの初期化 - L2モード or L3モードにするのか - L2モード: Macアドレスを手動で 与えた上で動作させる仕組み - L3モード: 任意のIPアドレスでARPの解 決を自動でサポートしてくれる 設定項目が減って嬉しい - 送って戻ってきたパケットが正しいか を判断する機能は無いので、RXに来たパ ケットをDumpする必要があります 39 # クライアントインスタンスを作る c = STLClient(server = t_global.args.ip) # 投げたいパケットとそのストリームを定義 s = STLStream( packet = self.pkt_handler.create_stream(frame_size), random_seed = 0x1234, mode = STLTXCont(), ) # TRexのバックエンドアプリと接続 c.connect() # ポートの初期化とL3での動作モード設定 c.reset(ports = self.rx_ports) c.set_service_mode(ports = self.tx_ports, enabled = True) c.set_l3_mode(port = e.port, src_ipv4 = e.ipaddr, dst_ipv4 = e.gw) c.add_streams(s, ports = self.tx_ports) # 実際にリクエストが返ってきたパケットの tcpdump設定 c.start_capture(rx_ports = e.port, limit = e.capture_size) # 負荷試験をスタート c.start(ports = self.tx_ports, mult = speed, duration = duration, force=True) # リクエスト終了まで待つ c.wait_on_traffic(ports = self.rx_ports) 生成したパケットをTRexを使って投げつける例

Slide 40

Slide 40 text

PGW-U自体のリソース計測 - node exporterでCPU使用率とメモリ使用率が時系列で取得できるので、 パケット処理結果から負荷に関する観察を行うことができる 40 実際に観察するのに利用したダッシュボード

Slide 41

Slide 41 text

さらにアプリケーションまで見てみる - perfコマンドを使ってカーネル内部の関数がどの様に呼ばれているのかを見ること でアプリケーションでのボトルネックを探ることができる 41 sudo perf record -a -g -F 99 sudo perf script > perf_data.txt perl stackcollapse-perf.pl perf_data.txt|perl flamegraph.pl > flamegraph.svg DLを測定中にperfを行った結果 perfを行うコマンド例

Slide 42

Slide 42 text

性能測定したデータをPrometheusに渡す - 測定終了後に パラメーターを取得 Pushgatewayに送信 - Prometheus でそれを ウォッチして取得 42 # TRexで負荷をかけた部分のデータを取得 stats = c.get_stats(self.rx_ports) if t_global.args.is_send_metric:   metrix_for_prom = "".   join([    format_metrics_for_prom(stats[port],self.labels.with_ports(port)) for port in self.rx_ports])  send_metrics(self.pushgateway_host, self.jobname, metrix_for_prom) # pushgateway にメトリックを送る def send_metrics(pushgateway_host, job_name, payload):   url = f"http://{ pushgateway_host }/metrics/job/{ job_name }"   headers = {     'Accept': '*/*',     'Host': pushgateway_host,   }   req = urllib.request.Request(url, payload.encode('utf-8'), headers)   with urllib.request.urlopen(req) as res:    body = res.read() def format_metrics_for_prom(metrics, labels):   lines = [(f'{key}') + labels.to_label() + (f' {value:.8f}') for (key, value) in metrics.items() ]   lines.append("")   return "\n".join(lines) PushGatewayにメトリックを送る例

Slide 43

Slide 43 text

性能測定したデータをPrometheusに渡す - 右のようなヘルパークラスを作って Labelをつける - actionとuuid,frame_sizeは入れた方が 実験をする時には便利 - 以下のように条件を入れることができて 絞り込みに便利 43 class LabelParam():   def __init__(self, duration, multiplier, frame_size,  action):     self.duration = duration     self.multiplier = multiplier     self.uid = str(uuid.uuid4())     self.frame_size = frame_size     self.action = action   def with_ports(self, ports):     self.ports = ports     return self   def to_label(self):     items = []     for k, v in self.__dict__.items():       if v is None:          continue       items.append(f'{k}="{v}"')     return "{"+", ".join(items)+"}" PushGatewayに送るときにラベルを付ける例 Prometheusでどの回の実験だったかを こんな感じに絞り込みができて便利

Slide 44

Slide 44 text

必要な測定データ抽出 44 - Grafanaから欲しい範囲のデータを CSVでdumpします - Jupyter Notebook上でpandasを 使ってCSVを読み出し、 Matplotlibでグラフ化します import matplotlib.pyplot as plt import lib.clue as clue df = clue.get_dataframe_from_csv('raw_data/scenario-mue-32cpu-dl.csv') target = df.loc[df['dot1q'] == '999'] plt.bar(target['frame_size'], target['rx_bps']/1000/1000/1000.0, width=100.0) plt.title("32Core-DL(v4) framesize-RxGbps") plt.xlabel("frame size[byte]") plt.ylabel("Rx throughpt[Gbps]") plt.ticklabel_format(style='plain') plt.grid(True) plt.savefig("./graph/cpu32-dl-bbs-rx.png") plt.show() CSVデータからグラフを作る例 こんな感じの結果が出ます

Slide 45

Slide 45 text

測定データを利用したデータ分析 45 - CSVを再度読ませてsklearnを使って線 形回帰モデルを作ります - ここではCPU負荷とframesize の因果関係を元に線形回帰します correlation = result['framesize'].corr(result['softirq_mean']) print(f'Correlation between softirq and payload length: {correlation}') # 独立変数と従属変数を指定 X = result['framesize'].values.reshape(-1,1) Y = result['softirq_mean'] # 線形回帰モデルのインスタンスを作成 model = LinearRegression() # モデルをデータにフィット model.fit(X, Y) # 結果の係数と切片を表示 print('Coefficient (slope): ', model.coef_) print('Intercept: ', model.intercept_) # フレームサイズとソフトIRQの平均値の散布図をプロット sns.scatterplot(x='framesize', y='softirq_mean', hue='core', data=result, palette='viridis') # 回帰直線をプロット plt.title('Linear Regression Model: DLv4 Packet Framesize vs mean SoftIRQ') plt.xlabel("frame size[byte]") plt.ylabel("softirq_mean[%]") plt.ylim(-0.1, 1.1) plt.plot(X, model.predict(X), color='red') plt.grid(True) plt.savefig("./graph/all_corr_v4_dl.png") plt.show() sklearnを使って線形回帰をする例 こんな感じの結果が出ます

Slide 46

Slide 46 text

評価条件 - 固定 - 収容テナント数(==VLAN): 1000 - Bearer: 1000000 - SGW: 100 - Req/s: 100Gbps - SMTはoff, IRQ Affinityの調整済み, nic queueも調整済み - RSSも有効, CPUパフォーマンスも調整済み - 変動 - パケットサイズを64, 128, 256, 512, 1024, 1424, 3024 のパターンで試行 - さらにこれらをCPUコア数を絞った上で実行します - シングルコア性能とマルチコア性能、そしてそれらをペイロード長を 変えながら調べていくことで基本性能を評価することができます 46

Slide 47

Slide 47 text

評価結果: シングルコア性能 - Single Flowで負荷をかけた場合は単一コア性能が測定できます - ULの性能はジャンボパケットの場合は十分良さそうに見えてます - (あまりに良過ぎて目を疑ったけど、CPUは一つのコアで動いててびびった - DLはヘッダーを構成してくっつけてCsumを計算するのでそれなりに重い 47

Slide 48

Slide 48 text

評価結果: マルチコア性能 - ULはマルチコアにしたことでショートパケットの処理性能が改善 他はわりと頭打ちっぽい雰囲気 - DLは全体的に性能が改善しました(なぜか1500あたりは下がってる) 48

Slide 49

Slide 49 text

- ULは全てにおいて高性能だったのはCPUに対した負荷が掛からずとも 処理しきれているからだった 割とDecapの負荷は低いのだなという知見を得た - DLの場合は中間のペイロードサイズで24コアだけが負荷が落ち着いてる ので不思議だが、3024byteだと32コアでも負荷が下がってる概ね直観に 当てはまっている - o 評価結果: FramesizeとCPU負荷で線形回帰 49

Slide 50

Slide 50 text

- 全体としてショートからロングにかけてCPU負荷は下がると言うのは直観 にあってる挙動で概ね期待通りでした(多少は謎もありましたが...) - 皆さんも実装するこんな感じの結果になるのかなと思います - 業務でこのように測定評価するとCPU Coreの数ごとの負荷の実態がわかるので、 Productionに入れようと考えた時にどれくらいHWスペックを調整すると 良いかの塩梅を検討する材料にできます - ただこの結果を出すにはいくつかの改善すべき道のりがありました 評価結果: 一覧とまとめ 50 全てのフレームサイズとコア数の組でマルチフローで測ったbps

Slide 51

Slide 51 text

PGW-Uのチューニングと改善 51

Slide 52

Slide 52 text

測定を通じて見つけた三つの問題点 1. eBPFMapからデータが消える事例 - 大量のエントリを流した際にエントリ数が大きくなるとデータが無くなってしまってた 2. GTPv1-Uパケットの処理をマルチコア対応した事例 - RSSが効いておらずでシングルコアでの処理になってた - IntelのNICドライバに機能を追加してマルチコア対応させた その結果$(nproc| CPUコア数)倍の効率アップができた事例 3. checksum機能をoptoutした事例 - パケットのcheck sumの処理で遅くなってそうだったので処理性能を向上させるために実施 - ※これは先ほどの評価の後に取り組んだものです 52

Slide 53

Slide 53 text

- eBPF Mapに対して100万エントリ叩き込んだケースで起きた話でした - BPF_MAP_TYPE_LRU_PERCPU_HASHというMapTypeを使ったことが起因 - 使ってないやつは捨ててもらって最適化してもらおうと考えたが、なんと LRUはFullになったら捨てるわけではなく、MAXのエントリサイズの数割で 削除を始めてしまう....UEが繋がらない原因がわからず悩みました - しかも保持エントリ数に波がある。3割保持の時もあれば、7割保持とか... - 解決方法は以下のTypeとFlagをつけることで解決 - BPF_MAP_TYPE_PERCPU_HASH - グッバイLRU… - BPF_F_NO_PREALLOC - 実行時にメモリアロケートをするフラグ。実利用分だけ使って欲しい。 ディフォルトは事前にアロケートしてしまう。 その1 eBPFMapからデータが消える事例 53

Slide 54

Slide 54 text

その2 GTPv1に対してマルチコア対応した事例 - htopをみると1発でわかる対応のされてなさ(CPUが一個しか使われてない) - core 18だけが100%に張り付いてしまってる - ちなみにショートパケットだと 3~4GbE 程度の性能が出る 54

Slide 55

Slide 55 text

GTPv1-UでMultiFlowパケットを投げるとは? - 一般的にパケットのFlowを識別するには5Tupleの情報を利用します - 5Tupleとは Srcip, Dstip, Sport, Dport, Proto のパラメーターの事を指します - しかし、GTPv1-Uには一般に使われる5Tupleでは負荷分散が不十分 - Srcip: SGWの数 - Dstip: 自分宛なので固定😇 - Sport,Dport,Proto: 必ずUDPで必ず 2152 というポート番号を使ってくる😇 - そこでTEIDを要素に含めることで負荷分散が十分になりPerFlowな処理ができる - UE単位でIDが付与されるため、ユーザー単位でFlowの識別が可能になる 55 GTPv1 Header Format (cf. 3GPP TS 29.281 ) ちなみにUDPとGTPv1のDumpはこんな感じ

Slide 56

Slide 56 text

LTEアーキテクチャでGTPを見ると... 56 UE eNB HSS MME PGW SGW S1-U S5 SGi S6a LTE-Uu S1-MME UE: User Equipment eNB: eNodeB, evolved Node B MME: Mobility Management Entity HSS: Home Subscriber Server SGW: Serving-Gateway PGW: Packet Data Network-Gateway GTPトンネル: internet (& Operator network S11 GTPに含まれるTEIDと呼 ばれるIDでUEからの通 信を識別します 再掲

Slide 57

Slide 57 text

余談: SGWは実際どれくらいあるのか? - SGW -> PGW の通信なので Srcip は変わるのでは?と思うが、 残念ながらそんなに各MNOはSGWを多く置いてるわけではない - ざっくり数十程度のオーダーのイメージ - IPアドレスの分散はそこまで期待はできない。例えばあるキャリア さんの同一エリアからいっぱいくると実質一つのIPのSGWかも...😇 57

Slide 58

Slide 58 text

ethtoolでGTPがRSS対応してないか見る そんな都合のいい対応はなかった😇 58 https://man7.org/linux/man-pages/man8/ethtool.8.html

Slide 59

Slide 59 text

諦めずにLinuxのdriverを眺めてみる まさかのIntelにはあった!!!!!🥳 しかも5G対応の機能まであった... これをEthtoolで設定可能にするように コネコネしたら行けそう... 59

Slide 60

Slide 60 text

RSSを有効にして$proc倍性能を上げました - コネコネしました(完) - TEIDを見てRSSを効かせるようになった - htopで見てもCPUコアがおおよそ全部働いてる🎉 60

Slide 61

Slide 61 text

更なるチャレンジも💪 - この結果を元にLinux kernel にパッチを出した。絶賛レビュー中 - https://patchwork.kernel.org/project/netdevbpf/patch/20231012060115.107183-1-hayatak [email protected]/ - これでRSSがGTPに対して効くので、 モバイルのシステムがLinux上で 効率的に使えるようになって嬉しい:) - こんな感じのノリでGTPv1-UにRSSが効きます 61 ethtool -N ens3 rx-flow-hash gtpu4 sde ethtool -N ens3 rx-flow-hash gtpc4 sde パッチに関するやり取りの写真 英語のメールに心折れかけてます

Slide 62

Slide 62 text

その3 Checksum処理のチューニング - GTPをEncapする時にはUDP checksumを計算する実装になっている - perfした結果を眺めてみると確かにそれなりにコストはかかってそうな 雰囲気がある 62 DLのテスト中にPGW-Uで取ったperf結果 IP TCP IP ETH GTP/ UDP Dot1q

Slide 63

Slide 63 text

Checksum処理の無効化は可能だった - 3GPP TS29.281 を見てみると双方がサポートしていればチェックサムは0で 良いことになっている - つまりUDP CsumがなくてSGWが受け付けてくれるなら問題はない - 実際に主要な会社では問題が無いという事もわかった - よって、UDP CsumをOptoutする機能を追加した - 結果としてこのケースにおいてショートパケットで 3-4Gbps ほど改善できた 63 CSumあり => CSumなし =>

Slide 64

Slide 64 text

1424byteの不自然な谷も改善方向に - 当初の1424byteのケースでは不自然に性能が落ちてたが - 今回の無効化処理によってこの谷は改善された 64 Before(CSum有効) After(Csum無効)

Slide 65

Slide 65 text

今後の展望とまとめ 65

Slide 66

Slide 66 text

今後の展望 - 実は今回のサーバースペックだと、Traffic Gen単体でショートパケットの 場合においては完璧にPGW-Uに圧力をかけ切れなかった。 今後は複数Nodeをどうにかして使って測定できないかなどを検討してる - ショートパケットで 60-80GbE までは一応出る感じだがMaxで出せていない - SingleにおいてULとDLの差がすごいの未解決問題 - なんですごい差があるのかわからず。Intel Vtuneとかの高性能なプロファイラで でもう少し長く睨めっこしたりすると分かるのかもと思う。もうちょっと掘り下げる課題が... - 今回測定に利用したコード類など整理や社内での調整ができたら公開したいなと 思ったりしてます - 謝辞 - 性能測定のお手伝いをしてくれた同僚の @masu-mi -san に感謝です - ぜひ整理でも手伝ってください :) 66

Slide 67

Slide 67 text

まとめ - 自作PGW-Uを題材にパケット処理系の測定と改善の実例を紹介しました - この発表を通じて以下について伝えました - どのようにパケット処理を高速化するのか? - →パケット処理のフレームワークといくつかの定石を利用すること高速化できます - どのようにして測定をするのか? - →TRexとPython使って所望のパケットを大量に送信することで測定できます - どのように改善するのか? - →データ分析を行い、メトリックを観察して洞察を得ながら取り組みます - ついでにモバイル網のコンポーネントは自作可能ということもお伝えしました :) - Pythonでパケット生成から計測評価までを一貫で出来て便利でした🥳 - Let's Enjoy Python and Packet Processing! 67

Slide 68

Slide 68 text

Thank you !!😻 68 @takemioIO @takehaya @takehaya

Slide 69

Slide 69 text

全ての「モノ」がつながる社会を支える
 テクノロジーカンパニー
 69