モバイルネットワークのデータプレーンをXDPで作る話 / XDP based Mobile Network Data Plane

モバイルネットワークのデータプレーンをXDPで作る話 / XDP based Mobile Network Data Plane

Db970064044641bf2b495822d66f0685?s=128

Yuya Kusakabe

June 26, 2020
Tweet

Transcript

  1. 2.

    自己紹介 • 日下部雄也 @higebu • 2010/04~2016/07: ニフティ ◦ IaaSの開発運用 •

    2016/08~現在: さくらインターネット ◦ ここからモバイルネットワークに入門した • 2019/08~現在: BBSakura Networks出向 ◦ BBSakura NetworksはさくらとBBIXのジョイントベンチャー ◦ モバイルネットワーク関連のシステムの開発、運用をやっている ◦ 2020/04から開発本部長 • 普段使っているエディタはVim • 北海道小樽市在住
  2. 6.

    モバイルゲートウェイとは • お客様が作成することができるGTPトンネルの終端 • 所属しているSIMの通信がここを通る • 下記の機能がある ◦ インターフェース(スイッチと接続する機能) ◦

    所属しているSIMと、スイッチの先のサーバなどとの間で通信を行えるようにする ◦ インターネット接続(NAPT) ◦ デバイス間通信 ◦ スタティックルート ◦ SIMルート ◦ トラフィックコントロール(帯域制限) • 機能の詳細は マニュアル 参照 • 以後、MGWと呼ぶ
  3. 11.

    構成変更について • 2019/12/17以降の構成 SGW PGW-C PGW-U さくらのクラウド上の スイッチたち インターネット VLAN

    VLAN VLAN VLAN IDを変換しつつ通信に必要な処理を全部やる ※CUPSをしてるけど間のプロトコルは標準無視して gRPCでやってる
  4. 13.

    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
  5. 15.

    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()
  6. 16.

    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()
  7. 17.

    デバイス間通信(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()
  8. 18.

    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()
  9. 19.

    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()
  10. 20.

    インターネット -> 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()
  11. 21.

    トラフィックコントロール(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()
  12. 23.
  13. 25.

    • 最初は物理サーバで開発していて、だいたいできて来たので、クラウド上で動かそうと 思ったらそもそも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に対応していなかった
  14. 26.

    • クラウド上で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に対応していなかった
  15. 27.

    • SGWはエラーを返して来ていないけど通らないので、原因がわかるのに時間がかかった • spare bitを1にしてしまったのが原因だった ◦ 3GPP TS 29.060/29.281には0にしないといけないし、受け取った側は評価してはいけないと 書いてある

    • キャリアの設備でも仕様通りではない挙動をする設備がある。。。 • お客様や関係者の皆様には大変ご迷惑おかけしました 一部キャリアの一部基地局でDLの通信が通らない事象
  16. 29.
  17. 31.

    EOF

  18. 32.

    参考 • 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)
  19. 33.

    参考 • 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