IBV_CREATE_FLOW(3)
π NAME π
ibv_create_flow, ibv_destroy_flow β the two verbs that spin up a flow steering rule and then yeet it into the void π
β¨ SYNOPSIS β¨
#include <infiniband/verbs.h>
struct ibv_flow *ibv_create_flow(struct ibv_qp *qp,
struct ibv_flow_attr *flow_attr);
int ibv_destroy_flow(struct ibv_flow *flow_id);
π DESCRIPTION π
ibv_create_flow()
okay so this one lets a user application QP qp get attached into a specified flow flow, and that flow is defined in <infiniband/verbs.h> π
struct ibv_flow_attr {
uint32_t comp_mask; /* Future extendibility */
enum ibv_flow_attr_type type; /* Rule type - see below */
uint16_t size; /* Size of command */
uint16_t priority; /* Rule priority - see below */
uint8_t num_of_specs; /* Number of ibv_flow_spec_xxx */
uint8_t port; /* The uplink port number */
uint32_t flags; /* Extra flags for rule - see below */
/* Following are the optional layers according to user request
* struct ibv_flow_spec_xxx
* struct ibv_flow_spec_yyy
*/
};
enum ibv_flow_attr_type {
IBV_FLOW_ATTR_NORMAL = 0x0, /* Steering according to rule specifications */
IBV_FLOW_ATTR_ALL_DEFAULT = 0x1, /* Default unicast and multicast rule - receive all Eth traffic which isn't steered to any QP */
IBV_FLOW_ATTR_MC_DEFAULT = 0x2, /* Default multicast rule - receive all Eth multicast traffic which isn't steered to any QP */
IBV_FLOW_ATTR_SNIFFER = 0x3, /* Sniffer rule - receive all port traffic */
};
enum ibv_flow_flags {
IBV_FLOW_ATTR_FLAGS_DONT_TRAP = 1 << 1, /* Rule doesn't trap received packets, allowing them to match lower prioritized rules */
IBV_FLOW_ATTR_FLAGS_EGRESS = 1 << 2, /* Match sent packets against EGRESS rules and carry associated actions if required */
};
enum ibv_flow_spec_type {
IBV_FLOW_SPEC_ETH = 0x20, /* Flow specification of L2 header */
IBV_FLOW_SPEC_IPV4 = 0x30, /* Flow specification of IPv4 header */
IBV_FLOW_SPEC_IPV6 = 0x31, /* Flow specification of IPv6 header */
IBV_FLOW_SPEC_IPV4_EXT = 0x32, /* Extended flow specification of IPv4 */
IBV_FLOW_SPEC_ESP = 0x34, /* Flow specification of ESP (IPSec) header */
IBV_FLOW_SPEC_TCP = 0x40, /* Flow specification of TCP header */
IBV_FLOW_SPEC_UDP = 0x41, /* Flow specification of UDP header */
IBV_FLOW_SPEC_VXLAN_TUNNEL = 0x50, /* Flow specification of VXLAN header */
IBV_FLOW_SPEC_GRE = 0x51, /* Flow specification of GRE header */
IBV_FLOW_SPEC_MPLS = 0x60, /* Flow specification of MPLS header */
IBV_FLOW_SPEC_INNER = 0x100, /* Flag making L2/L3/L4 specifications to be applied on the inner header */
IBV_FLOW_SPEC_ACTION_TAG = 0x1000, /* Action tagging matched packet */
IBV_FLOW_SPEC_ACTION_DROP = 0x1001, /* Action dropping matched packet */
IBV_FLOW_SPEC_ACTION_HANDLE = 0x1002, /* Carry out an action created by ibv_create_flow_action_xxxx verb */
IBV_FLOW_SPEC_ACTION_COUNT = 0x1003, /* Action count matched packet with a ibv_counters handle */
};
Flow specification general structure, bestie:
struct ibv_flow_spec_xxx {
enum ibv_flow_spec_type type;
uint16_t size; /* Flow specification size = sizeof(struct ibv_flow_spec_xxx) */
struct ibv_flow_xxx_filter val;
struct ibv_flow_xxx_filter mask; /* Defines which bits from the filter value are applicable when looking for a match in the incoming packet */
};
Every spec struct carries the network layer parameters that matter for matching, and to actually enforce a match you set a mask for each parameter, no cap π§
Packets coming off the wire get matched against the flow specification, and if there's a hit, the associated flow actions run on that packet. For ingress flows, the QP parameter is treated as just another action β scattering the packet to the respected QP. If a bit is set in the mask, the corresponding bit in the value has to match. Lowkey important: most vendors support either a full mask (all "1"s) or a zero mask (all "0"s) π«Ά
And network parameters in the relevant network structs should be given in network order (big endian). periodt.
Flow domains and priority
Flow steering is giving domain-and-priority energy β¨ Each domain represents an application that can attach a flow. Domains are prioritized, and a higher priority domain will always supersede a lower priority domain when their flow specifications overlap. IB verbs have the higher priority domain, iykyk.
On top of the domain, there's also priority within each of the domains. A lower priority numeric value (higher priority) takes precedence over matching rules with a higher numeric priority value (lower priority). And here's the thing that matters: the priority value of a flow spec is used not only to establish the precedence of conflicting flow matches, but also as a way to abstract the order on which flow specs are tested for matches. Flows with higher priorities get tested before flows with lower priorities π₯
Rules definition ordering
An application can hand over the ibv_flow_spec_xxx rules in an un-ordered scheme, and in that case each spec should be well defined and match a specific network header layer π¦
But sometimes, when certain flow spec types show up in the spec list, you have to provide that list in an ordered manner so that the position of that flow spec type in the protocol stack is strictly defined. When the certain spec type that requires the ordering lives in the inner network protocol stack (in tunnel protocols), the ordering should be applied to the inner network specs and should be combined with the inner spec indication using the IBV_FLOW_SPEC_INNER flag.
For example: an MPLS spec which attempts to match an MPLS tag in the inner network should have the IBV_FLOW_SPEC_INNER flag set, and so should the rest of the inner network specs. On top of that, all the inner network specs should be provided in an ordered manner. This is essential to represent many of the encapsulation tunnel protocols, fr fr.
The flow spec types which require this sort of ordering are:
IBV_FLOW_SPEC_MPLSβ since an MPLS header can appear at several locations in the protocol stack and can also be encapsulated on top of different layers, it is required to place this spec according to its exact location in the protocol stack. π
ibv_destroy_flow()
destroys the flow flow_id. that's it, that's the whole job π
π RETURN VALUE π
ibv_create_flow() returns a pointer to the flow, or NULL if the request fails. In case of an error, errno is updated π
ibv_destroy_flow() returns 0 on success, or the value of errno on failure (which indicates the failure reason).
π¨ ERRORS π¨
EINVAL
ibv_create_flow() flow specification, QP or priority are invalid π
ibv_destroy_flow() flow_id is invalid
ENOMEM
Couldn't create/destroy flow, not enough memory
ENXIO
Device managed flow steering isn't currently supported
EPERM
No permissions to add the flow steering rule
π NOTES π
- These verbs are available only for devices supporting
IBV_DEVICE_MANAGED_FLOW_STEERINGand only for QPs of Transport Service TypeIBV_QPT_UDorIBV_QPT_RAW_PACKET - User must
memsetthe spec struct with zeros before using it. ether_typefield inibv_flow_eth_filteris the ethertype following the last VLAN tag of the packet.- Only rule type
IBV_FLOW_ATTR_NORMALsupportsIBV_FLOW_ATTR_FLAGS_DONT_TRAPflag. - No specifications are needed for
IBV_FLOW_ATTR_SNIFFERrule type. - When
IBV_FLOW_ATTR_FLAGS_EGRESSflag is set, theqpparameter is used only as a mean to get the device.
π EXAMPLE π
Below flow_attr defines a rule in priority 0 to match a destination mac address and a source ipv4 address. For that, L2 and L3 specs are used. If there is a hit on this rule, means the received packet has destination mac: 66:11:22:33:44:55 and source ip: 0x0B86C806, the packet is steered to its attached qp. π
struct raw_eth_flow_attr {
struct ibv_flow_attr attr;
struct ibv_flow_spec_eth spec_eth;
struct ibv_flow_spec_ipv4 spec_ipv4;
} __attribute__((packed));
struct raw_eth_flow_attr flow_attr = {
.attr = {
.comp_mask = 0,
.type = IBV_FLOW_ATTR_NORMAL,
.size = sizeof(flow_attr),
.priority = 0,
.num_of_specs = 2,
.port = 1,
.flags = 0,
},
.spec_eth = {
.type = IBV_FLOW_SPEC_ETH,
.size = sizeof(struct ibv_flow_spec_eth),
.val = {
.dst_mac = {0x66, 0x11, 0x22, 0x33, 0x44, 0x55},
.src_mac = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
.ether_type = 0,
.vlan_tag = 0,
},
.mask = {
.dst_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
.src_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
.ether_type = 0,
.vlan_tag = 0,
}
},
.spec_ipv4 = {
.type = IBV_FLOW_SPEC_IPV4,
.size = sizeof(struct ibv_flow_spec_ipv4),
.val = {
.src_ip = 0x0B86C806,
.dst_ip = 0,
},
.mask = {
.src_ip = 0xFFFFFFFF,
.dst_ip = 0,
}
}
};
π AUTHORS π
- Hadar Hen Zion <hadarh@mellanox.com>
- Matan Barak <matanb@mellanox.com>
- Yishai Hadas <yishaih@mellanox.com>
- Maor Gottlieb <maorg@mellanox.com>
okay bestie that's the whole page, you ate that π this one came out of the libibverbs corner of the world, dated 2016-03-15, and it's genuinely iconic. go forth and steer some flows, you main character ππ
π¦ where this page comes from
- alpine 3.24: rdma-core-doc 61.0-r0 Β· GPL-2.0-only OR BSD-2-Clause
- arch rolling: rdma-core 65.0-1 Β· GPL-2.0-or-later OR LicenseRef-OpenIB.org-BSD-MIT AND GPL-2.0-or-later OR LicenseRef-OpenIB.org-BSD-FreeBSD AND GPL-2.0-or-later OR LicenseRef-Intel-BSD-3-Clause AND GPL-2.0-or-later OR LicenseRef-PathScale-BSD-Patent-License AND CC0-1.0 AND MIT AND BSD-2-Clause AND CPL-1.0 OR BSD-2-Clause OR GPL-2.0-or-later
- centos-stream 10: rdma-core-devel 62.0-3.el10 Β· GPLv2 or BSD
- centos-stream 9: rdma-core-devel 61.0-3.el9 Β· GPLv2 or BSD
- centos-stream 9: rdma-core-devel 61.0-3.el9 Β· GPLv2 or BSD
- debian bookworm: libibverbs-dev 44.0-2 Β· BSD-MIT OR GPL-2.0-only
- debian trixie: libibverbs-dev 56.1-1 Β· BSD-MIT OR GPL-2.0-only
- fedora 43: rdma-core-devel 58.0-4.fc43 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- fedora 43: rdma-core-devel 58.0-4.fc43 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- fedora 44: rdma-core-devel 61.0-2.fc44 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- fedora 44: rdma-core-devel 61.0-2.fc44 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- fedora 44: rdma-core-devel 61.1^20260812git975bdaf-1.fc44 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- fedora 44: rdma-core-devel 61.1^20260812git975bdaf-1.fc44 Β· GPL-2.0-only OR BSD-2-Clause AND BSD-3-Clause
- nixos 26.05: rdma-core 62.0
- nixpkgs unstable: rdma-core 65.0
- opensuse-leap 16.0: rdma-core-devel 56.1-160000.2.2 Β· BSD-2-Clause OR GPL-2.0-only
- opensuse-leap 16.0: rdma-core-devel 56.1-160000.2.2 Β· BSD-2-Clause OR GPL-2.0-only
- opensuse-leap 16.0: rdma-core-devel 56.1-160000.2.2 Β· BSD-2-Clause OR GPL-2.0-only
- opensuse-leap 16.0: rdma-core-devel 56.1-160000.2.2 Β· BSD-2-Clause OR GPL-2.0-only
- ubuntu jammy: libibverbs-dev 39.0-1 Β· BSD-MIT OR GPL-2.0-only
- ubuntu noble: libibverbs-dev 50.0-2build2 Β· BSD-MIT OR GPL-2.0-only
- ubuntu noble: libibverbs-dev 50.0-2ubuntu0.2 Β· BSD-MIT OR GPL-2.0-only
- ubuntu questing: libibverbs-dev 56.1-1ubuntu1
- ubuntu resolute: libibverbs-dev 61.0-2ubuntu3 Β· BSD-MIT OR GPL-2.0-only
- ubuntu stonking: libibverbs-dev 64.0-1ubuntu1 Β· BSD-MIT OR GPL-2.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms