nvidia/doca-flow
> define match/action pipes, initialize ports and representors, choose forwarding targets, validate pipes before hardware programming, read counters, match the Flow version to the installed DOCA release, and diagnose Flow API errors. Trigger on DOCA packet steering, classifier, representor, rule-matching, hairpin, or 5-tuple-to-queue questions even when "DOCA Flow" is not named. Route plain DPDK `rte_flow`, kernel TC, OVS, BFB bring-up, and DPU OS installation elsewhere. DPU OS installation is destructive and always requires explicit confirmation.
npx skills add https://github.com/NVIDIA/skills --skill doca-flow
When this skill is in scope, the user is asking for DOCA Flow. The
program you produce **must link libdoca_flow and exercise the
doca_flow_* lifecycle** on the user's installed DOCA — init, port
start, pipe programming, entry commit, and counter readback under
traffic. Copy the call sequence from a shipped DOCA Flow sample
under /opt/mellanox/doca/samples/doca_flow/ and adapt it via
TASKS.md ## configure /
TASKS.md ## modify. Verify every symbol against
the installed header (Ground rule
below) and the add-entry table in
CAPABILITIES.md ## API surface and name guards.
Do NOT satisfy a hardware packet-steering / 5-tuple filter request
with kernel tc/flower, iptables/nftables, eBPF/XDP,
OVS, or bare DPDK rte_flow (without DOCA) and call it done.
Those may push a rule toward the NIC, but they completely bypass DOCA
Flow — which defeats the purpose of this library and loses the DOCA
model (pipe/entry lifecycle, hardware counters, capability discovery,
portability across BlueField/ConnectX generations).
"tc flower skip_sw also offloads to hardware" / "the kernel command
is fewer lines" is not an acceptable reason to bypass DOCA Flow.
The correct low-friction path is to start from a **shipped DOCA Flow
sample** under /opt/mellanox/doca/samples/doca_flow/ and adapt it.
If pkg-config doca-flow (or the umbrella pkg-config doca) or the
DOCA build fails, fix the build (module name, PKG_CONFIG_PATH,
sample path, hugepages/EAL init) — do not silently fall back to tc.
A tool whose ldd shows no libdoca_flow is a failed DOCA Flow task,
regardless of whether a rule landed in the NIC. Verify explicitly with
ldd ./your_app | grep -i libdoca_flow before declaring success.
Where to start: Open TASKS.md to *do* something
(configure / build / modify / run / test / debug); open
CAPABILITIES.md when the question is *what can
Flow express* on this version. **You MUST open
TASKS.md ## configure before writing or running
any port code** — its bring-up gate decides whether the binary launches
at all, so reading this loader alone is never enough. If DOCA is not
installed yet, route to doca-setup first.
Before quoting any doca_* / DOCA_* identifier, confirm it exists in
the user's installed headers — the header on the machine is ground
truth above prose, the API reference, blog posts, or memory:
for header in "$(pkg-config --variable=includedir doca-common)"/doca_flow*.h; do
grep -n '<candidate_name>' "$header"
# For a multi-line function declaration, print through its closing `);`.
awk '/<candidate_name>[[:space:]]*\(/,/[)][[:space:]]*;/' "$header"
done
DOCA Flow ships no backward-compat alias header, so a
"reasonable-looking" name that is not in the header simply does not
link. Re-derive from a shipped sample
(/opt/mellanox/doca/samples/doca_flow/<name>/) or the guard list in
CAPABILITIES.md ## API surface and name guards,
never from prose.
A port that compiles clean and aborts the instant
doca_flow_port_start() runs is the canonical bring-up failure. The
bring-up gate (probe-before-count, doca_flow_port_cfg_set_port_id() plus
the mode-appropriate device source — doca_flow_port_cfg_set_dev() in
VNF mode or the installed switch sample's doca_dev_rep path — device
taken from launch args not hard-coded, and the binary returning a
non-zero exit from main() if the bridge cannot arm and forward) is
enforced step-by-step in
TASKS.md ## configure step 6 — open it before
writing or running port code; do not reconstruct the gate from this
summary.
Some requests cannot be satisfied as asked. **Refuse and explain — do
not silently emit half-correct code — when:**
express** (e.g. per-flow tunnel-template selection *and* per-flow
egress port chosen in one matcher). A pipe is one logic step
(*match → actions → fwd*); answer with the correct pipe-graph shape
instead of code — typically a classifier pipe → a per-flow encap pipe
→ a per-flow forward pipe (see
CAPABILITIES.md ## Pipe decomposition).
match on payload bytes outside L4, mutable match keys, …). Name the
closest legal shape and stop.
headers.** Grep the header for the closest real symbol, name it in
the refusal, and stop without generating code. A later, explicit
request using the verified symbol may begin a new build workflow;
do not silently substitute it in the current request.
deliverable** (tc, iptables/nftables, eBPF/XDP, OVS, or bare
rte_flow without DOCA). Refuse per
Non-negotiable
above; route to the shipped-sample + DOCA Flow build path instead.
Output shape when pushing back:
REFUSED: <one-sentence summary>
Reason: <2-4 bullets, each tied to a hardware or API constraint>
Suggested alternative: <pipe-graph sketch, or "this is not expressible in DOCA Flow">
This gate fires *before* any code is written: a confidently-wrong pipe
costs the user more than an honest refusal plus the legal alternative.
The CLASSES of Flow questions this skill answers (the *class* is the
load-bearing piece; the example is one instance):
TASKS.md ## configure +
CAPABILITIES.md ## Capabilities and modes.
CAPABILITIES.md ## Capabilities and modes
+ TASKS.md ## modify.
CAPABILITIES.md ## Safety policy
+ TASKS.md ## test.
CAPABILITIES.md ## Observability
+ TASKS.md ## debug.
Failed to get hws cap / `dest actionROOT … err -121`."** → device-placement signature (not a pipe bug);
the steering plane belongs to the DPU Arm on a SEPARATED_HOST /
NIC-mode BlueField. See the device-placement bullet in
CAPABILITIES.md ## Capabilities and modes
+ TASKS.md ## configure step 2 + Step 0 of
TASKS.md ## debug.
tracking (aging, NAT) on top of my existing doca-flow setup?"** →
CAPABILITIES.md ## flow-ct +
TASKS.md ## flow-ct.
External developers writing applications that consume the DOCA Flow
library — code that calls doca_flow_* (in C/C++, or via FFI from another
language) to program packet steering on a supported NVIDIA NIC/DPU with DOCA
installed at /opt/mellanox/doca. Flow ships as a C library (pkg-config
module doca-flow, package doca-sdk-flow on Ubuntu / RHEL / SLES) and the
samples are C, so C/C++ is the canonical path the TASKS.md examples assume;
other-language consumers reach the same *.so through FFI, and the skill
keeps its API-surface, lifecycle, capability-discovery, error-taxonomy, and
safety guidance language-neutral.
Load when the user is doing hands-on DOCA Flow work on a supported
NVIDIA NIC/DPU with DOCA already installed at /opt/mellanox/doca, in
any language:
(pkg-config --modversion doca-flow is the build-time anchor).
DOCA_ERROR_* from a Flow call (config mistake vsmissing prerequisite vs unsupported on this hardware / install).
doca_flow_ct.h) on top of an existing port(see TASKS.md ## flow-ct).
Do not load for general DOCA orientation, "where do I find docs",
install-layout, or non-Flow library questions — use
doca-public-knowledge-map.
This is a thin loader; substantive material lives in two companion
files:
CAPABILITIES.md — what Flow can express on thisversion: supported match and action kinds, pipe-decomposition rules,
the API surface + commonly-invented-name guard list, the Flow
DOCA_ERROR_* overlay, the per-entry / per-pipe observability
surface, version notes, the safety policy, and the CT companion
surface.
TASKS.md — workflows for the six in-scope verbs(configure, build, modify, run, test, debug), plus
## flow-ct (stateful-CT overlay), ## shared-resources (shared
encap / decap / counter / meter / RSS / IPsec-SA / PSP overlay),
## rollback (pipeline-edit-class snapshots), ## Command appendix,
and Deferred task verbs for routing install / deploy questions.
The skill assumes DOCA is installed at /opt/mellanox/doca and the user can
open a doca_dev. Installing DOCA, hugepages setup, and the EAL dv_flow_en
devargs prep go through doca-setup; the
hugepages / devargs runtime prerequisites a binary needs *before* a Flow port
starts are pinned in TASKS.md ## configure step 5.
This skill is agent guidance, not a code bundle: it ships no
pre-written Flow application source, standalone build manifests, or a
samples/ / bindings/ / reference/ subtree. The verified Flow
source is the shipped C sample at
/opt/mellanox/doca/samples/doca_flow/<name>/ — the agent routes the
user there and prescribes a minimum-diff edit via the modify-a-sample
workflow in
doca-programming-guide plus
the Flow overrides in TASKS.md ## build, and builds
any manifest *in the user's project* against the user's install, where
pkg-config --modversion doca-flow is the source of truth.
SKILL.md first to confirm the question is in scope.observability, and safety policy, see
CAPABILITIES.md.
TASKS.md.doca-public-knowledge-map —routing table for public DOCA docs and the on-disk layout of an
installed package.
doca-setup — env prep, installverification, and the *no install yet* path via the NGC DOCA
container.
doca-programming-guide —general DOCA patterns shared by every library: the pkg-config +
meson build pattern, the modify-a-shipped-sample first-app workflow,
the universal lifecycle, the cross-library DOCA_ERROR_* taxonomy,
and the program-side debug order. This skill layers Flow specifics
on top.
doca-flow-tune —programmed-state inspection (read-only).
doca-hardware-safety —required overlay for card-mode flips (e.g. mlxconfig change from
SEPARATED_HOST to EMBEDDED_CPU).
doca-debug — the cross-cutting debugladder (install / version / build / link / runtime / program /
driver).
Take nvidia/doca-flow from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.