この投稿では、FRR DOCA データプレーン プラグインの作成方法と、新しい DOCA フロー ライブラリを使用して PBR ルールをオフロードする方法を紹介します。前回の記事では、DPDK rte_flow
ライブラリを使用して BlueField 上の PBR ルールを高速化するための FRR データプレーン プラグインの作成について説明しましたが、今回は、DOCA フロー ライブラリを使用して PBR ルール をオフロードする方法について説明します。パート 1 については、NVIDIA BlueField DPU と DPDK を使ったアプリケーションの開発をご覧ください。
Zebra に DOCA データプレーン プラグインを追加する
ハードウェアの初期化には DPDK API を使いましたが、データプレーン フローのパイプラインのセットアップには DOCA フローのAPI を使いました。そのためには、DPDK (libdpdk.pc
) と DOCA フロー (doca-flow.pc
) の共有ライブラリを DOCA データプレーン プラグインとリンクする必要がありました。
root@dpu-arm:~# export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/mellanox/dpdk/lib/aarch
64-linux-gnu/pkgconfig
root@dpu-arm:~# pkg-config --libs doca-flow
-ldoca_flow
root@dpu-arm:~# pkg-config --cflags doca-flow
-DALLOW_EXPERIMENTAL_API -include rte_config.h -mcpu=cortex-a72 -DALLOW_EXPERIMENTAL_API -I/opt/mellanox/dpdk/include/dpdk -I/opt/mellanox/dpdk/include/dpdk/../aarch64-linux-gnu/dpdk -I/opt/mellanox/dpdk/include/dpdk -I/usr/include/libnl3
root@dpu-arm:~#
FRR の makefile (configure.ac
) に DPDK と DOCA フローの pkg check and-define macro
を追加しました。
if test "$enable_dp_doca" = "yes"; then
PKG_CHECK_MODULES([DOCA], [libdpdk doca-flow], [
AC_DEFINE([HAVE_DOCA], [1], [Enable DOCA backend])
DOCA=true
], [
AC_MSG_ERROR([configuration specifies --enable-dp-doca but DOCA libs were not found])
])
fi
DPDK と DOCA 両方の flow
libs と cflags
を zebra-dp-doca make
のマクロ (zebra/subdir.am
) に入れました。
zebra_zebra_dplane_doca_la_CFLAGS = $(DOCA_CFLAGS)
zebra_zebra_dplane_doca_la_LIBADD = $(DOCA_LIBS)
DOCA データプレーン プラグインは、/etc/frr/daemons
を使用して FRR サービス開始時に有効化することができます。
zebra_options= " -M dplane_doca -A 127.0.0.1"
ハードウェアの初期化およびポート マッピング
DPDK API のrte_eal_init
と rte_eth_dev_info_get
を使用して、ハードウェアの初期化と Zebra インターフェイスと DPDK ポート マッピングのセットアップを行います。このワークフローは、前述の DPDK データプレーン プラグインと同じです。
root@dpu-arm:~# vtysh -c "show dplane doca port"
Total ports: 6 cores: 8
Port Device IfName IfIndex sw,domain,port
0 0000:03:00.0 p0 4 0000:03:00.0,0,65535
1 0000:03:00.0 pf0hpf 6 0000:03:00.0,0,4095
2 0000:03:00.0 pf0vf0 15 0000:03:00.0,0,4096
3 0000:03:00.0 pf0vf1 16 0000:03:00.0,0,4097
4 0000:03:00.1 p1 5 0000:03:00.1,1,65535
5 0000:03:00.1 pf1hpf 7 0000:03:00.1,1,20479
root@dpu-arm:~#
DOCA フロー初期化
PBR ルールのプログラミングに doca-flow
を使うには、doca-flow
と doca-flow-port
のデータベースを初期化する必要がありました。この初期化は、rte_eal_init
を使ってハードウェアを初期化した後に行われました。
doca_flow_init は、フローとキュー数の設定をして、doca-flow
ライブラリを初期化するために使用しました。
struct doca_flow_cfg flow_cfg; memset(&flow_cfg, 0, sizeof(flow_cfg)); flow_cfg.total_sessions = ZD_DOCA_FLOW_MAX; flow_cfg.queues = doca_ctx->nb_cores;
doca_flow_init(&flow_cfg, &err);
DPDK を使ってハードウェア ポートを設定したので、doca-flow-port
データベースに dpdk_port-id
でインストールする必要がありました。
struct doca_flow_port_cfg port_cfg;
memset(&port_cfg, 0, sizeof(port_cfg));
port_cfg.port_id = dpdk_port_id;
port_cfg.type = DOCA_FLOW_PORT_DPDK_BY_ID;
snprintf(port_id_str, ZD_PORT_STR_MAX, "%u", port_cfg.port_id);
port_cfg.devargs = port_id_str;
doca_port = doca_flow_port_start(&port_cfg, &err);
doca-flow の API を使った PBR ルールのプログラム
DOCA フローは、match、action、forward、monitor の各属性に対応した一連のデータ構造でプログラムされています。
struct doca_flow_match match, match_mask;
struct doca_flow_actions actions;
struct doca_flow_fwd fwd;
struct doca_flow_monitor monitor;
フロー マッチ
これは、match と match-mask で指定されます。match-mask はオプションであり、指定しない場合は doca-flow
ライブラリによって自動入力されます。
memset(&match, 0, sizeof(match));
memset(&match_mask, 0, sizeof(match_mask));
match.out_src_ip.type = DOCA_FLOW_IP4_ADDR;
match.out_src_ip.ipv4_addr = src_ip;
match_mask.out_src_ip.ipv4_addr = src_ip_mask;
match.out_dst_ip.type = DOCA_FLOW_IP4_ADDR;
match.out_dst_ip.ipv4_addr = dst_ip;
match_mask.out_src_ip.ipv4_addr = dst_ip_mask;
match.out_l4_type = ip_proto;
match.out_src_port = RTE_BE16 (l4_src_port);
match_mask.out_src_port = UINT16_MAX;
match.out_dst_port = RTE_BE16 (l4_dst_port);
match_mask.out_dst_port = UINT16_MAX;
eth
や eth-mask
などのフィールドは追加しないようにしました。これは、doca-flow
ライブラリが、他のマッチ フィールドである dst_ip
や src_ip
に基づいて、RTE_ETHER_TYPE_IPV4
や RTE_ETHER_TYPE_IPV6
にそのフィールドを自動追加することができるからです。
フロー アクション
パケットをルーティングするために、宛先 MAC アドレスをゲートウェイ (leaf2) の MAC に変更し、TTL を減少し、送信元 MAC アドレスを変更する必要がありました。これは元々、パート 1「Developing Applications with NVIDIA BlueField DPU and DPDK」で説明したものです。
memset(&actions, 0, sizeof(actions)); actions.dec_ttl = true; memcpy(actions.mod_src_mac, uplink_mac, DOCA_ETHER_ADDR_LEN); memcpy(actions.mod_dst_mac, gw_mac, DOCA_ETHER_ADDR_LEN);
フロー フォワード
そして、出力ポートをアップリンクに設定しました。
memset(&fwd, 0, sizeof(fwd));
fwd.type = DOCA_FLOW_FWD_PORT;
fwd.port_id = out_port_id;
フロー モニタリング
トラブルシューティングのためにフロー カウンターを設定しました。
memset(&monitor, 0, sizeof(monitor)); monitor.flags |= DOCA_FLOW_MONITOR_COUNT;
DOCA フロー パイプとエントリ
フローの作成は、2 つのステップで行います。
- フロー パイプを作成します。
- フロー パイプにフロー エントリを追加します。
最初のステップでは、Lookup ステージのソフトウェア テンプレートが作成されます。ステップ 2 では、このテンプレートを使って、ハードウェアにフローをプログラムします。
パイプは、多くの類似したフローをプログラムする必要がある場合に便利です。このような場合、1 つのマッチ テンプレート (パイプ) を設定し、フロー エントリ作成時にどのマッチ フィールドを更新する必要があるかを示すことができます (例: レイヤー 4 の宛先ポート)。後続のフロー エントリは、パイプ (レイヤー 4 の宛先ポート) と異なるマッチ フィールドにのみ追加する必要があります。
PBR の場合、各フロー パターンがユニークなので、すでに追加していたフロー属性を使って、PBR ルールごとに別のパイプとエントリを作成しました。
struct doca_flow_pipe_cfg pipe_cfg;
pipe_cfg.name = "pbr";
pipe_cfg.port = in_dport->doca_port;
pipe_cfg.match = &match;
pipe_cfg.match_mask = &match_mask;
pipe_cfg.actions = &actions;
pipe_cfg.monitor = &monitor;
pipe_cfg.is_root = true;
flow_pipe = doca_flow_create_pipe(&pipe_cfg, &fwd, NULL, &err);
flow_entry = doca_flow_pipe_add_entry(0, flow_pipe, &match, &actions, &monitor, &fwd, &err);
フローの削除
フロー パイプとエントリ作成の API は、その後の削除のためにキャッシュされなければならないパイプとフロー ポインターを返します。
doca_flow_pipe_rm_entry(0, flow_entry);
doca_flow_destroy_pipe(port_id, flow_pipe);
フローの統計
フロー作成時に、DOCA_FLOW_MONITOR_COUNT
フラグを設定しました。doca_flow_query
を使用して、フローの統計情報を照会しました。
struct doca_flow_query query;
// hit counters – query.total_pkts and query.total_bytes
memset(&query, 0, sizeof(query));
doca_flow_query(flow_entry, &query);
ハードウェア アクセラレーションの検証
FRR-PBR のルール設定とトラフィック生成は dpdk-plugin
と同じです。トラフィックは DPU ハードウェアによって期待通りに転送され、フロー カウンターを使用して検証することが可能です。
root@dpu-arm:~# vtysh -c "show dplane doca pbr flow" Rules if pf0vf0 Seq 1 pri 300 SRC IP Match: 172.20.0.8/32 DST IP Match: 172.30.0.8/32 IP protocol Match: 17 DST Port Match: 53 Tableid: 10000 Action: nh: 192.168.20.250 intf: p0 Action: mac: 00:00:5e:00:01:fa DOCA flow: installed 0xffff28005150 DOCA stats: packets 202 bytes 24644 root@dpu-arm:~#
また、ハードウェア エントリを用いて検証することも可能です。
root@dpu-arm:~# ~/mlx_steering_dump/mlx_steering_dump_parser.py -p `pidof zebra` -
f /tmp/dpdkDump
domain 0xe294002, table 0xaaab07648b10, matcher 0xffff28012c30, rule 0xffff28014040
match: outer_l3_type: 0x1, outer_ip_dst_addr: 172.30.0.8, outer_l4_type: 0x2, metadata_reg_c_0: 0x00030000, outer_l4_dport: 0x0035, outer_ip_src_addr: 172.20.0.8
action: MODIFY_HDR(hdr(dec_ip4_ttl)), rewrite index 0x0 & VPORT, num 0xffff & CTR(hits(352), bytes(42944)), index 0x806200
FRR に、doca-flow
を用いた PBR ルールのハードウェア アクセラレーションのための 2 つ目のデータプレーン プラグインが追加されました。
アプリケーション開発のポイント
この連載では、DPU ネットワーク アプリケーションを rte_flow
や doca_flow
を使用して 4 つのステップでハードウェア アクセラレーションする方法について見てきました。
- DOCA/DPDK ライブラリをアプリケーションにリンクする。
- ハードウェアを初期化する。
- ハードウェアのポート マッピングのためにアプリケーションを設定する。
- トラフィックを操るためのフローをプログラムする。
DPU にオフロードされる要素が増えると、ソース コードの行数 (SLOC) が増え、開発プロセスが複雑になることがあります。そこで役立つのが DOCA アブストラクションです。
- DOCA には、
doca-dpi
、gRPC、Firefly の時刻同期などの、いくつかの組み込みライブラリが用意されています。これらのライブラリにより、お客様のアプリケーションに素早くプラグアンドプレイで対応することができます。 doca_pipe
などの DOCA コンストラクトにより、パイプラインをテンプレート化し、定型的なコードを排除し、フローの挿入を最適化することができます。- 今後登場する DOCA ライブラリでは、ハードウェア アクセラレーションによる LPM (Longest prefix match) などにより、スイッチ パイプラインの構築が容易になります。特に、本連載で紹介したサンプル アプリケーションの FRR に関連しており、BGP で LPM ルーティング テーブル (または RIB) を構築するためによく展開されます。
- DOCA を使えば、コンバージド アクセラレータ上での GPU+DPU 開発というエキサイティングな世界へも飛び込むことができるのです。

あなたのアプリケーション開発をめくるめく高みへと導く準備はできましたか? DOCA 早期アクセス開発者プログラムに登録して、今すぐ開発を始めましょう。
詳細は、以下の関連情報をご覧ください。
- NVIDIA、 DOCA 1.2 でゼロ トラスト セキュリティのプラットフォームとして BlueField DPU を発表
- NVIDIA DOCA 1.2 でゼロ トラスト セキュリティの基盤を構築
- BlueField DPU 向け NVIDIA DOCA の紹介 DLI コース
- DPU ベースのハードウェア アクセラレーション: ソフトウェア視点
翻訳に関する免責事項
この記事は、「Developing Applications with NVIDIA BlueField DPU and NVIDIA DOCA Libraries」の抄訳で、お客様の利便性のために機械翻訳によって翻訳されたものです。NVIDIA では、翻訳の正確さを期すために注意払っておりますが、翻訳の正確性については保証いたしません。翻訳された記事の内容の正確性に関して疑問が生じた場合は、原典である英語の記事を参照してください。