Slide 1

Slide 1 text

モバイルネットワークの データプレーンをXDPで作る話 2020/06/26 ENOG 63 日下部雄也 BBSakura Networks株式会社

Slide 2

Slide 2 text

自己紹介 ● 日下部雄也 @higebu ● 2010/04~2016/07: ニフティ ○ IaaSの開発運用 ● 2016/08~現在: さくらインターネット ○ ここからモバイルネットワークに入門した ● 2019/08~現在: BBSakura Networks出向 ○ BBSakura NetworksはさくらとBBIXのジョイントベンチャー ○ モバイルネットワーク関連のシステムの開発、運用をやっている ○ 2020/04から開発本部長 ● 普段使っているエディタはVim ● 北海道小樽市在住

Slide 3

Slide 3 text

目次 ● さくらのセキュアモバイルコネクトとは ● 補足: さくらのクラウドのスイッチについて ● 構成変更について ● PGW-Uの中身 ● 苦労話

Slide 4

Slide 4 text

さくらのセキュアモバイルコネクトとは ● SIMを入れたデバイスからインターネットを経由しない 閉域網でさくらのクラウドと通信できるサービス ● SIM1枚当たり13円/月 ● 詳しくは https://www.sakura.ad.jp/services/sim/

Slide 5

Slide 5 text

さくらのセキュアモバイルコネクトとは

Slide 6

Slide 6 text

モバイルゲートウェイとは ● お客様が作成することができるGTPトンネルの終端 ● 所属しているSIMの通信がここを通る ● 下記の機能がある ○ インターフェース(スイッチと接続する機能) ○ 所属しているSIMと、スイッチの先のサーバなどとの間で通信を行えるようにする ○ インターネット接続(NAPT) ○ デバイス間通信 ○ スタティックルート ○ SIMルート ○ トラフィックコントロール(帯域制限) ● 機能の詳細は マニュアル 参照 ● 以後、MGWと呼ぶ

Slide 7

Slide 7 text

補足: さくらのクラウドのスイッチについて

Slide 8

Slide 8 text

補足: さくらのクラウドのスイッチについて ● 実態はVLAN ● PR:「さくらのクラウド」のアーキテクチャは、意外なほどシンプルだった や、ENOG18発表資料 さくらのクラウド インフラの紹介 参照 ENOG18発表資料 さくらのクラウド インフラの紹介 P.13

Slide 9

Slide 9 text

構成変更について

Slide 10

Slide 10 text

構成変更について https://speakerdeck.com/higebu/20180124-sakura-secure-mobile-connect-deep-dive?slide=21 ● 2019/12/17のメンテナンス で構成が変わってXDPベースになっている ● 以前の構成については2018/01/24のさくらの夕べで発表した ● (この発表資料を見た、とある企業から特許に関する問い合わせがあったが問題なく話は終結している) ● 今後もモバイル関連の技術についてもっとオープンに議論していきたいという気持ちで発表しています

Slide 11

Slide 11 text

構成変更について ● 2019/12/17以降の構成 SGW PGW-C PGW-U さくらのクラウド上の スイッチたち インターネット VLAN VLAN VLAN VLAN IDを変換しつつ通信に必要な処理を全部やる ※CUPSをしてるけど間のプロトコルは標準無視して gRPCでやってる

Slide 12

Slide 12 text

PGW-Uの中身

Slide 13

Slide 13 text

MGW PGW-Uの中身 mgw vrf vlan dummy roaming mgmt global vrf global default vrf eth0 XDP vlan vrf eth1 VLAN trunkなポートに接続さ れている TC eBPF Maps FIB Table C-Plane API netlink(3) bpf(2) netlink(3) bpf(2) スタティックルート機能で設定し た経路はここに入る ● C-PlaneはGo製 ● コンパネでMGWを作成すると上のMGWの中身が作成され、 eBPF Mapsに必要な情報が書き込まれる ● PGWCからのトンネル作成のリクエストが来ると、 eBPF Mapsに必要な情報が書き込まれる ● XDPのプログラムでは来たパケットを eBPF Mapsの情報を元に適切に処理して、 XDP_DROPしたり、XDP_PASSしたり、XDP_TXしたりしている ● 帯域制御のためにTCも使っている ● dummyインターフェースはProxy ARPのため ○ Proxy ARPしたい経路をここに向けると、 VLANインターフェースからの ARPに応答してくれるようになる インターネットに抜けるための VRF

Slide 14

Slide 14 text

ここからは機能ごとのパケット処理の ざっくりした説明をします 詳細はソースコードを読んでください ≒入社してください

Slide 15

Slide 15 text

UE -> MGWに接続されたスイッチ(UL) ● 前提(以降のページでは書かない) ○ PGW-CへのCreate Session Request時に通信に必要な情報がPGW-Uに伝わっていなければならない ○ 必要な情報というのは、具体的にはSGWのU側のIP、PGW/SGWのU側で使うTEID、VLAN IDやVLANインターフェースのIDを含むMGWの情報 ● 処理内容 ○ 不要なパケットはDROPするが、LinuxにARPテーブルの管理を任せるため、ARPはPASSする(以降のページでは書かない) ○ TEID Aを元にeBPF Mapからトンネル情報、MGW情報を取得する ○ トンネル情報を元にパケットを書き換え ■ bpf_xdp_adjust_head()でIP/UDP/GTPヘッダの長さの分パケットのプラス方向に先頭アドレスを移動(decap) ■ bpf_fib_lookup()でソース/宛先MACアドレスを取得できればこれを使ってXDP_TX、取得できなければXDP_PASSする ● このとき参照するFIBテーブルはMGWのVRFのものなので、スタティックルート機能で設定した経路も使われる Ethernet 802.1q IP UDP GTP User Packet(IP) RX TX Ethernet 802.1q User Packet(IP) VLAN X (ローミングネットワークの VLAN) VLAN Y (MGWに接続されているスイッチの VLAN) TEID A XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem()

Slide 16

Slide 16 text

MGWに接続されたスイッチ -> UE(DL) ● 処理内容 ○ eBPF Mapを使って、VLAN IDからMGW情報、MGW IDとUEのIPアドレスからトンネル情報を取得する ○ トンネル情報を元にパケットを書き換え ■ bpf_xdp_adjust_head()でIP/UDP/GTPヘッダの長さの分パケットのマイナス方向に先頭アドレスを移動(encap) ■ トンネル情報からIP/UDP/GTPヘッダを書き込む ● 主にSGWのIP、GTPのTEIDを書き込む ■ bpf_fib_lookup()でソース/宛先MACアドレスを取得できればこれを使ってXDP_TX、取得できなければXDP_PASSする ● bpf_fib_lookup()で使うインターフェースはローミング用のインターフェース Ethernet 802.1q User Packet(IP) RX TX Ethernet 802.1q User Packet(IP) VLAN X (ローミングネットワークの VLAN) VLAN Y (MGWに接続されているスイッチの VLAN) TEID A IP UDP GTP 宛先IPがUEのアドレス XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem()

Slide 17

Slide 17 text

デバイス間通信(UL/DL) ● 処理内容 ○ TEID Aを元にeBPF Mapからトンネル情報A、MGW情報を取得する ○ MGW IDと宛先のUEのIPアドレスからトンネル情報Bを取得する ■ 宛先のUEのセッションがあれば、トンネル情報Bを取得できる ○ トンネル情報Bを元にパケットを書き換え ■ 宛先IPをトンネル情報Bに入っているSGW Bのものにし、GTPのTEIDもBのものに書き換える ■ bpf_fib_lookup()でソース/宛先MACアドレスを取得できればこれを使ってXDP_TX、取得できなければXDP_PASSする ● この辺りは @takemioIO が詳しい Ethernet 802.1q IP UDP GTP User Packet(IP) RX TX Ethernet 802.1q User Packet(IP) VLAN X (ローミングネットワークの VLAN) VLAN X TEID A IP UDP GTP TEID B 宛先IPが同じMGWに所属している別 のUEのアドレス ソースIPは SGW Aのもの 宛先IPは SGW Bのもの XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem()

Slide 18

Slide 18 text

SIMルート(DL) ● 前提 ○ SIMルートのMapが(BPF_MAP_TYPE_LPM_TRIE)あり、MGW IDをキーにしたMapのMap(BPF_MAP_TYPE_HASH_OF_MAPS)がある ○ SIMルートのMapはキーがIPレンジ、値がトンネル情報になっている ● 処理内容 ○ eBPF Mapを使って、VLAN IDからMGW情報を取得 ○ MGW IDからMGW毎のSIMルートMapを取得 ○ 宛先IPを使ってSIMルートMapからトンネル情報を取得 ○ トンネル情報を元にパケットを書き換え ■ ここは普通のDLと一緒 ● 特開2019-216323 Ethernet 802.1q User Packet(IP) RX TX Ethernet 802.1q User Packet(IP) VLAN X (ローミングネットワークの VLAN) VLAN Y (MGWに接続されているスイッチの VLAN) TEID A IP UDP GTP SIMルートに登録されている IPレンジにマッチする宛先 IP XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem()

Slide 19

Slide 19 text

UE -> インターネット(UL) ● 前提 ○ conntrackテーブル(BPF_MAP_TYPE_LRU_HASH)とイベント送信用のMap(BPF_MAP_TYPE_PERF_EVENT_ARRAY)を用意しておく ● 処理内容 ○ TEID Aを元にeBPF Mapからトンネル情報、MGW情報を取得する ○ 宛先IPがグローバルアドレスだった場合、NAPTの処理に入る ■ conntrackテーブルから、5タプル+方向をキーにNAPT情報を取得する ■ NAPT情報がなければ、グローバル側のソースポート(ICMPの場合はEcho ID)の割り当てをしつつ、NAPT情報を作成 ● このときNAPT情報のイベントを送信をする(abuse対応で使う) ○ トンネル情報とNAPT情報を元にパケットを書き換え ■ 主にVLAN ID、ソースIP、ソースポートを書き換える ■ decapは普通のULと一緒だが、bpf_fib_lookup()で使うインターフェースをグローバル用のインターフェースにする Ethernet 802.1q IP UDP GTP IP RX TX Ethernet 802.1q VLAN X (ローミングネットワークの VLAN) VLAN Z (グローバルネットワークの VLAN) TEID A 宛先IPがグローバルアドレス L4 Data IP L4 Data ソースIPがPGW-Uの グローバルアドレス XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem() bpf_map_update_elem() bpf_map_delete_elem()

Slide 20

Slide 20 text

インターネット -> UE(DL) ● 処理内容 ○ conntrackテーブルから所謂5タプル+方向をキーとして、NAPT情報、トンネル情報を取得する ○ NAPT情報、トンネル情報を元にパケットを書き換え ■ bpf_xdp_adjust_head()でIP/UDP/GTPヘッダの長さの分パケットのマイナス方向に先頭アドレスを移動(encap) ■ NAPT情報を使って、インナーパケットのIP/L4ヘッダを書き換える ■ トンネル情報を使って、アウターパケットのIP/UDP/GTPヘッダを書き込む ■ bpf_fib_lookup()でソース/宛先MACアドレスを取得できればこれを使ってXDP_TX、取得できなければXDP_PASSする Ethernet 802.1q RX TX Ethernet 802.1q VLAN X (ローミングネットワークの VLAN) VLAN Z (グローバルネットワークの VLAN) TEID A IP UDP GTP IP L4 Data IP L4 Data 宛先IPがPGW-Uのグローバルアドレス XDP program eBPF Maps FIB Table bpf_fib_lookup() bpf_map_lookup_elem() bpf_map_update_elem() bpf_map_delete_elem()

Slide 21

Slide 21 text

トラフィックコントロール(UL/DL) ● 前提 ○ TCが有効なMGWでは、MGW情報のTCをするかどうかのフラグをオンにし、TCで使うClass IDを持たせている ● 処理内容 ○ XDPプログラム ■ bpf_xdp_adjust_meta()でメタデータ領域を確保する ■ 取得したMGW情報内のTCのClass IDをメタデータ領域に書き込む ■ 状況に応じてパケットを書き換えてXDP_PASSする ○ TC ■ ingress側で、XDPメタデータ内のTCのClass IDをskb->markに書き込んで、bpf_redirect() ● iptablesでset-markするのと同じ ■ egress側はTC_ACT_OKするだけ ● この辺りは @_notchi が詳しい Ethernet 802.1q GTP or User Packet RX TX Ethernet 802.1q GTP or User Packet XDP program TC ingress cls_bpf TC egress cls_bpf bpf_redirect()

Slide 22

Slide 22 text

その他 ● 通信量カウント用のMapを用意して、SIM毎の通信量カウントをしている ● xdpcapを使って緊急時にパケットキャプチャをやれるようにしている ● 命令数が4096に制限されていて、有限ループも使えなかった時代の名残で、プログラムが 4つに分かれ ていて、メインのプログラムから bpf_tail_call()で呼び出している

Slide 23

Slide 23 text

苦労話

Slide 24

Slide 24 text

● Linuxのバグだと気付くのに時間がかかった ● VLANのパケットはskbが生成されるときにuntagされる ● skb_vlan_untag()で呼ばれるskb_reorder_vlan_header()でXDP metadataが置いて行かれてた ● 4.19以降に↓のパッチが入って直っています ● [v3] net: Fix missing meta data in skb with vlan packet XDP metadataがVLANに対応していなかった

Slide 25

Slide 25 text

● 最初は物理サーバで開発していて、だいたいできて来たので、クラウド上で動かそうと 思ったらそもそもXDPが動かないことに気付いた ● virtio_netでXDPをやるにはキューをXDP用に別途用意しないといけない ○ [net-next,v6,0/5] XDP for virtio_net “queues must be available to dedicate to XDP” ● 他にも必要な機能があって、さくらのクラウドがマルチキュー対応した ○ サーバの仮想NICがマルチキューに対応しました ○ https://www.linux-kvm.org/page/Multiqueue ● サーバ作成時にタグとして @nic-double-queue を付けるとキューの数がCPUコア数 *NIC数*2になる機能を作っていただいた ● ちなみにさくらのクラウドではvnet_hdrがオフになっているので、ethtoolでオフロードをオ フにしまくらなくてもXDPが使える さくらのクラウドがXDPに対応していなかった

Slide 26

Slide 26 text

● クラウド上でXDPは動いたけど、virtio_netでXDP metadataが使えなかった ● 対応させた -> [bpf-next,v6,2/2] virtio_net: add XDP meta data support ● qemuでVM起動するときのNICのオプションを変えるとソースのどこを通るようになるの かがわかるようになった(もう忘れた) ● 関係ない話ですが、LKMLにパッチをメールで送信するのが難しいです virtio_netがXDP metadataに対応していなかった

Slide 27

Slide 27 text

● SGWはエラーを返して来ていないけど通らないので、原因がわかるのに時間がかかった ● spare bitを1にしてしまったのが原因だった ○ 3GPP TS 29.060/29.281には0にしないといけないし、受け取った側は評価してはいけないと 書いてある ● キャリアの設備でも仕様通りではない挙動をする設備がある。。。 ● お客様や関係者の皆様には大変ご迷惑おかけしました 一部キャリアの一部基地局でDLの通信が通らない事象

Slide 28

Slide 28 text

C-Planeが大変という話 ● ソフトウェアでのパケット処理あれこれ〜何故我々はロードバランサを自作するに至ったのか〜 (LINE) に↓のようなスライドがあって、めっちゃわかるーという気持ちになった ● D-Planeでなるべくややこしい処理をしないために C-Planeでお膳立てしてあげる必要がある ● ARPやルートの管理をLinuxに任せられるのでD-Planeはパケット処理に集中できる ● うちのPGW-UはCP: 8,000行、DP: 1,600行(2,900 instructions)くらいで、PGW-Cは5,000行くらい (自動生成コード除く)

Slide 29

Slide 29 text

終わり

Slide 30

Slide 30 text

モバイルコアの開発に 興味がある方はぜひ。。。 http://recruit.softbank.jp/career/positions/detail/000920/

Slide 31

Slide 31 text

EOF

Slide 32

Slide 32 text

参考 ● GoでEPC ○ JANOG42 GoでEPC作って本番運用している話 ● XDP ○ Cilium BPF and XDP Reference Guide ○ Suricata eBPF and XDP ○ Linux Documantation/bpf ○ Linux samples/bpf ○ XDP Hands-On Tutorial ○ BPF Features by Linux Kernel Version ○ Linux Observability with BPF ○ yunazuno.log ○ @IT Berkeley Packet Filter(BPF)入門 ○ JANOG45 パケット処理の独自実装や高速化手法の 比較と実践 独自パケット処理実装方法解説( XDP)

Slide 33

Slide 33 text

参考 ● LinuxのVRF ○ https://www.kernel.org/doc/Documentation/networking/vrf.txt ○ https://cumulusnetworks.com/blog/vrf-for-linux/ ○ http://yunazuno.hatenablog.com/entry/2017/06/17/225917 ● NAPT ○ https://tools.ietf.org/html/rfc2663 ○ https://tools.ietf.org/html/rfc3022 ○ https://tools.ietf.org/html/rfc6888 ○ https://github.com/cilium/cilium/tree/master/bpf ○ https://github.com/torvalds/linux/tree/master/net/netfilter