5K Views
June 26, 20
スライド概要
@higebu
モバイルネットワークの データプレーンをXDPで作る話 2020/06/26 ENOG 63 日下部雄也 BBSakura Networks株式会社
自己紹介 ● 日下部雄也 @higebu ● 2010/04~2016/07: ニフティ ○ ● 2016/08~現在: さくらインターネット ○ ● IaaSの開発運用 ここからモバイルネットワークに入門した 2019/08~現在: BBSakura Networks出向 ○ BBSakura NetworksはさくらとBBIXのジョイントベンチャー ○ モバイルネットワーク関連のシステムの開発、運用をやっている ○ 2020/04から開発本部長 ● 普段使っているエディタはVim ● 北海道小樽市在住
目次 ● さくらのセキュアモバイルコネクトとは ● 補足: さくらのクラウドのスイッチについて ● 構成変更について ● PGW-Uの中身 ● 苦労話
さくらのセキュアモバイルコネクトとは ● SIMを入れたデバイスからインターネットを経由しない 閉域網でさくらのクラウドと通信できるサービス ● SIM1枚当たり13円/月 ● 詳しくは https://www.sakura.ad.jp/services/sim/
さくらのセキュアモバイルコネクトとは
モバイルゲートウェイとは ● お客様が作成することができるGTPトンネルの終端 ● 所属しているSIMの通信がここを通る ● 下記の機能がある ○ インターフェース(スイッチと接続する機能) ○ 所属しているSIMと、スイッチの先のサーバなどとの間で通信を行えるようにする ○ インターネット接続(NAPT) ○ デバイス間通信 ○ スタティックルート ○ SIMルート ○ トラフィックコントロール(帯域制限) ● 機能の詳細は マニュアル 参照 ● 以後、MGWと呼ぶ
補足: さくらのクラウドのスイッチについて
補足: さくらのクラウドのスイッチについて ● 実態はVLAN ● PR:「さくらのクラウド」のアーキテクチャは、意外なほどシンプルだったや、ENOG18発表資料 さくらのクラウド インフラの紹介 参照 ENOG18発表資料 さくらのクラウド インフラの紹介 P.13
構成変更について
構成変更について ● 2019/12/17のメンテナンス で構成が変わってXDPベースになっている ● 以前の構成については2018/01/24のさくらの夕べで発表した ● (この発表資料を見た、とある企業から特許に関する問い合わせがあったが問題なく話は終結している) ● 今後もモバイル関連の技術についてもっとオープンに議論していきたいという気持ちで発表しています https://speakerdeck.com/higebu/20180124-sakura-secure-mobile-connect-deep-dive?slide=21
構成変更について ● 2019/12/17以降の構成 インターネット VLAN PGW-C SGW VLAN PGW-U VLAN VLAN IDを変換しつつ通信に必要な処理を全部やる ※CUPSをしてるけど間のプロトコルは標準無視してgRPCでやってる さくらのクラウド上の スイッチたち
PGW-Uの中身
PGW-Uの中身 スタティックルート機能で設定し た経路はここに入る API インターネットに抜けるためのVRF vrf MGW C-Plane netlink(3) vlan bpf(2) dummy global vrf global vlan default vrf roaming mgmt bpf(2) netlink(3) eBPF Maps ● ● ● ● ● ● FIB Table mgw vrf TC eth1 XDP VLAN trunkなポートに接続さ れている eth0 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に応答してくれるようになる
ここからは機能ごとのパケット処理の ざっくりした説明をします 詳細はソースコードを読んでください ≒入社してください
UE -> MGWに接続されたスイッチ(UL) VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP GTP User Packet(IP) RX XDP program bpf_map_lookup_elem() eBPF Maps TEID A bpf_fib_lookup() VLAN Y (MGWに接続されているスイッチのVLAN) Ethernet ● ● 802.1q User Packet(IP) TX 前提(以降のページでは書かない) ○ 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のものなので、スタティックルート機能で設定した経路も使われる FIB Table
MGWに接続されたスイッチ -> UE(DL) VLAN Y (MGWに接続されているスイッチのVLAN) Ethernet 802.1q User Packet(IP) RX XDP program bpf_map_lookup_elem() eBPF Maps 宛先IPがUEのアドレス bpf_fib_lookup() VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP GTP User Packet(IP) TX TEID A ● 処理内容 ○ 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()で使うインターフェースはローミング用のインターフェース FIB Table
デバイス間通信(UL/DL) VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP ソースIPは SGW Aのもの GTP User Packet(IP) RX XDP program bpf_map_lookup_elem() eBPF Maps TEID A 宛先IPが同じMGWに所属している別 のUEのアドレス bpf_fib_lookup() VLAN X Ethernet 802.1q IP UDP 宛先IPは SGW Bのもの ● User Packet(IP) TX TEID B 処理内容 ○ TEID Aを元にeBPF Mapからトンネル情報A、MGW情報を取得する ○ MGW IDと宛先のUEのIPアドレスからトンネル情報Bを取得する ■ ○ ● GTP 宛先のUEのセッションがあれば、トンネル情報Bを取得できる トンネル情報Bを元にパケットを書き換え ■ 宛先IPをトンネル情報Bに入っているSGW Bのものにし、GTPのTEIDもBのものに書き換える ■ bpf_fib_lookup()でソース/宛先MACアドレスを取得できればこれを使ってXDP_TX、取得できなければXDP_PASSする この辺りは @takemioIO が詳しい FIB Table
SIMルート(DL) VLAN Y (MGWに接続されているスイッチのVLAN) Ethernet 802.1q User Packet(IP) RX XDP program bpf_map_lookup_elem() eBPF Maps SIMルートに登録されている IPレンジにマッチする宛先IP bpf_fib_lookup() VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP GTP User Packet(IP) TX TEID A ● ● 前提 ○ 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からトンネル情報を取得 ○ トンネル情報を元にパケットを書き換え ■ ● 特開2019-216323 ここは普通のDLと一緒 FIB Table
UE -> インターネット(UL) VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP GTP IP L4 Data RX XDP program bpf_map_lookup_elem() bpf_map_update_elem() bpf_map_delete_elem() eBPF Maps TEID A 宛先IPがグローバルアドレス bpf_fib_lookup() VLAN Z (グローバルネットワークのVLAN) Ethernet 802.1q IP L4 Data TX ソースIPがPGW-Uの グローバルアドレス ● 前提 ○ ● 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()で使うインターフェースをグローバル用のインターフェースにする FIB Table
インターネット -> UE(DL) VLAN Z (グローバルネットワークのVLAN) Ethernet 802.1q IP L4 RX Data XDP program bpf_map_lookup_elem() bpf_map_update_elem() bpf_map_delete_elem() eBPF Maps 宛先IPがPGW-Uのグローバルアドレス bpf_fib_lookup() VLAN X (ローミングネットワークのVLAN) Ethernet 802.1q IP UDP GTP IP L4 Data TX TEID A ● 処理内容 ○ 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する FIB Table
トラフィックコントロール(UL/DL) Ethernet 802.1q GTP or User Packet RX XDP program TC ingress cls_bpf bpf_redirect() Ethernet ● 802.1q TCが有効なMGWでは、MGW情報のTCをするかどうかのフラグをオンにし、TCで使うClass IDを持たせている 処理内容 ○ ○ XDPプログラム ■ bpf_xdp_adjust_meta()でメタデータ領域を確保する ■ 取得したMGW情報内のTCのClass IDをメタデータ領域に書き込む ■ 状況に応じてパケットを書き換えてXDP_PASSする ■ ingress側で、XDPメタデータ内のTCのClass IDをskb->markに書き込んで、bpf_redirect() TC ● ■ ● TX 前提 ○ ● GTP or User Packet iptablesでset-markするのと同じ egress側はTC_ACT_OKするだけ この辺りは @_notchi が詳しい TC egress cls_bpf
その他 ● 通信量カウント用の Mapを用意して、SIM毎の通信量カウントをしている ● xdpcapを使って緊急時にパケットキャプチャをやれるようにしている ● 命令数が4096に制限されていて、有限ループも使えなかった時代の名残で、プログラムが 4つに分かれ ていて、メインのプログラムから bpf_tail_call()で呼び出している
苦労話
XDP metadataがVLANに対応していなかった ● 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に対応していなかった ● 最初は物理サーバで開発していて、だいたいできて来たので、クラウド上で動かそうと 思ったらそもそも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が使える
virtio_netがXDP metadataに対応していなかった ● クラウド上でXDPは動いたけど、virtio_netでXDP metadataが使えなかった ● 対応させた -> [bpf-next,v6,2/2] virtio_net: add XDP meta data support ● qemuでVM起動するときのNICのオプションを変えるとソースのどこを通るようになるの かがわかるようになった(もう忘れた) ● 関係ない話ですが、LKMLにパッチをメールで送信するのが難しいです
一部キャリアの一部基地局でDLの通信が通らない事象 ● SGWはエラーを返して来ていないけど通らないので、原因がわかるのに時間がかかった ● spare bitを1にしてしまったのが原因だった ○ 3GPP TS 29.060/29.281には0にしないといけないし、受け取った側は評価してはいけないと 書いてある ● キャリアの設備でも仕様通りではない挙動をする設備がある。。。 ● お客様や関係者の皆様には大変ご迷惑おかけしました🙇
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行くらい (自動生成コード除く)
終わり
モバイルコアの開発に 興味がある方はぜひ。。。 http://recruit.softbank.jp/career/positions/detail/000920/
EOF
参考 ● 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)
参考 ● ● 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