Bandwidth Degradation When Passing Packets between OVS Bridges and DOCA Flow apps

Hello,

I am using the BlueField-2 DPU to perform an experiment to use OVS bridges to send packets to a DOCA Flow app in VNF mode which forwards packets to another OVS bridge. I’d expect this to give me a bandwidth at line-rate (100Gbps), but I am only getting at about 80+Gbps. I wonder what’s the reason behind the bandwidth degradation?

The setup: I have two hosts each equipped with a BlueField-2 SmartNIC and the uplink port p0 of the two DPUs are connected to a switch. Then I run pktgen on the two hosts to test the network bandwidth. The following picture shows the topology:

The VNF mode DOCA Flow app is not performing any additional actions; it simply creates two pipes that forward traffic from one port to the other.

DOCA version on both SmartNICs:

[main] release build
DOCA SDK     Version (Compilation): 3.2.0118
DOCA Runtime Version (Runtime):     3.2.0118

ARM OS:

5.15.0-1081-bluefield #83-Ubuntu SMP Fri Oct 17 10:11:15 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux

BlueField:

$ sudo mlxfwmanager --query
Querying Mellanox devices firmware ...

Device #1:
----------

  Device Type:      BlueField2
  Part Number:      MBF2M516C-CECO_Ax
  Description:      BlueField-2 E-Series DPU 100GbE Dual-Port QSFP56; integrated BMC; PCIe Gen4 x16; Secure Boot Enabled; Crypto Enabled; 16GB on-board DDR; 1GbE OOB management; Tall Bracket; FHHL
  PSID:             MT_0000000733
  PCI Device Name:  /dev/mst/mt41686_pciconf0
  Base GUID:        (removed for privacy)
  Base MAC:         (removed for privacy)
  Versions:         Current        Available     
     FW             24.46.1006     N/A           
     PXE            3.8.0100       N/A           
     UEFI           14.39.0013     N/A           
     UEFI Virtio blk   22.4.0014      N/A           
     UEFI Virtio net   21.4.0013      N/A           

The OVS bridges are configured the same way on the both SmartNICs:

$ sudo ovs-vsctl show
    Bridge br0
        Port br0
            Interface br0
                type: internal
        Port pf0hpf
            Interface pf0hpf
        Port en3f0pf0sf0
            Interface en3f0pf0sf0
    Bridge br1
        Port p0
            Interface p0
        Port en3f0pf0sf1
            Interface en3f0pf0sf1
        Port br1
            Interface br1
                type: internal
    ovs_version: "3.2.0044"

$ sudo ovs-vsctl get Open_vSwitch . other_config:hw-offload
"true"

The same DOCA Flow app is run with the same command on both SmartNICs:

$ sudo ./simple_fwd -- -a aux/2,dv_flow_en=2 -a aux/3,dv_flow_en=2 -l 60

Then, on the hosts, I run pktgen with the same command:

$ sudo ./pktgen -l 16-31 -n 8 -a 0000:81:00.0 -- -T -j --rxd=2048 --txd=2048 -m "[17:18].0"

On Host 1, in pktgen:

set 0 size 1500
set 0 proto tcp
set 0 dst mac (Host 2's MAC)
set 0 dst ip (Host 2's IP)
set 0 src ip (Host 1's IP)/32
set 0 rate 100
start 0

Then, pktgen on Host 1 reports it is sending traffic at about 98Gbps. On Host 2, pktgen reports it is receiving traffic at about 83Gbps.

For comparison, I removed my DOCA Flow app from the datapath by connecting pf0hpf and p0 directly using an OVS bridge on both SmartNICs and rerun the experiment with the same steps, and now on Host 1/2 pktgen sends/receives traffic at 99.9Gbps.

$ sudo ovs-vsctl show
    Bridge br0
        Port br0
            Interface br0
                type: internal
        Port pf0hpf
            Interface pf0hpf
        Port p0
            Interface p0
    ovs_version: "3.2.0044"

For another comparison, I implemented a DOCA Flow app in switch mode and got rid of the OVS bridges completely, directly bridging pf0hpf and p0 representors using my DOCA Flow app. This app also simply forwards traffic from one port to the other without doing any additional actions. I rerun the experiment with the same steps and pktgen on Host 1/2 also can send/receive traffic at 99.9Gbps.

This indicates that there’s something going on then I combine OVS bridges with a VNF mode DOCA Flow app. I believe this “bump-in-the-wire” is a standard practice, so my question is: is this bandwidth drop expected? If so, what’s the reason behind this? Is it because the packets are cycling back-and-forth between the eSwitch and the hardware accelerators? If not so, did I make any misconfigurations? What can I do to debug this issue?

Any suggestions would be greatly appreciated! And I am more than happy to provide further information or source code.

Thank you very much!

From a quick look, since the OVS and VNF datapath is forwarding between DOCA en3f0pf0sf0 and en3f0pf0sf1, i am wondering if there is a need to enable hairpin in simple_fwd? Perhaps this part of traffic is not being offloaded and is going through RSS/software? Can you try enabling haripin (-hq) and see?

Otherwise you can check if any flow is going to software, or check the PMD/software and hw-offload counters. Eg.
ovs-appctl dpctl/dump-flows -m
ovs-appctl dpif-netdev/pmd-stats-show
ovs-appctl dpctl/offload-stats-show

Thanks.

Hello,

Thank you very much for the reply!

In my code I’ve enabled hairpin, so that shouldn’t be the issue.

I believe the packet processing is offloaded to the hardware. All following commands are ran on SmartNIC 1:

$ sudo ovs-appctl dpif/show
doca@ovs-doca: hit:26639425 missed:346
  br0:
    br0 65534/1: (tap)
    en3f0pf0sf0 2/2: (doca: dpdk-devargs=0000:03:00.0,dv_xmeta_en=4,dv_flow_en=2,reuse_tag=1,fdb_def_rule_en=0,repr_matching_en=0,vport_match=1,mpesw_suppress_pf_rep=1,representor=pf0sf0, dpdk-lsc-interrupt=false, dpdk-vf-mac=<REMOVED>, n_rxq=1, n_rxq_desc=2048, n_txq_desc=2048)
    pf0hpf 1/3: (doca: dpdk-devargs=0000:03:00.0,dv_xmeta_en=4,dv_flow_en=2,reuse_tag=1,fdb_def_rule_en=0,repr_matching_en=0,vport_match=1,mpesw_suppress_pf_rep=1,representor=pf0vf65535, dpdk-lsc-interrupt=false, dpdk-vf-mac=<REMOVED>, n_rxq=1, n_rxq_desc=2048, n_txq_desc=2048)
  offloaded flows: 3
  offloaded packets: 0.00% (3583652931/18446744073012943158)
  offloaded bytes: 565.78% (7329997859212/1295562571885)
  br1:
    br1 65534/5: (tap)
    en3f0pf0sf1 2/6: (doca: dpdk-devargs=0000:03:00.0,dv_xmeta_en=4,dv_flow_en=2,reuse_tag=1,fdb_def_rule_en=0,repr_matching_en=0,vport_match=1,mpesw_suppress_pf_rep=1,representor=pf0sf1, dpdk-lsc-interrupt=false, dpdk-vf-mac=<REMOVED>, n_rxq=1, n_rxq_desc=2048, n_txq_desc=2048)
    p0 1/4: (doca: dpdk-devargs=0000:03:00.0,dv_xmeta_en=4,dv_flow_en=2,reuse_tag=1,fdb_def_rule_en=0,repr_matching_en=0,vport_match=1,mpesw_suppress_pf_rep=1, dpdk-lsc-interrupt=false, n_rxq=1, n_rxq_desc=2048, n_txq_desc=2048)
  offloaded flows: 3
  offloaded packets: 0.00% (2990112613/18446744072416522891)
  offloaded bytes: 564.32% (6119736388128/1084436734294)

The output suggests that the flows are offloaded.

From the command that you provided:

$ sudo ovs-appctl dpctl/dump-flows -m
flow-dump from pmd on cpu core: 7
ufid:f0acbeab-9885-4e2c-8327-f0bb392710a5, recirc_id(0),dp_hash(0/0),skb_priority(0/0),nv_mp_pid(0/0),nv_mp_preferred(0/0),nv_mp_strict(0/0),in_port(en3f0pf0sf1),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),packet_type(ns=0,id=0),eth(src=<HOST1_MAC>,dst=<HOST2_MAC>),eth_type(0x0800),ipv4(src=192.168.168.3/0.0.0.0,dst=192.168.168.4/0.0.0.0,proto=6/0,tos=0/0,ttl=64/0,frag=no),tcp(src=1234/0,dst=5678/0),tcp_flags(0/0), packets:7064343, bytes:641504742308, used:0.376s, flags:., offloaded:yes, dp:doca, actions:p0, dp-extra-info:miniflow_bits(4,2)
ufid:54e7b191-7e92-4234-b7ee-240077999b61, recirc_id(0),dp_hash(0/0),skb_priority(0/0),nv_mp_pid(0/0),nv_mp_preferred(0/0),nv_mp_strict(0/0),in_port(p0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),packet_type(ns=0,id=0),eth(src=<HOST1_MAC>,dst=<HOST2_MAC>),eth_type(0/0xffff), packets:55, bytes:3300, used:1.997s, offloaded:yes, dp:doca, actions:drop, dp-extra-info:miniflow_bits(4,1)
ufid:03755d00-763c-4c4f-ad46-efa6adee4f10, recirc_id(0),dp_hash(0/0),skb_priority(0/0),nv_mp_pid(0/0),nv_mp_preferred(0/0),nv_mp_strict(0/0),in_port(pf0hpf),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),packet_type(ns=0,id=0),eth(src=<HOST1_MAC>,dst=<HOST2_MAC>),eth_type(0x0800),ipv4(src=192.168.168.3/0.0.0.0,dst=192.168.168.4/0.0.0.0,proto=6/0,tos=0/0,ttl=64/0,frag=no),tcp(src=1234/0,dst=5678/0),tcp_flags(0/0), packets:890635172, bytes:828320846192, used:0.377s, flags:., offloaded:yes, dp:doca, actions:en3f0pf0sf0, dp-extra-info:miniflow_bits(4,2)

I removed some unrelated flows with 0 packets. Again, this suggests all flows are offloaded.

I don’t see anything concerning from the other two commands:

$ sudo ovs-appctl dpif-netdev/pmd-stats-show
pmd thread numa_id 0 core_id 7:
  packets received: 100344489
  packet recirculations: 0
  avg. datapath passes per packet: 1.00
  phwol hits: 0
  mfex opt hits: 0
  simple match hits: 0
  emc hits: 100340116
  smc hits: 0
  megaflow hits: 1382
  avg. subtable lookups per megaflow hit: 1.08
  miss with success upcall: 475
  miss with failed upcall: 2516
  avg. packets per output batch: 14.84
  idle cycles: 354717053484 (81.74%)
  processing cycles: 79262232453 (18.26%)
  avg cycles per packet: 4324.89 (433979285937/100344489)
  avg processing cycles per packet: 789.90 (79262232453/100344489)
main thread:
  packets received: 0
  packet recirculations: 0
  avg. datapath passes per packet: 0.00
  phwol hits: 0
  mfex opt hits: 0
  simple match hits: 0
  emc hits: 0
  smc hits: 0
  megaflow hits: 0
  avg. subtable lookups per megaflow hit: 0.00
  miss with success upcall: 0
  miss with failed upcall: 0
  avg. packets per output batch: 0.00

$ sudo ovs-appctl dpctl/offload-stats-show
HW Offload stats:
     Total                 Enqueued offloads:       0
     Total                 Inserted offloads:      52
     Total             CT bi-dir Connections:       0
     Total            CT uni-dir Connections:       0
     Total   Cumulative Average latency (us):   11009
     Total    Cumulative Latency stddev (us):    6223
     Total       Cumulative Latency max (us):   21349
     Total       Cumulative Latency min (us):      11
     Total  Exponential Average latency (us):   10994
     Total   Exponential Latency stddev (us):    6967
     [  0]                 Enqueued offloads:       0
     [  0]                 Inserted offloads:      49
     [  0]             CT bi-dir Connections:       0
     [  0]            CT uni-dir Connections:       0
     [  0]   Cumulative Average latency (us):       0
     [  0]    Cumulative Latency stddev (us):       0
     [  0]       Cumulative Latency max (us):       0
     [  0]       Cumulative Latency min (us):       0
     [  0]  Exponential Average latency (us):       0
     [  0]   Exponential Latency stddev (us):       0
     [  1]                 Enqueued offloads:       0
     [  1]                 Inserted offloads:       3
     [  1]             CT bi-dir Connections:       0
     [  1]            CT uni-dir Connections:       0
     [  1]   Cumulative Average latency (us):   33027
     [  1]    Cumulative Latency stddev (us):   18670
     [  1]       Cumulative Latency max (us):   64049
     [  1]       Cumulative Latency min (us):      35
     [  1]  Exponential Average latency (us):   32983
     [  1]   Exponential Latency stddev (us):   20902
     [  2]                 Enqueued offloads:       0
     [  2]                 Inserted offloads:       0
     [  2]             CT bi-dir Connections:       0
     [  2]            CT uni-dir Connections:       0
     [  2]   Cumulative Average latency (us):       0
     [  2]    Cumulative Latency stddev (us):       0
     [  2]       Cumulative Latency max (us):       0
     [  2]       Cumulative Latency min (us):       0
     [  2]  Exponential Average latency (us):       0
     [  2]   Exponential Latency stddev (us):       0

If you see anything concerning, please let me know!

Thank you again for the reply!

The “packets received” counter from pmd-stats-show seems a little high, did this increase during the test, or is it a residue value? We can clear it and check again after a test. Eg.
sudo ovs-appctl dpif-netdev/pmd-stats-clear

The OVS flows definitely looks fine.
Would this be a problem between the two OVS bridges or within simple_fwd? Does it help if we increase the queues for simple_fwd. Eg.
sudo ./simple_fwd – -a aux/2,dv_flow_en=2 -a aux/3,dv_flow_en=2 -q 4 -t 1

Thanks.

Hello,

Thank you for the reply!

The counter from pmd-stats-show is a residue value and it doesn’t increase during test. Increasing the number of queues for simple_fwd didn’t help. I believe it only increases the number of queues for the RSS packet processing, and it shouldn’t affect when the flows are already offloaded to the hardware.

I actually made a simplified version of simple_fwd to rule out other factors, still I am not getting the line rate with this DOCA Flow app, I have attached the source below. I would really appreciate if you could take a look and see if there are anything suspicious!

simple_fwd.zip (25.0 KB)

Thanks a lot!

Thanks for the info.
The pmd counter is not increasing, so it doesnt look like an OVS software or offload issue.
The simple_fwd app looks ok, I suspect its not the issue here.
The path is like this:
pf0hpf → OVS(br0) → sf0 → DOCA VNF port-pair → sf1 → OVS(br1) → p0

Given no pmd rx packets, and full rate in switch mode, this looks like some kind of performance limitation when using OVS offload together with a VNF mode DOCA Flow app.
I think this might need further investigation and you are probably best to open a Support case for it.
Otherwise perhaps you could try using the DOCA Flow Tune Tool to isolate or tweak the throughput.

Thank you for looking into this! I’ve also tried using the DOCA Flow tune tool but it doesn’t provide valuable info, all I can see is the visualization of the single pipe (seems the hardware meters are not supported on my bluefield). Yeah, I am going to open a support ticket for this. Thanks again!