Version in base suite: 24.11.4-0+deb13u1 Base version: dpdk_24.11.4-0+deb13u1 Target version: dpdk_24.11.8-0+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/d/dpdk/dpdk_24.11.4-0+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/d/dpdk/dpdk_24.11.8-0+deb13u1.dsc .github/workflows/build.yml | 28 .mailmap | 58 MAINTAINERS | 5 VERSION | 2 app/graph/conn.c | 136 +- app/pdump/main.c | 12 app/test-bbdev/main.c | 1 app/test-bbdev/meson.build | 6 app/test-bbdev/test_bbdev.c | 8 app/test-bbdev/test_bbdev_perf.c | 126 + app/test-bbdev/test_bbdev_vector.c | 1 app/test-crypto-perf/cperf_options_parsing.c | 5 app/test-dma-perf/benchmark.c | 6 app/test-dma-perf/main.c | 11 app/test-dma-perf/main.h | 2 app/test-eventdev/evt_options.c | 2 app/test-pmd/cmdline_flow.c | 51 app/test-pmd/config.c | 213 ++- app/test-pmd/parameters.c | 42 app/test-pmd/testpmd.c | 14 app/test-pmd/testpmd.h | 4 app/test-regex/main.c | 9 app/test/meson.build | 6 app/test/suites/meson.build | 19 app/test/test.h | 19 app/test/test_atomic.c | 66 - app/test/test_bpf.c | 1215 +++++++++++++++++++ app/test/test_cfgfile.c | 8 app/test/test_cryptodev.c | 46 app/test/test_debug.c | 6 app/test/test_dispatcher.c | 1 app/test/test_eal_flags.c | 101 - app/test/test_external_mem.c | 4 app/test/test_fib6.c | 74 + app/test/test_hash.c | 134 ++ app/test/test_interrupts.c | 2 app/test/test_mbuf.c | 38 app/test/test_mcslock.c | 10 app/test/test_memcpy.c | 20 app/test/test_mp_secondary.c | 4 app/test/test_pcapng.c | 65 - app/test/test_pdump.c | 4 app/test/test_security_inline_proto.c | 104 + app/test/test_stack.c | 11 app/test/test_table_acl.c | 30 app/test/test_telemetry_data.c | 21 app/test/test_threads.c | 17 app/test/test_timer_secondary.c | 52 buildtools/get-test-suites.py | 3 config/arm/arm32_armv8_linux_gcc | 3 debian/changelog | 16 debian/librte-eal25.symbols | 2 debian/librte-rib25.symbols | 3 debian/patches/disable_ppc64_autopkgtest_fails.patch | 9 debian/patches/series | 1 debian/patches/vhost-crypto-return-saved-vq.patch | 21 debian/tests/control | 1 devtools/checkpatches.sh | 8 doc/guides/nics/features/i40e.ini | 2 doc/guides/nics/features/iavf.ini | 4 doc/guides/nics/features/ice.ini | 6 doc/guides/nics/i40e.rst | 4 doc/guides/nics/igc.rst | 2 doc/guides/nics/mlx5.rst | 25 doc/guides/rel_notes/release_24_11.rst | 672 ++++++++++ doc/guides/tools/img/mldev_model_ops_subtest_a.svg | 4 doc/guides/tools/img/mldev_model_ops_subtest_b.svg | 4 doc/guides/tools/img/mldev_model_ops_subtest_d.svg | 4 drivers/bus/dpaa/base/qbman/bman_driver.c | 3 drivers/bus/dpaa/base/qbman/qman.c | 9 drivers/bus/dpaa/base/qbman/qman_driver.c | 6 drivers/bus/fslmc/fslmc_vfio.c | 21 drivers/bus/ifpga/bus_ifpga_driver.h | 10 drivers/bus/ifpga/ifpga_bus.c | 12 drivers/bus/ifpga/version.map | 1 drivers/bus/pci/linux/pci.c | 1 drivers/bus/pci/linux/pci_vfio.c | 2 drivers/bus/pci/pci_common.c | 4 drivers/bus/pci/windows/pci.c | 1 drivers/bus/vmbus/vmbus_common.c | 1 drivers/common/cnxk/cnxk_security.c | 27 drivers/common/cnxk/cnxk_telemetry_nix.c | 84 - drivers/common/cnxk/hw/npa.h | 6 drivers/common/cnxk/roc_cpt_debug.c | 27 drivers/common/cnxk/roc_dev.c | 15 drivers/common/cnxk/roc_mbox.h | 4 drivers/common/cnxk/roc_nix_debug.c | 31 drivers/common/cnxk/roc_nix_inl.c | 2 drivers/common/cnxk/roc_nix_inl_dev.c | 11 drivers/common/cnxk/roc_nix_stats.c | 46 drivers/common/cnxk/roc_npa.c | 3 drivers/common/cnxk/roc_ree.c | 17 drivers/common/cnxk/roc_se.c | 15 drivers/common/cnxk/roc_se.h | 2 drivers/common/idpf/idpf_common_rxtx.h | 2 drivers/common/idpf/idpf_common_rxtx_avx512.c | 10 drivers/common/mlx5/linux/mlx5_common_os.c | 85 + drivers/common/mlx5/linux/mlx5_common_os.h | 9 drivers/common/mlx5/linux/mlx5_nl.c | 6 drivers/common/mlx5/mlx5_devx_cmds.c | 18 drivers/common/mlx5/mlx5_prm.h | 2 drivers/common/mlx5/version.map | 1 drivers/common/mlx5/windows/mlx5_glue.h | 2 drivers/common/sfc_efx/base/ef10_mac.c | 35 drivers/crypto/cnxk/cnxk_ae.h | 7 drivers/crypto/cnxk/cnxk_cryptodev_ops.c | 3 drivers/crypto/cnxk/cnxk_se.h | 107 + drivers/crypto/ipsec_mb/pmd_snow3g.c | 3 drivers/crypto/openssl/rte_openssl_pmd_ops.c | 6 drivers/crypto/qat/dev/qat_crypto_pmd_gens.h | 33 drivers/crypto/scheduler/scheduler_multicore.c | 4 drivers/crypto/virtio/virtio_cryptodev.c | 19 drivers/dma/cnxk/cnxk_dmadev.c | 3 drivers/dma/dpaa/dpaa_qdma.c | 7 drivers/dma/dpaa2/dpaa2_qdma.c | 2 drivers/dma/odm/odm_dmadev.c | 18 drivers/event/cnxk/cn10k_eventdev.c | 8 drivers/event/cnxk/cnxk_eventdev.c | 2 drivers/event/cnxk/cnxk_eventdev_adptr.c | 4 drivers/event/cnxk/cnxk_tim_evdev.c | 2 drivers/ml/cnxk/cn10k_ml_ops.c | 3 drivers/net/af_packet/rte_eth_af_packet.c | 124 + drivers/net/af_xdp/rte_eth_af_xdp.c | 10 drivers/net/ark/ark_ethdev.c | 4 drivers/net/ark/ark_pktchkr.c | 10 drivers/net/ark/ark_pktgen.c | 10 drivers/net/atlantic/atl_ethdev.c | 3 drivers/net/axgbe/axgbe_common.h | 2 drivers/net/axgbe/axgbe_dev.c | 3 drivers/net/axgbe/axgbe_ethdev.c | 11 drivers/net/axgbe/axgbe_ethdev.h | 4 drivers/net/axgbe/axgbe_mdio.c | 4 drivers/net/axgbe/axgbe_phy.h | 6 drivers/net/axgbe/axgbe_phy_impl.c | 15 drivers/net/bnxt/bnxt.h | 17 drivers/net/bnxt/bnxt_cpr.c | 100 + drivers/net/bnxt/bnxt_cpr.h | 31 drivers/net/bnxt/bnxt_ethdev.c | 279 ---- drivers/net/bnxt/bnxt_hwrm.c | 410 +++++- drivers/net/bnxt/bnxt_hwrm.h | 1 drivers/net/bnxt/bnxt_ring.c | 11 drivers/net/bnxt/bnxt_rxq.c | 50 drivers/net/bnxt/bnxt_rxr.c | 47 drivers/net/bnxt/bnxt_rxr.h | 7 drivers/net/bnxt/bnxt_stats.c | 23 drivers/net/bnxt/bnxt_txq.c | 6 drivers/net/bnxt/bnxt_txr.c | 204 ++- drivers/net/bnxt/hsi_struct_def_dpdk.h | 3 drivers/net/bnxt/tf_core/cfa_tcam_mgr_session.c | 390 ------ drivers/net/bnxt/tf_core/tf_em_common.c | 23 drivers/net/bnxt/tf_core/tf_em_host.c | 23 drivers/net/bnxt/tf_core/v3/tfc_cpm.c | 12 drivers/net/bnxt/tf_ulp/bnxt_ulp.c | 8 drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c | 14 drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c | 6 drivers/net/bnxt/tf_ulp/ulp_mapper.c | 5 drivers/net/bnxt/tf_ulp/ulp_mapper_tfc.c | 4 drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c | 2 drivers/net/bnxt/tf_ulp/ulp_utils.c | 1100 ----------------- drivers/net/bnxt/tf_ulp/ulp_utils.h | 2 drivers/net/bonding/rte_eth_bond_8023ad.c | 12 drivers/net/bonding/rte_eth_bond_pmd.c | 54 drivers/net/cnxk/cn10k_tx.h | 8 drivers/net/cnxk/cn20k_tx.h | 8 drivers/net/cnxk/cn9k_tx.h | 8 drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c | 50 drivers/net/cpfl/cpfl_ethdev.c | 2 drivers/net/cpfl/cpfl_flow_engine_fxp.c | 2 drivers/net/cpfl/cpfl_flow_parser.c | 22 drivers/net/cpfl/cpfl_fxp_rule.h | 2 drivers/net/cpfl/cpfl_representor.h | 2 drivers/net/cpfl/cpfl_rxtx.c | 1 drivers/net/dpaa/dpaa_ethdev.c | 31 drivers/net/dpaa/dpaa_flow.c | 4 drivers/net/dpaa/dpaa_rxtx.c | 5 drivers/net/dpaa/fmlib/fm_lib.c | 3 drivers/net/dpaa2/base/dpaa2_hw_dpni.c | 34 drivers/net/dpaa2/dpaa2_ethdev.c | 107 - drivers/net/dpaa2/dpaa2_rxtx.c | 85 - drivers/net/dpaa2/mc/fsl_dpni.h | 6 drivers/net/e1000/base/e1000_82575.c | 4 drivers/net/e1000/base/e1000_ich8lan.c | 8 drivers/net/e1000/base/e1000_mac.c | 2 drivers/net/e1000/base/e1000_manage.c | 4 drivers/net/e1000/igb_ethdev.c | 8 drivers/net/e1000/igb_rxtx.c | 3 drivers/net/enetc/base/enetc_hw.h | 7 drivers/net/enetc/enetc_rxtx.c | 4 drivers/net/enic/enic_flow.c | 6 drivers/net/failsafe/failsafe.c | 17 drivers/net/gve/base/gve_adminq.c | 15 drivers/net/gve/base/gve_osdep.h | 4 drivers/net/gve/gve_ethdev.c | 2 drivers/net/gve/gve_ethdev.h | 1 drivers/net/gve/gve_rx.c | 3 drivers/net/gve/gve_rx_dqo.c | 1 drivers/net/gve/gve_tx.c | 46 drivers/net/hinic/base/hinic_compat.h | 12 drivers/net/hns3/hns3_rxtx.c | 9 drivers/net/i40e/base/i40e_dcb.c | 6 drivers/net/i40e/base/i40e_nvm.c | 67 - drivers/net/i40e/base/i40e_prototype.h | 2 drivers/net/i40e/base/i40e_type.h | 2 drivers/net/i40e/i40e_ethdev.c | 66 - drivers/net/i40e/i40e_ethdev.h | 14 drivers/net/i40e/i40e_fdir.c | 23 drivers/net/i40e/i40e_flow.c | 101 - drivers/net/i40e/i40e_rxtx.c | 3 drivers/net/i40e/i40e_rxtx_vec_avx2.c | 4 drivers/net/i40e/i40e_rxtx_vec_avx512.c | 2 drivers/net/i40e/rte_pmd_i40e.c | 10 drivers/net/iavf/iavf.h | 3 drivers/net/iavf/iavf_ethdev.c | 115 + drivers/net/iavf/iavf_fsub.c | 4 drivers/net/iavf/iavf_generic_flow.c | 38 drivers/net/iavf/iavf_generic_flow.h | 1 drivers/net/iavf/iavf_ipsec_crypto.c | 4 drivers/net/iavf/iavf_rxtx.c | 54 drivers/net/iavf/iavf_rxtx_vec_avx2.c | 20 drivers/net/iavf/iavf_rxtx_vec_avx512.c | 22 drivers/net/iavf/iavf_tm.c | 37 drivers/net/iavf/iavf_vchnl.c | 145 +- drivers/net/ice/base/ice_acl_ctrl.c | 6 drivers/net/ice/base/ice_bitops.h | 14 drivers/net/ice/base/ice_dcb.c | 8 drivers/net/ice/base/ice_fdir.c | 22 drivers/net/ice/base/ice_ptp_hw.c | 6 drivers/net/ice/base/ice_sched.c | 3 drivers/net/ice/base/ice_switch.c | 2 drivers/net/ice/ice_dcf_ethdev.c | 12 drivers/net/ice/ice_dcf_sched.c | 15 drivers/net/ice/ice_diagnose.c | 2 drivers/net/ice/ice_ethdev.c | 48 drivers/net/ice/ice_fdir_filter.c | 9 drivers/net/ice/ice_rxtx_vec_avx2.c | 4 drivers/net/ice/ice_rxtx_vec_avx512.c | 2 drivers/net/ice/ice_tm.c | 60 drivers/net/idpf/idpf_ethdev.c | 2 drivers/net/idpf/idpf_rxtx.c | 1 drivers/net/igc/igc_ethdev.c | 19 drivers/net/igc/igc_txrx.c | 62 drivers/net/ixgbe/ixgbe_bypass_api.h | 8 drivers/net/ixgbe/ixgbe_ethdev.c | 57 drivers/net/ixgbe/ixgbe_ethdev.h | 5 drivers/net/ixgbe/ixgbe_fdir.c | 112 - drivers/net/ixgbe/ixgbe_flow.c | 158 +- drivers/net/ixgbe/ixgbe_ipsec.c | 10 drivers/net/ixgbe/ixgbe_ipsec.h | 3 drivers/net/ixgbe/ixgbe_pf.c | 5 drivers/net/ixgbe/ixgbe_rxtx.c | 17 drivers/net/ixgbe/ixgbe_vf_representor.c | 63 drivers/net/mana/mana.c | 14 drivers/net/mana/mana.h | 2 drivers/net/mana/mp.c | 8 drivers/net/mana/rx.c | 6 drivers/net/mana/tx.c | 8 drivers/net/memif/rte_eth_memif.c | 27 drivers/net/memif/rte_eth_memif.h | 1 drivers/net/mlx4/mlx4_mp.c | 6 drivers/net/mlx5/hws/mlx5dr_action.c | 11 drivers/net/mlx5/hws/mlx5dr_cmd.c | 4 drivers/net/mlx5/hws/mlx5dr_internal.h | 6 drivers/net/mlx5/hws/mlx5dr_rule.c | 6 drivers/net/mlx5/hws/mlx5dr_send.c | 4 drivers/net/mlx5/linux/mlx5_ethdev_os.c | 21 drivers/net/mlx5/linux/mlx5_mp_os.c | 6 drivers/net/mlx5/linux/mlx5_os.c | 366 ++++- drivers/net/mlx5/mlx5.c | 62 drivers/net/mlx5/mlx5.h | 26 drivers/net/mlx5/mlx5_ethdev.c | 280 ++-- drivers/net/mlx5/mlx5_flow.c | 38 drivers/net/mlx5/mlx5_flow.h | 43 drivers/net/mlx5/mlx5_flow_aso.c | 44 drivers/net/mlx5/mlx5_flow_dv.c | 18 drivers/net/mlx5/mlx5_flow_flex.c | 4 drivers/net/mlx5/mlx5_flow_hw.c | 705 +++++++---- drivers/net/mlx5/mlx5_rx.c | 13 drivers/net/mlx5/mlx5_rx.h | 40 drivers/net/mlx5/mlx5_rxq.c | 85 + drivers/net/mlx5/mlx5_rxtx_vec.c | 2 drivers/net/mlx5/mlx5_trigger.c | 26 drivers/net/mlx5/mlx5_txpp.c | 3 drivers/net/mlx5/windows/mlx5_os.c | 38 drivers/net/mvpp2/mrvl_ethdev.c | 1 drivers/net/netvsc/hn_ethdev.c | 488 +++++++ drivers/net/netvsc/hn_nvs.h | 6 drivers/net/netvsc/hn_rxtx.c | 40 drivers/net/netvsc/hn_var.h | 2 drivers/net/netvsc/hn_vf.c | 212 ++- drivers/net/nfb/nfb.h | 14 drivers/net/nfb/nfb_ethdev.c | 168 +- drivers/net/nfb/nfb_rx.c | 2 drivers/net/nfb/nfb_rxmode.c | 12 drivers/net/nfb/nfb_stats.c | 57 drivers/net/nfb/nfb_tx.c | 2 drivers/net/nfp/flower/nfp_flower_ctrl.c | 5 drivers/net/nfp/nfpcore/nfp6000_pcie.c | 8 drivers/net/ngbe/base/ngbe_phy_yt.c | 3 drivers/net/ngbe/ngbe_ethdev.c | 5 drivers/net/ngbe/ngbe_rxtx.c | 13 drivers/net/octeontx/base/octeontx_pkovf.c | 4 drivers/net/octeontx/octeontx_ethdev.c | 4 drivers/net/pcap/pcap_ethdev.c | 46 drivers/net/pcap/pcap_osdep_windows.c | 8 drivers/net/r8169/r8169_hw.c | 3 drivers/net/sfc/sfc.h | 2 drivers/net/sfc/sfc_ethdev.c | 140 +- drivers/net/sfc/sfc_ev.c | 7 drivers/net/sfc/sfc_port.c | 8 drivers/net/sfc/sfc_repr.c | 2 drivers/net/tap/rte_eth_tap.c | 58 drivers/net/tap/rte_eth_tap.h | 4 drivers/net/tap/tap_flow.c | 23 drivers/net/txgbe/base/txgbe_dcb_hw.c | 2 drivers/net/txgbe/base/txgbe_hw.c | 3 drivers/net/txgbe/base/txgbe_regs.h | 6 drivers/net/txgbe/txgbe_ethdev.c | 5 drivers/net/txgbe/txgbe_rxtx.c | 59 drivers/vdpa/nfp/nfp_vdpa.c | 4 dts/framework/testbed_model/capability.py | 8 examples/ethtool/ethtool-app/main.c | 8 examples/fips_validation/main.c | 17 examples/ip_fragmentation/main.c | 3 examples/ip_pipeline/conn.c | 6 examples/ip_reassembly/main.c | 3 examples/ipsec-secgw/ipsec_worker.c | 4 examples/ipsec-secgw/ipsec_worker.h | 4 examples/ipsec-secgw/parser.c | 4 examples/ipsec-secgw/sa.c | 6 examples/ipsec-secgw/sp4.c | 2 examples/ipsec-secgw/sp6.c | 2 examples/ipv4_multicast/main.c | 3 examples/l2fwd-crypto/main.c | 12 examples/l2fwd-jobstats/main.c | 4 examples/l3fwd-graph/main.c | 3 examples/l3fwd-power/main.c | 1 examples/l3fwd/main.c | 3 examples/packet_ordering/main.c | 2 examples/pipeline/cli.c | 4 examples/pipeline/conn.c | 6 examples/ptpclient/ptpclient.c | 2 examples/vm_power_manager/channel_manager.c | 15 examples/vm_power_manager/channel_monitor.c | 14 examples/vm_power_manager/main.c | 2 lib/bbdev/rte_bbdev.c | 2 lib/bpf/bpf_jit_arm64.c | 162 +- lib/bpf/bpf_jit_x86.c | 14 lib/bpf/bpf_load.c | 2 lib/bpf/bpf_validate.c | 205 ++- lib/cfgfile/rte_cfgfile.c | 90 - lib/cmdline/cmdline_parse.c | 6 lib/cmdline/cmdline_parse_num.c | 2 lib/cmdline/cmdline_parse_string.c | 3 lib/cmdline/cmdline_rdline.c | 3 lib/cryptodev/rte_cryptodev.c | 38 lib/dmadev/rte_dmadev.c | 44 lib/dmadev/rte_dmadev.h | 66 - lib/eal/common/eal_common_dev.c | 7 lib/eal/common/eal_common_memory.c | 9 lib/eal/common/eal_common_options.c | 22 lib/eal/common/eal_common_proc.c | 139 +- lib/eal/common/eal_common_tailqs.c | 2 lib/eal/common/eal_common_trace.c | 90 - lib/eal/common/malloc_heap.c | 2 lib/eal/freebsd/eal_interrupts.c | 6 lib/eal/freebsd/eal_memory.c | 5 lib/eal/include/generic/rte_spinlock.h | 31 lib/eal/include/rte_bitops.h | 6 lib/eal/include/rte_common.h | 6 lib/eal/include/rte_epoll.h | 3 lib/eal/include/rte_interrupts.h | 21 lib/eal/include/rte_lcore_var.h | 2 lib/eal/include/rte_thread.h | 15 lib/eal/linux/eal_interrupts.c | 120 + lib/eal/linux/eal_memalloc.c | 34 lib/eal/unix/rte_thread.c | 11 lib/eal/version.map | 2 lib/eal/windows/eal_interrupts.c | 6 lib/eal/windows/eal_lcore.c | 68 - lib/eal/windows/getline.c | 61 lib/eal/windows/include/getline.h | 28 lib/eal/windows/include/rte_os_shim.h | 1 lib/eal/windows/meson.build | 1 lib/eal/windows/rte_thread.c | 9 lib/eal/x86/rte_cycles.c | 2 lib/ethdev/ethdev_driver.c | 8 lib/ethdev/rte_ethdev.c | 1 lib/ethdev/rte_ethdev_telemetry.c | 13 lib/ethdev/rte_flow.c | 27 lib/eventdev/rte_event_eth_rx_adapter.c | 106 - lib/eventdev/rte_event_eth_tx_adapter.c | 8 lib/eventdev/rte_event_timer_adapter.c | 22 lib/fib/dir24_8.c | 3 lib/fib/trie.c | 90 - lib/gso/gso_common.c | 12 lib/gso/gso_tcp4.c | 5 lib/gso/gso_tunnel_tcp4.c | 6 lib/gso/gso_tunnel_udp4.c | 4 lib/gso/gso_udp4.c | 5 lib/hash/rte_cuckoo_hash.c | 84 - lib/hash/rte_hash.h | 8 lib/hash/rte_hash_crc.h | 10 lib/hash/rte_thash_x86_gfni.h | 4 lib/ip_frag/ip_frag_common.h | 1 lib/ip_frag/ip_frag_internal.c | 18 lib/ip_frag/ip_reassembly.h | 1 lib/ip_frag/rte_ip_frag_common.c | 21 lib/ip_frag/rte_ipv4_reassembly.c | 17 lib/ip_frag/rte_ipv6_reassembly.c | 31 lib/mbuf/rte_mbuf.c | 12 lib/mbuf/rte_mbuf.h | 2 lib/mldev/rte_mldev.h | 8 lib/net/net_crc_avx512.c | 4 lib/pcapng/rte_pcapng.c | 83 - lib/pcapng/rte_pcapng.h | 10 lib/pdcp/pdcp_process.c | 2 lib/pipeline/rte_swx_ctl.c | 11 lib/pipeline/rte_swx_pipeline.c | 27 lib/pipeline/rte_swx_pipeline_internal.h | 10 lib/power/power_uncore_ops.h | 24 lib/power/rte_power_pmd_mgmt.c | 27 lib/power/rte_power_uncore.c | 2 lib/rcu/rte_rcu_qsbr.h | 2 lib/rib/rib6_internal.h | 22 lib/rib/rte_rib6.c | 13 lib/rib/version.map | 7 lib/ring/rte_ring_peek_zc.h | 8 lib/sched/rte_red.h | 9 lib/security/rte_security.c | 41 lib/table/rte_lru.h | 38 lib/table/rte_lru_arm64.h | 14 lib/table/rte_lru_x86.h | 4 lib/table/rte_swx_table_em.c | 2 lib/table/rte_swx_table_learner.c | 4 lib/table/rte_table_hash_key16.c | 4 lib/table/rte_table_hash_key32.c | 4 lib/table/rte_table_hash_key8.c | 4 lib/telemetry/telemetry.c | 5 lib/telemetry/telemetry_data.c | 6 lib/vhost/fd_man.c | 51 lib/vhost/fd_man.h | 1 lib/vhost/socket.c | 7 lib/vhost/vdpa.c | 8 lib/vhost/vduse.c | 29 lib/vhost/vhost.c | 94 + lib/vhost/vhost.h | 7 lib/vhost/vhost_crypto.c | 83 - lib/vhost/vhost_user.c | 105 - lib/vhost/virtio_net.c | 105 - lib/vhost/virtio_net_ctrl.c | 44 license/exceptions.txt | 2 usertools/dpdk-pmdinfo.py | 5 452 files changed, 10122 insertions(+), 5605 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp_bxcb0i7/dpdk_24.11.4-0+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp_bxcb0i7/dpdk_24.11.8-0+deb13u1.dsc: no acceptable signature found diff -Nru dpdk-24.11.4/.github/workflows/build.yml dpdk-24.11.8/.github/workflows/build.yml --- dpdk-24.11.4/.github/workflows/build.yml 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/.github/workflows/build.yml 2026-10-14 13:10:05.000000000 +0000 @@ -21,7 +21,7 @@ runs-on: ubuntu-24.04 steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Check patches @@ -95,7 +95,7 @@ steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Generate cache keys id: get_ref_keys run: | @@ -103,7 +103,7 @@ echo 'libabigail=libabigail-${{ env.LIBABIGAIL_VERSION }}-${{ matrix.config.os }}' >> $GITHUB_OUTPUT echo 'abi=abi-${{ matrix.config.os }}-${{ matrix.config.compiler }}-${{ matrix.config.cross }}-${{ env.REF_GIT_TAG }}' >> $GITHUB_OUTPUT - name: Retrieve ccache cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.ccache key: ${{ steps.get_ref_keys.outputs.ccache }}-${{ github.ref }} @@ -111,13 +111,13 @@ ${{ steps.get_ref_keys.outputs.ccache }}-refs/heads/main - name: Retrieve libabigail cache id: libabigail-cache - uses: actions/cache@v4 + uses: actions/cache@v5 if: env.ABI_CHECKS == 'true' with: path: libabigail key: ${{ steps.get_ref_keys.outputs.libabigail }} - name: Retrieve ABI reference cache - uses: actions/cache@v4 + uses: actions/cache@v5 if: env.ABI_CHECKS == 'true' with: path: reference @@ -166,7 +166,7 @@ run: .ci/linux-build.sh - name: Upload logs on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: meson-logs-${{ join(matrix.config.*, '-') }} path: | @@ -187,9 +187,9 @@ steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.x' - name: Install dependencies @@ -206,7 +206,7 @@ meson compile -C build - name: Upload logs on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: meson-logs-${{ join(matrix.config.*, '-') }} path: | @@ -232,7 +232,7 @@ echo 'image=image-${{ matrix.config.image }}-'$(date -u +%Y-%m-%d) >> $GITHUB_OUTPUT - name: Retrieve image cache id: image_cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.image key: ${{ steps.get_keys.outputs.image }} @@ -279,7 +279,7 @@ steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Generate various keys id: get_keys run: | @@ -287,7 +287,7 @@ echo 'logs=meson-logs-${{ join(matrix.config.*, '-') }}' | tr -d ':' >> $GITHUB_OUTPUT - name: Retrieve image cache id: image_cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.image key: ${{ needs.prepare-container-images.outputs.image }} @@ -297,7 +297,7 @@ echo 'Image ${{ matrix.config.image }} is not cached.' false - name: Retrieve ccache cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.ccache key: ${{ steps.get_keys.outputs.ccache }}-${{ github.ref }} @@ -338,7 +338,7 @@ run: docker kill dpdk - name: Upload logs on failure if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ steps.get_keys.outputs.logs }} path: | diff -Nru dpdk-24.11.4/.mailmap dpdk-24.11.8/.mailmap --- dpdk-24.11.4/.mailmap 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/.mailmap 2026-10-14 13:10:05.000000000 +0000 @@ -16,6 +16,7 @@ Abraham Tovar Adam Bynes Adam Dybkowski +Adam Hassick Adam Ludkiewicz Adel Belkhiri Adham Masarwah @@ -61,6 +62,7 @@ Alexander Solganik Alexander V Gutkin Alexandre Ferrieux +Alexandru-Ionut Jipa Alexey Kardashevskiy Alex Kiselev Alex Marginean @@ -70,14 +72,18 @@ Alex Vesker Alex Wang Alex Zelezniak +Alexey Simakov Alfredo Cardigliano Ali Alnubani +Ali Volkan Atli +Aliaksei Belovus Alice Michael Alin Rauta Ali Volkan Atli Allain Legacy Allen Hubbe Alok Makhariya +Alok Mishra Alok Prasad Alvaro Karsz Alvin Zhang @@ -208,6 +214,7 @@ Boon Ang Boris Ouretskey Boris Pismenny +Borys Tsyrulnikov Brad Larson Brandon Lo Brendan Ryan @@ -251,6 +258,7 @@ Chengwen Feng Chenmin Sun Chenming Chang +Chenna Arnoori Chenxingyu Wang Chenxu Di Chenyu Huang @@ -279,8 +287,10 @@ Ciara Loftus Ciara Power Claire Murphy +Claudia Cauli Clemens Famulla-Conrad Cody Doucette +Congjie Zhou Congwen Zhang Conor Fogarty Conor Walsh @@ -307,6 +317,9 @@ Daniel Mrzyglod Daniel Shelepov Daniel Verkamp +Daniele Di Proietto +Daniil Agalakov +Daniil Iskhakov Daniil Ushkov Dan Nowlin Danny Patel @@ -314,6 +327,7 @@ Dan Wei Danylo Vodopianov Dapeng Yu +Daphne Priscilla Darek Stojaczyk Daria Kolistratova Dariusz Chaberski @@ -339,6 +353,7 @@ David Su David Verbeiren David Wilder +David Zage David Zeng Dawid Gorecki Dawid Jurczak @@ -349,10 +364,13 @@ Declan Doherty Deepak Khandelwal Deepak Kumar Jain +Deepthi Kavalur Deirdre O'Connor Dekel Peled Dengdui Huang +Denis Lyulin Denis Pryazhennikov +Denis Sergeev Dennis Marinus Derek Chickles Des O Dea @@ -472,11 +490,13 @@ Gao Feng Gaoxiang Liu Gargi Sau +Garvit Varshney Gary Mussar Gaurav Singh Gautam Dawar Gavin Hu Gavin Li +Gena Tertychnyi Geoffrey Le Gourriérec Geoffrey Lv Geoff Thorpe @@ -638,6 +658,7 @@ James Grant James Hershaw James Poole +James Raphael Tiovalen Jamie Lavigne Jananee Parthasarathy Jan Beulich @@ -801,6 +822,9 @@ Karra Satwik Kathleen Capella Kazatsker Kirill +Ke Xu +Ke Zhang +Keegan Freyhof Kefu Chai Keiichi Watanabe Keith Wiles @@ -861,7 +885,7 @@ Leyi Rong Liang Ma Liang-Min Larry Wang -Liangxing Wang +Liangxing Wang Liang Xu Liang Zhang Li Feng @@ -876,6 +900,7 @@ Lingli Chen Lingyu Liu Lin Li +Linhu Li Linsi Yuan Lior Margalit Li Qiang @@ -892,6 +917,7 @@ Luca Boccassi Luca Vizzarro Luc Pelletier +Luigi Rizzo Luka Jankovic Lukas Sismis Lukasz Bartosik @@ -937,6 +963,7 @@ Marat Khalili Marcel Apfelbaum Marcel Cornu +Marcel Telka Marcelo Ricardo Leitner Marcin Baran Marcin Danilewicz @@ -1000,6 +1027,7 @@ Maxime Coquelin Maxime Gouin Maxime Leroy +Maxime Peim Md Fahad Iqbal Polash Megha Ajmera Meijuan Zhao @@ -1015,7 +1043,7 @@ Michael Lilja Michael Luo Michael McConville -Michael Pfeiffer +Michael Pfeiffer Michael Qiu Michael Rossberg Michael Santana @@ -1035,6 +1063,7 @@ Michał Mirosław Michal Nowak Michal Schmidt +Michal Sieron Michal Swiatkowski Michal Wilczynski Michel Machado @@ -1043,6 +1072,7 @@ Mihai Brodschi Mihai Pogonaru Mike Baucom +Mike Bly Mike Pattrick Mike Sowka Mike Stolarchuk @@ -1065,7 +1095,9 @@ Mohamed Feroz Abdul Majeeth Mohammad Abdul Awal Mohammad Iqbal Ahmad +Mohammad Shuab Siddique Mohammed Gamal +Mohand Alrasheed Mohsin Kazmi Mohsin Mazhar Shaikh Mohsin Shaikh @@ -1074,6 +1106,7 @@ Muhammad Ahmad Muhammad Bilal Mukesh Dua +Mukul Katiyar Murphy Yang Murthy NSSR Muthurajan Jayakumar @@ -1153,6 +1186,7 @@ Ophir Munk Or Ami Ori Kam +Ouyang Hao Owen Hilyard Pabitra Dalai Pablo Cascón @@ -1267,6 +1301,7 @@ Radu Nicolau Rafael Ávila de Espíndola Rafal Kozik +Raghavendra Ningoji Ragothaman Jayaraman Rahul Bhansali Rahul Gupta @@ -1378,6 +1413,8 @@ Savinay Dharmappa Scott Branden Scott Daniels +Scott Mitchell +Scott W Taylor Scott Wasson Scott W Taylor Seán Harte @@ -1386,6 +1423,7 @@ Sean Zhang Sebastian Basierski Selwin Sebastian +Sergei Iashin Sergey Balabanov Sergey Dyasly Sergey Madaminov @@ -1440,6 +1478,7 @@ Shu Shen Shujing Dong Shuo Li +Shuzo Ichiyoshi Shweta Choudaha Shyam Kumar Shrivastav Shy Shyman @@ -1464,6 +1503,7 @@ Solganik Alexander Somnath Kotur Song Jiale +Song Yoong Siang Song Zhu Sony Chacko Sotiris Salloumis @@ -1531,6 +1571,8 @@ Takuya Asada Tal Avraham Tal Shnaiderman +Talluri Chaitanyababu +Tamar Mashiah Tanzeel Ahmed Tao Y Yang Tao Zhu @@ -1636,7 +1678,7 @@ Vikash Poddar Vimal Chungath Vincent Guo -Vincent Jardin +Vincent Jardin Vincent Li Vincent S. Cojot Vinh Tran @@ -1667,7 +1709,7 @@ Waterman Cao Wathsala Vithanage Weichun Chen -Wei Dai +Wei Dai Weifeng Li Weiguo Li Wei Huang @@ -1702,6 +1744,7 @@ Wojciech Liguzinski Wojciech Panfil Wojciech Zmuda +Xavier Guillaume Xavier Simonart Xiangjun Meng Xiaoban Wu @@ -1741,6 +1784,11 @@ Yaacov Hazan Yahui Cao Yajun Wu +Yan Lu +Yan Xia +Yang Ming +Yang Xu +Yang Zhang Yangchao Zhou Yanglong Wu Yang Ming @@ -1756,6 +1804,7 @@ Yaroslav Brustinov Yash Sharma Yasufumi Ogawa +Yehor Malikov Yelena Krivosheev Yerden Zhumabekov Yevgeny Kliteynik @@ -1829,6 +1878,7 @@ Zhigang Hu Zhigang Lu Zhiguang He +Zhiguang Jin Zhihong Peng Zhihong Wang Zhike Wang diff -Nru dpdk-24.11.4/MAINTAINERS dpdk-24.11.8/MAINTAINERS --- dpdk-24.11.4/MAINTAINERS 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/MAINTAINERS 2026-10-14 13:10:05.000000000 +0000 @@ -545,6 +545,7 @@ F: doc/guides/prog_guide/eventdev/eventdev.rst F: drivers/event/skeleton/ F: app/test/test_eventdev.c +F: app/test/test_event_ring.c F: examples/l3fwd/l3fwd_event* Eventdev Ethdev Rx Adapter API @@ -1706,7 +1707,8 @@ F: lib/hash/ F: doc/guides/prog_guide/hash_lib.rst F: doc/guides/prog_guide/toeplitz_hash_lib.rst -F: app/test/test_*hash* +F: app/test/test_hash* +F: app/test/test_thash* F: app/test/test_func_reentrancy.c LPM @@ -1931,7 +1933,6 @@ F: app/test-eventdev/ F: doc/guides/tools/testeventdev.rst F: doc/guides/tools/img/eventdev_* -F: app/test/test_event_ring.c Graph application M: Sunil Kumar Kori diff -Nru dpdk-24.11.4/VERSION dpdk-24.11.8/VERSION --- dpdk-24.11.4/VERSION 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/VERSION 2026-10-14 13:10:05.000000000 +0000 @@ -1 +1 @@ -24.11.4 +24.11.8 diff -Nru dpdk-24.11.4/app/graph/conn.c dpdk-24.11.8/app/graph/conn.c --- dpdk-24.11.4/app/graph/conn.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/graph/conn.c 2026-10-14 13:10:05.000000000 +0000 @@ -20,12 +20,12 @@ #define MSG_CMD_TOO_LONG "Command too long." static int -data_event_handle(struct conn *conn, int fd_client) +data_event_handle(struct conn *c, int fd_client) { ssize_t len, i, rc = 0; /* Read input message */ - len = read(fd_client, conn->buf, conn->buf_size); + len = read(fd_client, c->buf, c->buf_size); if (len == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) return 0; @@ -38,37 +38,37 @@ /* Handle input messages */ for (i = 0; i < len; i++) { - if (conn->buf[i] == '\n') { + if (c->buf[i] == '\n') { size_t n; - conn->msg_in[conn->msg_in_len] = 0; - conn->msg_out[0] = 0; + c->msg_in[c->msg_in_len] = 0; + c->msg_out[0] = 0; - conn->msg_handle(conn->msg_in, conn->msg_out, conn->msg_out_len_max, - conn->msg_handle_arg); + c->msg_handle(c->msg_in, c->msg_out, c->msg_out_len_max, + c->msg_handle_arg); - n = strlen(conn->msg_out); + n = strlen(c->msg_out); if (n) { - rc = write(fd_client, conn->msg_out, n); + rc = write(fd_client, c->msg_out, n); if (rc == -1) goto exit; } - conn->msg_in_len = 0; - } else if (conn->msg_in_len < conn->msg_in_len_max) { - conn->msg_in[conn->msg_in_len] = conn->buf[i]; - conn->msg_in_len++; + c->msg_in_len = 0; + } else if (c->msg_in_len < c->msg_in_len_max) { + c->msg_in[c->msg_in_len] = c->buf[i]; + c->msg_in_len++; } else { rc = write(fd_client, MSG_CMD_TOO_LONG, strlen(MSG_CMD_TOO_LONG)); if (rc == -1) goto exit; - conn->msg_in_len = 0; + c->msg_in_len = 0; } } /* Write prompt */ - rc = write(fd_client, conn->prompt, strlen(conn->prompt)); + rc = write(fd_client, c->prompt, strlen(c->prompt)); rc = (rc == -1) ? -1 : 0; exit: @@ -76,11 +76,11 @@ } static int -control_event_handle(struct conn *conn, int fd_client) +control_event_handle(struct conn *c, int fd_client) { int rc; - rc = epoll_ctl(conn->fd_client_group, EPOLL_CTL_DEL, fd_client, NULL); + rc = epoll_ctl(c->fd_client_group, EPOLL_CTL_DEL, fd_client, NULL); if (rc == -1) goto exit; @@ -99,7 +99,7 @@ { int fd_server, fd_client_group, rc; struct sockaddr_in server_address; - struct conn *conn = NULL; + struct conn *c = NULL; int reuse = 1; memset(&server_address, 0, sizeof(server_address)); @@ -115,20 +115,20 @@ goto exit; /* Memory allocation */ - conn = calloc(1, sizeof(struct conn)); - if (conn == NULL) + c = calloc(1, sizeof(struct conn)); + if (c == NULL) goto exit; - conn->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1); - conn->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1); - conn->buf = calloc(1, p->buf_size); - conn->msg_in = calloc(1, p->msg_in_len_max + 1); - conn->msg_out = calloc(1, p->msg_out_len_max + 1); - - if ((conn->welcome == NULL) || (conn->prompt == NULL) || (conn->buf == NULL) || - (conn->msg_in == NULL) || (conn->msg_out == NULL)) { - conn_free(conn); - conn = NULL; + c->welcome = calloc(1, CONN_WELCOME_LEN_MAX + 1); + c->prompt = calloc(1, CONN_PROMPT_LEN_MAX + 1); + c->buf = calloc(1, p->buf_size); + c->msg_in = calloc(1, p->msg_in_len_max + 1); + c->msg_out = calloc(1, p->msg_out_len_max + 1); + + if ((c->welcome == NULL) || (c->prompt == NULL) || (c->buf == NULL) || + (c->msg_in == NULL) || (c->msg_out == NULL)) { + conn_free(c); + c = NULL; goto exit; } @@ -138,8 +138,8 @@ fd_server = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd_server == -1) { - conn_free(conn); - conn = NULL; + conn_free(c); + c = NULL; goto exit; } @@ -161,47 +161,47 @@ goto free; /* Fill in */ - rte_strscpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); - rte_strscpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); - conn->buf_size = p->buf_size; - conn->msg_in_len_max = p->msg_in_len_max; - conn->msg_out_len_max = p->msg_out_len_max; - conn->msg_in_len = 0; - conn->fd_server = fd_server; - conn->fd_client_group = fd_client_group; - conn->msg_handle = p->msg_handle; - conn->msg_handle_arg = p->msg_handle_arg; + rte_strscpy(c->welcome, p->welcome, CONN_WELCOME_LEN_MAX); + rte_strscpy(c->prompt, p->prompt, CONN_PROMPT_LEN_MAX); + c->buf_size = p->buf_size; + c->msg_in_len_max = p->msg_in_len_max; + c->msg_out_len_max = p->msg_out_len_max; + c->msg_in_len = 0; + c->fd_server = fd_server; + c->fd_client_group = fd_client_group; + c->msg_handle = p->msg_handle; + c->msg_handle_arg = p->msg_handle_arg; exit: - return conn; + return c; free: - conn_free(conn); + conn_free(c); close(fd_server); - conn = NULL; - return conn; + c = NULL; + return c; } void -conn_free(struct conn *conn) +conn_free(struct conn *c) { - if (conn == NULL) + if (c == NULL) return; - if (conn->fd_client_group) - close(conn->fd_client_group); + if (c->fd_client_group) + close(c->fd_client_group); - if (conn->fd_server) - close(conn->fd_server); + if (c->fd_server) + close(c->fd_server); - free(conn->msg_out); - free(conn->msg_in); - free(conn->prompt); - free(conn->welcome); - free(conn); + free(c->msg_out); + free(c->msg_in); + free(c->prompt); + free(c->welcome); + free(c); } int -conn_req_poll(struct conn *conn) +conn_req_poll(struct conn *c) { struct sockaddr_in client_address; socklen_t client_address_length; @@ -209,12 +209,12 @@ int fd_client, rc; /* Check input arguments */ - if (conn == NULL) + if (c == NULL) return -1; /* Server socket */ client_address_length = sizeof(client_address); - fd_client = accept4(conn->fd_server, (struct sockaddr *)&client_address, + fd_client = accept4(c->fd_server, (struct sockaddr *)&client_address, &client_address_length, SOCK_NONBLOCK); if (fd_client == -1) { if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) @@ -227,20 +227,20 @@ event.events = EPOLLIN | EPOLLRDHUP | EPOLLHUP; event.data.fd = fd_client; - rc = epoll_ctl(conn->fd_client_group, EPOLL_CTL_ADD, fd_client, &event); + rc = epoll_ctl(c->fd_client_group, EPOLL_CTL_ADD, fd_client, &event); if (rc == -1) { close(fd_client); goto exit; } /* Client */ - rc = write(fd_client, conn->welcome, strlen(conn->welcome)); + rc = write(fd_client, c->welcome, strlen(c->welcome)); if (rc == -1) { close(fd_client); goto exit; } - rc = write(fd_client, conn->prompt, strlen(conn->prompt)); + rc = write(fd_client, c->prompt, strlen(c->prompt)); if (rc == -1) { close(fd_client); goto exit; @@ -253,17 +253,17 @@ } int -conn_msg_poll(struct conn *conn) +conn_msg_poll(struct conn *c) { int fd_client, rc, rc_data = 0, rc_control = 0; struct epoll_event event; /* Check input arguments */ - if (conn == NULL) + if (c == NULL) return -1; /* Client group */ - rc = epoll_wait(conn->fd_client_group, &event, 1, 0); + rc = epoll_wait(c->fd_client_group, &event, 1, 0); if ((rc == -1) || rc == 0) return rc; @@ -271,11 +271,11 @@ /* Data available */ if (event.events & EPOLLIN) - rc_data = data_event_handle(conn, fd_client); + rc_data = data_event_handle(c, fd_client); /* Control events */ if (event.events & (EPOLLRDHUP | EPOLLERR | EPOLLHUP)) - rc_control = control_event_handle(conn, fd_client); + rc_control = control_event_handle(c, fd_client); if (rc_data || rc_control) return -1; diff -Nru dpdk-24.11.4/app/pdump/main.c dpdk-24.11.8/app/pdump/main.c --- dpdk-24.11.4/app/pdump/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/pdump/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -247,7 +247,7 @@ } static int -parse_pdump(const char *optarg) +parse_pdump(const char *arg) { struct rte_kvargs *kvlist; int ret = 0, cnt1, cnt2; @@ -257,9 +257,9 @@ pt = &pdump_t[num_tuples]; /* initial check for invalid arguments */ - kvlist = rte_kvargs_parse(optarg, valid_pdump_arguments); + kvlist = rte_kvargs_parse(arg, valid_pdump_arguments); if (kvlist == NULL) { - printf("--pdump=\"%s\": invalid argument passed\n", optarg); + printf("--pdump=\"%s\": invalid argument passed\n", arg); return -1; } @@ -268,7 +268,7 @@ cnt2 = rte_kvargs_count(kvlist, PDUMP_PCI_ARG); if (!((cnt1 == 1 && cnt2 == 0) || (cnt1 == 0 && cnt2 == 1))) { printf("--pdump=\"%s\": must have either port or " - "device_id argument\n", optarg); + "device_id argument\n", arg); ret = -1; goto free_kvlist; } else if (cnt1 == 1) { @@ -290,7 +290,7 @@ /* queue parsing and validation */ cnt1 = rte_kvargs_count(kvlist, PDUMP_QUEUE_ARG); if (cnt1 != 1) { - printf("--pdump=\"%s\": must have queue argument\n", optarg); + printf("--pdump=\"%s\": must have queue argument\n", arg); ret = -1; goto free_kvlist; } @@ -303,7 +303,7 @@ cnt2 = rte_kvargs_count(kvlist, PDUMP_TX_DEV_ARG); if (cnt1 == 0 && cnt2 == 0) { printf("--pdump=\"%s\": must have either rx-dev or " - "tx-dev argument\n", optarg); + "tx-dev argument\n", arg); ret = -1; goto free_kvlist; } else if (cnt1 == 1 && cnt2 == 1) { diff -Nru dpdk-24.11.4/app/test/meson.build dpdk-24.11.8/app/test/meson.build --- dpdk-24.11.4/app/test/meson.build 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/meson.build 2026-10-14 13:10:05.000000000 +0000 @@ -110,7 +110,7 @@ 'net'] + packet_burst_generator_deps + virtual_pmd_deps, 'test_link_bonding_mode4.c': ['ethdev', 'net_ring', 'net_bond', 'net'] + packet_burst_generator_deps, - 'test_link_bonding_rssconf.c': ['ethdev', 'bus_vdev', 'net_bond'], + 'test_link_bonding_rssconf.c': ['ethdev', 'bus_vdev', 'net_bond', 'net_null'], 'test_logs.c': [], 'test_lpm.c': ['net', 'lpm'], 'test_lpm6.c': ['lpm'], @@ -133,7 +133,7 @@ 'test_mp_secondary.c': ['hash'], 'test_net_ether.c': ['net'], 'test_net_ip6.c': ['net'], - 'test_pcapng.c': ['ethdev', 'net', 'pcapng', 'bus_vdev'], + 'test_pcapng.c': ['net_null', 'net', 'ethdev', 'pcapng', 'bus_vdev'], 'test_pdcp.c': ['eventdev', 'pdcp', 'net', 'timer', 'security'], 'test_pdump.c': ['pdump'] + sample_packet_forward_deps, 'test_per_lcore.c': [], @@ -201,7 +201,7 @@ 'test_trace.c': [], 'test_trace_perf.c': [], 'test_trace_register.c': [], - 'test_vdev.c': ['kvargs', 'bus_vdev'], + 'test_vdev.c': ['kvargs', 'bus_vdev', 'net_null'], 'test_version.c': [], } diff -Nru dpdk-24.11.4/app/test/suites/meson.build dpdk-24.11.8/app/test/suites/meson.build --- dpdk-24.11.4/app/test/suites/meson.build 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/suites/meson.build 2026-10-14 13:10:05.000000000 +0000 @@ -60,28 +60,35 @@ if nohuge test_args += test_no_huge_args elif not has_hugepage - continue #skip this tests + continue # skip this test endif if not asan and (get_option('b_sanitize') == 'address' or get_option('b_sanitize') == 'address,undefined') continue # skip this test endif - if get_option('default_library') == 'shared' test_args += ['-d', dpdk_drivers_build_dir] endif + # use unique file-prefix to allow parallel runs + file_prefix = [] + trace_prefix = [] + if is_linux + file_prefix = ['--file-prefix=' + test_name.underscorify()] + trace_prefix = [file_prefix[0] + '_with_traces'] + endif + test(test_name, dpdk_test, - args : test_args, + args : test_args + file_prefix, env: ['DPDK_TEST=' + test_name], timeout : timeout_seconds_fast, is_parallel : false, suite : 'fast-tests') if not is_windows and test_name == 'trace_autotest' - test_args += ['--trace=.*'] - test_args += ['--trace-dir=@0@'.format(meson.current_build_dir())] + trace_extra = ['--trace=.*', + '--trace-dir=@0@'.format(meson.current_build_dir())] test(test_name + '_with_traces', dpdk_test, - args : test_args, + args : test_args + trace_extra + trace_prefix, env: ['DPDK_TEST=' + test_name], timeout : timeout_seconds_fast, is_parallel : false, diff -Nru dpdk-24.11.4/app/test/test.h dpdk-24.11.8/app/test/test.h --- dpdk-24.11.4/app/test/test.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test.h 2026-10-14 13:10:05.000000000 +0000 @@ -12,6 +12,7 @@ #include #include +#include #include #define TEST_SUCCESS EXIT_SUCCESS @@ -211,4 +212,22 @@ #define REGISTER_PERF_TEST REGISTER_TEST_COMMAND #define REGISTER_DRIVER_TEST REGISTER_TEST_COMMAND +/** + * Scale test iterations inversely with core count. + * + * On high core count systems, tests with per-core work can exceed + * timeout limits due to increased lock contention and scheduling + * overhead. This helper scales iterations to keep total test time + * roughly constant regardless of core count. + * + * @param base Base iteration count (used on single-core systems) + * @param min Minimum iterations (floor to ensure meaningful testing) + * @return Scaled iteration count + */ +static inline unsigned int +test_scale_iterations(unsigned int base, unsigned int min) +{ + return RTE_MAX(base / rte_lcore_count(), min); +} + #endif diff -Nru dpdk-24.11.4/app/test/test_atomic.c dpdk-24.11.8/app/test/test_atomic.c --- dpdk-24.11.4/app/test/test_atomic.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_atomic.c 2026-10-14 13:10:05.000000000 +0000 @@ -10,11 +10,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include @@ -99,7 +101,15 @@ #define NUM_ATOMIC_TYPES 3 -#define N 1000000 +#define N_BASE 1000000u +#define N_MIN 10000u + +/* + * Number of iterations for each test, scaled inversely with core count. + * More cores means more contention which increases time per operation. + * Calculated once at test start to avoid repeated computation in workers. + */ +static unsigned int num_iterations; static rte_atomic16_t a16; static rte_atomic32_t a32; @@ -110,36 +120,36 @@ static int test_atomic_usual(__rte_unused void *arg) { - unsigned i; + unsigned int i; while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic16_inc(&a16); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic16_dec(&a16); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic16_add(&a16, 5); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic16_sub(&a16, 5); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic32_inc(&a32); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic32_dec(&a32); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic32_add(&a32, 5); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic32_sub(&a32, 5); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic64_inc(&a64); - for (i = 0; i < N; i++) + for (i = 0; i < num_iterations; i++) rte_atomic64_dec(&a64); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic64_add(&a64, 5); - for (i = 0; i < (N / 5); i++) + for (i = 0; i < (num_iterations / 5); i++) rte_atomic64_sub(&a64, 5); return 0; @@ -149,7 +159,7 @@ test_atomic_tas(__rte_unused void *arg) { while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); if (rte_atomic16_test_and_set(&a16)) rte_atomic64_inc(&count); @@ -167,12 +177,12 @@ uint32_t tmp16; uint32_t tmp32; uint64_t tmp64; - unsigned i; + unsigned int i; while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); - for (i = 0; i < N; i++) { + for (i = 0; i < num_iterations; i++) { tmp16 = rte_atomic16_add_return(&a16, 1); rte_atomic64_add(&count, tmp16); @@ -209,7 +219,7 @@ test_atomic_inc_and_test(__rte_unused void *arg) { while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); if (rte_atomic16_inc_and_test(&a16)) { rte_atomic64_inc(&count); @@ -236,7 +246,7 @@ test_atomic_dec_and_test(__rte_unused void *arg) { while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); if (rte_atomic16_dec_and_test(&a16)) rte_atomic64_inc(&count); @@ -268,11 +278,11 @@ unsigned int i; while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); expected = count128; - for (i = 0; i < N; i++) { + for (i = 0; i < num_iterations; i++) { do { rte_int128_t desired; @@ -399,14 +409,14 @@ static int test_atomic_exchange(__rte_unused void *arg) { - int i; + unsigned int i; test16_t nt16, ot16; /* new token, old token */ test32_t nt32, ot32; test64_t nt64, ot64; /* Wait until all of the other threads have been dispatched */ while (rte_atomic32_read(&synchro) == 0) - ; + rte_pause(); /* * Let the battle begin! Every thread attempts to steal the current @@ -415,7 +425,7 @@ * appropriate crc32 hash for the data) then the test iteration has * passed. If the token is invalid, increment the counter. */ - for (i = 0; i < N; i++) { + for (i = 0; i < num_iterations; i++) { /* Test 64bit Atomic Exchange */ nt64.u64 = rte_rand(); @@ -444,6 +454,8 @@ static int test_atomic(void) { + num_iterations = test_scale_iterations(N_BASE, N_MIN); + rte_atomic16_init(&a16); rte_atomic32_init(&a32); rte_atomic64_init(&a64); @@ -591,7 +603,7 @@ rte_atomic32_clear(&synchro); iterations = count128.val[0] - count128.val[1]; - if (iterations != (uint64_t)4*N*(rte_lcore_count()-1)) { + if (iterations != (uint64_t)4*num_iterations*(rte_lcore_count()-1)) { printf("128-bit compare and swap failed\n"); return -1; } diff -Nru dpdk-24.11.4/app/test/test_bpf.c dpdk-24.11.8/app/test/test_bpf.c --- dpdk-24.11.4/app/test/test_bpf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_bpf.c 2026-10-14 13:10:05.000000000 +0000 @@ -32,6 +32,260 @@ #include +/* Tests of most simple BPF programs (no instructions, one instruction etc.) */ + +/* + * Try to load a simple bpf program from the instructions array. + * + * When `expected_errno` is zero, expect it to load successfully. + * When `expected_errno` is non-zero, expect it to fail with this `rte_errno`. + * + * @param nb_ins + * Number of instructions in the `ins` array. + * @param ins + * BPF instructions array. + * @param expected_errno + * Expected result. + * @return + * TEST_SUCCESS on success, error code on failure. + */ +static int +bpf_load_test(uint32_t nb_ins, const struct ebpf_insn *ins, int expected_errno) +{ + const struct rte_bpf_prm prm = { + .ins = ins, + .nb_ins = nb_ins, + .prog_arg = { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uint64_t), + }, + }; + + struct rte_bpf *const bpf = rte_bpf_load(&prm); + const int actual_errno = rte_errno; + rte_bpf_destroy(bpf); + + if (expected_errno != 0) { + RTE_TEST_ASSERT_EQUAL(bpf, NULL, + "expect rte_bpf_load() == NULL"); + RTE_TEST_ASSERT_EQUAL(actual_errno, expected_errno, + "expect rte_errno == %d, found %d", + expected_errno, actual_errno); + } else + RTE_TEST_ASSERT_NOT_EQUAL(bpf, NULL, + "expect rte_bpf_load() != NULL"); + + return TEST_SUCCESS; +} + +/* + * Try and load completely empty BPF program. + * Should fail because there is no EXIT (and also return value is undefined). + */ +static int +test_no_instructions(void) +{ + static const struct ebpf_insn ins[] = {}; + return bpf_load_test(RTE_DIM(ins), ins, EINVAL); +} + +REGISTER_FAST_TEST(bpf_no_instructions_autotest, NOHUGE_OK, ASAN_OK, test_no_instructions); + +/* + * Try and load a BPF program comprising single EXIT instruction. + * Should fail because the return value is undefined. + */ +static int +test_exit_only(void) +{ + static const struct ebpf_insn ins[] = { + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, EINVAL); +} + +REGISTER_FAST_TEST(bpf_exit_only_autotest, NOHUGE_OK, ASAN_OK, test_exit_only); + +/* + * Try and load a BPF program with no EXIT instruction. + * Should fail because of this. + */ +static int +test_no_exit(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Set return value to the program argument. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, EINVAL); +} + +REGISTER_FAST_TEST(bpf_no_exit_autotest, NOHUGE_OK, ASAN_OK, test_no_exit); + +/* + * Try and load smallest possible valid BPF program. + */ +static int +test_minimal_working(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Set return value to the program argument. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, 0); +} + +REGISTER_FAST_TEST(bpf_minimal_working_autotest, NOHUGE_OK, ASAN_OK, test_minimal_working); + +/* + * Try and load valid BPF program adding one to the argument. + */ +static int +test_add_one(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Set return value to one. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_K), + .dst_reg = EBPF_REG_0, + .imm = 1, + }, + { + /* Add program argument to the return value. */ + .code = (EBPF_ALU64 | BPF_ADD | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, 0); +} + +REGISTER_FAST_TEST(bpf_add_one_autotest, NOHUGE_OK, ASAN_OK, test_add_one); + +/* + * Try and load valid BPF program subtracting one from the argument. + */ +static int +test_subtract_one(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Subtract one from the program argument. */ + .code = (EBPF_ALU64 | BPF_SUB | BPF_K), + .dst_reg = EBPF_REG_1, + .imm = 1, + }, + { + /* Set return value to the result. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, 0); +} + +REGISTER_FAST_TEST(bpf_subtract_one_autotest, NOHUGE_OK, ASAN_OK, test_subtract_one); + +/* + * Conditionally jump over invalid operation as first instruction. + */ +static int +test_jump_over_invalid_first(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Jump over the next instruction for some r1. */ + .code = (BPF_JMP | BPF_JEQ | BPF_K), + .dst_reg = EBPF_REG_1, + .imm = 42, + .off = 1, + }, + { + /* Write 0xDEADBEEF to [r1 + INT16_MIN]. */ + .code = (BPF_ST | BPF_MEM | EBPF_DW), + .dst_reg = EBPF_REG_1, + .off = INT16_MIN, + .imm = 0xDEADBEEF, + }, + { + /* Set return value to the program argument. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, EINVAL); +} + +REGISTER_FAST_TEST(bpf_jump_over_invalid_first_autotest, NOHUGE_OK, ASAN_OK, + test_jump_over_invalid_first); + +/* + * Conditionally jump over invalid operation as non-first instruction. + */ +static int +test_jump_over_invalid_non_first(void) +{ + static const struct ebpf_insn ins[] = { + { + /* Set return value to the program argument. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + /* Jump over the next instruction for some r1. */ + .code = (BPF_JMP | BPF_JEQ | BPF_K), + .dst_reg = EBPF_REG_1, + .imm = 42, + .off = 1, + }, + { + /* Write 0xDEADBEEF to [r1 + INT16_MIN]. */ + .code = (BPF_ST | BPF_MEM | EBPF_DW), + .dst_reg = EBPF_REG_1, + .off = INT16_MIN, + .imm = 0xDEADBEEF, + }, + { + /* Set return value to the program argument. */ + .code = (EBPF_ALU64 | EBPF_MOV | BPF_X), + .src_reg = EBPF_REG_1, + .dst_reg = EBPF_REG_0, + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + return bpf_load_test(RTE_DIM(ins), ins, EINVAL); +} + +REGISTER_FAST_TEST(bpf_jump_over_invalid_non_first_autotest, NOHUGE_OK, ASAN_OK, + test_jump_over_invalid_non_first); + /* * Basic functional tests for librte_bpf. * The main procedure - load eBPF program, execute it and @@ -137,6 +391,13 @@ return ret; } +/* Empty prepare function */ +static void +dummy_prepare(void *arg) +{ + RTE_SET_USED(arg); +} + /* store immediate test-cases */ static const struct ebpf_insn test_store1_prog[] = { { @@ -2901,6 +3162,70 @@ }, }; +/* divide INT64_MIN by -1 */ +static const struct ebpf_insn test_int64min_udiv_uint64max_prog[] = { + /* Load INT64_MIN into r0 */ + { + .code = (BPF_LD | BPF_IMM | EBPF_DW), + .dst_reg = EBPF_REG_0, + .imm = (int32_t)INT64_MIN, + }, + { + .imm = (int32_t)(INT64_MIN >> 32), + }, + /* Divide r0 by immediate -1 */ + { + .code = (EBPF_ALU64 | BPF_DIV | BPF_K), + .dst_reg = EBPF_REG_0, + .imm = -1, + }, + /* Exit for correctness otherwise */ + { + .code = (BPF_JMP | EBPF_EXIT), + }, +}; + +static int +test_int64min_udiv_uint64max_check(uint64_t rc, const void *arg) +{ + RTE_SET_USED(arg); + /* 0x8000000000000000ull / 0xFFFFFFFFFFFFFFFFull == 0 */ + TEST_ASSERT_EQUAL(rc, 0, "expected 0, found %#" PRIx64, rc); + return TEST_SUCCESS; +} + +/* modulo INT64_MIN by -1 */ +static const struct ebpf_insn test_int64min_umod_uint64max_prog[] = { + /* Load INT64_MIN into r0 */ + { + .code = (BPF_LD | BPF_IMM | EBPF_DW), + .dst_reg = EBPF_REG_0, + .imm = (int32_t)INT64_MIN, + }, + { + .imm = (int32_t)(INT64_MIN >> 32), + }, + /* Modulo r0 by immediate -1 */ + { + .code = (EBPF_ALU64 | BPF_MOD | BPF_K), + .dst_reg = EBPF_REG_0, + .imm = -1, + }, + /* Exit for correctness otherwise */ + { + .code = (BPF_JMP | EBPF_EXIT), + }, +}; + +static int +test_int64min_umod_uint64max_check(uint64_t rc, const void *arg) +{ + RTE_SET_USED(arg); + /* 0x8000000000000000ull % 0xFFFFFFFFFFFFFFFFull == 0x8000000000000000ull */ + TEST_ASSERT_EQUAL(rc, (uint64_t)INT64_MIN, "expected INT64_MIN, found %#" PRIx64, rc); + return TEST_SUCCESS; +} + /* all bpf test cases */ static const struct bpf_test tests[] = { { @@ -3209,6 +3534,34 @@ /* mbuf as input argument is not supported on 32 bit platform */ .allow_fail = (sizeof(uint64_t) != sizeof(uintptr_t)), }, + { + .name = "test_int64min_udiv_uint64max", + .arg_sz = sizeof(struct dummy_vect8), + .prm = { + .ins = test_int64min_udiv_uint64max_prog, + .nb_ins = RTE_DIM(test_int64min_udiv_uint64max_prog), + .prog_arg = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(struct dummy_vect8), + }, + }, + .prepare = dummy_prepare, + .check_result = test_int64min_udiv_uint64max_check, + }, + { + .name = "test_int64min_umod_uint64max", + .arg_sz = 1, + .prm = { + .ins = test_int64min_umod_uint64max_prog, + .nb_ins = RTE_DIM(test_int64min_umod_uint64max_prog), + .prog_arg = { + .type = RTE_BPF_ARG_PTR, + .size = 1, + }, + }, + .prepare = dummy_prepare, + .check_result = test_int64min_umod_uint64max_check, + }, }; static int @@ -3278,6 +3631,868 @@ REGISTER_FAST_TEST(bpf_autotest, true, true, test_bpf); +/* Tests of BPF JIT stack alignment when calling external functions (xfuncs). */ + +/* Function called from the BPF program in a test. */ +typedef uint64_t (*text_xfunc_t)(uint64_t argument); + +/* Call function from BPF program, verify that it incremented its argument. */ +static int +call_from_bpf_test(text_xfunc_t xfunc) +{ + static const struct ebpf_insn ins[] = { + { + .code = (BPF_JMP | EBPF_CALL), + .imm = 0, /* xsym #0 */ + }, + { + .code = (BPF_JMP | EBPF_EXIT), + }, + }; + const struct rte_bpf_xsym xsym[] = { + { + .name = "xfunc", + .type = RTE_BPF_XTYPE_FUNC, + .func = { + .val = (void *)xfunc, + .nb_args = 1, + .args = { + { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uint64_t), + }, + }, + .ret = { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uint64_t), + }, + }, + }, + }; + const struct rte_bpf_prm prm = { + .ins = ins, + .nb_ins = RTE_DIM(ins), + .xsym = xsym, + .nb_xsym = RTE_DIM(xsym), + .prog_arg = { + .type = RTE_BPF_ARG_RAW, + .size = sizeof(uint64_t), + }, + }; + + struct rte_bpf_jit jit; + + struct rte_bpf *const bpf = rte_bpf_load(&prm); + RTE_TEST_ASSERT_NOT_EQUAL(bpf, NULL, + "expect rte_bpf_load() != NULL"); + + RTE_TEST_ASSERT_SUCCESS(rte_bpf_get_jit(bpf, &jit), + "expect rte_bpf_get_jit() to succeed"); + + const text_xfunc_t jit_function = (void *)jit.func; + if (jit_function == NULL) { + rte_bpf_destroy(bpf); + return TEST_SKIPPED; + } + + const uint64_t argument = 42; + const uint64_t result = jit_function(argument); + rte_bpf_destroy(bpf); + + RTE_TEST_ASSERT_EQUAL(result, argument + 1, + "expect result == %ju, found %ju", + (uintmax_t)(argument + 1), (uintmax_t)result); + + return TEST_SUCCESS; +} + +/* + * Test alignment of a local variable. + * + * NOTE: May produce false negatives with sanitizers if they replace the stack. + */ + +/* Copy of the pointer to max_align stack variable, volatile to thwart optimization. */ +static volatile uintptr_t stack_alignment_test_pointer; + +static uint64_t +stack_alignment_xfunc(uint64_t argument) +{ + max_align_t max_align; + stack_alignment_test_pointer = (uintptr_t)&max_align; + return argument + 1; +} + +static int +test_stack_alignment(void) +{ + const int test_rc = call_from_bpf_test(stack_alignment_xfunc); + if (test_rc == TEST_SKIPPED) + return TEST_SKIPPED; + + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect call_from_bpf_test(stack_alignment_xfunc) to succeed"); + + const uintptr_t test_offset = stack_alignment_test_pointer; + RTE_TEST_ASSERT_NOT_EQUAL(test_offset, 0, "expect test_pointer != 0"); + + const size_t test_alignment = test_offset % alignof(max_align_t); + RTE_TEST_ASSERT_EQUAL(test_alignment, 0, + "expect test_alignment == 0, found %zu", test_alignment); + + return TEST_SUCCESS; +} + +REGISTER_FAST_TEST(bpf_stack_alignment_autotest, NOHUGE_OK, ASAN_OK, test_stack_alignment); + +/* + * Test copying `__uint128_t`. + * + * This operation is used by some variations of `rte_memcpy`; + * it can also be produced by vectorizer in the compiler. + */ + +#if defined(__SIZEOF_INT128__) + +static uint64_t +stack_copy_uint128_xfunc(uint64_t argument) +{ + /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */ + char alignas(16) src_buffer[16]; + char alignas(16) dst_buffer[16]; + void *const src = (char *volatile)src_buffer; + void *const dst = (char *volatile)dst_buffer; + const size_t size = 16; + + memset(src, 0x2a, size); + memset(dst, 0x55, size); + const int initial_memcmp_rc = memcmp(dst, src, size); + + const __uint128_t *const src128 = (const __uint128_t *)src; + __uint128_t *const dst128 = (__uint128_t *)dst; + *dst128 = *src128; + const int memcmp_rc = memcmp(dst, src, size); + + return argument + 1 + !initial_memcmp_rc + memcmp_rc; +} + +static int +test_stack_copy_uint128(void) +{ + const int test_rc = call_from_bpf_test(stack_copy_uint128_xfunc); + if (test_rc == TEST_SKIPPED) + return TEST_SKIPPED; + + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect call_from_bpf_test(stack_copy_uint128_xfunc) to succeed"); + + return TEST_SUCCESS; +} + +#else + +static int +test_stack_copy_uint128(void) +{ + return TEST_SKIPPED; +} + +#endif + +REGISTER_FAST_TEST(bpf_stack_copy_uint128_autotest, NOHUGE_OK, ASAN_OK, test_stack_copy_uint128); + +/* + * Test SSE2 load and store intrinsics. + * + * These intrinsics are used by e.g. lib/hash. + * + * Test both aligned and unaligned versions. Unaligned intrinsics may still fail + * when the stack is misaligned, since they only treat memory address as + * unaligned, not stack. + */ + +#if defined(__SSE2__) + +static uint64_t +stack_sse2_aligned_xfunc(uint64_t argument) +{ + /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */ + char alignas(16) src_buffer[16]; + char alignas(16) dst_buffer[16]; + void *const src = (char *volatile)src_buffer; + void *const dst = (char *volatile)dst_buffer; + const size_t size = 16; + + memset(src, 0x2a, size); + memset(dst, 0x55, size); + const int initial_memcmp_rc = memcmp(dst, src, size); + + const __m128i tmp = _mm_load_si128((const __m128i *)src); + _mm_store_si128((__m128i *)dst, tmp); + const int memcmp_rc = memcmp(dst, src, size); + + return argument + 1 + !initial_memcmp_rc + memcmp_rc; +} + +static uint64_t +stack_sse2_unaligned_xfunc(uint64_t argument) +{ + /* Pass addresses through volatiles to prevent compiler from optimizing it all out. */ + char alignas(16) src_buffer[17]; + char alignas(16) dst_buffer[17]; + void *const src = (char *volatile)src_buffer + 1; + void *const dst = (char *volatile)dst_buffer + 1; + const size_t size = 16; + + memset(src, 0x2a, size); + memset(dst, 0x55, size); + const int initial_memcmp_rc = memcmp(dst, src, size); + + const __m128i tmp = _mm_loadu_si128((const __m128i *)src); + _mm_storeu_si128((__m128i *)dst, tmp); + const int memcmp_rc = memcmp(dst, src, size); + + return argument + 1 + !initial_memcmp_rc + memcmp_rc; +} + +static int +test_stack_sse2(void) +{ + int test_rc; + + test_rc = call_from_bpf_test(stack_sse2_aligned_xfunc); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect call_from_bpf_test(stack_sse2_aligned_xfunc) to succeed"); + + test_rc = call_from_bpf_test(stack_sse2_unaligned_xfunc); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect call_from_bpf_test(stack_sse2_unaligned_xfunc) to succeed"); + + return TEST_SUCCESS; +} + +#else + +static int +test_stack_sse2(void) +{ + return TEST_SKIPPED; +} + +#endif + +REGISTER_FAST_TEST(bpf_stack_sse2_autotest, NOHUGE_OK, ASAN_OK, test_stack_sse2); + +/* + * Run memcpy and rte_memcpy with various data sizes and offsets (unaligned and aligned). + * + * May produce false negatives even if BPF breaks stack alignment since + * compilers may realign the stack in the beginning of the function to use + * vector instructions with width larger than the default stack alignment. + * However, represents very important use case that was broken in practice. + * + * For the reason specified above test 16-byte fixed-width memcpy explicitly. + */ + +static void *volatile stack_memcpy_dst; +static const void *volatile stack_memcpy_src; +static size_t volatile stack_memcpy_size; + +static uint64_t +stack_memcpy16_xfunc(uint64_t argument) +{ + RTE_ASSERT(stack_memcpy_size == 16); + memcpy(stack_memcpy_dst, stack_memcpy_src, 16); + return argument + 1; +} + +static uint64_t +stack_rte_memcpy16_xfunc(uint64_t argument) +{ + RTE_ASSERT(stack_memcpy_size == 16); + rte_memcpy(stack_memcpy_dst, stack_memcpy_src, 16); + return argument + 1; +} + +static uint64_t +stack_memcpy_xfunc(uint64_t argument) +{ + memcpy(stack_memcpy_dst, stack_memcpy_src, stack_memcpy_size); + return argument + 1; +} + +static uint64_t +stack_rte_memcpy_xfunc(uint64_t argument) +{ + rte_memcpy(stack_memcpy_dst, stack_memcpy_src, stack_memcpy_size); + return argument + 1; +} + +static int +stack_memcpy_subtest(text_xfunc_t xfunc, size_t size, size_t src_offset, size_t dst_offset) +{ + stack_memcpy_size = size; + + char *const src_buffer = malloc(size + src_offset); + char *const dst_buffer = malloc(size + dst_offset); + + if (src_buffer == NULL || dst_buffer == NULL) { + free(dst_buffer); + free(src_buffer); + return TEST_FAILED; + } + + memset(src_buffer + src_offset, 0x2a, size); + stack_memcpy_src = src_buffer + src_offset; + + memset(dst_buffer + dst_offset, 0x55, size); + stack_memcpy_dst = dst_buffer + dst_offset; + + const int initial_memcmp_rc = memcmp(stack_memcpy_dst, stack_memcpy_src, size); + const int test_rc = call_from_bpf_test(xfunc); + const int memcmp_rc = memcmp(stack_memcpy_dst, stack_memcpy_src, size); + + free(dst_buffer); + free(src_buffer); + + if (test_rc == TEST_SKIPPED) + return TEST_SKIPPED; + + RTE_TEST_ASSERT_FAIL(initial_memcmp_rc, "expect memcmp() to fail initially"); + RTE_TEST_ASSERT_SUCCESS(test_rc, "expect call_from_bpf_test(xfunc) to succeed"); + RTE_TEST_ASSERT_SUCCESS(memcmp_rc, "expect memcmp() to succeed"); + + return TEST_SUCCESS; +} + +static int +test_stack_memcpy(void) +{ + for (int offsets = 0; offsets < 4; ++offsets) { + const bool src_offset = offsets & 1; + const bool dst_offset = offsets & 2; + int test_rc; + + test_rc = stack_memcpy_subtest(stack_memcpy16_xfunc, + 16, src_offset, dst_offset); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect stack_memcpy_subtest(stack_memcpy16_xfunc, " + "16, %i, %i) to succeed", + src_offset, dst_offset); + + test_rc = stack_memcpy_subtest(stack_rte_memcpy16_xfunc, + 16, src_offset, dst_offset); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect stack_memcpy_subtest(stack_rte_memcpy16_xfunc, " + "16, %i, %i) to succeed", + src_offset, dst_offset); + + for (size_t size = 1; size <= 1024; size <<= 1) { + test_rc = stack_memcpy_subtest(stack_memcpy_xfunc, + size, src_offset, dst_offset); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect stack_memcpy_subtest(stack_memcpy_xfunc, " + "%zu, %i, %i) to succeed", + size, src_offset, dst_offset); + + test_rc = stack_memcpy_subtest(stack_rte_memcpy_xfunc, + size, src_offset, dst_offset); + if (test_rc == TEST_SKIPPED) + return test_rc; + RTE_TEST_ASSERT_SUCCESS(test_rc, + "expect stack_memcpy_subtest(stack_rte_memcpy_xfunc, " + "%zu, %i, %i) to succeed", + size, src_offset, dst_offset); + } + } + return TEST_SUCCESS; +} + +REGISTER_FAST_TEST(bpf_stack_memcpy_autotest, NOHUGE_OK, ASAN_OK, test_stack_memcpy); + +#ifdef TEST_BPF_ELF_LOAD + +/* + * Helper function to write BPF object data to temporary file. + * Returns temp file path on success, NULL on failure. + * Caller must free the returned path and unlink the file. + */ +static char * +create_temp_bpf_file(const uint8_t *data, size_t size, const char *name) +{ + char *tmpfile = NULL; + int fd; + ssize_t written; + + if (asprintf(&tmpfile, "/tmp/dpdk_bpf_%s_XXXXXX.o", name) < 0) { + printf("%s@%d: asprintf failed: %s\n", + __func__, __LINE__, strerror(errno)); + return NULL; + } + + /* Create and open temp file */ + fd = mkstemps(tmpfile, strlen(".o")); + if (fd < 0) { + printf("%s@%d: mkstemps(%s) failed: %s\n", + __func__, __LINE__, tmpfile, strerror(errno)); + free(tmpfile); + return NULL; + } + + /* Write BPF object data */ + written = write(fd, data, size); + close(fd); + + if (written != (ssize_t)size) { + printf("%s@%d: write failed: %s\n", + __func__, __LINE__, strerror(errno)); + unlink(tmpfile); + free(tmpfile); + return NULL; + } + + return tmpfile; +} + +#include "test_bpf_load.h" + +/* + * Test loading BPF program from an object file. + * This test uses same arguments as previous test_call1 example. + */ +static int +test_bpf_elf_load(void) +{ + static const char test_section[] = "call1"; + uint8_t tbuf[sizeof(struct dummy_vect8)]; + const struct rte_bpf_xsym xsym[] = { + { + .name = RTE_STR(dummy_func1), + .type = RTE_BPF_XTYPE_FUNC, + .func = { + .val = (void *)dummy_func1, + .nb_args = 3, + .args = { + [0] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(struct dummy_offset), + }, + [1] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(uint32_t), + }, + [2] = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(uint64_t), + }, + }, + }, + }, + }; + int ret; + + /* Create temp file from embedded BPF object */ + char *tmpfile = create_temp_bpf_file(app_test_bpf_load_o, + app_test_bpf_load_o_len, + "load"); + if (tmpfile == NULL) + return -1; + + /* Try to load BPF program from temp file */ + const struct rte_bpf_prm prm = { + .xsym = xsym, + .nb_xsym = RTE_DIM(xsym), + .prog_arg = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(tbuf), + }, + }; + + struct rte_bpf *bpf = rte_bpf_elf_load(&prm, tmpfile, test_section); + unlink(tmpfile); + free(tmpfile); + + /* If libelf support is not available */ + if (bpf == NULL && rte_errno == ENOTSUP) + return TEST_SKIPPED; + + TEST_ASSERT(bpf != NULL, "failed to load BPF %d:%s", rte_errno, strerror(rte_errno)); + + /* Prepare test data */ + struct dummy_vect8 *dv = (struct dummy_vect8 *)tbuf; + + memset(dv, 0, sizeof(*dv)); + dv->in[0].u64 = (int32_t)TEST_FILL_1; + dv->in[0].u32 = dv->in[0].u64; + dv->in[0].u16 = dv->in[0].u64; + dv->in[0].u8 = dv->in[0].u64; + + /* Execute loaded BPF program */ + uint64_t rc = rte_bpf_exec(bpf, tbuf); + ret = test_call1_check(rc, tbuf); + TEST_ASSERT(ret == 0, "test_call1_check failed: %d", ret); + + /* Test JIT if available */ + struct rte_bpf_jit jit; + ret = rte_bpf_get_jit(bpf, &jit); + TEST_ASSERT(ret == 0, "rte_bpf_get_jit failed: %d", ret); + + if (jit.func != NULL) { + memset(dv, 0, sizeof(*dv)); + dv->in[0].u64 = (int32_t)TEST_FILL_1; + dv->in[0].u32 = dv->in[0].u64; + dv->in[0].u16 = dv->in[0].u64; + dv->in[0].u8 = dv->in[0].u64; + + rc = jit.func(tbuf); + ret = test_call1_check(rc, tbuf); + TEST_ASSERT(ret == 0, "jit test_call1_check failed: %d", ret); + } + + rte_bpf_destroy(bpf); + + printf("%s: ELF load test passed\n", __func__); + return TEST_SUCCESS; +} + +#include +#include +#include + +#include "test_bpf_filter.h" + +#define BPF_TEST_BURST 128 +#define BPF_TEST_POOLSIZE 256 /* at least 2x burst */ +#define BPF_TEST_PKT_LEN 64 /* Ether + IP + TCP */ + +static int null_vdev_setup(const char *name, uint16_t *port, struct rte_mempool *pool) +{ + int ret; + + /* Make a null device */ + ret = rte_vdev_init(name, NULL); + TEST_ASSERT(ret == 0, "rte_vdev_init(%s) failed: %d", name, ret); + + ret = rte_eth_dev_get_port_by_name(name, port); + TEST_ASSERT(ret == 0, "failed to get port id for %s: %d", name, ret); + + struct rte_eth_conf conf = { }; + ret = rte_eth_dev_configure(*port, 1, 1, &conf); + TEST_ASSERT(ret == 0, "failed to configure port %u: %d", *port, ret); + + struct rte_eth_txconf txconf = { }; + ret = rte_eth_tx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY, &txconf); + TEST_ASSERT(ret == 0, "failed to setup tx queue port %u: %d", *port, ret); + + struct rte_eth_rxconf rxconf = { }; + ret = rte_eth_rx_queue_setup(*port, 0, BPF_TEST_BURST, SOCKET_ID_ANY, + &rxconf, pool); + TEST_ASSERT(ret == 0, "failed to setup rx queue port %u: %d", *port, ret); + + ret = rte_eth_dev_start(*port); + TEST_ASSERT(ret == 0, "failed to start port %u: %d", *port, ret); + + return 0; +} + +static unsigned int +setup_mbufs(struct rte_mbuf *burst[], unsigned int n) +{ + struct rte_ether_hdr eh = { + .ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4), + }; + const struct rte_ipv4_hdr iph = { + .version_ihl = RTE_IPV4_VHL_DEF, + .total_length = rte_cpu_to_be_16(BPF_TEST_PKT_LEN - sizeof(eh)), + .time_to_live = IPDEFTTL, + .src_addr = rte_cpu_to_be_32(ip_src_addr), + .dst_addr = rte_cpu_to_be_32(ip_dst_addr), + }; + unsigned int tcp_count = 0; + + rte_eth_random_addr(eh.dst_addr.addr_bytes); + + for (unsigned int i = 0; i < n; i++) { + struct rte_mbuf *mb = burst[i]; + + /* Setup Ethernet header */ + *rte_pktmbuf_mtod(mb, struct rte_ether_hdr *) = eh; + + /* Setup IP header */ + struct rte_ipv4_hdr *ip + = rte_pktmbuf_mtod_offset(mb, struct rte_ipv4_hdr *, sizeof(eh)); + *ip = iph; + + if (rte_rand() & 1) { + struct rte_udp_hdr *udp + = rte_pktmbuf_mtod_offset(mb, struct rte_udp_hdr *, + sizeof(eh) + sizeof(iph)); + + ip->next_proto_id = IPPROTO_UDP; + *udp = (struct rte_udp_hdr) { + .src_port = rte_cpu_to_be_16(9), /* discard */ + .dst_port = rte_cpu_to_be_16(9), /* discard */ + .dgram_len = BPF_TEST_PKT_LEN - sizeof(eh) - sizeof(iph), + }; + + } else { + struct rte_tcp_hdr *tcp + = rte_pktmbuf_mtod_offset(mb, struct rte_tcp_hdr *, + sizeof(eh) + sizeof(iph)); + + ip->next_proto_id = IPPROTO_TCP; + *tcp = (struct rte_tcp_hdr) { + .src_port = rte_cpu_to_be_16(9), /* discard */ + .dst_port = rte_cpu_to_be_16(9), /* discard */ + .tcp_flags = RTE_TCP_RST_FLAG, + }; + ++tcp_count; + } + } + + return tcp_count; +} + +static int bpf_tx_test(uint16_t port, const char *tmpfile, struct rte_mempool *pool, + const char *section, uint32_t flags) +{ + const struct rte_bpf_prm prm = { + .prog_arg = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(struct rte_mbuf), + }, + }; + int ret; + + /* Try to load BPF TX program from temp file */ + ret = rte_bpf_eth_tx_elf_load(port, 0, &prm, tmpfile, section, flags); + if (ret != 0) { + printf("%s@%d: failed to load BPF filter from file=%s error=%d:(%s)\n", + __func__, __LINE__, tmpfile, rte_errno, rte_strerror(rte_errno)); + return ret; + } + + struct rte_mbuf *pkts[BPF_TEST_BURST] = { }; + ret = rte_pktmbuf_alloc_bulk(pool, pkts, BPF_TEST_BURST); + TEST_ASSERT(ret == 0, "failed to allocate mbufs"); + + uint16_t expect = setup_mbufs(pkts, BPF_TEST_BURST); + + uint16_t sent = rte_eth_tx_burst(port, 0, pkts, BPF_TEST_BURST); + TEST_ASSERT_EQUAL(sent, expect, "rte_eth_tx_burst returned: %u expected %u", + sent, expect); + + /* The unsent packets should be dropped */ + rte_pktmbuf_free_bulk(pkts + sent, BPF_TEST_BURST - sent); + + /* Pool should have same number of packets avail */ + unsigned int avail = rte_mempool_avail_count(pool); + TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE, + "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE); + + rte_bpf_eth_tx_unload(port, 0); + return TEST_SUCCESS; +} + +/* Test loading a transmit filter which only allows IPv4 packets */ +static int +test_bpf_elf_tx_load(void) +{ + static const char null_dev[] = "net_null_bpf0"; + char *tmpfile = NULL; + struct rte_mempool *mb_pool = NULL; + uint16_t port = UINT16_MAX; + int ret; + + printf("%s start\n", __func__); + + /* Make a pool for packets */ + mb_pool = rte_pktmbuf_pool_create("bpf_tx_test_pool", BPF_TEST_POOLSIZE, + 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, + SOCKET_ID_ANY); + + ret = null_vdev_setup(null_dev, &port, mb_pool); + if (ret != 0) + goto fail; + + /* Create temp file from embedded BPF object */ + tmpfile = create_temp_bpf_file(app_test_bpf_filter_o, app_test_bpf_filter_o_len, "tx"); + if (tmpfile == NULL) + goto fail; + + /* Do test with VM */ + ret = bpf_tx_test(port, tmpfile, mb_pool, "filter", 0); + if (ret != 0) + goto fail; + + /* Repeat with JIT */ + ret = bpf_tx_test(port, tmpfile, mb_pool, "filter", RTE_BPF_ETH_F_JIT); + if (ret == 0) + printf("%s: TX ELF load test passed\n", __func__); + +fail: + if (tmpfile) { + unlink(tmpfile); + free(tmpfile); + } + + if (port != UINT16_MAX) + rte_vdev_uninit(null_dev); + + rte_mempool_free(mb_pool); + + if (ret == 0) + return TEST_SUCCESS; + else if (ret == -ENOTSUP) + return TEST_SKIPPED; + else + return TEST_FAILED; +} + +/* Test loading a receive filter */ +static int bpf_rx_test(uint16_t port, const char *tmpfile, struct rte_mempool *pool, + const char *section, uint32_t flags, uint16_t expected) +{ + struct rte_mbuf *pkts[BPF_TEST_BURST]; + const struct rte_bpf_prm prm = { + .prog_arg = { + .type = RTE_BPF_ARG_PTR, + .size = sizeof(struct rte_mbuf), + }, + }; + int ret; + + /* Load BPF program to drop all packets */ + ret = rte_bpf_eth_rx_elf_load(port, 0, &prm, tmpfile, section, flags); + if (ret != 0) { + printf("%s@%d: failed to load BPF filter from file=%s error=%d:(%s)\n", + __func__, __LINE__, tmpfile, rte_errno, rte_strerror(rte_errno)); + return ret; + } + + uint16_t rcvd = rte_eth_rx_burst(port, 0, pkts, BPF_TEST_BURST); + TEST_ASSERT_EQUAL(rcvd, expected, + "rte_eth_rx_burst returned: %u expect: %u", rcvd, expected); + + /* Drop the received packets */ + rte_pktmbuf_free_bulk(pkts, rcvd); + + rte_bpf_eth_rx_unload(port, 0); + + /* Pool should now be full */ + unsigned int avail = rte_mempool_avail_count(pool); + TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE, + "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE); + + return TEST_SUCCESS; +} + +/* Test loading a receive filters, first with drop all and then with allow all packets */ +static int +test_bpf_elf_rx_load(void) +{ + static const char null_dev[] = "net_null_bpf0"; + struct rte_mempool *pool = NULL; + char *tmpfile = NULL; + uint16_t port; + int ret; + + printf("%s start\n", __func__); + + /* Make a pool for packets */ + pool = rte_pktmbuf_pool_create("bpf_rx_test_pool", 2 * BPF_TEST_BURST, + 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, + SOCKET_ID_ANY); + TEST_ASSERT(pool != NULL, "failed to create mempool"); + + ret = null_vdev_setup(null_dev, &port, pool); + if (ret != 0) + goto fail; + + /* Create temp file from embedded BPF object */ + tmpfile = create_temp_bpf_file(app_test_bpf_filter_o, app_test_bpf_filter_o_len, "rx"); + if (tmpfile == NULL) + goto fail; + + /* Do test with VM */ + ret = bpf_rx_test(port, tmpfile, pool, "drop", 0, 0); + if (ret != 0) + goto fail; + + /* Repeat with JIT */ + ret = bpf_rx_test(port, tmpfile, pool, "drop", RTE_BPF_ETH_F_JIT, 0); + if (ret != 0) + goto fail; + + /* Repeat with allow all */ + ret = bpf_rx_test(port, tmpfile, pool, "allow", 0, BPF_TEST_BURST); + if (ret != 0) + goto fail; + + /* Repeat with JIT */ + ret = bpf_rx_test(port, tmpfile, pool, "allow", RTE_BPF_ETH_F_JIT, BPF_TEST_BURST); + if (ret != 0) + goto fail; + + printf("%s: RX ELF load test passed\n", __func__); + + /* The filter should free the mbufs */ + unsigned int avail = rte_mempool_avail_count(pool); + TEST_ASSERT_EQUAL(avail, BPF_TEST_POOLSIZE, + "Mempool available %u != %u leaks?", avail, BPF_TEST_POOLSIZE); + +fail: + if (tmpfile) { + unlink(tmpfile); + free(tmpfile); + } + + if (port != UINT16_MAX) + rte_vdev_uninit(null_dev); + + rte_mempool_free(pool); + + return ret == 0 ? TEST_SUCCESS : TEST_FAILED; +} + + +static int +test_bpf_elf(void) +{ + int ret; + + ret = test_bpf_elf_load(); + if (ret == TEST_SUCCESS) + ret = test_bpf_elf_tx_load(); + if (ret == TEST_SUCCESS) + ret = test_bpf_elf_rx_load(); + + return ret; +} + +#else + +static int +test_bpf_elf(void) +{ + printf("BPF compile not supported, skipping test\n"); + return TEST_SKIPPED; +} + +#endif /* !TEST_BPF_ELF_LOAD */ + +REGISTER_FAST_TEST(bpf_elf_autotest, NOHUGE_OK, ASAN_OK, test_bpf_elf); + #ifndef RTE_HAS_LIBPCAP static int diff -Nru dpdk-24.11.4/app/test/test_cfgfile.c dpdk-24.11.8/app/test/test_cfgfile.c --- dpdk-24.11.4/app/test/test_cfgfile.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_cfgfile.c 2026-10-14 13:10:05.000000000 +0000 @@ -178,12 +178,8 @@ ret = remove(filename); TEST_ASSERT_SUCCESS(ret, "Failed to remove file"); - char tmp[PATH_MAX] = "/tmp/"; -#ifdef RTE_EXEC_ENV_WINDOWS - ret = GetTempPathA(sizeof(tmp), tmp); - TEST_ASSERT(ret > 0, "Failed to get tmp directory"); -#endif - snprintf(filename, sizeof(filename), "%s%s", tmp, "cfg_save.ini"); + ret = make_tmp_file(filename, "save", ""); + TEST_ASSERT(ret == 0, "Failed to make empty tmp filename for save"); ret = rte_cfgfile_save(cfgfile, filename); TEST_ASSERT_SUCCESS(ret, "Failed to save to %s", filename); diff -Nru dpdk-24.11.4/app/test/test_cryptodev.c dpdk-24.11.8/app/test/test_cryptodev.c --- dpdk-24.11.4/app/test/test_cryptodev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_cryptodev.c 2026-10-14 13:10:05.000000000 +0000 @@ -9687,7 +9687,6 @@ int ret = TEST_SUCCESS; int to_trn = 0; int to_trn_tbl[16]; - int segs = 1; unsigned int trn_data = 0; struct rte_cryptodev_info dev_info; uint64_t feat_flags; @@ -9756,7 +9755,6 @@ */ while (trn_data < input_vec_len) { - ++segs; to_trn = (input_vec_len - trn_data < fragsz) ? (input_vec_len - trn_data) : fragsz; @@ -9764,6 +9762,7 @@ buf->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf = buf->next; + ut_params->ibuf->nb_segs++; memset(rte_pktmbuf_mtod(buf, uint8_t *), 0, rte_pktmbuf_tailroom(buf)); @@ -9773,6 +9772,7 @@ buf_oop->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf_oop = buf_oop->next; + ut_params->obuf->nb_segs++; memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), 0, rte_pktmbuf_tailroom(buf_oop)); TEST_ASSERT_NOT_NULL(ut_params->obuf, "Output buffer not initialized"); @@ -9787,16 +9787,12 @@ trn_data += to_trn; } - ut_params->ibuf->nb_segs = segs; - - segs = 1; if (fragsz_oop && oop) { to_trn = 0; ecx = 0; trn_data = frag_size_oop; while (trn_data < output_vec_len) { - ++segs; to_trn = (output_vec_len - trn_data < frag_size_oop) ? @@ -9808,13 +9804,13 @@ buf_oop->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf_oop = buf_oop->next; + ut_params->obuf->nb_segs++; memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), 0, rte_pktmbuf_tailroom(buf_oop)); TEST_ASSERT_NOT_NULL(rte_pktmbuf_append(ut_params->obuf, to_trn), "Failed to append to mbuf"); trn_data += to_trn; } - ut_params->obuf->nb_segs = segs; } /* Setup Cipher Parameters */ @@ -15811,7 +15807,6 @@ uint64_t feature_flags; unsigned int trn_data = 0; void *digest_mem = NULL; - uint32_t segs = 1; unsigned int to_trn = 0; struct rte_mbuf *buf = NULL; uint8_t *auth_tag, *plaintext; @@ -15872,12 +15867,12 @@ */ while (trn_data < tdata->plaintext.len) { - ++segs; to_trn = (tdata->plaintext.len - trn_data < fragsz) ? (tdata->plaintext.len - trn_data) : fragsz; buf->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf = buf->next; + ut_params->ibuf->nb_segs++; memset(rte_pktmbuf_mtod(buf, uint8_t *), 0, rte_pktmbuf_tailroom(buf)); @@ -15895,7 +15890,6 @@ TEST_ASSERT_NOT_NULL(digest_mem, "Failed to append digest data"); } } - ut_params->ibuf->nb_segs = segs; /* * Place digest at the end of the last buffer @@ -17046,7 +17040,6 @@ int retval; int to_trn = 0; int to_trn_tbl[SGL_MAX_NO]; - int segs = 1; unsigned int trn_data = 0; uint8_t *plaintext, *ciphertext, *auth_tag; struct rte_cryptodev_info dev_info; @@ -17171,7 +17164,6 @@ */ while (trn_data < tdata->plaintext.len) { - ++segs; to_trn = (tdata->plaintext.len - trn_data < fragsz) ? (tdata->plaintext.len - trn_data) : fragsz; @@ -17179,6 +17171,7 @@ buf->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf = buf->next; + ut_params->ibuf->nb_segs++; memset(rte_pktmbuf_mtod(buf, uint8_t *), 0, rte_pktmbuf_tailroom(buf)); @@ -17188,6 +17181,7 @@ buf_last_oop = buf_oop->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); buf_oop = buf_oop->next; + ut_params->obuf->nb_segs++; memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), 0, rte_pktmbuf_tailroom(buf_oop)); TEST_ASSERT_NOT_NULL(rte_pktmbuf_append(ut_params->obuf, to_trn), "Failed to append to mbuf"); @@ -17217,9 +17211,6 @@ uint64_t digest_phys = 0; - ut_params->ibuf->nb_segs = segs; - - segs = 1; if (fragsz_oop && oop) { to_trn = 0; ecx = 0; @@ -17235,7 +17226,6 @@ trn_data = frag_size_oop; while (trn_data < tdata->plaintext.len) { - ++segs; to_trn = (tdata->plaintext.len - trn_data < frag_size_oop) ? @@ -17247,6 +17237,7 @@ buf_last_oop = buf_oop->next = rte_pktmbuf_alloc(ts_params->mbuf_pool); TEST_ASSERT_NOT_NULL(buf_oop->next, "Unexpected end of chain"); + ut_params->obuf->nb_segs++; buf_oop = buf_oop->next; memset(rte_pktmbuf_mtod(buf_oop, uint8_t *), 0, rte_pktmbuf_tailroom(buf_oop)); @@ -17260,8 +17251,6 @@ TEST_ASSERT_NOT_NULL(digest_mem, "Failed to append auth tag"); } } - - ut_params->obuf->nb_segs = segs; } /* @@ -17564,8 +17553,15 @@ RTE_LCORE_FOREACH_WORKER(i) { if (worker_core_count > 1) break; - snprintf(vdev_args, sizeof(vdev_args), - "%s%d", temp_str, i); + ret = snprintf(vdev_args, sizeof(vdev_args), "%s%d", temp_str, i); + + /* If too many args the result will have been truncated */ + if (ret >= VDEV_ARGS_SIZE) { + RTE_LOG(ERR, USER1, + "Cryptodev scheduler test vdev arg size exceeded\n"); + return TEST_FAILED; + } + strcpy(temp_str, vdev_args); strlcat(temp_str, ";", sizeof(temp_str)); worker_core_count++; @@ -17579,8 +17575,14 @@ return TEST_FAILED; } strcpy(temp_str, vdev_args); - snprintf(vdev_args, sizeof(vdev_args), "%s,socket_id=%d", - temp_str, socket_id); + ret = snprintf(vdev_args, sizeof(vdev_args), "%s,socket_id=%d", temp_str, + socket_id); + if (ret >= VDEV_ARGS_SIZE) { + RTE_LOG(ERR, USER1, + "Cryptodev scheduler test vdev arg size exceeded\n"); + return TEST_FAILED; + } + RTE_LOG(DEBUG, USER1, "vdev_args: %s\n", vdev_args); nb_devs = rte_cryptodev_device_count_by_driver( rte_cryptodev_driver_id_get( diff -Nru dpdk-24.11.4/app/test/test_debug.c dpdk-24.11.8/app/test/test_debug.c --- dpdk-24.11.4/app/test/test_debug.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_debug.c 2026-10-14 13:10:05.000000000 +0000 @@ -154,15 +154,15 @@ test_args[2] = "-l"; test_args[3] = core; - if (rte_eal_has_hugepages()) { + if (rte_eal_has_hugepages() && RTE_EXEC_ENV_IS_LINUX) { test_args[4] = ""; test_args[5] = ""; test_args[6] = ""; test_args[7] = ""; } else { test_args[4] = "--no-huge"; - test_args[5] = "-m"; - test_args[6] = "2048"; + test_args[5] = "-m2048"; + test_args[6] = "--no-telemetry"; #ifdef RTE_ARCH_PPC_64 /* iova=pa is the default, but fails on ppc64 with --no-huge */ test_args[7] = "--iova-mode=va"; diff -Nru dpdk-24.11.4/app/test/test_dispatcher.c dpdk-24.11.8/app/test/test_dispatcher.c --- dpdk-24.11.4/app/test/test_dispatcher.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_dispatcher.c 2026-10-14 13:10:05.000000000 +0000 @@ -385,6 +385,7 @@ .sched_type = RTE_SCHED_TYPE_ATOMIC, .op = RTE_EVENT_OP_FORWARD, .priority = RTE_EVENT_DEV_PRIORITY_NORMAL, + .impl_opaque = in_event->impl_opaque, .u64 = sn }; } diff -Nru dpdk-24.11.4/app/test/test_eal_flags.c dpdk-24.11.8/app/test/test_eal_flags.c --- dpdk-24.11.4/app/test/test_eal_flags.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_eal_flags.c 2026-10-14 13:10:05.000000000 +0000 @@ -10,88 +10,88 @@ #include #include -#ifdef RTE_EXEC_ENV_WINDOWS +#ifndef RTE_EXEC_ENV_LINUX static int test_missing_c_flag(void) { - printf("missing_c_flag not supported on Windows, skipping test\n"); + printf("missing_c_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_main_lcore_flag(void) { - printf("main_lcore_flag not supported on Windows, skipping test\n"); + printf("main_lcore_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_invalid_n_flag(void) { - printf("invalid_n_flag not supported on Windows, skipping test\n"); + printf("invalid_n_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_no_hpet_flag(void) { - printf("no_hpet_flag not supported on Windows, skipping test\n"); + printf("no_hpet_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_no_huge_flag(void) { - printf("no_huge_flag not supported on Windows, skipping test\n"); + printf("no_huge_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_allow_flag(void) { - printf("allow_flag not supported on Windows, skipping test\n"); + printf("allow_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_invalid_b_flag(void) { - printf("invalid_b_flag not supported on Windows, skipping test\n"); + printf("invalid_b_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_invalid_vdev_flag(void) { - printf("invalid_vdev_flag not supported on Windows, skipping test\n"); + printf("invalid_vdev_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_invalid_r_flag(void) { - printf("invalid_r_flag not supported on Windows, skipping test\n"); + printf("invalid_r_flag only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_memory_flags(void) { - printf("memory_flags not supported on Windows, skipping test\n"); + printf("memory_flags only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_file_prefix(void) { - printf("file_prefix not supported on Windows, skipping test\n"); + printf("file_prefix only supported on Linux, skipping test\n"); return TEST_SKIPPED; } static int test_misc_flags(void) { - printf("misc_flags not supported on Windows, skipping test\n"); + printf("misc_flags only supported on Linux, skipping test\n"); return TEST_SKIPPED; } @@ -121,6 +121,7 @@ #define no_shconf "--no-shconf" #define allow "--allow" #define vdev "--vdev" +#define no_pci "--no-pci" #define memtest "memtest" #define memtest1 "memtest1" #define memtest2 "memtest2" @@ -445,17 +446,17 @@ /* Test with invalid vdev option */ const char *vdevinval[] = {prgname, prefix, no_huge, - vdev, "eth_dummy"}; + no_pci, vdev, "eth_dummy"}; /* Test with valid vdev option */ const char *vdevval1[] = {prgname, prefix, no_huge, - vdev, "net_ring0"}; + no_pci, vdev, "net_ring0"}; const char *vdevval2[] = {prgname, prefix, no_huge, - vdev, "net_ring0,args=test"}; + no_pci, vdev, "net_ring0,args=test"}; const char *vdevval3[] = {prgname, prefix, no_huge, - vdev, "net_ring0,nodeaction=r1:0:CREATE"}; + no_pci, vdev, "net_ring0,nodeaction=r1:0:CREATE"}; if (launch_proc(vdevinval) == 0) { printf("Error - process did run ok with invalid " @@ -992,24 +993,24 @@ const char *argv5[] = {prgname, prefix, mp_flag, "--syslog=invalid"}; /* With no-sh-conf, also use no-huge to ensure this test runs on BSD */ - const char *argv6[] = {prgname, "-m", DEFAULT_MEM_SIZE, + const char *argv6[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, no_shconf, nosh_prefix, no_huge}; /* With --huge-dir */ const char *argv7[] = {prgname, "-m", DEFAULT_MEM_SIZE, - "--file-prefix=hugedir", "--huge-dir", hugepath}; + no_pci, "--file-prefix=hugedir", "--huge-dir", hugepath}; /* With empty --huge-dir (should fail) */ const char *argv8[] = {prgname, "-m", DEFAULT_MEM_SIZE, - "--file-prefix=hugedir", "--huge-dir"}; + no_pci, "--file-prefix=hugedir", "--huge-dir"}; /* With invalid --huge-dir */ const char *argv9[] = {prgname, "-m", DEFAULT_MEM_SIZE, - "--file-prefix=hugedir", "--huge-dir", "invalid"}; + no_pci, "--file-prefix=hugedir", "--huge-dir", "invalid"}; /* With invalid --huge-dir sub-directory */ const char *argv10[] = {prgname, "-m", DEFAULT_MEM_SIZE, - "--file-prefix=hugedir", "--huge-dir", hugepath_dir}; + no_pci, "--file-prefix=hugedir", "--huge-dir", hugepath_dir}; /* With valid --huge-dir sub-directory */ const char *argv11[] = {prgname, "-m", DEFAULT_MEM_SIZE, - "--file-prefix=hugedir", "--huge-dir", hugepath_dir2}; + no_pci, "--file-prefix=hugedir", "--huge-dir", hugepath_dir2}; /* Secondary process with invalid --huge-dir (should run as flag has no * effect on secondary processes) */ const char *argv12[] = {prgname, prefix, mp_flag, @@ -1017,35 +1018,35 @@ /* try running with base-virtaddr param */ const char *argv13[] = {prgname, "--file-prefix=virtaddr", - "--base-virtaddr=0x23456789"}; + no_pci, "--base-virtaddr=0x23456789"}; /* try running with --vfio-intr INTx flag */ const char *argv14[] = {prgname, "--file-prefix=intr", - "--vfio-intr=legacy"}; + no_pci, "--vfio-intr=legacy"}; /* try running with --vfio-intr MSI flag */ const char *argv15[] = {prgname, "--file-prefix=intr", - "--vfio-intr=msi"}; + no_pci, "--vfio-intr=msi"}; /* try running with --vfio-intr MSI-X flag */ const char *argv16[] = {prgname, "--file-prefix=intr", - "--vfio-intr=msix"}; + no_pci, "--vfio-intr=msix"}; /* try running with --vfio-intr invalid flag */ const char *argv17[] = {prgname, "--file-prefix=intr", - "--vfio-intr=invalid"}; + no_pci, "--vfio-intr=invalid"}; /* With process type as auto-detect */ const char * const argv18[] = {prgname, "--file-prefix=auto", - "--proc-type=auto"}; + no_pci, "--proc-type=auto"}; /* With process type as auto-detect with no-shconf */ const char * const argv19[] = {prgname, "--proc-type=auto", - no_shconf, nosh_prefix, no_huge}; + no_pci, no_shconf, nosh_prefix, no_huge}; /* With process type as --create-uio-dev flag */ const char * const argv20[] = {prgname, "--file-prefix=uiodev", - "--create-uio-dev"}; + no_pci, "--create-uio-dev"}; /* Try running with --huge-worker-stack flag */ const char * const argv21[] = {prgname, prefix, mp_flag, @@ -1255,43 +1256,43 @@ DEFAULT_MEM_SIZE, "--file-prefix=" memtest }; /* primary process with memtest1 and default mem mode */ - const char *argv1[] = {prgname, "-m", + const char *argv1[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--file-prefix=" memtest1 }; /* primary process with memtest1 and legacy mem mode */ - const char *argv2[] = {prgname, "-m", + const char *argv2[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--file-prefix=" memtest1, "--legacy-mem" }; /* primary process with memtest2 and legacy mem mode */ - const char *argv3[] = {prgname, "-m", + const char *argv3[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--file-prefix=" memtest2, "--legacy-mem" }; /* primary process with memtest2 and default mem mode */ - const char *argv4[] = {prgname, "-m", + const char *argv4[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--file-prefix=" memtest2 }; /* primary process with --in-memory mode */ - const char * const argv5[] = {prgname, "-m", + const char * const argv5[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--in-memory" }; /* primary process with memtest1 and --in-memory mode */ - const char * const argv6[] = {prgname, "-m", + const char * const argv6[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--in-memory", "--file-prefix=" memtest1 }; /* primary process with parent file-prefix and --in-memory mode */ - const char * const argv7[] = {prgname, "-m", + const char * const argv7[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--in-memory", "--file-prefix", prefix }; /* primary process with memtest1 and --single-file-segments mode */ - const char * const argv8[] = {prgname, "-m", + const char * const argv8[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--single-file-segments", "--file-prefix=" memtest1 }; /* primary process with memtest1 and --huge-unlink=never mode */ - const char * const argv9[] = {prgname, "-m", + const char * const argv9[] = {prgname, no_pci, "-m", DEFAULT_MEM_SIZE, "--huge-unlink=never", "--file-prefix=" memtest1 }; @@ -1542,41 +1543,41 @@ "-m", DEFAULT_MEM_SIZE}; /* valid -m flag */ - const char *argv1[] = {prgname, + const char *argv1[] = {prgname, no_pci, "--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE}; /* valid (zero) --socket-mem flag */ char arg2_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv2[] = {prgname, + const char *argv2[] = {prgname, no_pci, "--file-prefix=" memtest, arg2_socket_mem}; /* invalid (incomplete) --socket-mem flag */ char arg3_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv3[] = {prgname, + const char *argv3[] = {prgname, no_pci, "--file-prefix=" memtest, arg3_socket_mem}; /* invalid (mixed with invalid data) --socket-mem flag */ char arg4_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv4[] = {prgname, + const char *argv4[] = {prgname, no_pci, "--file-prefix=" memtest, arg4_socket_mem}; /* invalid (with numeric value as last character) --socket-mem flag */ char arg5_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv5[] = {prgname, + const char *argv5[] = {prgname, no_pci, "--file-prefix=" memtest, arg5_socket_mem}; /* invalid (with empty socket) --socket-mem flag */ char arg6_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv6[] = {prgname, + const char *argv6[] = {prgname, no_pci, "--file-prefix=" memtest, arg6_socket_mem}; /* invalid (null) --socket-mem flag */ - const char *argv7[] = {prgname, + const char *argv7[] = {prgname, no_pci, "--file-prefix=" memtest, "--socket-mem="}; /* valid --socket-mem specified together with -m flag */ char arg8_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv8[] = {prgname, + const char *argv8[] = {prgname, no_pci, "--file-prefix=" memtest, "-m", DEFAULT_MEM_SIZE, arg8_socket_mem}; @@ -1594,12 +1595,12 @@ /* invalid --socket-mem flag (with extra socket) */ char invalid_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv9[] = {prgname, + const char *argv9[] = {prgname, no_pci, "--file-prefix=" memtest, invalid_socket_mem}; /* valid --socket-mem flag */ char valid_socket_mem[SOCKET_MEM_STRLEN]; - const char *argv10[] = {prgname, + const char *argv10[] = {prgname, no_pci, "--file-prefix=" memtest, valid_socket_mem}; if (launch_proc(argv0) != 0) { diff -Nru dpdk-24.11.4/app/test/test_external_mem.c dpdk-24.11.8/app/test/test_external_mem.c --- dpdk-24.11.4/app/test/test_external_mem.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_external_mem.c 2026-10-14 13:10:05.000000000 +0000 @@ -10,11 +10,11 @@ #include #include -#ifdef RTE_EXEC_ENV_WINDOWS +#ifndef RTE_EXEC_ENV_LINUX static int test_external_mem(void) { - printf("external_mem not supported on Windows, skipping test\n"); + printf("external_mem only supported on Linux, skipping test\n"); return TEST_SKIPPED; } diff -Nru dpdk-24.11.4/app/test/test_fib6.c dpdk-24.11.8/app/test/test_fib6.c --- dpdk-24.11.4/app/test/test_fib6.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_fib6.c 2026-10-14 13:10:05.000000000 +0000 @@ -22,6 +22,7 @@ static int32_t test_add_del_invalid(void); static int32_t test_get_invalid(void); static int32_t test_lookup(void); +static int32_t test_drift(void); #define MAX_ROUTES (1 << 16) /** Maximum number of tbl8 for 2-byte entries */ @@ -387,6 +388,78 @@ return TEST_SUCCESS; } +/* + * Reproducer for the rsvd_tbl8s drift bug. depth_diff used to maintain + * rsvd_tbl8s is computed from the current RIB state, so it is not + * invariant between the ADD of a prefix and its later DEL when a + * covering parent prefix is removed in between. + * + * Layout: one /28 parent (fcde::/28) and three /48 siblings under it + * (fcde:0:6000::/48, fcde:1:6000::/48, fcde:2:6000::/48). The second + * hextet's high 12 bits are zero, so the three /48 IPs all fall inside + * the /28. + * + * One asymmetric sequence is enough to wrap the counter: + * ADD /28 rsvd_tbl8s += 1 + * ADD /48 child_0,1,2 (with /28 parent) rsvd_tbl8s += 2 each (+6) + * DEL /28 (sibling /48 found) rsvd_tbl8s -= 0 + * DEL /48 child_0,1,2 (no parent left) rsvd_tbl8s -= 3 each (-9) + */ +static int32_t +test_drift(void) +{ + struct rte_fib6_conf config = { 0 }; + struct rte_fib6 *fib; + struct rte_ipv6_addr parent = + RTE_IPV6(0xfcde, 0, 0, 0, 0, 0, 0, 0); + struct rte_ipv6_addr child[3] = { + RTE_IPV6(0xfcde, 0, 0x6000, 0, 0, 0, 0, 0), + RTE_IPV6(0xfcde, 1, 0x6000, 0, 0, 0, 0, 0), + RTE_IPV6(0xfcde, 2, 0x6000, 0, 0, 0, 0, 0), + }; + unsigned int c; + int ret; + + config.max_routes = 1024; + config.rib_ext_sz = 0; + config.default_nh = 0; + config.type = RTE_FIB6_TRIE; + config.trie.nh_sz = RTE_FIB6_TRIE_2B; + config.trie.num_tbl8 = 256; + + fib = rte_fib6_create(__func__, SOCKET_ID_ANY, &config); + RTE_TEST_ASSERT(fib != NULL, "Failed to create FIB\n"); + + ret = rte_fib6_add(fib, &parent, 28, 0xa); + RTE_TEST_ASSERT(ret == 0, "ADD /28 failed (ret=%d)\n", ret); + + for (c = 0; c < 3; c++) { + ret = rte_fib6_add(fib, &child[c], 48, 0xb + c); + RTE_TEST_ASSERT(ret == 0, + "ADD /48 child %u failed (ret=%d)\n", c, ret); + } + + ret = rte_fib6_delete(fib, &parent, 28); + RTE_TEST_ASSERT(ret == 0, "DEL /28 failed (ret=%d)\n", ret); + + for (c = 0; c < 3; c++) { + ret = rte_fib6_delete(fib, &child[c], 48); + RTE_TEST_ASSERT(ret == 0, + "DEL /48 child %u failed (ret=%d)\n", c, ret); + } + + /* Pre-fix: -ENOSPC. Post-fix: succeeds. */ + ret = rte_fib6_add(fib, &parent, 28, 0xe); + RTE_TEST_ASSERT(ret == 0, + "Fresh ADD /28 spuriously failed (ret=%d)\n", ret); + + ret = rte_fib6_delete(fib, &parent, 28); + RTE_TEST_ASSERT(ret == 0, "Final DEL /28 failed (ret=%d)\n", ret); + + rte_fib6_free(fib); + return TEST_SUCCESS; +} + static struct unit_test_suite fib6_fast_tests = { .suite_name = "fib6 autotest", .setup = NULL, @@ -397,6 +470,7 @@ TEST_CASE(test_add_del_invalid), TEST_CASE(test_get_invalid), TEST_CASE(test_lookup), + TEST_CASE(test_drift), TEST_CASES_END() } }; diff -Nru dpdk-24.11.4/app/test/test_hash.c dpdk-24.11.8/app/test/test_hash.c --- dpdk-24.11.4/app/test/test_hash.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_hash.c 2026-10-14 13:10:05.000000000 +0000 @@ -2319,6 +2319,137 @@ return 0; } +static void *old_data; + +static void +test_hash_free_key_data_func(void *p __rte_unused, void *key_data) +{ + old_data = key_data; +} + +/* + * Test automatic RCU free on overwrite via rte_hash_add_key_data. + * - Create hash with RW_CONCURRENCY_LF and RCU QSBR in DQ mode + * with a free_key_data_func callback that increments a counter. + * - Register a pseudo reader thread. + * - Add key with data (void *)1. + * - Overwrite same key with data (void *)2 via rte_hash_add_key_data. + * - Report quiescent state, trigger reclamation. + * - Verify the free callback was called exactly once. + * - Delete the key, report quiescent state, reclaim again. + * - Verify the free callback was called a second time. + */ +static int +test_hash_rcu_qsbr_replace_auto_free(void) +{ + struct rte_hash_rcu_config rcu = { + .v = NULL, + .mode = RTE_HASH_QSBR_MODE_DQ, + .free_key_data_func = test_hash_free_key_data_func, + .key_data_ptr = NULL, + }; + struct rte_hash_parameters params = { + .name = "test_replace_auto_free", + .entries = 16, + .key_len = sizeof(uint32_t), + .hash_func = NULL, + .hash_func_init_val = 0, + .socket_id = SOCKET_ID_ANY, + .extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF, + }; + struct rte_hash *hash = NULL; + uint32_t key = 55; + int32_t status; + int ret = -1; + size_t sz; + + printf("\n# Running RCU replace auto-free test\n"); + + hash = rte_hash_create(¶ms); + if (hash == NULL) { + printf("hash creation failed\n"); + goto end; + } + + sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE); + rcu.v = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE); + if (rcu.v == NULL) { + printf("RCU QSBR alloc failed\n"); + goto end; + } + status = rte_rcu_qsbr_init(rcu.v, RTE_MAX_LCORE); + if (status != 0) { + printf("RCU QSBR init failed\n"); + goto end; + } + + status = rte_hash_rcu_qsbr_add(hash, &rcu); + if (status != 0) { + printf("RCU QSBR add failed\n"); + goto end; + } + + /* Register pseudo reader */ + status = rte_rcu_qsbr_thread_register(rcu.v, 0); + if (status != 0) { + printf("RCU QSBR thread register failed\n"); + goto end; + } + rte_rcu_qsbr_thread_online(rcu.v, 0); + + old_data = NULL; + + /* Add key with data = (void *)1 */ + status = rte_hash_add_key_data(hash, &key, (void *)(uintptr_t)1); + if (status != 0) { + printf("failed to add key (status=%d)\n", status); + goto end; + } + + /* Overwrite same key with data = (void *)2 */ + status = rte_hash_add_key_data(hash, &key, (void *)(uintptr_t)2); + if (status != 0) { + printf("failed to overwrite key (status=%d)\n", status); + goto end; + } + + /* Reader quiescent and reclaim */ + rte_rcu_qsbr_quiescent(rcu.v, 0); + rte_hash_rcu_qsbr_dq_reclaim(hash, NULL, NULL, NULL); + + if (old_data != (void *)(uintptr_t)1) { + printf("old data should be 0x1 but is %p\n", old_data); + goto end; + } + + /* Delete the key */ + status = rte_hash_del_key(hash, &key); + if (status < 0) { + printf("failed to delete key (status=%d)\n", status); + goto end; + } + + /* Reader quiescent and reclaim again */ + rte_rcu_qsbr_quiescent(rcu.v, 0); + rte_hash_rcu_qsbr_dq_reclaim(hash, NULL, NULL, NULL); + + if (old_data != (void *)(uintptr_t)2) { + printf("old data should be 2 but is %p\n", old_data); + goto end; + } + + ret = 0; +end: + if (rcu.v != NULL) { + rte_rcu_qsbr_thread_offline(rcu.v, 0); + rte_rcu_qsbr_thread_unregister(rcu.v, 0); + } + rte_hash_free(hash); + rte_free(rcu.v); + + return ret; +} + /* * Do all unit and performance tests. */ @@ -2400,6 +2531,9 @@ if (test_hash_rcu_qsbr_dq_reclaim() < 0) return -1; + if (test_hash_rcu_qsbr_replace_auto_free() < 0) + return -1; + return 0; } diff -Nru dpdk-24.11.4/app/test/test_interrupts.c dpdk-24.11.8/app/test/test_interrupts.c --- dpdk-24.11.4/app/test/test_interrupts.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_interrupts.c 2026-10-14 13:10:05.000000000 +0000 @@ -429,7 +429,7 @@ int ret = -1; struct rte_intr_handle *test_intr_handle; - if (RTE_EXEC_ENV_IS_WINDOWS) + if (RTE_EXEC_ENV_IS_WINDOWS || RTE_EXEC_ENV_IS_FREEBSD) return TEST_SKIPPED; if (test_interrupt_init() < 0) { diff -Nru dpdk-24.11.4/app/test/test_mbuf.c dpdk-24.11.8/app/test/test_mbuf.c --- dpdk-24.11.4/app/test/test_mbuf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_mbuf.c 2026-10-14 13:10:05.000000000 +0000 @@ -541,6 +541,26 @@ rte_pktmbuf_free(copy2); + /* test offset copy at the end */ + copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool, + 2 * sizeof(uint32_t), UINT32_MAX); + if (copy2 == NULL) + GOTO_FAIL("cannot copy at the end of the copy\n"); + + if (rte_pktmbuf_pkt_len(copy2) != 0) + GOTO_FAIL("copy at the end, length incorrect\n"); + + if (rte_pktmbuf_data_len(copy2) != 0) + GOTO_FAIL("copy at the end, data length incorrect\n"); + + rte_pktmbuf_free(copy2); + + /* test offset copy past the end */ + copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool, + 2 * sizeof(uint32_t) + 1, UINT32_MAX); + if (copy2 != NULL) + GOTO_FAIL("can copy past the end of the copy\n"); + /* test truncation copy */ copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool, 0, sizeof(uint32_t)); @@ -2017,13 +2037,13 @@ /* read length greater than mbuf data_len */ if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1, NULL) != NULL) - GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n", + GOTO_FAIL("%s: Requested offset + len is larger than mbuf data len!\n", __func__); /* read length greater than mbuf pkt_len */ if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1, NULL) != NULL) - GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n", + GOTO_FAIL("%s: Requested offset + len is larger than mbuf pkt len!\n", __func__); /* read data of zero len from valid offset */ @@ -2045,21 +2065,21 @@ /* read data of max length from valid offset */ data_copy = rte_pktmbuf_read(m, hdr_len, UINT_MAX, NULL); - if (data_copy == NULL) - GOTO_FAIL("%s: Error in reading packet data!\n", __func__); - /* check if the received address is the beginning of data segment */ - if (data_copy != data) - GOTO_FAIL("%s: Corrupted data address!\n", __func__); + if (data_copy != NULL) + GOTO_FAIL("%s: Requested offset + max len is larger than mbuf pkt len!\n", + __func__); /* try to read from mbuf with max size offset */ data_copy = rte_pktmbuf_read(m, UINT_MAX, 0, NULL); if (data_copy != NULL) - GOTO_FAIL("%s: Error in reading packet data!\n", __func__); + GOTO_FAIL("%s: Requested max offset is larger than mbuf pkt len!\n", + __func__); /* try to read from mbuf with max size offset and len */ data_copy = rte_pktmbuf_read(m, UINT_MAX, UINT_MAX, NULL); if (data_copy != NULL) - GOTO_FAIL("%s: Error in reading packet data!\n", __func__); + GOTO_FAIL("%s: Requested max offset + max len is larger than mbuf pkt len!\n", + __func__); rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m)); diff -Nru dpdk-24.11.4/app/test/test_mcslock.c dpdk-24.11.8/app/test/test_mcslock.c --- dpdk-24.11.4/app/test/test_mcslock.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_mcslock.c 2026-10-14 13:10:05.000000000 +0000 @@ -42,6 +42,10 @@ static unsigned int count; +#define MAX_LOOP_BASE 1000000u +#define MAX_LOOP_MIN 10000u +static unsigned int max_loop; + static RTE_ATOMIC(uint32_t) synchro; static int @@ -60,8 +64,6 @@ static uint64_t time_count[RTE_MAX_LCORE] = {0}; -#define MAX_LOOP 1000000 - static int load_loop_fn(void *func_param) { @@ -78,7 +80,7 @@ rte_wait_until_equal_32((uint32_t *)(uintptr_t)&synchro, 1, rte_memory_order_relaxed); begin = rte_get_timer_cycles(); - while (lcount < MAX_LOOP) { + while (lcount < max_loop) { if (use_lock) rte_mcslock_lock(&p_ml_perf, &ml_perf_me); @@ -175,6 +177,8 @@ rte_mcslock_t ml_me; rte_mcslock_t ml_try_me; + max_loop = test_scale_iterations(MAX_LOOP_BASE, MAX_LOOP_MIN); + /* * Test mcs lock & unlock on each core */ diff -Nru dpdk-24.11.4/app/test/test_memcpy.c dpdk-24.11.8/app/test/test_memcpy.c --- dpdk-24.11.4/app/test/test_memcpy.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_memcpy.c 2026-10-14 13:10:05.000000000 +0000 @@ -36,6 +36,16 @@ /* Data is aligned on this many bytes (power of 2) */ #define ALIGNMENT_UNIT 32 +/* + * Subset of offsets to test. These values cover the structurally + * interesting alignment cases for SSE/AVX copy paths: + * aligned (0), off-by-one (1), partial vector (7, 15, 17), + * vector boundaries (16, 31). Testing all 1024 src x dst + * combinations of offsets 0..31 is unnecessary since many + * map to the same code paths, and causes the test to timeout + * on slow (e.g. emulated 32-bit) build environments. + */ +static const unsigned int test_offsets[] = {0, 1, 7, 15, 16, 17, 31}; /* * Create two buffers, and initialise one with random values. These are copied @@ -103,13 +113,15 @@ func_test(void) { unsigned int off_src, off_dst, i; + unsigned int n_offsets = RTE_DIM(test_offsets); int ret; - for (off_src = 0; off_src < ALIGNMENT_UNIT; off_src++) { - for (off_dst = 0; off_dst < ALIGNMENT_UNIT; off_dst++) { + for (off_src = 0; off_src < n_offsets; off_src++) { + for (off_dst = 0; off_dst < n_offsets; off_dst++) { for (i = 0; i < RTE_DIM(buf_sizes); i++) { - ret = test_single_memcpy(off_src, off_dst, - buf_sizes[i]); + ret = test_single_memcpy(test_offsets[off_src], + test_offsets[off_dst], + buf_sizes[i]); if (ret != 0) return -1; } diff -Nru dpdk-24.11.4/app/test/test_mp_secondary.c dpdk-24.11.8/app/test/test_mp_secondary.c --- dpdk-24.11.4/app/test/test_mp_secondary.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_mp_secondary.c 2026-10-14 13:10:05.000000000 +0000 @@ -15,11 +15,11 @@ #include #include -#ifdef RTE_EXEC_ENV_WINDOWS +#ifndef RTE_EXEC_ENV_LINUX int test_mp_secondary(void) { - printf("mp_secondary not supported on Windows, skipping test\n"); + printf("Multiprocess support only present on Linux, skipping test\n"); return TEST_SKIPPED; } #else diff -Nru dpdk-24.11.4/app/test/test_pcapng.c dpdk-24.11.8/app/test/test_pcapng.c --- dpdk-24.11.4/app/test/test_pcapng.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_pcapng.c 2026-10-14 13:10:05.000000000 +0000 @@ -4,7 +4,16 @@ #include #include +#include + +#ifdef RTE_EXEC_ENV_WINDOWS +#include +#include +#include +#include +#else #include +#endif #include #include @@ -23,6 +32,52 @@ #include "test.h" +#ifdef RTE_EXEC_ENV_WINDOWS +static uint64_t +current_timestamp(void) +{ + FILETIME ft; + ULARGE_INTEGER ul; + + GetSystemTimeAsFileTime(&ft); + ul.LowPart = ft.dwLowDateTime; + ul.HighPart = ft.dwHighDateTime; + /* FILETIME is 100ns intervals since 1601-01-01, convert to ns since Unix epoch */ + return (ul.QuadPart - 116444736000000000ULL) * 100; +} + +/* + * Create temporary file with suffix for Windows. + * Returns file descriptor or -1 on failure. + */ +static int +mkstemps(char *tmpl, int suffixlen) +{ + char temp_dir[MAX_PATH]; + char temp_file[MAX_PATH]; + DWORD ret; + + ret = GetTempPathA(sizeof(temp_dir), temp_dir); + if (ret == 0 || ret > sizeof(temp_dir)) + return -1; + + if (GetTempFileNameA(temp_dir, "pcap", 0, temp_file) == 0) + return -1; + + /* + * GetTempFileNameA with uUnique=0 creates the file to reserve the name. + * Remove it since we open a different name with the original suffix appended. + */ + DeleteFileA(temp_file); + + /* Append the original suffix (e.g. ".pcapng") to the temp file */ + strlcat(temp_file, tmpl + strlen(tmpl) - suffixlen, sizeof(temp_file)); + strlcpy(tmpl, temp_file, PATH_MAX); + + return _open(tmpl, _O_RDWR | _O_BINARY | _O_CREAT | _O_EXCL, 0666); +} +#endif /* RTE_EXEC_ENV_WINDOWS */ + #define PCAPNG_TEST_DEBUG 0 #define TOTAL_PACKETS 4096 @@ -273,6 +328,7 @@ pcap_breakloop(ctx->pcap); } +#ifndef RTE_EXEC_ENV_WINDOWS static uint64_t current_timestamp(void) { @@ -281,6 +337,7 @@ clock_gettime(CLOCK_REALTIME, &ts); return rte_timespec_to_ns(&ts); } +#endif /* * Open the resulting pcapng file with libpcap @@ -324,7 +381,7 @@ static int test_add_interface(void) { - char file_name[] = "/tmp/pcapng_test_XXXXXX.pcapng"; + char file_name[PATH_MAX] = "/tmp/pcapng_test_XXXXXX.pcapng"; static rte_pcapng_t *pcapng; int ret, tmp_fd; uint64_t now = current_timestamp(); @@ -373,7 +430,7 @@ ret = valid_pcapng_file(file_name, now, 0); /* if test fails want to investigate the file */ if (ret == 0) - unlink(file_name); + remove(file_name); return ret; @@ -385,7 +442,7 @@ static int test_write_packets(void) { - char file_name[] = "/tmp/pcapng_test_XXXXXX.pcapng"; + char file_name[PATH_MAX] = "/tmp/pcapng_test_XXXXXX.pcapng"; static rte_pcapng_t *pcapng; int ret, tmp_fd, count; uint64_t now = current_timestamp(); @@ -430,7 +487,7 @@ ret = valid_pcapng_file(file_name, now, count); /* if test fails want to investigate the file */ if (ret == 0) - unlink(file_name); + remove(file_name); return ret; diff -Nru dpdk-24.11.4/app/test/test_pdump.c dpdk-24.11.8/app/test/test_pdump.c --- dpdk-24.11.4/app/test/test_pdump.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_pdump.c 2026-10-14 13:10:05.000000000 +0000 @@ -204,6 +204,10 @@ test_pdump(void) { int ret = 0; + + if (RTE_EXEC_ENV_IS_FREEBSD) + return TEST_SKIPPED; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { printf("IN PRIMARY PROCESS\n"); ret = run_pdump_server_tests(); diff -Nru dpdk-24.11.4/app/test/test_security_inline_proto.c dpdk-24.11.8/app/test/test_security_inline_proto.c --- dpdk-24.11.4/app/test/test_security_inline_proto.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_security_inline_proto.c 2026-10-14 13:10:05.000000000 +0000 @@ -38,6 +38,7 @@ #else +#include #include #include #include @@ -94,8 +95,7 @@ }, .txmode = { .mq_mode = RTE_ETH_MQ_TX_NONE, - .offloads = RTE_ETH_TX_OFFLOAD_SECURITY | - RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE, + .offloads = RTE_ETH_TX_OFFLOAD_SECURITY, }, .lpbk_mode = 1, /* enable loopback */ }; @@ -1266,7 +1266,6 @@ printf("Event descriptor not set\n"); return -1; } - vector->notify_event = true; if (event_desc->metadata != (uint64_t)vector->sa_data) { printf("Mismatch in event specific metadata\n"); return -1; @@ -1289,6 +1288,10 @@ return -1; } + /* Ensure event subtype is visible before signaling notify_event. */ + rte_io_wmb(); + vector->notify_event = true; + return 0; } @@ -1435,6 +1438,16 @@ break; } while (j++ < 5 || nb_rx == 0); + /* Wait for soft expiry event from the err-ring poll thread. */ + if ((flags->sa_expiry_pkts_soft || flags->sa_expiry_bytes_soft) && + td->ipsec_xform.direction == RTE_SECURITY_IPSEC_SA_DIR_EGRESS) { + j = 0; + while (!vector.notify_event && j++ < 100) { + rte_delay_us(1000); + rte_io_rmb(); + } + } + if (!flags->sa_expiry_pkts_hard && !flags->sa_expiry_bytes_hard && (nb_rx != nb_sent)) { @@ -1498,10 +1511,13 @@ destroy_default_flow(port_id); if (flags->sa_expiry_pkts_soft || flags->sa_expiry_bytes_soft || flags->sa_expiry_pkts_hard || flags->sa_expiry_bytes_hard) { - if (vector.notify_event && (vector.event == event)) - ret = TEST_SUCCESS; - else + if (vector.notify_event) { + rte_io_rmb(); + ret = (vector.event == event) ? + TEST_SUCCESS : TEST_FAILED; + } else { ret = TEST_FAILED; + } rte_eth_dev_callback_unregister(port_id, RTE_ETH_EVENT_IPSEC, test_ipsec_inline_sa_exp_event_callback, &vector); @@ -1996,10 +2012,36 @@ } memcpy(&local_port_conf, &port_conf, sizeof(port_conf)); + local_port_conf.rxmode.offloads &= dev_info.rx_offload_capa; + local_port_conf.txmode.offloads &= dev_info.tx_offload_capa; + + if (!(local_port_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SECURITY) || + !(local_port_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_SECURITY)) { + printf("Inline IPsec unsupported: required security offloads are missing\n"); + return TEST_SKIPPED; + } + /* Add Multi seg flags */ if (sg_mode) { - uint16_t max_data_room = RTE_MBUF_DEFAULT_DATAROOM * - dev_info.rx_desc_lim.nb_seg_max; + uint32_t max_data_room; + + if (!(dev_info.rx_offload_capa & RTE_ETH_RX_OFFLOAD_SCATTER) || + !(dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MULTI_SEGS)) { + printf("SG mode unsupported: required scatter or multi-seg offloads are missing\n"); + return TEST_SKIPPED; + } + + if (dev_info.rx_desc_lim.nb_seg_max == 0) { + printf("SG mode unsupported: invalid max Rx segments (0)\n"); + return TEST_SKIPPED; + } + + max_data_room = RTE_MBUF_DEFAULT_DATAROOM * dev_info.rx_desc_lim.nb_seg_max; + if (max_data_room <= 256) { + printf("SG mode unsupported: max data room (%u) too small\n", + max_data_room); + return TEST_SKIPPED; + } local_port_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_SCATTER; local_port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS; @@ -2054,6 +2096,25 @@ plaintext_len = 0; } + /* Check that at least one inline IPsec capability is registered */ + void *sec_ctx = rte_eth_dev_get_sec_ctx(port_id); + const struct rte_security_capability *cap; + + if (sec_ctx == NULL) { + printf("No security context on port %d\n", port_id); + return TEST_SKIPPED; + } + for (cap = rte_security_capabilities_get(sec_ctx); + cap != NULL && cap->action != RTE_SECURITY_ACTION_TYPE_NONE; cap++) { + if (cap->action == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL && + cap->protocol == RTE_SECURITY_PROTOCOL_IPSEC) + break; + } + if (cap == NULL || cap->action == RTE_SECURITY_ACTION_TYPE_NONE) { + printf("No inline IPsec capabilities registered\n"); + return TEST_SKIPPED; + } + return 0; } @@ -2082,6 +2143,8 @@ struct rte_event_dev_config eventdev_conf = {0}; struct rte_event_queue_conf eventq_conf = {0}; struct rte_event_port_conf ev_port_conf = {0}; + struct rte_eth_conf local_port_conf; + struct rte_eth_dev_info dev_info; const uint16_t nb_txd = 1024, nb_rxd = 1024; uint16_t nb_rx_queue = 1, nb_tx_queue = 1; uint8_t ev_queue_id = 0, tx_queue_id = 0; @@ -2093,13 +2156,20 @@ printf("Start event inline IPsec test.\n"); + if (rte_event_dev_count() == 0) { + printf("Event inline IPsec unsupported: no event devices available\n"); + return TEST_SKIPPED; + } + nb_ports = rte_eth_dev_count_avail(); if (nb_ports == 0) { printf("Test require: 1 port, available: 0\n"); return TEST_SKIPPED; } - init_mempools(NB_MBUF); + ret = init_mempools(NB_MBUF); + if (ret != 0) + return ret; if (tx_pkts_burst == NULL) { tx_pkts_burst = (struct rte_mbuf **)rte_calloc("tx_buff", @@ -2122,9 +2192,23 @@ /* configuring port 0 for the test is enough */ port_id = 0; + if (rte_eth_dev_info_get(port_id, &dev_info)) { + printf("Failed to get devinfo"); + return -1; + } + + memcpy(&local_port_conf, &port_conf, sizeof(port_conf)); + local_port_conf.rxmode.offloads &= dev_info.rx_offload_capa; + local_port_conf.txmode.offloads &= dev_info.tx_offload_capa; + if ((local_port_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_SECURITY) == 0 || + (local_port_conf.txmode.offloads & RTE_ETH_TX_OFFLOAD_SECURITY) == 0) { + printf("Event inline IPsec unsupported: required security offloads are missing\n"); + return TEST_SKIPPED; + } + /* port configure */ ret = rte_eth_dev_configure(port_id, nb_rx_queue, - nb_tx_queue, &port_conf); + nb_tx_queue, &local_port_conf); if (ret < 0) { printf("Cannot configure device: err=%d, port=%d\n", ret, port_id); diff -Nru dpdk-24.11.4/app/test/test_stack.c dpdk-24.11.8/app/test/test_stack.c --- dpdk-24.11.4/app/test/test_stack.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_stack.c 2026-10-14 13:10:05.000000000 +0000 @@ -268,10 +268,12 @@ return 0; } -#define NUM_ITERS_PER_THREAD 100000 +#define NUM_ITERS_BASE 100000u +#define NUM_ITERS_MIN 1000u struct test_args { struct rte_stack *s; + unsigned int num_iters; }; static struct test_args thread_test_args; @@ -280,9 +282,9 @@ stack_thread_push_pop(__rte_unused void *args) { void *obj_table[MAX_BULK]; - int i; + unsigned int i; - for (i = 0; i < NUM_ITERS_PER_THREAD; i++) { + for (i = 0; i < thread_test_args.num_iters; i++) { unsigned int num; num = rte_rand() % MAX_BULK; @@ -308,12 +310,14 @@ { unsigned int lcore_id; struct rte_stack *s; + unsigned int iterations; int result = 0; if (rte_lcore_count() < 2) { printf("Not enough cores for test_stack_multithreaded, expecting at least 2\n"); return TEST_SKIPPED; } + iterations = test_scale_iterations(NUM_ITERS_BASE, NUM_ITERS_MIN); printf("[%s():%u] Running with %u lcores\n", __func__, __LINE__, rte_lcore_count()); @@ -325,6 +329,7 @@ return -1; } + thread_test_args.num_iters = iterations; thread_test_args.s = s; if (rte_eal_mp_remote_launch(stack_thread_push_pop, NULL, CALL_MAIN)) diff -Nru dpdk-24.11.4/app/test/test_table_acl.c dpdk-24.11.8/app/test/test_table_acl.c --- dpdk-24.11.4/app/test/test_table_acl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_table_acl.c 2026-10-14 13:10:05.000000000 +0000 @@ -312,22 +312,6 @@ return 0; } -/* - * The format for these rules DO NOT need the port ranges to be - * separated by ' : ', just ':'. It's a lot more readable and - * cleaner, IMO. - */ -char lines[][128] = { - "@0.0.0.0/0 0.0.0.0/0 0:65535 0:65535 2/0xff", /* Protocol check */ - "@192.168.3.1/32 0.0.0.0/0 0:65535 0:65535 0/0", /* Src IP checl */ - "@0.0.0.0/0 10.4.4.1/32 0:65535 0:65535 0/0", /* dst IP check */ - "@0.0.0.0/0 0.0.0.0/0 105:105 0:65535 0/0", /* src port check */ - "@0.0.0.0/0 0.0.0.0/0 0:65535 206:206 0/0", /* dst port check */ -}; - -char line[128]; - - static int setup_acl_pipeline(void) { @@ -343,6 +327,20 @@ parse_5tuple parser; char acl_name[64]; + /* + * The format for these rules DO NOT need the port ranges to be + * separated by ' : ', just ':'. It's a lot more readable and + * cleaner, IMO. + */ + static const char * const lines[] = { + "@0.0.0.0/0 0.0.0.0/0 0:65535 0:65535 2/0xff", /* Protocol check */ + "@192.168.3.1/32 0.0.0.0/0 0:65535 0:65535 0/0", /* Src IP check */ + "@0.0.0.0/0 10.4.4.1/32 0:65535 0:65535 0/0", /* dst IP check */ + "@0.0.0.0/0 0.0.0.0/0 105:105 0:65535 0/0", /* src port check */ + "@0.0.0.0/0 0.0.0.0/0 0:65535 206:206 0/0", /* dst port check */ + }; + char line[LINE_MAX]; + /* Pipeline configuration */ p = rte_pipeline_create(&pipeline_params); if (p == NULL) { diff -Nru dpdk-24.11.4/app/test/test_telemetry_data.c dpdk-24.11.8/app/test/test_telemetry_data.c --- dpdk-24.11.4/app/test/test_telemetry_data.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_telemetry_data.c 2026-10-14 13:10:05.000000000 +0000 @@ -406,6 +406,26 @@ } static int +test_array_with_dict_values(void) +{ + rte_tel_data_start_array(&response_data, RTE_TEL_CONTAINER); + + struct rte_tel_data *d1 = rte_tel_data_alloc(); + rte_tel_data_start_dict(d1); + rte_tel_data_add_dict_string(d1, "name", "foo"); + rte_tel_data_add_dict_uint(d1, "size", 42); + rte_tel_data_add_array_container(&response_data, d1, 0); + + struct rte_tel_data *d2 = rte_tel_data_alloc(); + rte_tel_data_start_dict(d2); + rte_tel_data_add_dict_string(d2, "name", "bar"); + rte_tel_data_add_dict_uint(d2, "size", 666); + rte_tel_data_add_array_container(&response_data, d2, 0); + + return CHECK_OUTPUT("[{\"name\":\"foo\",\"size\":42},{\"name\":\"bar\",\"size\":666}]"); +} + +static int test_case_array_u64(void) { int i; @@ -597,6 +617,7 @@ test_array_with_array_string_values, test_array_with_array_uint_hex_values_padding, test_array_with_array_uint_hex_values_nopadding, + test_array_with_dict_values, test_string_char_escaping, test_array_char_escaping, test_dict_char_escaping, diff -Nru dpdk-24.11.4/app/test/test_threads.c dpdk-24.11.8/app/test/test_threads.c --- dpdk-24.11.4/app/test/test_threads.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_threads.c 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include #include "test.h" @@ -23,7 +24,7 @@ rte_atomic_store_explicit(&thread_id_ready, 1, rte_memory_order_release); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 1) - ; + rte_pause(); return 0; } @@ -39,7 +40,7 @@ "Failed to create thread."); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0, "Unexpected thread id."); @@ -63,7 +64,7 @@ &thread_main_id) == 0, "Failed to create thread."); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0, "Unexpected thread id."); @@ -87,7 +88,7 @@ "Failed to create thread"); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); priority = RTE_THREAD_PRIORITY_NORMAL; RTE_TEST_ASSERT(rte_thread_set_priority(thread_id, priority) == 0, @@ -139,7 +140,7 @@ "Failed to create thread"); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_get_affinity_by_id(thread_id, &cpuset0) == 0, "Failed to get thread affinity"); @@ -192,7 +193,7 @@ "Failed to create attributes affinity thread."); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_get_affinity_by_id(thread_id, &cpuset1) == 0, "Failed to get attributes thread affinity"); @@ -221,7 +222,7 @@ "Failed to create attributes priority thread."); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_get_priority(thread_id, &priority) == 0, "Failed to get thread priority"); @@ -245,7 +246,7 @@ "Failed to create thread."); while (rte_atomic_load_explicit(&thread_id_ready, rte_memory_order_acquire) == 0) - ; + rte_pause(); RTE_TEST_ASSERT(rte_thread_equal(thread_id, thread_main_id) != 0, "Unexpected thread id."); diff -Nru dpdk-24.11.4/app/test/test_timer_secondary.c dpdk-24.11.8/app/test/test_timer_secondary.c --- dpdk-24.11.4/app/test/test_timer_secondary.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test/test_timer_secondary.c 2026-10-14 13:10:05.000000000 +0000 @@ -12,22 +12,25 @@ #include #include #include +#include #include +#include #include "test.h" -#ifdef RTE_EXEC_ENV_WINDOWS +#ifndef RTE_EXEC_ENV_LINUX int test_timer_secondary(void) { - printf("timer_secondary not supported on Windows, skipping test\n"); + printf("timer_secondary only supported on Linux, skipping test\n"); return TEST_SKIPPED; } #else #include "process.h" -#define NUM_TIMERS (1 << 20) /* ~1M timers */ +#define NUM_TIMERS_MAX (1 << 20) /* ~1M timers */ +#define NUM_TIMERS_MIN (1 << 14) /* 16K minimum */ #define NUM_LCORES_NEEDED 3 #define TEST_INFO_MZ_NAME "test_timer_info_mz" #define MSECPERSEC 1E3 @@ -38,13 +41,14 @@ unsigned int main_lcore; unsigned int mgr_lcore; unsigned int sec_lcore; + unsigned int num_timers; uint32_t timer_data_id; - volatile int expected_count; - volatile int expired_count; + RTE_ATOMIC(unsigned int) expected_count; + RTE_ATOMIC(unsigned int) expired_count; struct rte_mempool *tim_mempool; - struct rte_timer *expired_timers[NUM_TIMERS]; + struct rte_timer *expired_timers[NUM_TIMERS_MAX]; int expired_timers_idx; - volatile int exit_flag; + RTE_ATOMIC(int) exit_flag; }; static int @@ -78,7 +82,8 @@ { struct test_info *test_info = tim->arg; - test_info->expired_count++; + rte_atomic_fetch_add_explicit(&test_info->expired_count, 1, + rte_memory_order_relaxed); test_info->expired_timers[test_info->expired_timers_idx++] = tim; } @@ -90,7 +95,8 @@ uint64_t prev_tsc = 0, cur_tsc, diff_tsc; struct test_info *test_info = arg; - while (!test_info->exit_flag) { + while (!rte_atomic_load_explicit(&test_info->exit_flag, + rte_memory_order_acquire)) { cur_tsc = rte_rdtsc(); diff_tsc = cur_tsc - prev_tsc; @@ -138,8 +144,10 @@ "test data"); test_info = mz->addr; + test_info->num_timers = test_scale_iterations(NUM_TIMERS_MAX, NUM_TIMERS_MIN); + test_info->tim_mempool = rte_mempool_create("test_timer_mp", - NUM_TIMERS, sizeof(struct rte_timer), 0, 0, + test_info->num_timers, sizeof(struct rte_timer), 0, 0, NULL, NULL, NULL, NULL, rte_socket_id(), 0); ret = rte_timer_data_alloc(&test_info->timer_data_id); @@ -160,32 +168,38 @@ TEST_ASSERT_SUCCESS(ret, "Failed to launch timer manage loop"); ret = timer_secondary_spawn_wait(*sec_lcorep); - TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed"); + /* must set exit flag even on error case, so check ret later */ rte_delay_ms(2000); + rte_atomic_store_explicit(&test_info->exit_flag, 1, + rte_memory_order_release); - test_info->exit_flag = 1; + TEST_ASSERT_SUCCESS(ret, "Secondary process execution failed"); rte_eal_wait_lcore(*mgr_lcorep); #ifdef RTE_LIBRTE_TIMER_DEBUG rte_timer_alt_dump_stats(test_info->timer_data_id, stdout); #endif - return test_info->expected_count == test_info->expired_count ? + return rte_atomic_load_explicit(&test_info->expected_count, + rte_memory_order_relaxed) == + rte_atomic_load_explicit(&test_info->expired_count, + rte_memory_order_relaxed) ? TEST_SUCCESS : TEST_FAILED; } else if (proc_type == RTE_PROC_SECONDARY) { uint64_t ticks, timeout_ms; struct rte_timer *tim; - int i; + unsigned int i; mz = rte_memzone_lookup(TEST_INFO_MZ_NAME); TEST_ASSERT_NOT_NULL(mz, "Couldn't lookup memzone for " "test info"); test_info = mz->addr; - for (i = 0; i < NUM_TIMERS; i++) { - rte_mempool_get(test_info->tim_mempool, (void **)&tim); + for (i = 0; i < test_info->num_timers; i++) { + ret = rte_mempool_get(test_info->tim_mempool, (void **)&tim); + TEST_ASSERT_SUCCESS(ret, "Couldn't get timer from mempool"); rte_timer_init(tim); @@ -200,7 +214,8 @@ if (ret < 0) return TEST_FAILED; - test_info->expected_count++; + rte_atomic_fetch_add_explicit(&test_info->expected_count, + 1, rte_memory_order_relaxed); /* randomly leave timer running or stop it */ if (rte_rand() & 1) @@ -209,7 +224,8 @@ ret = rte_timer_alt_stop(test_info->timer_data_id, tim); if (ret == 0) { - test_info->expected_count--; + rte_atomic_fetch_sub_explicit(&test_info->expected_count, + 1, rte_memory_order_relaxed); rte_mempool_put(test_info->tim_mempool, (void *)tim); } diff -Nru dpdk-24.11.4/app/test-bbdev/main.c dpdk-24.11.8/app/test-bbdev/main.c --- dpdk-24.11.4/app/test-bbdev/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-bbdev/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include "main.h" diff -Nru dpdk-24.11.4/app/test-bbdev/meson.build dpdk-24.11.8/app/test-bbdev/meson.build --- dpdk-24.11.4/app/test-bbdev/meson.build 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-bbdev/meson.build 2026-10-14 13:10:05.000000000 +0000 @@ -1,12 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation -if is_windows - build = false - reason = 'not supported on Windows' - subdir_done() -endif - sources = files( 'main.c', 'test_bbdev.c', diff -Nru dpdk-24.11.4/app/test-bbdev/test_bbdev.c dpdk-24.11.8/app/test-bbdev/test_bbdev.c --- dpdk-24.11.4/app/test-bbdev/test_bbdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-bbdev/test_bbdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -548,9 +548,9 @@ static int test_bbdev_op_type(void) { +#define OPS_COUNT 32 struct rte_mempool *mp_dec; - const unsigned int OPS_COUNT = 32; struct rte_bbdev_dec_op *dec_ops_arr[OPS_COUNT]; struct rte_bbdev_enc_op *enc_ops_arr[OPS_COUNT]; @@ -576,14 +576,15 @@ rte_mempool_free(mp_dec); return TEST_SUCCESS; +#undef OPS_COUNT } static int test_bbdev_op_pool_size(void) { +#define OPS_COUNT 128 struct rte_mempool *mp_none; - const unsigned int OPS_COUNT = 128; struct rte_bbdev_enc_op *ops_enc_arr[OPS_COUNT]; struct rte_bbdev_enc_op *ops_ext_arr[OPS_COUNT]; struct rte_bbdev_enc_op *ops_ext2_arr[OPS_COUNT]; @@ -627,6 +628,7 @@ rte_mempool_free(mp_none); return TEST_SUCCESS; +#undef OPS_COUNT } static int @@ -815,7 +817,7 @@ TEST_ASSERT(dev1->data->dev_id < RTE_BBDEV_MAX_DEVS, "Failed test rte_bbdev_allocate: " - "invalid dev_id %" PRIu8 ", max number of devices %d ", + "invalid dev_id %" PRIu16 ", max number of devices %d ", dev1->data->dev_id, RTE_BBDEV_MAX_DEVS); TEST_ASSERT(dev1->state == RTE_BBDEV_INITIALIZED, diff -Nru dpdk-24.11.4/app/test-bbdev/test_bbdev_perf.c dpdk-24.11.8/app/test-bbdev/test_bbdev_perf.c --- dpdk-24.11.4/app/test-bbdev/test_bbdev_perf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-bbdev/test_bbdev_perf.c 2026-10-14 13:10:05.000000000 +0000 @@ -1570,12 +1570,13 @@ static void gen_qm8_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) { - int qm = 8; - int qam = 256; +#define QM 8 +#define QAM 256 + int m, k; - double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; + double I, Q, p0, p1, llr_, b[QM], log_syml_prob[QAM]; /* 5.1.4 of TS38.211 */ - const double symbols_I[256] = { + const double symbols_I[QAM] = { 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, 1, 3, 3, 1, 1, 11, 11, 9, 9, 11, 11, 9, 9, 13, 13, 15, 15, 13, 13, @@ -1596,7 +1597,7 @@ -9, -9, -11, -11, -9, -9, -13, -13, -15, -15, -13, -13, -15, -15, -11, -11, -9, -9, -11, -11, -9, -9, -13, -13, -15, -15, -13, -13, -15, -15}; - const double symbols_Q[256] = { + const double symbols_Q[QAM] = { 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, 11, 9, 11, 9, 13, 15, 13, 15, 11, 9, 11, 9, 13, 15, 13, 15, 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, @@ -1619,8 +1620,8 @@ -13, -15, -11, -9, -11, -9, -13, -15, -13, -15}; /* Average constellation point energy */ N0 *= 170.0; - for (k = 0; k < qm; k++) - b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; + for (k = 0; k < QM; k++) + b[k] = llrs[QM * i + k] < 0 ? 1.0 : 0.0; /* 5.1.4 of TS38.211 */ I = (1 - 2 * b[0]) * (8 - (1 - 2 * b[2]) * (4 - (1 - 2 * b[4]) * (2 - (1 - 2 * b[6])))); @@ -1633,16 +1634,16 @@ * Calculate the log of the probability that each of * the constellation points was transmitted */ - for (m = 0; m < qam; m++) + for (m = 0; m < QAM; m++) log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) + pow(Q - symbols_Q[m], 2.0)) / N0; /* Calculate an LLR for each of the k_64QAM bits in the set */ - for (k = 0; k < qm; k++) { + for (k = 0; k < QM; k++) { p0 = -999999; p1 = -999999; /* For each constellation point */ - for (m = 0; m < qam; m++) { - if ((m >> (qm - k - 1)) & 1) + for (m = 0; m < QAM; m++) { + if ((m >> (QM - k - 1)) & 1) p1 = maxstar(p1, log_syml_prob[m]); else p0 = maxstar(p0, log_syml_prob[m]); @@ -1655,8 +1656,10 @@ llr_ = llr_max; if (llr_ < -llr_max) llr_ = -llr_max; - llrs[qm * i + k] = (int8_t) llr_; + llrs[QM * i + k] = (int8_t) llr_; } +#undef QM +#undef QAM } @@ -1667,18 +1670,19 @@ static void gen_qm6_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) { - int qm = 6; - int qam = 64; +#define QM 6 +#define QAM 64 + int m, k; - double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; + double I, Q, p0, p1, llr_, b[QM], log_syml_prob[QAM]; /* 5.1.4 of TS38.211 */ - const double symbols_I[64] = { + const double symbols_I[QAM] = { 3, 3, 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, -3, -3, -1, -1, -3, -3, -1, -1, -5, -5, -7, -7, -5, -5, -7, -7, -3, -3, -1, -1, -3, -3, -1, -1, -5, -5, -7, -7, -5, -5, -7, -7}; - const double symbols_Q[64] = { + const double symbols_Q[QAM] = { 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, -3, -1, -3, -1, -5, -7, -5, -7, -3, -1, -3, -1, -5, -7, -5, -7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, @@ -1686,8 +1690,8 @@ -3, -1, -3, -1, -5, -7, -5, -7}; /* Average constellation point energy */ N0 *= 42.0; - for (k = 0; k < qm; k++) - b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; + for (k = 0; k < QM; k++) + b[k] = llrs[QM * i + k] < 0 ? 1.0 : 0.0; /* 5.1.4 of TS38.211 */ I = (1 - 2 * b[0])*(4 - (1 - 2 * b[2]) * (2 - (1 - 2 * b[4]))); Q = (1 - 2 * b[1])*(4 - (1 - 2 * b[3]) * (2 - (1 - 2 * b[5]))); @@ -1698,16 +1702,16 @@ * Calculate the log of the probability that each of * the constellation points was transmitted */ - for (m = 0; m < qam; m++) + for (m = 0; m < QAM; m++) log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) + pow(Q - symbols_Q[m], 2.0)) / N0; /* Calculate an LLR for each of the k_64QAM bits in the set */ - for (k = 0; k < qm; k++) { + for (k = 0; k < QM; k++) { p0 = -999999; p1 = -999999; /* For each constellation point */ - for (m = 0; m < qam; m++) { - if ((m >> (qm - k - 1)) & 1) + for (m = 0; m < QAM; m++) { + if ((m >> (QM - k - 1)) & 1) p1 = maxstar(p1, log_syml_prob[m]); else p0 = maxstar(p0, log_syml_prob[m]); @@ -1720,8 +1724,10 @@ llr_ = llr_max; if (llr_ < -llr_max) llr_ = -llr_max; - llrs[qm * i + k] = (int8_t) llr_; + llrs[QM * i + k] = (int8_t) llr_; } +#undef QM +#undef QAM } /* @@ -1731,19 +1737,20 @@ static void gen_qm4_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) { - int qm = 4; - int qam = 16; +#define QM 4 +#define QAM 16 + int m, k; - double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; + double I, Q, p0, p1, llr_, b[QM], log_syml_prob[QAM]; /* 5.1.4 of TS38.211 */ - const double symbols_I[16] = {1, 1, 3, 3, 1, 1, 3, 3, + const double symbols_I[QAM] = {1, 1, 3, 3, 1, 1, 3, 3, -1, -1, -3, -3, -1, -1, -3, -3}; - const double symbols_Q[16] = {1, 3, 1, 3, -1, -3, -1, -3, + const double symbols_Q[QAM] = {1, 3, 1, 3, -1, -3, -1, -3, 1, 3, 1, 3, -1, -3, -1, -3}; /* Average constellation point energy */ N0 *= 10.0; - for (k = 0; k < qm; k++) - b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; + for (k = 0; k < QM; k++) + b[k] = llrs[QM * i + k] < 0 ? 1.0 : 0.0; /* 5.1.4 of TS38.211 */ I = (1 - 2 * b[0]) * (2 - (1 - 2 * b[2])); Q = (1 - 2 * b[1]) * (2 - (1 - 2 * b[3])); @@ -1754,16 +1761,16 @@ * Calculate the log of the probability that each of * the constellation points was transmitted */ - for (m = 0; m < qam; m++) + for (m = 0; m < QAM; m++) log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) + pow(Q - symbols_Q[m], 2.0)) / N0; /* Calculate an LLR for each of the k_64QAM bits in the set */ - for (k = 0; k < qm; k++) { + for (k = 0; k < QM; k++) { p0 = -999999; p1 = -999999; /* For each constellation point */ - for (m = 0; m < qam; m++) { - if ((m >> (qm - k - 1)) & 1) + for (m = 0; m < QAM; m++) { + if ((m >> (QM - k - 1)) & 1) p1 = maxstar(p1, log_syml_prob[m]); else p0 = maxstar(p0, log_syml_prob[m]); @@ -1776,8 +1783,10 @@ llr_ = llr_max; if (llr_ < -llr_max) llr_ = -llr_max; - llrs[qm * i + k] = (int8_t) llr_; + llrs[QM * i + k] = (int8_t) llr_; } +#undef QM +#undef QAM } static void @@ -3441,7 +3450,7 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops[num_to_process]; + struct rte_bbdev_dec_op **ops = alloca(sizeof(struct rte_bbdev_dec_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; int ret, i, j; @@ -3550,7 +3559,7 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops[num_to_process]; + struct rte_bbdev_dec_op **ops = alloca(sizeof(struct rte_bbdev_dec_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; @@ -3648,7 +3657,7 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_enc_op *ops[num_to_process]; + struct rte_bbdev_enc_op **ops = alloca(sizeof(struct rte_bbdev_enc_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; int ret, i, j; @@ -3742,7 +3751,7 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_enc_op *ops[num_to_process]; + struct rte_bbdev_enc_op **ops = alloca(sizeof(struct rte_bbdev_enc_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; int ret, i, j; @@ -3838,7 +3847,7 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_fft_op *ops[num_to_process]; + struct rte_bbdev_fft_op **ops = alloca(sizeof(struct rte_bbdev_fft_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; int ret, i, j; @@ -3932,7 +3941,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_to_process = tp->op_params->num_to_process; - struct rte_bbdev_mldts_op *ops[num_to_process]; + struct rte_bbdev_mldts_op **ops = + alloca(sizeof(struct rte_bbdev_mldts_op *) * num_to_process); struct test_buffers *bufs = NULL; struct rte_bbdev_info info; int ret, i, j; @@ -4022,8 +4032,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops_enq[num_ops]; - struct rte_bbdev_dec_op *ops_deq[num_ops]; + struct rte_bbdev_dec_op **ops_enq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); + struct rte_bbdev_dec_op **ops_deq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4135,8 +4145,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops_enq[num_ops]; - struct rte_bbdev_dec_op *ops_deq[num_ops]; + struct rte_bbdev_dec_op **ops_enq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); + struct rte_bbdev_dec_op **ops_deq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4278,8 +4288,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops_enq[num_ops]; - struct rte_bbdev_dec_op *ops_deq[num_ops]; + struct rte_bbdev_dec_op **ops_enq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); + struct rte_bbdev_dec_op **ops_deq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4397,8 +4407,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_dec_op *ops_enq[num_ops]; - struct rte_bbdev_dec_op *ops_deq[num_ops]; + struct rte_bbdev_dec_op **ops_enq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); + struct rte_bbdev_dec_op **ops_deq = alloca(sizeof(struct rte_bbdev_dec_op *) * num_ops); struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4535,8 +4545,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_enc_op *ops_enq[num_ops]; - struct rte_bbdev_enc_op *ops_deq[num_ops]; + struct rte_bbdev_enc_op **ops_enq = alloca(sizeof(struct rte_bbdev_enc_op *) * num_ops); + struct rte_bbdev_enc_op **ops_deq = alloca(sizeof(struct rte_bbdev_enc_op *) * num_ops); struct rte_bbdev_enc_op *ref_op = tp->op_params->ref_enc_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4637,8 +4647,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_enc_op *ops_enq[num_ops]; - struct rte_bbdev_enc_op *ops_deq[num_ops]; + struct rte_bbdev_enc_op **ops_enq = alloca(sizeof(struct rte_bbdev_enc_op *) * num_ops); + struct rte_bbdev_enc_op **ops_deq = alloca(sizeof(struct rte_bbdev_enc_op *) * num_ops); struct rte_bbdev_enc_op *ref_op = tp->op_params->ref_enc_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4739,8 +4749,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_fft_op *ops_enq[num_ops]; - struct rte_bbdev_fft_op *ops_deq[num_ops]; + struct rte_bbdev_fft_op **ops_enq = alloca(sizeof(struct rte_bbdev_fft_op *) * num_ops); + struct rte_bbdev_fft_op **ops_deq = alloca(sizeof(struct rte_bbdev_fft_op *) * num_ops); struct rte_bbdev_fft_op *ref_op = tp->op_params->ref_fft_op; struct test_buffers *bufs = NULL; int i, j, ret; @@ -4839,8 +4849,8 @@ const uint16_t queue_id = tp->queue_id; const uint16_t burst_sz = tp->op_params->burst_sz; const uint16_t num_ops = tp->op_params->num_to_process; - struct rte_bbdev_mldts_op *ops_enq[num_ops]; - struct rte_bbdev_mldts_op *ops_deq[num_ops]; + struct rte_bbdev_mldts_op **ops_enq = alloca(sizeof(struct rte_bbdev_mldts_op *) * num_ops); + struct rte_bbdev_mldts_op **ops_deq = alloca(sizeof(struct rte_bbdev_mldts_op *) * num_ops); struct rte_bbdev_mldts_op *ref_op = tp->op_params->ref_mldts_op; struct test_buffers *bufs = NULL; int i, j, ret; diff -Nru dpdk-24.11.4/app/test-bbdev/test_bbdev_vector.c dpdk-24.11.8/app/test-bbdev/test_bbdev_vector.c --- dpdk-24.11.4/app/test-bbdev/test_bbdev_vector.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-bbdev/test_bbdev_vector.c 2026-10-14 13:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #include #include #include +#include #include "test_bbdev_vector.h" diff -Nru dpdk-24.11.4/app/test-crypto-perf/cperf_options_parsing.c dpdk-24.11.8/app/test-crypto-perf/cperf_options_parsing.c --- dpdk-24.11.4/app/test-crypto-perf/cperf_options_parsing.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-crypto-perf/cperf_options_parsing.c 2026-10-14 13:10:05.000000000 +0000 @@ -440,8 +440,7 @@ if (strlen(arg) > (sizeof(opts->device_type) - 1)) return -1; - strncpy(opts->device_type, arg, sizeof(opts->device_type) - 1); - *(opts->device_type + sizeof(opts->device_type) - 1) = '\0'; + strlcpy(opts->device_type, arg, sizeof(opts->device_type)); return 0; } @@ -1062,7 +1061,7 @@ opts->segment_sz = 0; opts->imix_distribution_count = 0; - strncpy(opts->device_type, "crypto_aesni_mb", + strlcpy(opts->device_type, "crypto_aesni_mb", sizeof(opts->device_type)); opts->nb_qps = 1; diff -Nru dpdk-24.11.4/app/test-dma-perf/benchmark.c dpdk-24.11.8/app/test-dma-perf/benchmark.c --- dpdk-24.11.4/app/test-dma-perf/benchmark.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-dma-perf/benchmark.c 2026-10-14 13:10:05.000000000 +0000 @@ -450,10 +450,10 @@ while (1) { for (i = 0; i < nr_buf; i++) { - const void *src = rte_pktmbuf_mtod(dsts[i], void *); - void *dst = rte_pktmbuf_mtod(srcs[i], void *); + const void *src = rte_pktmbuf_mtod(srcs[i], void *); + void *dst = rte_pktmbuf_mtod(dsts[i], void *); - /* copy buffer form src to dst */ + /* copy buffer from src to dst */ rte_memcpy(dst, src, (size_t)buf_size); worker_info->total_cpl++; } diff -Nru dpdk-24.11.4/app/test-dma-perf/main.c dpdk-24.11.8/app/test-dma-perf/main.c --- dpdk-24.11.4/app/test-dma-perf/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-dma-perf/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -124,6 +124,7 @@ { uint32_t i; uint32_t nb_lcores = rte_lcore_count(); + uint32_t main_lcore = rte_get_main_lcore(); struct test_configure_entry *mem_size = &case_cfg->mem_size; struct test_configure_entry *buf_size = &case_cfg->buf_size; struct test_configure_entry *ring_size = &case_cfg->ring_size; @@ -139,6 +140,14 @@ return; } + for (uint32_t i = 0; i < case_cfg->num_worker; i++) { + if (case_cfg->dma_config[i].lcore_dma_map.lcore == main_lcore) { + printf("Case %u: worker %u cannot run on the EAL main lcore (%u).\n", + case_id, i, main_lcore); + return; + } + } + printf("Number of used lcores: %u.\n", nb_lcores); if (mem_size->incr != 0) @@ -221,7 +230,7 @@ if (value == NULL || entry == NULL) goto out; - strncpy(input, value, 254); + strlcpy(input, value, sizeof(input)); if (*input == '\0') goto out; diff -Nru dpdk-24.11.4/app/test-dma-perf/main.h dpdk-24.11.8/app/test-dma-perf/main.h --- dpdk-24.11.4/app/test-dma-perf/main.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-dma-perf/main.h 2026-10-14 13:10:05.000000000 +0000 @@ -10,7 +10,7 @@ #include #include -#define MAX_WORKER_NB 128 +#define MAX_WORKER_NB RTE_MAX_LCORE #define MAX_OUTPUT_STR_LEN 512 #define MAX_DMA_NB 128 diff -Nru dpdk-24.11.4/app/test-eventdev/evt_options.c dpdk-24.11.8/app/test-eventdev/evt_options.c --- dpdk-24.11.4/app/test-eventdev/evt_options.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-eventdev/evt_options.c 2026-10-14 13:10:05.000000000 +0000 @@ -23,7 +23,7 @@ memset(opt, 0, sizeof(*opt)); opt->verbose_level = 1; /* Enable minimal prints */ opt->dev_id = 0; - strncpy(opt->test_name, "order_queue", EVT_TEST_NAME_MAX_LEN); + strlcpy(opt->test_name, "order_queue", sizeof(opt->test_name)); opt->nb_flows = 1024; opt->socket_id = SOCKET_ID_ANY; opt->pool_sz = 16 * 1024; diff -Nru dpdk-24.11.4/app/test-pmd/cmdline_flow.c dpdk-24.11.8/app/test-pmd/cmdline_flow.c --- dpdk-24.11.4/app/test-pmd/cmdline_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-pmd/cmdline_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -4573,7 +4573,8 @@ .help = "tag control information", .next = NEXT(item_vlan, NEXT_ENTRY(COMMON_UNSIGNED), item_param), - .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, hdr.vlan_tci)), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, + hdr.vlan_tci, "\xff\xff")), }, [ITEM_VLAN_PCP] = { .name = "pcp", @@ -4604,8 +4605,8 @@ .help = "inner EtherType", .next = NEXT(item_vlan, NEXT_ENTRY(COMMON_UNSIGNED), item_param), - .args = ARGS(ARGS_ENTRY_HTON(struct rte_flow_item_vlan, - hdr.eth_proto)), + .args = ARGS(ARGS_ENTRY_MASK_HTON(struct rte_flow_item_vlan, + hdr.eth_proto, "\xff\xff")), }, [ITEM_VLAN_HAS_MORE_VLAN] = { .name = "has_more_vlan", @@ -11806,7 +11807,7 @@ if (!ctx->object) return len; buf = (uint8_t *)ctx->object + arg_data->offset; - strncpy(buf, str, len); + memcpy(buf, str, len); if (ctx->objmask) memset((uint8_t *)ctx->objmask + arg_data->offset, 0xff, len); return len; @@ -13972,7 +13973,7 @@ data_tail = data + ACTION_RAW_ENCAP_MAX_DATA; for (i = n - 1 ; i >= 0; --i) { const struct rte_flow_item_gtp *gtp; - const struct rte_flow_item_geneve_opt *opt; + const struct rte_flow_item_geneve_opt *geneve_opt; struct rte_flow_item_ipv6_routing_ext *ext; item = in->args.vc.pattern + i; @@ -14044,16 +14045,16 @@ size = sizeof(struct rte_geneve_hdr); break; case RTE_FLOW_ITEM_TYPE_GENEVE_OPT: - opt = (const struct rte_flow_item_geneve_opt *) + geneve_opt = (const struct rte_flow_item_geneve_opt *) item->spec; size = offsetof(struct rte_flow_item_geneve_opt, option_len) + sizeof(uint8_t); - if (opt->option_len && opt->data) { - *total_size += opt->option_len * + if (geneve_opt->option_len && geneve_opt->data) { + *total_size += geneve_opt->option_len * sizeof(uint32_t); rte_memcpy(data_tail - (*total_size), - opt->data, - opt->option_len * sizeof(uint32_t)); + geneve_opt->data, + geneve_opt->option_len * sizeof(uint32_t)); } break; case RTE_FLOW_ITEM_TYPE_L2TPV3OIP: @@ -14103,7 +14104,7 @@ goto error; } else { const struct rte_flow_item_gtp_psc - *opt = item->spec; + *gtp_opt = item->spec; struct rte_gtp_psc_generic_hdr *hdr; size_t hdr_size = RTE_ALIGN(sizeof(*hdr), sizeof(int32_t)); @@ -14111,7 +14112,7 @@ *total_size += hdr_size; hdr = (typeof(hdr))(data_tail - (*total_size)); memset(hdr, 0, hdr_size); - *hdr = opt->hdr; + *hdr = gtp_opt->hdr; hdr->ext_hdr_len = 1; gtp_psc = i; size = 0; @@ -14133,25 +14134,25 @@ size = 0; if (item->spec) { const struct rte_flow_item_gre_opt - *opt = item->spec; - if (opt->checksum_rsvd.checksum) { + *gre_opt = item->spec; + if (gre_opt->checksum_rsvd.checksum) { *total_size += - sizeof(opt->checksum_rsvd); + sizeof(gre_opt->checksum_rsvd); rte_memcpy(data_tail - (*total_size), - &opt->checksum_rsvd, - sizeof(opt->checksum_rsvd)); + &gre_opt->checksum_rsvd, + sizeof(gre_opt->checksum_rsvd)); } - if (opt->key.key) { - *total_size += sizeof(opt->key.key); + if (gre_opt->key.key) { + *total_size += sizeof(gre_opt->key.key); rte_memcpy(data_tail - (*total_size), - &opt->key.key, - sizeof(opt->key.key)); + &gre_opt->key.key, + sizeof(gre_opt->key.key)); } - if (opt->sequence.sequence) { - *total_size += sizeof(opt->sequence.sequence); + if (gre_opt->sequence.sequence) { + *total_size += sizeof(gre_opt->sequence.sequence); rte_memcpy(data_tail - (*total_size), - &opt->sequence.sequence, - sizeof(opt->sequence.sequence)); + &gre_opt->sequence.sequence, + sizeof(gre_opt->sequence.sequence)); } } proto = 0x2F; diff -Nru dpdk-24.11.4/app/test-pmd/config.c dpdk-24.11.8/app/test-pmd/config.c --- dpdk-24.11.4/app/test-pmd/config.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-pmd/config.c 2026-10-14 13:10:05.000000000 +0000 @@ -69,6 +69,8 @@ #define NS_PER_SEC 1E9 +#define FLOW_QUEUE_FLUSH_MAX_ITERS (10) + static const struct { enum tx_pkt_split split; const char *name; @@ -1813,6 +1815,15 @@ port->queue_sz = queue_attr->size; for (std_queue = 0; std_queue < nb_queue; std_queue++) attr_list[std_queue] = queue_attr; + free(port->job_list); + port->job_list = calloc(nb_queue, sizeof(*port->job_list)); + if (port->job_list == NULL) { + TESTPMD_LOG(ERR, "Failed to allocate memory for operations tracking on port %u\n", + port_id); + return -ENOMEM; + } + for (unsigned int i = 0; i < nb_queue; i++) + LIST_INIT(&port->job_list[i]); /* Poisoning to make sure PMDs update it in case of error. */ memset(&error, 0x66, sizeof(error)); if (rte_flow_configure(port_id, port_attr, nb_queue, attr_list, &error)) @@ -2917,6 +2928,7 @@ pf->flow = flow; job->pf = pf; port->flow_list = pf; + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Flow rule #%"PRIu64" creation enqueued\n", pf->id); return 0; } @@ -2954,6 +2966,7 @@ free(job); return port_flow_complain(&error); } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); return 0; } @@ -3007,6 +3020,7 @@ ret = port_flow_complain(&error); continue; } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Flow rule #%"PRIu64" destruction enqueued\n", pf->id); *tmp = pf->next; @@ -3140,6 +3154,7 @@ uf->flow = pf->flow; *tmp = uf; job->pf = pf; + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Flow rule #%"PRIu64" update enqueued\n", pf->id); return 0; @@ -3194,6 +3209,7 @@ free(job); return port_flow_complain(&error); } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Indirect action #%u creation queued\n", pia->id); return 0; } @@ -3255,6 +3271,7 @@ ret = port_flow_complain(&error); continue; } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); *tmp = pia->next; printf("Indirect action #%u destruction queued\n", pia->id); @@ -3329,6 +3346,7 @@ free(job); return port_flow_complain(&error); } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Indirect action #%u update queued\n", id); return 0; } @@ -3344,8 +3362,11 @@ struct rte_flow_error error; struct port_indirect_action *pia = action_get_by_id(port_id, id); const struct rte_flow_op_attr attr = { .postpone = postpone}; + struct rte_port *port; struct queue_job *job; + port = &ports[port_id]; + if (!pia || !pia->handle) return; job = calloc(1, sizeof(*job)); @@ -3364,6 +3385,7 @@ port_flow_complain(&error); free(job); } else { + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("port-%u: indirect action #%u update-and-query queued\n", port_id, id); } @@ -3405,6 +3427,7 @@ free(job); return port_flow_complain(&error); } + LIST_INSERT_HEAD(&port->job_list[queue_id], job, chain); printf("Indirect action #%u update queued\n", id); return 0; } @@ -3520,6 +3543,19 @@ return 0; } +static void +port_free_queue_job(struct queue_job *job) +{ + if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY || + job->type == QUEUE_JOB_TYPE_FLOW_UPDATE) + free(job->pf); + else if (job->type == QUEUE_JOB_TYPE_ACTION_DESTROY) + free(job->pia); + + LIST_REMOVE(job, chain); + free(job); +} + /** Pull queue operation results from the queue. */ static int port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id, @@ -3557,6 +3593,8 @@ return ret; } while (success < nb_flows) { + struct queue_job *job; + ret = rte_flow_pull(port_id, queue_id, res, port->queue_sz, &error); if (ret < 0) { @@ -3569,6 +3607,13 @@ for (i = 0; i < ret; i++) { if (res[i].status == RTE_FLOW_OP_SUCCESS) success++; + job = res[i].user_data; + /* + * It is assumed that each enqueued async flow operation + * has a queue_job entry. + */ + RTE_ASSERT(job != NULL); + port_free_queue_job(job); } } rule += n; @@ -3717,15 +3762,10 @@ if (res[i].status == RTE_FLOW_OP_SUCCESS) success++; job = (struct queue_job *)res[i].user_data; - if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY || - job->type == QUEUE_JOB_TYPE_FLOW_UPDATE) - free(job->pf); - else if (job->type == QUEUE_JOB_TYPE_ACTION_DESTROY) - free(job->pia); - else if (job->type == QUEUE_JOB_TYPE_ACTION_QUERY) + if (job->type == QUEUE_JOB_TYPE_ACTION_QUERY) port_action_handle_query_dump(port_id, job->pia, &job->query); - free(job); + port_free_queue_job(job); } printf("Queue #%u pulled %u operations (%u failed, %u succeeded)\n", queue_id, ret, ret - success, success); @@ -3939,6 +3979,128 @@ return -EINVAL; } +static int +port_flow_queue_job_flush(portid_t port_id, queueid_t queue_id) +{ + struct rte_flow_op_result *res; + struct rte_flow_error error; + unsigned int expected_ops; + struct rte_port *port; + struct queue_job *job; + unsigned int success; + unsigned int polled; + int iterations; + int ret; + + port = &ports[port_id]; + + printf("Flushing flow queue %u on port %u\n", queue_id, port_id); + + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x44, sizeof(error)); + if (rte_flow_push(port_id, queue_id, &error)) + return port_flow_complain(&error); + + /* Count expected operations. */ + expected_ops = 0; + LIST_FOREACH(job, &port->job_list[queue_id], chain) + expected_ops++; + + res = calloc(expected_ops, sizeof(*res)); + if (res == NULL) + return -ENOMEM; + + polled = 0; + success = 0; + iterations = FLOW_QUEUE_FLUSH_MAX_ITERS; + while (iterations > 0 && expected_ops > 0) { + /* Poisoning to make sure PMDs update it in case of error. */ + memset(&error, 0x55, sizeof(error)); + ret = rte_flow_pull(port_id, queue_id, res, expected_ops, &error); + if (ret < 0) { + port_flow_complain(&error); + free(res); + return ret; + } + if (ret == 0) { + /* Prevent infinite loop when driver does not return any completion. */ + iterations--; + continue; + } + + expected_ops -= ret; + polled += ret; + for (int i = 0; i < ret; i++) { + if (res[i].status == RTE_FLOW_OP_SUCCESS) + success++; + + job = res[i].user_data; + /* + * It is assumed that each enqueued async flow operation + * has a queue_job entry. + */ + RTE_ASSERT(job != NULL); + port_free_queue_job(job); + } + } + free(res); + + printf("Flushed flow queue %u on port %u (%u failed, %u succeeded).\n", + queue_id, port_id, polled - success, success); + + if (iterations == 0 && expected_ops > 0) { + /* + * Driver was not able to return all completions for flow operations in time. + * Log the error and free the queue_job entries to prevent leak. + */ + + TESTPMD_LOG(ERR, "Unable to fully flush flow queue %u on port %u (left ops %u)\n", + queue_id, port_id, expected_ops); + + while (!LIST_EMPTY(&port->job_list[queue_id])) { + job = LIST_FIRST(&port->job_list[queue_id]); + port_free_queue_job(job); + } + + return 0; + } + + /* + * It is assumed that each enqueued async flow operation + * has a queue_job entry, so if expected_ops reached zero, + * then the queue_job list should be empty. + */ + RTE_ASSERT(LIST_EMPTY(&port->job_list[queue_id])); + + return 0; +} + +static int +port_flow_queues_job_flush(portid_t port_id) +{ + struct rte_port *port; + int ret; + + port = &ports[port_id]; + + if (port->queue_nb == 0) + return 0; + + for (queueid_t queue_id = 0; queue_id < port->queue_nb; ++queue_id) { + if (LIST_EMPTY(&port->job_list[queue_id])) + continue; + + ret = port_flow_queue_job_flush(port_id, queue_id); + if (ret < 0) { + TESTPMD_LOG(ERR, "Flushing flows queue %u failed on port %u (ret %d)\n", + queue_id, port_id, ret); + return ret; + } + } + + return 0; +} + /** Remove all flow rules. */ int port_flow_flush(portid_t port_id) @@ -3953,6 +4115,11 @@ port = &ports[port_id]; + ret = port_flow_queues_job_flush(port_id); + if (ret < 0) + TESTPMD_LOG(ERR, "Flushing flows queues failed on port %u (ret %d)\n", + port_id, ret); + if (port->flow_list == NULL) return ret; @@ -4469,15 +4636,9 @@ static void ring_rx_descriptor_display(const struct rte_memzone *ring_mz, -#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC portid_t port_id, -#else - __rte_unused portid_t port_id, -#endif uint16_t desc_id) { - struct igb_ring_desc_16_bytes *ring = - (struct igb_ring_desc_16_bytes *)ring_mz->addr; #ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC int ret; struct rte_eth_dev_info dev_info; @@ -4507,12 +4668,15 @@ } #endif /* 16 bytes RX descriptor */ + struct igb_ring_desc_16_bytes *ring = + (struct igb_ring_desc_16_bytes *)ring_mz->addr; ring[desc_id].lo_dword.dword = rte_le_to_cpu_64(ring[desc_id].lo_dword.dword); ring_rxd_display_dword(ring[desc_id].lo_dword); ring[desc_id].hi_dword.dword = rte_le_to_cpu_64(ring[desc_id].hi_dword.dword); ring_rxd_display_dword(ring[desc_id].hi_dword); + RTE_SET_USED(port_id); } static void @@ -4721,7 +4885,6 @@ { struct rte_eth_rss_conf rss_conf = {0}; uint8_t rss_key[RSS_HASH_KEY_LENGTH]; - uint64_t rss_hf; uint8_t i; int diag; struct rte_eth_dev_info dev_info; @@ -4762,8 +4925,7 @@ } return; } - rss_hf = rss_conf.rss_hf; - if (rss_hf == 0) { + if (rss_conf.rss_hf == 0) { printf("RSS disabled\n"); return; } @@ -4775,7 +4937,7 @@ } printf("RSS functions:\n"); - rss_types_display(rss_hf, TESTPMD_RSS_TYPES_CHAR_NUM_PER_LINE); + rss_types_display(rss_conf.rss_hf, TESTPMD_RSS_TYPES_CHAR_NUM_PER_LINE); if (!show_rss_key) return; @@ -5125,6 +5287,7 @@ lcoreid_t lc_id; uint16_t nb_rx_queue, nb_tx_queue; uint16_t i, j, k, sm_id = 0; + uint8_t effective_nb_tcs; uint16_t total_tc_num; struct rte_port *port; uint8_t tc = 0; @@ -5170,6 +5333,7 @@ /* get the dcb info on the first RX and TX ports */ (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info); (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info); + effective_nb_tcs = RTE_MIN(rxp_dcb_info.nb_tcs, txp_dcb_info.nb_tcs); for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) { fwd_lcores[lc_id]->stream_nb = 0; @@ -5178,7 +5342,8 @@ /* if the nb_queue is zero, means this tc is * not enabled on the POOL */ - if (rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue == 0) + if (rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue == 0 || + txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue == 0) break; k = fwd_lcores[lc_id]->stream_nb + fwd_lcores[lc_id]->stream_idx; @@ -5203,7 +5368,7 @@ sm_id = (streamid_t) (sm_id + fwd_lcores[lc_id]->stream_nb); tc++; - if (tc < rxp_dcb_info.nb_tcs) + if (tc < effective_nb_tcs) continue; /* Restart from TC 0 on next RX port */ tc = 0; @@ -5218,6 +5383,8 @@ /* get the dcb information on next RX and TX ports */ rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info); rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info); + + effective_nb_tcs = RTE_MIN(rxp_dcb_info.nb_tcs, txp_dcb_info.nb_tcs); } } @@ -6384,8 +6551,8 @@ diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); if (diag < 0) { fprintf(stderr, - "rx_vlan_extend_set(port_pi=%d, on=%d) failed diag=%d\n", - port_id, on, diag); + "%s(port_pi=%d, on=%d) failed diag=%d\n", + __func__, port_id, on, diag); return; } ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; @@ -6539,8 +6706,8 @@ return; fprintf(stderr, - "tx_vlan_tpid_set(port_pi=%d, vlan_type=%d, tpid=%d) failed diag=%d\n", - port_id, vlan_type, tp_id, diag); + "%s(port_pi=%d, vlan_type=%d, tpid=%d) failed diag=%d\n", + __func__, port_id, vlan_type, tp_id, diag); } void diff -Nru dpdk-24.11.4/app/test-pmd/parameters.c dpdk-24.11.8/app/test-pmd/parameters.c --- dpdk-24.11.4/app/test-pmd/parameters.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-pmd/parameters.c 2026-10-14 13:10:05.000000000 +0000 @@ -769,42 +769,42 @@ } static int -parse_event_printing_config(const char *optarg, int enable) +parse_event_printing_config(const char *event_arg, int enable) { uint32_t mask = 0; - if (!strcmp(optarg, "unknown")) + if (!strcmp(event_arg, "unknown")) mask = UINT32_C(1) << RTE_ETH_EVENT_UNKNOWN; - else if (!strcmp(optarg, "intr_lsc")) + else if (!strcmp(event_arg, "intr_lsc")) mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_LSC; - else if (!strcmp(optarg, "queue_state")) + else if (!strcmp(event_arg, "queue_state")) mask = UINT32_C(1) << RTE_ETH_EVENT_QUEUE_STATE; - else if (!strcmp(optarg, "intr_reset")) + else if (!strcmp(event_arg, "intr_reset")) mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RESET; - else if (!strcmp(optarg, "vf_mbox")) + else if (!strcmp(event_arg, "vf_mbox")) mask = UINT32_C(1) << RTE_ETH_EVENT_VF_MBOX; - else if (!strcmp(optarg, "ipsec")) + else if (!strcmp(event_arg, "ipsec")) mask = UINT32_C(1) << RTE_ETH_EVENT_IPSEC; - else if (!strcmp(optarg, "macsec")) + else if (!strcmp(event_arg, "macsec")) mask = UINT32_C(1) << RTE_ETH_EVENT_MACSEC; - else if (!strcmp(optarg, "intr_rmv")) + else if (!strcmp(event_arg, "intr_rmv")) mask = UINT32_C(1) << RTE_ETH_EVENT_INTR_RMV; - else if (!strcmp(optarg, "dev_probed")) + else if (!strcmp(event_arg, "dev_probed")) mask = UINT32_C(1) << RTE_ETH_EVENT_NEW; - else if (!strcmp(optarg, "dev_released")) + else if (!strcmp(event_arg, "dev_released")) mask = UINT32_C(1) << RTE_ETH_EVENT_DESTROY; - else if (!strcmp(optarg, "flow_aged")) + else if (!strcmp(event_arg, "flow_aged")) mask = UINT32_C(1) << RTE_ETH_EVENT_FLOW_AGED; - else if (!strcmp(optarg, "err_recovering")) + else if (!strcmp(event_arg, "err_recovering")) mask = UINT32_C(1) << RTE_ETH_EVENT_ERR_RECOVERING; - else if (!strcmp(optarg, "recovery_success")) + else if (!strcmp(event_arg, "recovery_success")) mask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_SUCCESS; - else if (!strcmp(optarg, "recovery_failed")) + else if (!strcmp(event_arg, "recovery_failed")) mask = UINT32_C(1) << RTE_ETH_EVENT_RECOVERY_FAILED; - else if (!strcmp(optarg, "all")) + else if (!strcmp(event_arg, "all")) mask = ~UINT32_C(0); else { - fprintf(stderr, "Invalid event: %s\n", optarg); + fprintf(stderr, "Invalid event: %s\n", event_arg); return -1; } if (enable) @@ -968,11 +968,10 @@ break; case TESTPMD_OPT_STATS_PERIOD_NUM: { char *end = NULL; - unsigned int n; n = strtoul(optarg, &end, 10); if ((optarg[0] == '\0') || (end == NULL) || - (*end != '\0')) + (*end != '\0') || n <= 0 || n >= UINT16_MAX) rte_exit(EXIT_FAILURE, "Invalid stats-period value\n"); stats_period = n; @@ -1255,10 +1254,10 @@ set_pkt_forwarding_mode(optarg); break; case TESTPMD_OPT_RSS_IP_NUM: - rss_hf = RTE_ETH_RSS_IP; + rss_hf |= RTE_ETH_RSS_IP; break; case TESTPMD_OPT_RSS_UDP_NUM: - rss_hf = RTE_ETH_RSS_UDP; + rss_hf |= RTE_ETH_RSS_IP | RTE_ETH_RSS_UDP; break; case TESTPMD_OPT_RSS_LEVEL_INNER_NUM: rss_hf |= RTE_ETH_RSS_LEVEL_INNERMOST; @@ -1311,7 +1310,6 @@ break; case TESTPMD_OPT_HAIRPIN_MODE_NUM: { char *end = NULL; - unsigned int n; errno = 0; n = strtoul(optarg, &end, 0); diff -Nru dpdk-24.11.4/app/test-pmd/testpmd.c dpdk-24.11.8/app/test-pmd/testpmd.c --- dpdk-24.11.4/app/test-pmd/testpmd.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-pmd/testpmd.c 2026-10-14 13:10:05.000000000 +0000 @@ -3247,6 +3247,15 @@ } static void +port_free_job_list(portid_t pi) +{ + struct rte_port *port = &ports[pi]; + free(port->job_list); + port->job_list = NULL; + port->queue_nb = 0; +} + +static void flush_port_owned_resources(portid_t pi) { mcast_addr_pool_destroy(pi); @@ -3256,6 +3265,7 @@ port_flow_actions_template_flush(pi); port_flex_item_flush(pi); port_action_handle_flush(pi); + port_free_job_list(pi); } static void @@ -4371,6 +4381,8 @@ static void signal_handler(int signum __rte_unused) { + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); f_quit = 1; prompt_exit(); } @@ -4564,7 +4576,7 @@ #ifdef RTE_LIB_LATENCYSTATS if (latencystats_enabled != 0) { - int ret = rte_latencystats_init(1, NULL); + ret = rte_latencystats_init(1, NULL); if (ret) fprintf(stderr, "Warning: latencystats init() returned error %d\n", diff -Nru dpdk-24.11.4/app/test-pmd/testpmd.h dpdk-24.11.8/app/test-pmd/testpmd.h --- dpdk-24.11.4/app/test-pmd/testpmd.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-pmd/testpmd.h 2026-10-14 13:10:05.000000000 +0000 @@ -271,6 +271,7 @@ /* Descriptor for queue job. */ struct queue_job { + LIST_ENTRY(queue_job) chain; uint32_t type; /**< Job type. */ union { struct port_flow *pf; @@ -279,6 +280,8 @@ union port_action_query query; }; +LIST_HEAD(queue_job_list, queue_job); + struct port_flow_tunnel { LIST_ENTRY(port_flow_tunnel) chain; struct rte_flow_action *pmd_actions; @@ -360,6 +363,7 @@ struct port_flow *flow_list; /**< Associated flows. */ struct port_indirect_action *actions_list; /**< Associated indirect actions. */ + struct queue_job_list *job_list; /**< Pending async flow API operations, per queue. */ LIST_HEAD(, port_flow_tunnel) flow_tunnel_list; const struct rte_eth_rxtx_callback *rx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]; const struct rte_eth_rxtx_callback *tx_dump_cb[RTE_MAX_QUEUES_PER_PORT+1]; diff -Nru dpdk-24.11.4/app/test-regex/main.c dpdk-24.11.8/app/test-regex/main.c --- dpdk-24.11.4/app/test-regex/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/app/test-regex/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -103,7 +103,6 @@ char **argvopt; int opt; int opt_idx; - size_t len; static struct option lgopts[] = { { "help", 0, 0, ARG_HELP}, /* Rules database file to load. */ @@ -133,20 +132,16 @@ lgopts, &opt_idx)) != EOF) { switch (opt) { case ARG_RULES_FILE_NAME: - len = strnlen(optarg, MAX_FILE_NAME - 1); - if (len == MAX_FILE_NAME) + if (strlcpy(rules_file, optarg, MAX_FILE_NAME) >= MAX_FILE_NAME) rte_exit(EXIT_FAILURE, "Rule file name to long max %d\n", MAX_FILE_NAME - 1); - strncpy(rules_file, optarg, MAX_FILE_NAME - 1); break; case ARG_DATA_FILE_NAME: - len = strnlen(optarg, MAX_FILE_NAME - 1); - if (len == MAX_FILE_NAME) + if (strlcpy(data_file, optarg, MAX_FILE_NAME) >= MAX_FILE_NAME) rte_exit(EXIT_FAILURE, "Data file name to long max %d\n", MAX_FILE_NAME - 1); - strncpy(data_file, optarg, MAX_FILE_NAME - 1); break; case ARG_NUM_OF_JOBS: *nb_jobs = atoi(optarg); diff -Nru dpdk-24.11.4/buildtools/get-test-suites.py dpdk-24.11.8/buildtools/get-test-suites.py --- dpdk-24.11.4/buildtools/get-test-suites.py 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/buildtools/get-test-suites.py 2026-10-14 13:10:05.000000000 +0000 @@ -38,4 +38,5 @@ for suite in test_suites.keys(): print(f"{suite}={','.join(test_suites[suite])}") -print(f"non_suite_tests={','.join(non_suite_tests)}") +if non_suite_tests: + print(f"non_suite_tests={','.join(non_suite_tests)}") diff -Nru dpdk-24.11.4/config/arm/arm32_armv8_linux_gcc dpdk-24.11.8/config/arm/arm32_armv8_linux_gcc --- dpdk-24.11.4/config/arm/arm32_armv8_linux_gcc 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/config/arm/arm32_armv8_linux_gcc 2026-10-14 13:10:05.000000000 +0000 @@ -13,5 +13,8 @@ cpu = 'armv8-a' endian = 'little' +[built-in options] +c_args = '-mfpu=fp-armv8' + [properties] platform = 'generic_aarch32' diff -Nru dpdk-24.11.4/debian/changelog dpdk-24.11.8/debian/changelog --- dpdk-24.11.4/debian/changelog 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/changelog 2026-10-30 03:40:36.000000000 +0000 @@ -1,3 +1,19 @@ +dpdk (24.11.8-0+deb13u1) trixie-security; urgency=high + + * Non-maintainer upload by the Security Team. + * New upstream stable point release 24.11.8, incorporating the upstream + security fixes previously backported for the trixie candidate. Fixes: + CVE-2026-86561, CVE-2026-86562, CVE-2026-86563, CVE-2026-86564, + CVE-2026-86565, CVE-2026-86566, CVE-2026-86567, CVE-2026-86845, + CVE-2026-86846, CVE-2026-86847, CVE-2026-86848, CVE-2026-86849, + CVE-2026-86856, CVE-2026-93683, CVE-2026-100236. + https://mails.dpdk.org/archives/announce/2026-October/000568.html + * Backport upstream vhost-crypto queue-pointer return correction. + * Update EAL and RIB symbols for newly exported INTERNAL entries. The + optional rte_ifpga_find_afu_by_name INTERNAL export is absent upstream. + + -- Aron Xu Fri, 30 Oct 2026 11:40:36 +0800 + dpdk (24.11.4-0+deb13u1) trixie; urgency=medium [ Christian Ehrhardt ] diff -Nru dpdk-24.11.4/debian/librte-eal25.symbols dpdk-24.11.8/debian/librte-eal25.symbols --- dpdk-24.11.4/debian/librte-eal25.symbols 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/librte-eal25.symbols 2026-10-28 13:35:03.000000000 +0000 @@ -202,6 +202,7 @@ rte_intr_ack@DPDK_25 23.11 #MISSING: 22.11# rte_intr_ack@EXPERIMENTAL 19.08 (optional)rte_intr_allow_others@INTERNAL 21.11 + rte_intr_active_events_flags@INTERNAL 24.11.8 rte_intr_callback_register@DPDK_25 23.11 rte_intr_callback_unregister@DPDK_25 23.11 rte_intr_callback_unregister_pending@DPDK_25 23.11 @@ -460,6 +461,7 @@ #MISSING: 23.11# rte_thread_key_create@EXPERIMENTAL 21.08 rte_thread_key_delete@DPDK_25 23.11 #MISSING: 23.11# rte_thread_key_delete@EXPERIMENTAL 21.08 + rte_thread_mutex_init_shared@INTERNAL 24.11.8 rte_thread_register@DPDK_25 23.11 rte_thread_self@DPDK_25 23.11 #MISSING: 23.11# rte_thread_self@EXPERIMENTAL 22.11 diff -Nru dpdk-24.11.4/debian/librte-rib25.symbols dpdk-24.11.8/debian/librte-rib25.symbols --- dpdk-24.11.4/debian/librte-rib25.symbols 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/librte-rib25.symbols 2026-10-28 13:35:03.000000000 +0000 @@ -1,5 +1,6 @@ librte_rib.so.25 librte-rib25 #MINVER# DPDK_25@DPDK_25 24.11~rc1 + INTERNAL@INTERNAL 24.11.8 rte_rib6_create@DPDK_25 23.11 rte_rib6_find_existing@DPDK_25 23.11 rte_rib6_free@DPDK_25 23.11 @@ -8,10 +9,12 @@ rte_rib6_get_ip@DPDK_25 23.11 rte_rib6_get_nh@DPDK_25 23.11 rte_rib6_get_nxt@DPDK_25 23.11 + rte_rib6_get_parent@INTERNAL 24.11.8 rte_rib6_insert@DPDK_25 23.11 rte_rib6_lookup@DPDK_25 23.11 rte_rib6_lookup_exact@DPDK_25 23.11 rte_rib6_lookup_parent@DPDK_25 23.11 + rte_rib6_node_has_children@INTERNAL 24.11.8 rte_rib6_remove@DPDK_25 23.11 rte_rib6_set_nh@DPDK_25 23.11 rte_rib_create@DPDK_25 23.11 diff -Nru dpdk-24.11.4/debian/patches/disable_ppc64_autopkgtest_fails.patch dpdk-24.11.8/debian/patches/disable_ppc64_autopkgtest_fails.patch --- dpdk-24.11.4/debian/patches/disable_ppc64_autopkgtest_fails.patch 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/patches/disable_ppc64_autopkgtest_fails.patch 2026-10-28 05:10:52.000000000 +0000 @@ -5,11 +5,10 @@ Author: Luca Boccassi --- a/app/test/test_pdump.c +++ b/app/test/test_pdump.c -@@ -204,6 +204,11 @@ - test_pdump(void) - { - int ret = 0; -+ +@@ -208,6 +208,10 @@ + if (RTE_EXEC_ENV_IS_FREEBSD) + return TEST_SKIPPED; + +#if defined(__PPC64__) + return TEST_SKIPPED; +#endif diff -Nru dpdk-24.11.4/debian/patches/series dpdk-24.11.8/debian/patches/series --- dpdk-24.11.4/debian/patches/series 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/patches/series 2026-10-28 13:35:03.000000000 +0000 @@ -3,3 +3,4 @@ disable_riscv_autopkgtest_fails.patch add-install_tag-to-meson.patch doc-install-guides-and-api-docs-to-different-directory.patch +vhost-crypto-return-saved-vq.patch diff -Nru dpdk-24.11.4/debian/patches/vhost-crypto-return-saved-vq.patch dpdk-24.11.8/debian/patches/vhost-crypto-return-saved-vq.patch --- dpdk-24.11.4/debian/patches/vhost-crypto-return-saved-vq.patch 1970-01-01 00:00:00.000000000 +0000 +++ dpdk-24.11.8/debian/patches/vhost-crypto-return-saved-vq.patch 2026-10-28 13:35:03.000000000 +0000 @@ -0,0 +1,21 @@ +Description: Return the saved queue pointer after releasing crypto request mbufs + The request mbuf can be recycled by rte_mempool_put(), so reading its + vc_req->vq field afterward is unsafe. Return the queue pointer saved before + the mbuf was released. This is only the return-pointer hunk from the upstream + locking change; the rest of that commit is not backported here. +Author: David Marchand +Origin: upstream, https://github.com/DPDK/dpdk/commit/7b2ab3b1731e928d0a7ca66fa1d1e7448bf076a1 +Forwarded: not-needed +Last-Update: 2026-10-29 + +--- a/lib/vhost/vhost_crypto.c ++++ b/lib/vhost/vhost_crypto.c +@@ -1330,7 +1330,7 @@ vhost_crypto_finalize_one_request(struct + if (m_dst) + rte_mempool_put(m_dst->pool, (void *)m_dst); + +- return vc_req->vq; ++ return vq; + } + + static __rte_always_inline uint16_t diff -Nru dpdk-24.11.4/debian/tests/control dpdk-24.11.8/debian/tests/control --- dpdk-24.11.4/debian/tests/control 2025-12-24 14:21:11.000000000 +0000 +++ dpdk-24.11.8/debian/tests/control 2026-10-28 13:35:03.000000000 +0000 @@ -16,3 +16,4 @@ Restrictions: allow-stderr, skippable Depends: build-essential, jq, @builddeps@ Architecture: amd64 arm64 ppc64el riscv64 + diff -Nru dpdk-24.11.4/devtools/checkpatches.sh dpdk-24.11.8/devtools/checkpatches.sh --- dpdk-24.11.4/devtools/checkpatches.sh 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/devtools/checkpatches.sh 2026-10-14 13:10:05.000000000 +0000 @@ -294,10 +294,10 @@ current_file = ""; ret = 0; } - /^+++ b\// { + /^[+][+][+] b\// { current_file = $2; } - /^+.*__rte_experimental/ { + /^[+].*__rte_experimental/ { if (current_file ~ ".c$" ) { print "Please only put __rte_experimental tags in " \ "headers ("current_file")"; @@ -324,10 +324,10 @@ current_file = ""; ret = 0; } - /^+++ b\// { + /^[+][+][+] b\// { current_file = $2; } - /^+.*__rte_internal/ { + /^[+].*__rte_internal/ { if (current_file ~ ".c$" ) { print "Please only put __rte_internal tags in " \ "headers ("current_file")"; diff -Nru dpdk-24.11.4/doc/guides/nics/features/i40e.ini dpdk-24.11.8/doc/guides/nics/features/i40e.ini --- dpdk-24.11.4/doc/guides/nics/features/i40e.ini 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/features/i40e.ini 2026-10-14 13:10:05.000000000 +0000 @@ -16,7 +16,7 @@ Burst mode info = Y Power mgmt address monitor = Y Scattered Rx = Y -TSO = Y +TSO = P Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y diff -Nru dpdk-24.11.4/doc/guides/nics/features/iavf.ini dpdk-24.11.8/doc/guides/nics/features/iavf.ini --- dpdk-24.11.4/doc/guides/nics/features/iavf.ini 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/features/iavf.ini 2026-10-14 13:10:05.000000000 +0000 @@ -17,7 +17,7 @@ Power mgmt address monitor = Y MTU update = Y Scattered Rx = Y -TSO = Y +TSO = P Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y @@ -27,7 +27,7 @@ RSS reta update = Y VLAN filter = Y Traffic manager = Y -Inline crypto = Y +Inline crypto = P CRC offload = Y VLAN offload = P L3 checksum offload = Y diff -Nru dpdk-24.11.4/doc/guides/nics/features/ice.ini dpdk-24.11.8/doc/guides/nics/features/ice.ini --- dpdk-24.11.4/doc/guides/nics/features/ice.ini 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/features/ice.ini 2026-10-14 13:10:05.000000000 +0000 @@ -21,7 +21,7 @@ MTU update = Y Buffer split on Rx = P Scattered Rx = Y -TSO = Y +TSO = P Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y @@ -33,8 +33,8 @@ CRC offload = Y VLAN offload = Y QinQ offload = P -L3 checksum offload = P -L4 checksum offload = P +L3 checksum offload = Y +L4 checksum offload = Y Timestamp offload = P Inner L3 checksum = P Inner L4 checksum = P diff -Nru dpdk-24.11.4/doc/guides/nics/i40e.rst dpdk-24.11.8/doc/guides/nics/i40e.rst --- dpdk-24.11.4/doc/guides/nics/i40e.rst 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/i40e.rst 2026-10-14 13:10:05.000000000 +0000 @@ -440,12 +440,12 @@ The flex payload is selected from offset 0 to 15 of packet's payload by default, while it is masked out from matching. -Start ``testpmd`` with ``--disable-rss`` and ``--pkt-filter-mode=perfect``: +Start ``testpmd`` with ``--disable-rss``: .. code-block:: console .//app/dpdk-testpmd -l 0-15 -n 4 -- -i --disable-rss \ - --pkt-filter-mode=perfect --rxq=8 --txq=8 --nb-cores=8 \ + --rxq=8 --txq=8 --nb-cores=8 \ --nb-ports=1 Add a rule to direct ``ipv4-udp`` packet whose ``dst_ip=2.2.2.5, src_ip=2.2.2.3, src_port=32, dst_port=32`` to queue 1: diff -Nru dpdk-24.11.4/doc/guides/nics/igc.rst dpdk-24.11.8/doc/guides/nics/igc.rst --- dpdk-24.11.4/doc/guides/nics/igc.rst 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/igc.rst 2026-10-14 13:10:05.000000000 +0000 @@ -79,7 +79,7 @@ .. code-block:: console - ./dpdk-testpmd -l 4-8 -- i --rxq=4 --txq=4 --pkt-filter-mode=perfect --disable-rss + ./dpdk-testpmd -l 4-8 -- i --rxq=4 --txq=4 --disable-rss Add a rule to direct packet whose ``ether-type=0x801`` to queue 1: diff -Nru dpdk-24.11.4/doc/guides/nics/mlx5.rst dpdk-24.11.8/doc/guides/nics/mlx5.rst --- dpdk-24.11.4/doc/guides/nics/mlx5.rst 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/nics/mlx5.rst 2026-10-14 13:10:05.000000000 +0000 @@ -1372,27 +1372,36 @@ - ``tx_pp`` parameter [int] + This parameter applies to **ConnectX-6 Dx** only. If a nonzero value is specified the driver creates all necessary internal - objects to provide accurate packet send scheduling on mbuf timestamps. + objects (Clock Queue and Rearm Queue) + to provide accurate packet send scheduling on mbuf timestamps + using a cross-channel approach. The positive value specifies the scheduling granularity in nanoseconds, the packet send will be accurate up to specified digits. The allowed range is from 500 to 1 million of nanoseconds. The negative value specifies the module of granularity and engages the special test mode the check the schedule rate. By default (if the ``tx_pp`` is not specified) send scheduling on timestamps - feature is disabled. + feature is disabled on ConnectX-6 Dx. - Starting with ConnectX-7 the capability to schedule traffic directly - on timestamp specified in descriptor is provided, - no extra objects are needed anymore and scheduling capability - is advertised and handled regardless ``tx_pp`` parameter presence. + Starting with **ConnectX-7** the hardware provides a native wait-on-time capability + that inserts the scheduling delay directly in the WQE descriptor. + No Clock Queue or Rearm Queue is needed + and the ``tx_pp`` parameter is not required. + The driver automatically advertises send scheduling support + when the HCA wait-on-time capability is detected. + The ``tx_skew`` parameter can still be used on ConnectX-7 and above + to compensate for wire delay. - ``tx_skew`` parameter [int] The parameter adjusts the send packet scheduling on timestamps and represents the average delay between beginning of the transmitting descriptor processing by the hardware and appearance of actual packet data on the wire. The value - should be provided in nanoseconds and is valid only if ``tx_pp`` parameter is - specified. The default value is zero. + should be provided in nanoseconds + and applies to both ConnectX-6 Dx (with ``tx_pp``) + and ConnectX-7+ (wait-on-time) scheduling modes. + The default value is zero. - ``tx_vec_en`` parameter [int] diff -Nru dpdk-24.11.4/doc/guides/rel_notes/release_24_11.rst dpdk-24.11.8/doc/guides/rel_notes/release_24_11.rst --- dpdk-24.11.4/doc/guides/rel_notes/release_24_11.rst 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/rel_notes/release_24_11.rst 2026-10-14 13:10:05.000000000 +0000 @@ -1706,3 +1706,675 @@ * f2f75ffe14 net/mlx5/hws: fix ESP header match in strict mode * 98cf04bb90 test/graph: fix second run * 8a8c02d2bb vfio: fix custom containers in multiprocess + +24.11.5 Release Notes +--------------------- + + +24.11.5 Fixes +~~~~~~~~~~~~~ + +* app/dma-perf: fix buffer overflow with high core count +* app/dma-perf: fix reversed CPU copy +* app/graph: fix variable shadowing +* app/pdump: fix variable shadowing +* app/testpmd: fix DCB forwarding TC mismatch handling +* app/testpmd: fix flow queue job leaks +* app/testpmd: fix function names in logs +* app/testpmd: fix memory leak in port flow configure +* app/testpmd: fix variable shadowing +* bbdev: fix variable shadowing +* bitops: allow variable as first argument of shift macros +* bpf: disallow empty program +* bpf: fix add/subtract overflow +* bpf: fix signed shift overflows in ARM JIT +* bpf: fix starting with conditional jump +* bpf: fix x86 call stack alignment for external calls +* buildtools/test: suppress empty output +* bus/pci: fix variable shadowing +* common/cnxk: fix array out-of-bounds +* common/cnxk: fix engine capabilities fetch logic +* common/cnxk: fix width of DPC set field +* common/mlx5: fix bonding check +* common/mlx5: fix error logging for queue modify +* common/mlx5: fix MAC deletion on Linux +* common/mlx5: fix variable shadowing +* common/sfc_efx/base: fix flow control on legacy MCDI +* config/arm: fix 32-bit build +* crypto/cnxk: return decrypted data for RSA verify +* cryptodev: fix memory corruption in secondary process +* crypto/openssl: fix SM2 public key buffer overflow +* crypto/qat: align vector address +* doc: fix inline crypto feature status for iavf +* doc: fix TSO and checksum offload feature status for ice +* doc: fix TSO feature status for i40e +* doc: fix TSO feature status for iavf +* doc: remove references to obsolete testpmd flag +* eal: fix annotation on lcore variable allocator +* eal: fix cache guard for pedantic compilation +* eal: fix variable shadowing +* eal/linux: fix fbarray name collision in containers +* eal/linux: handle interrupt epoll events +* eal/x86: fix TSC frequency query +* ethdev: fix variable shadowing +* event/cnxk: fix crash on CN10K +* eventdev/eth_rx: fix crash with telemetry +* eventdev: fix variable shadowing +* examples/ethtool: fix error message about ports limit +* examples/ethtool: fix size of mempool name +* examples/fips_validation: fix dangling pointers +* examples/fips_validation: fix RSA memcpy +* examples/ipsec-secgw: fix build with glibc 2.43 +* examples/l2fwd-jobstats: fix stats availability +* examples/packet_ordering: fix format specifier for port ID +* examples/ptpclient: fix format specifier for port ID +* examples/vm_power: check truncation of socket path +* examples/vm_power_manager: fix format specifier for port ID +* fib: fix prefix addition handling +* hash: avoid leaking entries on RCU defer queue failure +* hash: fix maybe-uninitialized warnings on build +* hash: fix overflow of 32-bit offsets +* hash: fix unaligned access for CRC +* hash: free replaced data on overwrite when RCU is configured +* interrupts: add interrupt event info +* mbuf: fix packet copy +* mbuf: fix packet data read +* mem: check fbarray name truncation in secondary process +* net/af_packet: fix MTU set data size calculation +* net/af_xdp: fix external mbuf transmit +* net/axgbe: add 100 Mbps MAC speed select +* net/axgbe: fix 100M SGMII mode +* net/axgbe: fix auto-negotiation capabilities +* net/axgbe: fix MAC TCR speed select field width +* net/axgbe: fix SGMII auto-negotiation status bits +* net/bnxt: fix build with GCC 16 +* net/bnxt: fix commas instead of semicolons +* net/bnxt: fix crash in HWRM capabilities query +* net/bnxt: fix reported VLAN stripped flag for Thor2 +* net/bnxt: fix uninitialized read +* net/bnxt: remove unbuilt source files +* net/bnxt: support statistics query when port is stopped +* net/bnxt/tf_ulp: fix minsize build +* net/bonding: clamp Rx free threshold for small rings +* net/cpfl: fix variable shadowing +* net/dpaa2: add SG table walk upper bound in Rx +* net/dpaa2: fix burst mode info +* net/dpaa2: fix error packet dump +* net/dpaa2: fix L3/L4 checksum offload flags +* net/dpaa2: fix L4 packet type in slow parse path +* net/dpaa2: fix link after port stop/start +* net/dpaa2: fix resource leak on soft parser failure +* net/dpaa2: fix software taildrop buffer access +* net/dpaa2: fix spurious VLAN insertion on non-VLAN packet +* net/dpaa2: warn on Rx descriptor limit in high perf mode +* net/e1000: fix allocation of context desc for launch time +* net/e1000: fix variable shadowing +* net/e1000: use device timestamp for clock read in igc +* net: fix packet type for stacked VLAN +* net: fix variable shadowing +* net/hns3: fix outer UDP checksum with simple BD +* net/i40e: fix IPv6 GTPU handling +* net/i40e: fix QinQ stripping +* net/i40e: fix raw flow item validation +* net/i40e: fix unused variable +* net/i40e: fix variable shadowing +* net/i40e: move filter config to flow create +* net/i40e: validate raw flow items before dereferencing +* net/iavf: fix deletion of primary MAC address +* net/iavf: fix IPv4 flow subscription +* net/iavf: fix memory leak on egress IPsec flows +* net/iavf: fix memory leak on uninit +* net/iavf: fix reported max Tx and Rx queues +* net/iavf: fix struct size in IPsec status get +* net/iavf: negotiate PTP before reporting Rx timestamping +* net/ice/base: fix adjust timer programming for E830 +* net/ice/base: fix integer types in comparisons +* net/ice: check null scheduler root node +* net/ice: fix memory leak in DCF QoS bandwidth config +* net/ice: fix memory leak in FDIR flow parsing +* net/ice: fix priority mode printing in Tx scheduler dump +* net/ice: fix variable shadowing +* net/ice: re-enable strict priority on non-root levels +* net/idpf: fix typo in CQ scan threshold macro name +* net/intel: fix comma operator warnings +* net/intel: fix memory leak on Tx queue setup failure +* net/intel: update key length when getting RSS key +* net/ixgbe: add missing E610 MAC type checks +* net/ixgbe: fix memory leak in security flows +* net/ixgbe: fix potential null dereference in IPsec flow +* net/ixgbe: fix potential null dereference with IPsec config +* net/ixgbe: fix variable shadowing +* net/mana: fix CQE suppression handling on error completions +* net/mana: fix fast-path ops setup in secondary process +* net/mana: fix PD resource leak on device close +* net/memif: fix descriptor Tx flags corruption +* net/memif: fix multi-segment Rx corruption +* net/mlx4: fix fast-path ops setup in secondary process +* net/mlx5: allow MTU mismatch for running shared queue +* net/mlx5: check DevX disconnect/error interrupt events +* net/mlx5: fix bonding check +* net/mlx5: fix build with LTO +* net/mlx5: fix default memzone requirements in HWS +* net/mlx5: fix fast-path ops setup in secondary process +* net/mlx5: fix flex item capability check +* net/mlx5: fix flex parser creation length attribute +* net/mlx5: fix flow mark reading after reconfigure +* net/mlx5: fix HW flow counter query +* net/mlx5: fix internal HWS pattern template creation +* net/mlx5: fix IPv6 SRH flex node header length +* net/mlx5: fix IPv6 SRH flex parser initialization +* net/mlx5: fix job leak on indirect meter creation failure +* net/mlx5: fix memory leak after device spawn failure +* net/mlx5: fix meter ASO action leak on release to pool +* net/mlx5: fix MPESW PF probe for any number of ports +* net/mlx5: fix NAT64 HW registers calculation +* net/mlx5: fix port down in link detection failure +* net/mlx5: fix probing to allow BlueField Socket Direct +* net/mlx5: fix redundant control rules in promiscuous mode +* net/mlx5: fix send skew settings when using wait on time +* net/mlx5: fix shared Rx queue limitations +* net/mlx5: fix use-after-free in ASO management init +* net/mlx5: fix VLAN strip info for CQE compression +* net/mlx5: fix VXLAN and NVGRE encap in async flow API +* net/mlx5/hws: fix null dereference in rule skip +* net/mlx5/hws: fix stack alignment for ASan compatibility +* net/mlx5: report share group and queue ID +* net/mlx5/windows: fix MAC address ownership tracking +* net/mvpp2: fix variable shadowing +* net/netvsc: fix devargs memory leak on hotplug +* net/netvsc: fix double-free of primary Rx queue on uninit +* net/netvsc: fix event callback leak on Rx filter failure +* net/netvsc: fix race conditions on VF add/remove events +* net/netvsc: fix resource leak on init failure +* net/netvsc: fix resource leaks on MTU change +* net/netvsc: fix subchannel leak on device removal +* net/netvsc: support multi-process VF device removal +* net/netvsc: switch data path to synthetic on device stop +* net/nfb: fix bad pointer access in queue stats +* net/nfb: fix resources release +* net/nfb: stop only started queues in fail path +* net/nfb: use constant values for max Rx/Tx queues count +* net/nfb: use process private variable for internal +* net/r8169: ensure old mapping is used +* net/sfc: drop AUTO from FEC capabilities and fix comment +* net/sfc: fix reporting status of autonegotiation +* net/sfc: rework capability check that is done on FEC set +* net/tap: fix resource leaks in secondary process probe +* net/tap: fix resource leaks on creation failure +* net/tap: fix use-after-free on remote flow creation failure +* net/tap: free IPC reply buffer on queue count mismatch +* net/tap: free remote flow when implicit rule already exists +* net/tap: remove log when running without multiprocess +* net/tap: use correct length for interface names +* pcapng: chain additional mbuf when comment exceeds tailroom +* pcapng: document return values +* pcapng: fix variable shadowing +* pcapng: use malloc instead of fixed buffer size +* pdcp: add digest physical address +* pipeline: fix variable shadowing +* power: fix variable shadowing +* rcu: fix build with MSVC +* table: fix variable shadowing +* telemetry: fix adding dict in container array +* test: add file-prefix for all fast-tests on Linux +* test: add pause to synchronization spinloops +* test/atomic: scale test based on core count +* test/cfgfile: avoid temp filename truncation +* test/crypto: check for vdev args overflow +* test/crypto: fix mbuf segment number +* test: fix dependencies on net null driver +* test/mcslock: scale test based on core count +* test/memcpy: reduce alignment offset coverage +* test/pcapng: fix for Windows +* test/pcapng: skip test if null driver missing +* test/red: fix some undefined behaviour +* test/security: skip inline protocol test if no HW support +* test/stack: scale test based on core count +* test/table: avoid input line overflow +* test/timer: fix hang on secondary process failure +* test/timer: replace volatile with C11 atomics +* test/timer: scale test based on core count +* test/trace: fix parallel execution with traces enabled +* usertools/pmdinfo: fix search for PMD info string +* version: 24.11.5-rc1 +* vhost: fix descriptor chain bounds check in control queue +* vhost: fix mmap error check in VDUSE IOTLB miss handler +* vhost: fix use-after-free fdset during shutdown +* vhost: fix use-after-free race during cleanup +* vhost: fix virtqueue array size for control queue + +24.11.5 Validation +~~~~~~~~~~~~~~~~~~ + +* Intel(R) Testing + + * Basic Intel(R) NIC testing + + * Build & CFLAG compile: cover the build test combination with latest GCC/Clang version and the popular OS revision such as Ubuntu24.04.3, Ubuntu25.04, Fedora42, RHEL10, RHEL9.6, FreeBSD14.3, SUSE15.6, AzureLinux3.0, OpenAnolis8.10, OpenEuler24.04-SP2 + * i40E-(XXV710, X722) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. + * IXGBE-(E610) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. + * ICE-(E810, E2100) PF/VF: test scenarios including basic/Switch/Package Management/Flow Director/Advanced Tx/Advanced RSS/ACL/DCF/Flexible Descriptor, etc. + * IPsec: test scenarios including ipsec/ipsec-gw/ipsec library basic test - QAT&SW/FIB library, etc. + * Virtio: both function and performance test are covered. Such as PVP/Virtio_loopback/virtio-user loopback/virtio-net VM2VM perf testing/VMAWARE ESXI 8.0, etc. + * Cryptodev: test scenarios including Cryptodev API testing/CompressDev ISA-L/QAT/ZLIB PMD Testing/FIPS, etc. + * DLB: test scenarios including DLB2.0 and DLB2.5 + * Other: test scenarios including AF_XDP, Power, CBDMA, DSA + + * Performance test + + * Thoughput Performance + * Cryptodev Latency + * PF/VF NIC single core + * XXV710/E810 NIC Performance + + +* Nvidia(R) Testing + + * Basic functionality via testpmd/example applications + + * Tx/Rx + * xstats + * Timestamps + * Link status + * RTE flow and flow_director + * RSS + * VLAN filtering, stripping and insertion + * Checksum/TSO + * ptype + * link_status_interrupt example application + * l3fwd-power example application + * Multi-process example applications + * Hardware LRO tests + * Buffer Split tests + * Tx scheduling tests + + * BlueField-2 + + * DOCA 2.9.4 + * fw 24.43.4100 + + * ConnectX-7 + + * Ubuntu 22.04 + * Driver MLNX_OFED_LINUX-24.10-4.1.4.0 + * fw 28.43.4100 + + * ConnectX-6 Dx + + * Ubuntu 22.04 + * Driver MLNX_OFED_LINUX-24.10-4.1.4.0 + * fw 22.43.4100 + +24.11.6 Release Notes +--------------------- + + +24.11.6 Fixes +~~~~~~~~~~~~~ + +* docs: fix build issue due to missing spacing between paragraphs +* Revert "net: fix packet type for stacked VLAN" + +24.11.6 Validation +~~~~~~~~~~~~~~~~~~ + + + +24.11.7 Release Notes +--------------------- + + +24.11.7 Fixes +~~~~~~~~~~~~~ + +* app/bbdev: build on Windows +* app/dma-perf: fix hang with worker on main lcore +* app: remove use of strncpy +* app/testpmd: fix flow job list double-free on reattach +* app/testpmd: include IP fields in UDP RSS option +* app/testpmd: mask VLAN inner type in flow rule +* app/testpmd: mask VLAN TCI in flow rule +* app/testpmd: terminate process on second signal +* bitops: fix build with GCC 17 +* bpf/validate: fix BPF_ADD of pointer to a scalar +* bpf/validate: fix BPF_AND min calculations +* bpf/validate: fix BPF_DIV and BPF_MOD signed part +* bpf/validate: fix BPF_JGT/EBPF_JSGT no-jump max +* bpf/validate: fix BPF_JMP source range calculation +* bpf/validate: fix BPF_LDX | EBPF_DW signed range +* bpf/validate: fix BPF_LSH shift-out-of-bounds UB +* bpf/validate: fix BPF_MUL ranges minimum +* bpf/validate: fix BPF_MUL signed overflow UB +* bpf/validate: fix BPF_NEG of INT64_MIN and 0 +* bpf/validate: fix BPF_OR min calculations +* bpf/validate: fix BPF_SUB signed max zero case +* bpf/validate: fix BPF_XOR signed min calculation +* bpf/validate: prevent overflow when building graph +* bus/dpaa: fix FD leak for CCSR mmap +* bus/dpaa: fix FQ creation failure handling +* bus/dpaa: fix FQ query failure handling +* bus/fslmc: fix bus cleanup +* bus/ifpga: remove unused AFU lookup helper +* bus/pci: fix mapping leak in bus cleanup +* bus/vmbus: fix interrupt leak in cleanup +* cfgfile: prevent overflow on resize +* ci: update versions of actions in GHA +* cmdline: guard zero-size destination buffers +* cmdline: harden parser result buffer handling +* cmdline: prevent out-of-bounds read +* common/cnxk: add auth key length check in inbound SA +* common/cnxk: add cipher key length check in key set +* common/cnxk: fix event type for soft expiry +* common/cnxk: fix static analysis issues +* common/cnxk: fix thread-unsafe NIX telemetry parsing +* common/cnxk: fix TM link config selection in debug dump +* common/cnxk: fix xstats names query +* crypto/cnxk: enforce DES/3DES cipher key length +* crypto/cnxk: fix out-of-place AES-GCM +* cryptodev: reset pointer after failure in callback init +* crypto/ipsec_mb: avoid clearing SNOW3G digest in-place +* crypto/scheduler: fix session restore of pending enqueues +* crypto/virtio: remove explicit cookie allocation +* dev: report devargs truncation for multi-process hotplug +* devtools: fix regex matching literal plus in patches +* dma/cnxk: fix crash on secondary process cleanup +* dmadev: clarify reported completion index +* dmadev: validate telemetry parameters +* dma/dpaa2: propagate removal error +* dma/dpaa: fix out-of-bounds access in SG descriptor enqueue +* dma/odm: fix zero-length DMA transfer +* doc: fix some mldev model captions +* doc: fix stale packet pacing in mlx5 guide +* dts: fix topology capability comparison +* eal: add helper to initialize process-shared mutex +* eal/freebsd: fix memseg addresses in VA mode +* eal/windows: add getline function +* eal/windows: fix core count for more cores per NUMA +* ethdev: fix flow_ops_mutex for multi-process +* ethdev: fix out-of-bounds write in flex item conversion +* ethdev: fix out-of-bounds write in GENEVE option conversion +* ethdev: fix pointer check in GENEVE and raw flow copy +* ethdev: make telemetry parameter parsing thread-safe +* event/cnxk: fix static analysis issues +* eventdev/eth_rx: fix thread-unsafe telemetry parsing +* eventdev/eth_rx: reject out-of-range telemetry ID +* eventdev/timer: reject out-of-range telemetry ID +* examples/ipsec-secgw: drop packets in poll mode +* examples/l3fwd-power: fix latency query failure handling +* examples: remove artificial Tx queue limit +* examples: use strlcpy and strlcat +* examples/vm_power_manager: fix const discarding +* fib6: fix error code propagation on next hop update +* fib6: fix tbl8 reservation drift in trie +* interrupts: propagate epoll error +* ipc: avoid deadlock in async alarm callback +* ipc: fix log message in async request +* ipc: fix memory leak in async secondary path +* ipc: fix memory leaks on async request partial failure +* ipc: trigger async callback without peers +* ipc: use request ID instead of pointers +* ip_frag: drop IPv6 fragments with per-fragment headers +* ip_frag: fix unsafe tailq usage +* ip_frag: include protocol in IPv4 reassembly key +* ip_frag: randomize hash seed +* ip_frag: reject oversized reassembled datagrams +* maintainers: fix app/test attributions +* mem: fix data race in Linux hugepage prefault +* mem: update comment on virtual area reservation +* ml/cnxk: fix overwriting layer name during load +* mldev: fix some typos in Doxygen +* net/af_packet: fix indentation +* net/af_packet: fix parsing of numeric device args +* net/af_xdp: fix resource leak in close +* net/ark: fix null dereference on allocation failure +* net/ark: use standard IPv4 address parser +* net/atlantic: fix mbox mutex for multi-process +* net/axgbe: fix comma operator misuse +* net/axgbe: fix mutexes for multi-process +* net/bnxt: avoid link flap when setting flow control +* net/bnxt: avoid null Rx queue dereference +* net/bnxt: avoid queue use after free on close +* net/bnxt: clear stale Tx descriptor count +* net/bnxt: fix LRO capability reporting +* net/bnxt: fix mutexes for multi-process +* net/bnxt: fix NQ/CQ processing for interrupt handling +* net/bnxt: fix PTP timestamp flags in scalar Rx +* net/bnxt: fix QP resource count in backing store config +* net/bnxt: fix RSS hash mode configuration for VF +* net/bnxt: fix Rx timestamping for non-PTP packets +* net/bnxt: fix Tx address for external mbuf +* net/bnxt: modify check for short Tx BD +* net/bnxt: roll back Tx descriptors for invalid packets +* net/bnxt: skip timed Tx pacing setup when unsupported +* net/bnxt: support PTP for Thor2 +* net/bnxt: support PTP on Wh+ using HWRM interface +* net/bnxt: support Rx/Tx timestamp on Wh+ using HWRM +* net/bnxt/tf_core: check pool use allocation +* net/bonding: check mode before setting dedicated queues +* net/bonding: prevent crash on Rx/Tx from secondary process +* net/cnxk: fix telemetry SA info parameter parsing +* net/cnxk: fix underflow in LSO calculation +* net/dpaa2: add L4 destination port to RSS hash key +* net/dpaa2: fix Rx queue count for primary process +* net/dpaa2: use L4 port extraction for SCTP RSS +* net/dpaa: add null check in scheme delete +* net/dpaa: fix BMI xstats by ID +* net/dpaa: fix BMI xstats names +* net/dpaa: fix CGR modification +* net/dpaa: fix checksum offload with empty L3 length +* net/dpaa: fix device remove +* net/dpaa: fix interrupt unregister +* net/dpaa: fix mbuf leak in SG FD creation +* net/dpaa: fix port handle leak +* net/dpaa: fix xstats name for Tx undersized counter +* net/dpaa: remove duplicate packet types +* net/e1000/base: fix NVM loop bounds and pointer access +* net/e1000/base: fix possible variable overflow +* net/e1000/base: fix style +* net/e1000/base: propagate PHY control register write error +* net/e1000: check flex filter mask range +* net/e1000: fix igc RSS redirection table +* net/e1000: fix igc Tx descriptor ring wrap +* net/enetc: fix Tx BD structure +* net/enic: fix null dereference in flow mask check +* net/failsafe: fix hotplug mutex for multi-process +* net/gve: clear out shared memory region for statistics +* net/gve: copy data to QPL buffer when mbuf read does not +* net/gve: delay adding mbuf head to software ring +* net/gve: fix comma operator misuses +* net/gve: free context mbuf on later segment drop +* net/gve: increase range of DMA memzone IDs to 64 bits +* net/gve: restrict max ring size in GQ QPL to 2K +* net/gve: set mbuf to null in software ring after use +* net/hinic: fix mutexes for multi-process +* net/hns3: fix L4 checksum for tunnel packets +* net/i40e: activate alarm if interrupt delivery unavailable +* net/i40e/base: fix integer overflow in NVM timing logic +* net/i40e/base: fix loop counter width in DCB parsing +* net/i40e: fix blocking link wait on device start +* net/i40e: fix flexible payload filter +* net/i40e: fix simple Tx prepare rejecting tunnel type flags +* net/i40e: fix VLAN flow mask validation +* net/i40e: validate DDP segment header before use +* net/iavf: fix disabling of promiscuous modes on close +* net/iavf: fix duplicate VF reset during PF reset recovery +* net/iavf: fix event handler refcount leak on HW reset +* net/iavf: fix leak of flex metadata extraction field +* net/iavf: fix leak of IPsec crypto capabilities array +* net/iavf: fix leak of queue to traffic class mapping data +* net/iavf: fix local memory leaks in TM hierarchy commit +* net/iavf: fix memory leak on error when adding flow parser +* net/iavf: fix misleading admin queue failure logging +* net/iavf: fix race condition on link status change +* net/iavf: fix reset handling error log +* net/iavf: fix Rx packets statistics underflow +* net/iavf: fix scalar Rx path zero-length segment +* net/iavf: reject oversized frames in prep callback +* net/iavf: remove dead code in TM node parameter check +* net/iavf: remove PHC polling from Rx datapath +* net/iavf: wait for PF reset start before reinitializing +* net/ice: fix adapter stopped on device start failure +* net/ice: fix buffer leak in config of Tx queue TM node +* net/ice: fix DCF Rx packets statistics underflow +* net/ice: fix L2TPv2 outer MAC in training packet +* net/ice: fix Rx packets statistics underflow +* net/ice: fix shaper profile reference count tracking +* net/ice: fix TM hierarchy deletion +* net/ice: fix TM node ID validation against configured queues +* net/ice: reject unsupported flow item range +* net/ice: use configured outer TPID for VLAN filter in DVM +* net/intel: fix use of non-recommended string functions +* net/ixgbe: fix EEPROM read on copper media +* net/ixgbe: fix flow control frame byte adjustment +* net/ixgbe: fix good octets CRC adjustment +* net/ixgbe: fix L4 protocol mask handling +* net/ixgbe: fix MAC/VLAN item validation for ntuple +* net/ixgbe: fix non-shared data in IPsec session +* net/ixgbe: fix queue received bytes CRC adjustment +* net/ixgbe: fix SCTP protocol-only flow parsing +* net/ixgbe: fix shared PF pointer in representor +* net/ixgbe: reset flow state on clear paths +* net/mana: fix Rx mempool leak on port stop +* net/mlx5: fix double free in vectorized Rx recovery +* net/mlx5: fix flow counter race on query completion +* net/mlx5: fix handling of FCQ allocation failure +* net/mlx5: fix item prepending conditions +* net/mlx5: fix Rx split segment counter type +* net/mlx5: fix skipping PF representors +* net/mlx5: fix uninitialized skip count +* net/mlx5: prepend implicit items in sync flow creation +* net/mlx5: redirect LACP traffic for legacy E-Switch +* net/mlx5: remove nonsensical flow action class ID checks +* net/mlx5: use port index as representor index +* net/netvsc: retry full probe when IB device not ready +* net/netvsc: retry on SIOCGIFHWADDR failure during VF hotplug +* net/netvsc: retry VF hotplug until device disappears +* net/netvsc: retry when no matching MAC found +* net/nfp: fix null dereference in flower ctrl NFD3 Tx +* net/nfp: fix shifts in BAR size calculation +* net/ngbe: add CDR config for YT PHY +* net/ngbe: remove duplicate xstats counters +* net/ngbe: support USO +* net/octeontx/base: fix out-of-bounds DQ range lookup +* net/octeontx: fix overflow in device name formatting +* net/pcap: advertise Tx multi segment +* net/pcap: fix error accounting and backpressure on Tx +* net/pcap: fix Windows build +* net/pcap: reject non-Ethernet interfaces +* net/txgbe: enable Tx descriptor check per queue +* net/txgbe: fix link flow control config for Sapphire +* net/txgbe: fix mass of unknown interrupts +* net/txgbe: fix traffic class priority configuration +* net/txgbe: remove duplicate xstats counters +* net/txgbe: support USO +* pipeline: fix build with sanitizers or debug options +* power: fix off-by-one in uncore env bounds check +* power: remove duplicate uncore set frequency typedef +* power: validate enabled lcores in PMD management API +* ring: fix zero-copy burst API documentation +* security: harden telemetry parameter parsing +* spinlock: fix API comments +* spinlock: remove volatile qualifier +* tailq: fix name truncation +* telemetry: fix thread-unsafe command parsing +* test/dispatcher: preserve event opaque field +* test/eal: remove PCI probing for recursive calls +* test/eal: remove PCI probing for vdev tests +* test: fix failing tests on FreeBSD +* test/security: check for capabilities +* test/security: fix MTU calculation underflow +* test/security: remove fast-free Tx flag +* test/security: sync inline IPsec soft expiry check +* vdpa/nfp: fix double PCI unmap on unplug +* version: 24.11.7-rc1 + +24.11.7 Validation +~~~~~~~~~~~~~~~~~~ + +* Nvidia(R) Testing + + * Basic functionality via testpmd/example applications + + * Tx/Rx + * xstats + * Timestamps + * Link status + * RTE flow and flow_director + * RSS + * VLAN filtering, stripping and insertion + * Checksum/TSO + * ptype + * link_status_interrupt example application + * l3fwd-power example application + * Multi-process example applications + * Hardware LRO tests + * Buffer Split tests + * Tx scheduling tests + + * BlueField-2 + + * DOCA 2.9.5 + * fw 24.43.8016 + + * ConnectX-7 + + * Ubuntu 22.04 + * Driver MLNX_OFED_LINUX-24.10-5.1.6.1 + * fw 28.43.8016 + + * ConnectX-6 Dx + + * Ubuntu 22.04 + * Driver MLNX_OFED_LINUX-24.10-5.1.6.1 + * fw 22.43.8016 + +* Intel(R) Testing + + * Build & CFLAG compile: cover the build test with latest GCC/Clang version on the following OS + * Ubuntu26.04/Ubuntu25.10 + * RHEL9.6/RHEL10 + * Fedora43 + * FreeBSD15 + * SUSE16 + * OpenAnolis8.10 + * OpenEuler24.04-SP3 + * AzureLinux3.0 + + * Function tests + * Build & CFLAG compile: cover the build test combination with latest GCC/Clang version and the popular OS revision such as Ubuntu24.04.3, Ubuntu25.04, Fedora42, RHEL10, RHEL9.6, FreeBSD14.3, SUSE15.6, AzureLinux3.0, OpenAnolis8.10, OpenEuler24.04-SP2 + * i40E-(XXV710, X722) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. + * IXGBE-(E610, 82599) PF/VF: test scenarios including basic/RTE_FLOW/TSO/Jumboframe/checksum offload/mac_filter/VLAN/VXLAN/RSS, etc. + * ICE-(E810, E2100) PF/VF: test scenarios including basic/Switch/Package Management/Flow Director/Advanced Tx/Advanced RSS/ACL/DCF/Flexible Descriptor, etc. + * IPsec: test scenarios including ipsec/ipsec-gw/ipsec library basic test - QAT&SW/FIB library, etc. + * Virtio: both function and performance test are covered. Such as PVP/Virtio_loopback/virtio-user loopback/virtio-net VM2VM perf testing/VMAWARE ESXI 8.0, etc. + * Cryptodev: test scenarios including Cryptodev API testing/CompressDev ISA-L/QAT/ZLIB PMD Testing/FIPS, etc. + * DLB: test scenarios including DLB2.0 and DLB2.5 + * Other: test scenarios including AF_XDP, Power, CBDMA, DSA + + * Performance test + * Thoughput Performance + * Cryptodev Latency + * PF/VF NIC single core + * XXV710/E810 NIC Performance + +24.11.8 Release Notes +--------------------- + + +24.11.8 Fixes +~~~~~~~~~~~~~ + +* gso: fix overflow when writing to very small buffers (CVE-2026-100236) +* vhost: check number of queues for VDPA (CVE-2026-86856) +* vhost/crypto: catch incorrect request length (CVE-2026-86849) +* vhost/crypto: drop crypto session cache (CVE-2026-86845) +* vhost/crypto: fix TOCTOU OOB write in finalize path (CVE-2026-86846, CVE-2026-86848) +* vhost/crypto: fix write back chains termination (CVE-2026-86847) +* vhost: fix double-fetch vulnerability in control queue (CVE-2026-86562) +* vhost: fix header copy to multiple descriptors (CVE-2026-86566) +* vhost: fix indirect descriptor table double fetch (CVE-2026-93683) +* vhost: fix inflight descriptor table overflow (CVE-2026-86565) +* vhost: fix log base address mapping offset (CVE-2026-86563) +* vhost: fix missing memory size validation before mmap (CVE-2026-86561) +* vhost: fix out-of-bounds read in control virtqueue handler (CVE-2026-86562) +* vhost: fix VDUSE stale vring pointers after IOTLB invalidation (CVE-2026-86567) diff -Nru dpdk-24.11.4/doc/guides/tools/img/mldev_model_ops_subtest_a.svg dpdk-24.11.8/doc/guides/tools/img/mldev_model_ops_subtest_a.svg --- dpdk-24.11.4/doc/guides/tools/img/mldev_model_ops_subtest_a.svg 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/doc/guides/tools/img/mldev_model_ops_subtest_a.svg 2026-10-14 13:10:05.000000000 +0000 @@ -10,7 +10,7 @@ version="1.1" id="svg5" inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" - sodipodi:docname="mldev_model_ops_subtest_d.svg" + sodipodi:docname="mldev_model_ops_subtest_a.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -407,7 +407,7 @@ id="tspan390" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:5.64444px;font-family:Arial;-inkscape-font-specification:'Arial Bold';fill:#000000;stroke-width:0.5" x="-120.71075" - y="220.77164">mldev: model_ops / subtest D + y="220.77164">mldev: model_ops / subtest A mldev: model_ops / subtest A + y="220.32892">mldev: model_ops / subtest B mldev: model_ops / subest B + y="222.26495">mldev: model_ops / subtest D key); +#endif return -EIO; } @@ -1907,11 +1910,11 @@ cpu_relax(); DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ); res = mcr->result; - if (res == QM_MCR_RESULT_OK) - *fqd = mcr->queryfq.fqd; - hw_fqd_to_cpu(fqd); if (res != QM_MCR_RESULT_OK) return -EIO; + + *fqd = mcr->queryfq.fqd; + hw_fqd_to_cpu(fqd); return 0; } diff -Nru dpdk-24.11.4/drivers/bus/dpaa/base/qbman/qman_driver.c dpdk-24.11.8/drivers/bus/dpaa/base/qbman/qman_driver.c --- dpdk-24.11.4/drivers/bus/dpaa/base/qbman/qman_driver.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/dpaa/base/qbman/qman_driver.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) * * Copyright 2008-2016 Freescale Semiconductor Inc. - * Copyright 2017-2022 NXP + * Copyright 2017-2022, 2025-2026 NXP * */ @@ -247,7 +247,7 @@ const struct device_node *dt_node; size_t lenp; const u32 *chanid; - static int ccsr_map_fd; + int ccsr_map_fd; const uint32_t *qman_addr; uint64_t phys_addr; uint64_t regs_size; @@ -335,9 +335,9 @@ pr_err("Can not open /dev/mem for qman ccsr map\n"); return ccsr_map_fd; } - qman_ccsr_map = mmap(NULL, regs_size, PROT_READ | PROT_WRITE, MAP_SHARED, ccsr_map_fd, phys_addr); + close(ccsr_map_fd); if (qman_ccsr_map == MAP_FAILED) { pr_err("Can not map qman ccsr base\n"); return -EINVAL; diff -Nru dpdk-24.11.4/drivers/bus/fslmc/fslmc_vfio.c dpdk-24.11.8/drivers/bus/fslmc/fslmc_vfio.c --- dpdk-24.11.4/drivers/bus/fslmc/fslmc_vfio.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/fslmc/fslmc_vfio.c 2026-10-14 13:10:05.000000000 +0000 @@ -1378,7 +1378,7 @@ { struct rte_dpaa2_object *object = NULL; struct rte_dpaa2_driver *drv; - int ret, probe_all; + int ret; switch (dev->dev_type) { case DPAA2_IO: @@ -1396,22 +1396,9 @@ case DPAA2_ETH: case DPAA2_CRYPTO: case DPAA2_QDMA: - probe_all = rte_fslmc_bus.bus.conf.scan_mode != - RTE_BUS_SCAN_ALLOWLIST; - TAILQ_FOREACH(drv, &rte_fslmc_bus.driver_list, next) { - if (drv->drv_type != dev->dev_type) - continue; - if (rte_dev_is_probed(&dev->device)) - continue; - if (probe_all || - (dev->device.devargs && - dev->device.devargs->policy == - RTE_DEV_ALLOWED)) { - ret = drv->remove(dev); - if (ret) - DPAA2_BUS_ERR("Unable to remove"); - } - } + drv = dev->driver; + if (drv && drv->remove && drv->remove(dev)) + DPAA2_BUS_ERR("Unable to remove"); break; default: break; diff -Nru dpdk-24.11.4/drivers/bus/ifpga/bus_ifpga_driver.h dpdk-24.11.8/drivers/bus/ifpga/bus_ifpga_driver.h --- dpdk-24.11.4/drivers/bus/ifpga/bus_ifpga_driver.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/ifpga/bus_ifpga_driver.h 2026-10-14 13:10:05.000000000 +0000 @@ -117,16 +117,6 @@ } /** - * Find AFU by AFU name. - * - * @param name - * A pointer to AFU name string. - */ -__rte_internal -struct rte_afu_device * -rte_ifpga_find_afu_by_name(const char *name); - -/** * Register a ifpga afu device driver. * * @param driver diff -Nru dpdk-24.11.4/drivers/bus/ifpga/ifpga_bus.c dpdk-24.11.8/drivers/bus/ifpga/ifpga_bus.c --- dpdk-24.11.4/drivers/bus/ifpga/ifpga_bus.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/ifpga/ifpga_bus.c 2026-10-14 13:10:05.000000000 +0000 @@ -71,18 +71,6 @@ return NULL; } -struct rte_afu_device * -rte_ifpga_find_afu_by_name(const char *name) -{ - struct rte_afu_device *afu_dev = NULL; - - TAILQ_FOREACH(afu_dev, &ifpga_afu_dev_list, next) { - if (!strcmp(afu_dev->device.name, name)) - return afu_dev; - } - return NULL; -} - static const char * const valid_args[] = { #define IFPGA_ARG_NAME "ifpga" IFPGA_ARG_NAME, diff -Nru dpdk-24.11.4/drivers/bus/ifpga/version.map dpdk-24.11.8/drivers/bus/ifpga/version.map --- dpdk-24.11.4/drivers/bus/ifpga/version.map 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/ifpga/version.map 2026-10-14 13:10:05.000000000 +0000 @@ -3,7 +3,6 @@ rte_ifpga_driver_register; rte_ifpga_driver_unregister; - rte_ifpga_find_afu_by_name; local: *; }; diff -Nru dpdk-24.11.4/drivers/bus/pci/linux/pci.c dpdk-24.11.8/drivers/bus/pci/linux/pci.c --- dpdk-24.11.4/drivers/bus/pci/linux/pci.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/pci/linux/pci.c 2026-10-14 13:10:05.000000000 +0000 @@ -327,7 +327,6 @@ rte_pci_add_device(dev); } else { struct rte_pci_device *dev2; - int ret; TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); diff -Nru dpdk-24.11.4/drivers/bus/pci/linux/pci_vfio.c dpdk-24.11.8/drivers/bus/pci/linux/pci_vfio.c --- dpdk-24.11.4/drivers/bus/pci/linux/pci_vfio.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/pci/linux/pci_vfio.c 2026-10-14 13:10:05.000000000 +0000 @@ -810,7 +810,7 @@ } /* if we found our MSI-X BAR region, check if we can mmap it */ if (vfio_res->msix_table.bar_index != -1) { - int ret = pci_vfio_msix_is_mappable(vfio_dev_fd, + ret = pci_vfio_msix_is_mappable(vfio_dev_fd, vfio_res->msix_table.bar_index); if (ret < 0) { PCI_LOG(ERR, "Couldn't check if MSI-X BAR is mappable"); diff -Nru dpdk-24.11.4/drivers/bus/pci/pci_common.c dpdk-24.11.8/drivers/bus/pci/pci_common.c --- dpdk-24.11.4/drivers/bus/pci/pci_common.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/pci/pci_common.c 2026-10-14 13:10:05.000000000 +0000 @@ -440,6 +440,10 @@ error = -1; } dev->driver = NULL; + + if (drv->drv_flags & RTE_PCI_DRV_NEED_MAPPING) + rte_pci_unmap_device(dev); + dev->device.driver = NULL; free: diff -Nru dpdk-24.11.4/drivers/bus/pci/windows/pci.c dpdk-24.11.8/drivers/bus/pci/windows/pci.c --- dpdk-24.11.4/drivers/bus/pci/windows/pci.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/pci/windows/pci.c 2026-10-14 13:10:05.000000000 +0000 @@ -422,7 +422,6 @@ rte_pci_add_device(dev); } else { struct rte_pci_device *dev2 = NULL; - int ret; TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) { ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr); diff -Nru dpdk-24.11.4/drivers/bus/vmbus/vmbus_common.c dpdk-24.11.8/drivers/bus/vmbus/vmbus_common.c --- dpdk-24.11.4/drivers/bus/vmbus/vmbus_common.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/bus/vmbus/vmbus_common.c 2026-10-14 13:10:05.000000000 +0000 @@ -235,6 +235,7 @@ error = -1; rte_vmbus_unmap_device(dev); + rte_intr_instance_free(dev->intr_handle); dev->driver = NULL; dev->device.driver = NULL; diff -Nru dpdk-24.11.4/drivers/common/cnxk/cnxk_security.c dpdk-24.11.8/drivers/common/cnxk/cnxk_security.c --- dpdk-24.11.4/drivers/common/cnxk/cnxk_security.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/cnxk_security.c 2026-10-14 13:10:05.000000000 +0000 @@ -1151,22 +1151,33 @@ break; case RTE_CRYPTO_AUTH_MD5_HMAC: case RTE_CRYPTO_AUTH_SHA1_HMAC: - memcpy(in_sa->sha1_or_gcm.hmac_key, auth_key, - auth_key_len); - ctx_len = offsetof(struct roc_ie_on_inb_sa, - sha1_or_gcm.selector); + if (auth_key_len > (int)sizeof(in_sa->sha1_or_gcm.hmac_key)) { + plt_err("Auth key len %d exceeds max %zu for algo %u", auth_key_len, + sizeof(in_sa->sha1_or_gcm.hmac_key), auth_xform->auth.algo); + return -EINVAL; + } + memcpy(in_sa->sha1_or_gcm.hmac_key, auth_key, auth_key_len); + ctx_len = offsetof(struct roc_ie_on_inb_sa, sha1_or_gcm.selector); break; case RTE_CRYPTO_AUTH_SHA256_HMAC: case RTE_CRYPTO_AUTH_SHA384_HMAC: case RTE_CRYPTO_AUTH_SHA512_HMAC: + if (auth_key_len > (int)sizeof(in_sa->sha2.hmac_key)) { + plt_err("Auth key len %d exceeds max %zu for algo %u", auth_key_len, + sizeof(in_sa->sha2.hmac_key), auth_xform->auth.algo); + return -EINVAL; + } memcpy(in_sa->sha2.hmac_key, auth_key, auth_key_len); - ctx_len = offsetof(struct roc_ie_on_inb_sa, - sha2.selector); + ctx_len = offsetof(struct roc_ie_on_inb_sa, sha2.selector); break; case RTE_CRYPTO_AUTH_AES_XCBC_MAC: + if (auth_key_len > (int)sizeof(in_sa->aes_xcbc.key)) { + plt_err("Auth key len %d exceeds max %zu for algo %u", auth_key_len, + sizeof(in_sa->aes_xcbc.key), auth_xform->auth.algo); + return -EINVAL; + } memcpy(in_sa->aes_xcbc.key, auth_key, auth_key_len); - ctx_len = offsetof(struct roc_ie_on_inb_sa, - aes_xcbc.selector); + ctx_len = offsetof(struct roc_ie_on_inb_sa, aes_xcbc.selector); break; default: plt_err("Unsupported auth algorithm %u", auth_xform->auth.algo); diff -Nru dpdk-24.11.4/drivers/common/cnxk/cnxk_telemetry_nix.c dpdk-24.11.8/drivers/common/cnxk/cnxk_telemetry_nix.c --- dpdk-24.11.4/drivers/common/cnxk/cnxk_telemetry_nix.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/cnxk_telemetry_nix.c 2026-10-14 13:10:05.000000000 +0000 @@ -1015,76 +1015,56 @@ struct plt_tel_data *d) { struct nix_tel_node *node; - char *name, *param; char buf[1024]; + char *comma, *end; + unsigned long qid; int rc = -1; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) - goto exit; + if (params == NULL || !isdigit((unsigned char)params[0])) + return -1; - plt_strlcpy(buf, params, PCI_PRI_STR_SIZE + 1); - name = strtok(buf, ","); - if (name == NULL) - goto exit; - - param = strtok(NULL, "\0"); - - node = nix_tel_node_get_by_pcidev_name(name); - if (!node) - goto exit; + plt_strlcpy(buf, params, sizeof(buf)); /* was PCI_PRI_STR_SIZE + 1 */ + + /* params is "," */ + comma = strchr(buf, ','); + if (comma == NULL || !isdigit((unsigned char)comma[1])) + return -1; + *comma = '\0'; + + errno = 0; + qid = strtoul(comma + 1, &end, 10); + if (errno != 0 || (*end != '\0' && *end != ',')) + return -1; + + node = nix_tel_node_get_by_pcidev_name(buf); + if (node == NULL) + return -1; plt_tel_data_start_dict(d); if (strstr(cmd, "rq")) { - char *tok = strtok(param, ","); - int rq; - - if (!tok) - goto exit; - - rq = strtol(tok, NULL, 10); - if ((node->n_rq <= rq) || (rq < 0)) - goto exit; - + if (qid >= node->n_rq) + return -1; if (strstr(cmd, "ctx")) - rc = cnxk_tel_nix_rq_ctx(node->nix, rq, d); + rc = cnxk_tel_nix_rq_ctx(node->nix, qid, d); else - rc = cnxk_tel_nix_rq(node->rqs[rq], d); - + rc = cnxk_tel_nix_rq(node->rqs[qid], d); } else if (strstr(cmd, "cq")) { - char *tok = strtok(param, ","); - int cq; - - if (!tok) - goto exit; - - cq = strtol(tok, NULL, 10); - if ((node->n_cq <= cq) || (cq < 0)) - goto exit; - + if (qid >= node->n_cq) + return -1; if (strstr(cmd, "ctx")) - rc = cnxk_tel_nix_cq_ctx(node->nix, cq, d); + rc = cnxk_tel_nix_cq_ctx(node->nix, qid, d); else - rc = cnxk_tel_nix_cq(node->cqs[cq], d); - + rc = cnxk_tel_nix_cq(node->cqs[qid], d); } else if (strstr(cmd, "sq")) { - char *tok = strtok(param, ","); - int sq; - - if (!tok) - goto exit; - - sq = strtol(tok, NULL, 10); - if ((node->n_sq <= sq) || (sq < 0)) - goto exit; - + if (qid >= node->n_sq) + return -1; if (strstr(cmd, "ctx")) - rc = cnxk_tel_nix_sq_ctx(node->nix, sq, d); + rc = cnxk_tel_nix_sq_ctx(node->nix, qid, d); else - rc = cnxk_tel_nix_sq(node->sqs[sq], d); + rc = cnxk_tel_nix_sq(node->sqs[qid], d); } -exit: return rc; } diff -Nru dpdk-24.11.4/drivers/common/cnxk/hw/npa.h dpdk-24.11.8/drivers/common/cnxk/hw/npa.h --- dpdk-24.11.4/drivers/common/cnxk/hw/npa.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/hw/npa.h 2026-10-14 13:10:05.000000000 +0000 @@ -374,7 +374,8 @@ uint64_t fc_msh_dst : 11; uint64_t rsvd_438_435 : 4; uint64_t op_dpc_ena : 1; - uint64_t op_dpc_set : 6; + uint64_t op_dpc_set : 5; + uint64_t rsvd_637_637 : 1; uint64_t stream_ctx : 1; uint64_t unified_ctx : 1; uint64_t rsvd_511_448 : 64; /* W7 */ @@ -445,7 +446,8 @@ uint64_t fc_msh_dst : 11; uint64_t rsvd_630_627 : 4; uint64_t op_dpc_ena : 1; - uint64_t op_dpc_set : 6; + uint64_t op_dpc_set : 5; + uint64_t rsvd_637_637 : 1; uint64_t stream_ctx : 1; uint64_t rsvd_639 : 1; uint64_t rsvd_703_640 : 64; /* W10 */ diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_cpt_debug.c dpdk-24.11.8/drivers/common/cnxk/roc_cpt_debug.c --- dpdk-24.11.4/drivers/common/cnxk/roc_cpt_debug.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_cpt_debug.c 2026-10-14 13:10:05.000000000 +0000 @@ -25,29 +25,28 @@ cpt_dump(file, "W0: cookie \t0x%x\t\tmatch_id \t0x%04x \t", cpth->w0.cookie, cpth->w0.match_id); cpt_dump(file, "W0: err_sum \t%u \t", cpth->w0.err_sum); - cpt_dump(file, "W0: reas_sts \t0x%x\t\tet_owr \t%u\t\tpkt_fmt \t%u \t", - cpth->w0.reas_sts, cpth->w0.et_owr, cpth->w0.pkt_fmt); - cpt_dump(file, "W0: pad_len \t%u\t\tnum_frags \t%u\t\tpkt_out \t%u \t", - cpth->w0.pad_len, cpth->w0.num_frags, cpth->w0.pkt_out); + cpt_dump(file, "W0: reas_sts \t0x%x\t\tet_owr \t%u\t\tpkt_fmt \t%u \t", cpth->w0.reas_sts, + cpth->w0.et_owr, cpth->w0.pkt_fmt); + cpt_dump(file, "W0: pad_len \t%u\t\tnum_frags \t%u\t\tpkt_out \t%u \t", cpth->w0.pad_len, + cpth->w0.num_frags, cpth->w0.pkt_out); /* W1 */ - cpt_dump(file, "W1: wqe_ptr \t0x%016lx\t", - plt_be_to_cpu_64(cpth->wqe_ptr)); + cpt_dump(file, "W1: wqe_ptr \t0x%016" PRIx64 "\t", + (uint64_t)plt_be_to_cpu_64(cpth->wqe_ptr)); /* W2 */ - cpt_dump(file, "W2: frag_age \t0x%x\t\torig_pf_func \t0x%04x", - cpth->w2.frag_age, cpth->w2.orig_pf_func); - cpt_dump(file, "W2: il3_off \t0x%x\t\tfi_pad \t0x%x \t", - cpth->w2.il3_off, cpth->w2.fi_pad); + cpt_dump(file, "W2: frag_age \t0x%x\t\torig_pf_func \t0x%04x", cpth->w2.frag_age, + cpth->w2.orig_pf_func); + cpt_dump(file, "W2: il3_off \t0x%x\t\tfi_pad \t0x%x \t", cpth->w2.il3_off, cpth->w2.fi_pad); cpt_dump(file, "W2: fi_offset \t0x%x \t", cpth->w2.fi_offset); /* W3 */ - cpt_dump(file, "W3: hw_ccode \t0x%x\t\tuc_ccode \t0x%x\t\tspi \t0x%08x", - cpth->w3.hw_ccode, cpth->w3.uc_ccode, cpth->w3.spi); + cpt_dump(file, "W3: hw_ccode \t0x%x\t\tuc_ccode \t0x%x\t\tspi \t0x%08x", cpth->w3.hw_ccode, + cpth->w3.uc_ccode, cpth->w3.spi); /* W4 */ - cpt_dump(file, "W4: esn \t%" PRIx64 " \t OR frag1_wqe_ptr \t0x%" PRIx64, - cpth->esn, plt_be_to_cpu_64(cpth->frag1_wqe_ptr)); + cpt_dump(file, "W4: esn \t%" PRIx64 " \t OR frag1_wqe_ptr \t0x%" PRIx64, cpth->esn, + (uint64_t)plt_be_to_cpu_64(cpth->frag1_wqe_ptr)); /* offset of 0 implies 256B, otherwise it implies offset*8B */ offset = cpth->w2.fi_offset; diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_dev.c dpdk-24.11.8/drivers/common/cnxk/roc_dev.c --- dpdk-24.11.4/drivers/common/cnxk/roc_dev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_dev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1796,14 +1796,17 @@ rc = npa_lf_init(dev, pci_dev); if (rc) - goto stop_msg_thrd; + goto vf_flr_unregister; /* Setup LMT line base */ rc = dev_lmt_setup(dev); if (rc) - goto stop_msg_thrd; + goto vf_flr_unregister; return rc; +vf_flr_unregister: + if (!is_vf) + dev_vf_flr_unregister_irqs(pci_dev, dev); stop_msg_thrd: /* Exiting the mbox sync thread */ if (dev->sync.start_thread) { @@ -1812,10 +1815,14 @@ plt_thread_join(dev->sync.pfvf_msg_thread, NULL); } thread_fail: - pthread_mutex_destroy(&dev->sync.mutex); - pthread_cond_destroy(&dev->sync.pfvf_msg_cond); + if (pci_dev->max_vfs > 0) { + pthread_mutex_destroy(&dev->sync.mutex); + pthread_cond_destroy(&dev->sync.pfvf_msg_cond); + } iounmap: dev_vf_mbase_put(pci_dev, vf_mbase); + mbox_fini(&dev->mbox_vfpf); + mbox_fini(&dev->mbox_vfpf_up); mbox_unregister: dev_mbox_unregister_irq(pci_dev, dev); if (dev->ops) diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_mbox.h dpdk-24.11.8/drivers/common/cnxk/roc_mbox.h --- dpdk-24.11.4/drivers/common/cnxk/roc_mbox.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_mbox.h 2026-10-14 13:10:05.000000000 +0000 @@ -47,8 +47,8 @@ #define RVU_VF_VFPF_MBOX0 (0x0000) #define RVU_VF_VFPF_MBOX1 (0x0008) -#define MBOX_DOWN_MSG 1 -#define MBOX_UP_MSG 2 +#define MBOX_DOWN_MSG 1ULL +#define MBOX_UP_MSG 2ULL /* Mailbox message types */ #define MBOX_MSG_MASK 0xFFFF diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_nix_debug.c dpdk-24.11.8/drivers/common/cnxk/roc_nix_debug.c --- dpdk-24.11.4/drivers/common/cnxk/roc_nix_debug.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_nix_debug.c 2026-10-14 13:10:05.000000000 +0000 @@ -1141,7 +1141,7 @@ }; static uint8_t -nix_tm_reg_dump_prep(uint16_t hw_lvl, uint16_t schq, uint16_t link, +nix_tm_reg_dump_prep(struct nix *nix, uint16_t hw_lvl, uint16_t schq, uint64_t *reg, char regstr[][NIX_REG_NAME_SZ]) { FILE *file = NULL; @@ -1219,9 +1219,14 @@ snprintf(regstr[k++], NIX_REG_NAME_SZ, "NIX_AF_TL3[%u]_TOPOLOGY", schq); - reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, link); - snprintf(regstr[k++], NIX_REG_NAME_SZ, - "NIX_AF_TL3_TL2[%u]_LINK[%u]_CFG", schq, link); + /* Link configuration */ + if (!nix->sdp_link && + nix->tm_link_cfg_lvl == NIX_TXSCH_LVL_TL3) { + reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, nix->tx_link); + snprintf(regstr[k++], NIX_REG_NAME_SZ, + "NIX_AF_TL3_TL2[%u]_LINK[%u]_CFG", schq, + nix->tx_link); + } reg[k] = NIX_AF_TL3X_SCHEDULE(schq); snprintf(regstr[k++], NIX_REG_NAME_SZ, @@ -1252,9 +1257,14 @@ snprintf(regstr[k++], NIX_REG_NAME_SZ, "NIX_AF_TL2[%u]_TOPOLOGY", schq); - reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, link); - snprintf(regstr[k++], NIX_REG_NAME_SZ, - "NIX_AF_TL3_TL2[%u]_LINK[%u]_CFG", schq, link); + /* Link configuration */ + if (!nix->sdp_link && + nix->tm_link_cfg_lvl == NIX_TXSCH_LVL_TL2) { + reg[k] = NIX_AF_TL3_TL2X_LINKX_CFG(schq, nix->tx_link); + snprintf(regstr[k++], NIX_REG_NAME_SZ, + "NIX_AF_TL3_TL2[%u]_LINK[%u]_CFG", schq, + nix->tx_link); + } reg[k] = NIX_AF_TL2X_SCHEDULE(schq); snprintf(regstr[k++], NIX_REG_NAME_SZ, @@ -1361,8 +1371,7 @@ root = node; /* Dump registers only when HWRES is present */ - k = nix_tm_reg_dump_prep(node->hw_lvl, schq, nix->tx_link, reg, - regstr); + k = nix_tm_reg_dump_prep(nix, node->hw_lvl, schq, reg, regstr); if (!k) continue; @@ -1387,8 +1396,8 @@ /* Dump TL1 node data when root level is TL2 */ if (root && root->hw_lvl == NIX_TXSCH_LVL_TL2) { - k = nix_tm_reg_dump_prep(NIX_TXSCH_LVL_TL1, root->parent_hw_id, - nix->tx_link, reg, regstr); + k = nix_tm_reg_dump_prep(nix, NIX_TXSCH_LVL_TL1, + root->parent_hw_id, reg, regstr); if (!k) return; diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_nix_inl.c dpdk-24.11.8/drivers/common/cnxk/roc_nix_inl.c --- dpdk-24.11.4/drivers/common/cnxk/roc_nix_inl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_nix_inl.c 2026-10-14 13:10:05.000000000 +0000 @@ -825,7 +825,7 @@ do { roc_lmt_mov_seg((void *)lmt_base, &inst, 4); lmt_status = roc_lmt_submit_ldeor(lf->io_addr); - } while (lmt_status != 0); + } while (lmt_status == 0); /* Wait until CPT instruction completes */ do { diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_nix_inl_dev.c dpdk-24.11.8/drivers/common/cnxk/roc_nix_inl_dev.c --- dpdk-24.11.4/drivers/common/cnxk/roc_nix_inl_dev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_nix_inl_dev.c 2026-10-14 13:10:05.000000000 +0000 @@ -751,12 +751,11 @@ (entry.s.data0 << 7)); if (sa != NULL) { - uint64_t tmp = ~(uint32_t)0x0; - inl_dev->work_cb(&tmp, sa, (port_id << 8) | 0x1); - __atomic_store_n(ring_base + tail_l + 1, 0ULL, - __ATOMIC_RELAXED); - __atomic_fetch_add((uint32_t *)ring_base, 1, - __ATOMIC_ACQ_REL); + uint64_t tmp[2]; + tmp[0] = ~0ULL; + inl_dev->work_cb(tmp, sa, (port_id << 8) | 0x1); + __atomic_store_n(ring_base + tail_l + 1, 0ULL, __ATOMIC_RELAXED); + __atomic_fetch_add((uint32_t *)ring_base, 1, __ATOMIC_ACQ_REL); } else plt_err("Invalid SA"); diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_nix_stats.c dpdk-24.11.8/drivers/common/cnxk/roc_nix_stats.c --- dpdk-24.11.4/drivers/common/cnxk/roc_nix_stats.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_nix_stats.c 2026-10-14 13:10:05.000000000 +0000 @@ -503,46 +503,51 @@ struct idev_cfg *idev = idev_get_cfg(); uint64_t i, count = 0; - PLT_SET_USED(limit); - for (i = 0; i < CNXK_NIX_NUM_TX_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_tx_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_tx_xstats, i); count++; } for (i = 0; i < CNXK_NIX_NUM_RX_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_rx_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_rx_xstats, i); count++; } if (nix->inb_inl_dev && idev) { if (idev->nix_inl_dev) { for (i = 0; i < CNXK_INL_NIX_NUM_RX_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - inl_nix_rx_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, + inl_nix_rx_xstats, i); count++; } for (i = 0; i < CNXK_INL_NIX_RQ_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - inl_nix_rq_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, + inl_nix_rq_xstats, i); count++; } for (i = 0; i < PLT_DIM(inl_sw_xstats); i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, inl_sw_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, inl_sw_xstats, + i); count++; } } } for (i = 0; i < CNXK_NIX_NUM_QUEUE_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_q_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_q_xstats, i); count++; } if (roc_model_is_cn10k() || roc_model_is_cn20k()) { for (i = 0; i < CNXK_NIX_NUM_CN10K_RX_XSTATS; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - nix_cn10k_rx_xstats, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_cn10k_rx_xstats, i); count++; } } @@ -552,30 +557,29 @@ if (roc_model_is_cn9k()) { for (i = 0; i < CNXK_NIX_NUM_RX_XSTATS_CGX; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - nix_rx_xstats_cgx, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_rx_xstats_cgx, i); count++; } for (i = 0; i < CNXK_NIX_NUM_TX_XSTATS_CGX; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - nix_tx_xstats_cgx, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_tx_xstats_cgx, i); count++; } } else { for (i = 0; i < CNXK_NIX_NUM_RX_XSTATS_RPM; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - nix_rx_xstats_rpm, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_rx_xstats_rpm, i); count++; } for (i = 0; i < CNXK_NIX_NUM_TX_XSTATS_RPM; i++) { - NIX_XSTATS_NAME_PRINT(xstats_names, count, - nix_tx_xstats_rpm, i); + if (xstats_names && count < limit) + NIX_XSTATS_NAME_PRINT(xstats_names, count, nix_tx_xstats_rpm, i); count++; } } - return count; } diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_npa.c dpdk-24.11.8/drivers/common/cnxk/roc_npa.c --- dpdk-24.11.4/drivers/common/cnxk/roc_npa.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_npa.c 2026-10-14 13:10:05.000000000 +0000 @@ -856,6 +856,9 @@ struct npa_lf *lf = idev_npa_obj_get(); int rc = 0; + if (lf == NULL) + return NPA_ERR_DEVICE_NOT_BOUNDED; + plt_npa_dbg("lf=%p aura_handle=0x%" PRIx64, lf, aura_handle); rc = npa_aura_pool_pair_free(lf, aura_handle); if (rc) diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_ree.c dpdk-24.11.8/drivers/common/cnxk/roc_ree.c --- dpdk-24.11.4/drivers/common/cnxk/roc_ree.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_ree.c 2026-10-14 13:10:05.000000000 +0000 @@ -592,14 +592,15 @@ vf->block_address = ree_get_blkaddr(dev); if (!vf->block_address) { plt_err("Could not determine block PF number"); - goto fail; + rc = -ENODEV; + goto dev_fini; } /* Get number of queues available on the device */ rc = roc_ree_available_queues_get(vf, &nb_queues); if (rc) { plt_err("Could not determine the number of queues available"); - goto fail; + goto dev_fini; } /* Don't exceed the limits set per VF */ @@ -607,7 +608,8 @@ if (nb_queues == 0) { plt_err("No free queues available on the device"); - goto fail; + rc = -ENOSPC; + goto dev_fini; } vf->max_queues = nb_queues; @@ -618,18 +620,23 @@ rc = roc_ree_max_matches_get(vf, &max_matches); if (rc) { plt_err("Could not determine the maximum matches supported"); - goto fail; + goto dev_fini; } /* Don't exceed the limits set per VF */ max_matches = RTE_MIN(max_matches, REE_MAX_MATCHES_PER_VF); if (max_matches == 0) { plt_err("Could not determine the maximum matches supported"); - goto fail; + rc = -EIO; + goto dev_fini; } vf->max_matches = max_matches; plt_ree_dbg("Max matches supported by device: %d", vf->max_matches); + + return 0; +dev_fini: + dev_fini(dev, pci_dev); fail: return rc; } diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_se.c dpdk-24.11.8/drivers/common/cnxk/roc_se.c --- dpdk-24.11.4/drivers/common/cnxk/roc_se.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_se.c 2026-10-14 13:10:05.000000000 +0000 @@ -512,12 +512,22 @@ * less than 128. Pass it as regular AES-CBC cipher to CPT, but keep type in * se_ctx as AES_DOCSISBPI to skip block size checks in instruction preparation. */ + if (key_len > sizeof(fctx->enc.encr_key)) { + plt_err("Cipher key length %u exceeds max %zu", key_len, + sizeof(fctx->enc.encr_key)); + return -1; + } cpt_ciph_aes_key_type_set(fctx, key_len); fctx->enc.enc_cipher = ROC_SE_AES_CBC; memcpy(fctx->enc.encr_key, key, key_len); goto success; case ROC_SE_DES_DOCSISBPI: /* See case ROC_SE_DES3_CBC: for explanation */ + if (key_len * 3 > sizeof(fctx->enc.encr_key)) { + plt_err("DES-DOCSISBPI key length %u exceeds max %zu", key_len, + sizeof(fctx->enc.encr_key) / 3); + return -1; + } for (i = 0; i < 3; i++) memcpy(fctx->enc.encr_key + key_len * i, key, key_len); /* @@ -582,6 +592,11 @@ if (se_ctx->hash_type != ROC_SE_GMAC_TYPE) fctx->enc.enc_cipher = type; + if (key_len > sizeof(fctx->enc.encr_key)) { + plt_err("Cipher key length %u exceeds max %zu", key_len, + sizeof(fctx->enc.encr_key)); + return -1; + } memcpy(fctx->enc.encr_key, key, key_len); success: diff -Nru dpdk-24.11.4/drivers/common/cnxk/roc_se.h dpdk-24.11.8/drivers/common/cnxk/roc_se.h --- dpdk-24.11.4/drivers/common/cnxk/roc_se.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/cnxk/roc_se.h 2026-10-14 13:10:05.000000000 +0000 @@ -26,7 +26,7 @@ #define ROC_SE_MISC_MINOR_OP_DUMMY 0x04ULL #define ROC_SE_MISC_MINOR_OP_HW_SUPPORT 0x08ULL -#define ROC_SE_MAX_AAD_SIZE 64 +#define ROC_SE_MAX_AAD_SIZE 1024 #define ROC_SE_MAX_MAC_LEN 64 #define ROC_SE_OFF_CTRL_LEN 8 diff -Nru dpdk-24.11.4/drivers/common/idpf/idpf_common_rxtx.h dpdk-24.11.8/drivers/common/idpf/idpf_common_rxtx.h --- dpdk-24.11.4/drivers/common/idpf/idpf_common_rxtx.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/idpf/idpf_common_rxtx.h 2026-10-14 13:10:05.000000000 +0000 @@ -55,7 +55,7 @@ #define IDPF_VPMD_TX_MAX_BURST 32 #define IDPF_VPMD_DESCS_PER_LOOP 4 #define IDPF_RXQ_REARM_THRESH 64 -#define IDPD_TXQ_SCAN_CQ_THRESH 64 +#define IDPF_TXQ_SCAN_CQ_THRESH 64 #define IDPF_TX_CTYPE_NUM 8 /* MTS */ diff -Nru dpdk-24.11.4/drivers/common/idpf/idpf_common_rxtx_avx512.c dpdk-24.11.8/drivers/common/idpf/idpf_common_rxtx_avx512.c --- dpdk-24.11.4/drivers/common/idpf/idpf_common_rxtx_avx512.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/idpf/idpf_common_rxtx_avx512.c 2026-10-14 13:10:05.000000000 +0000 @@ -1150,7 +1150,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { idpf_singleq_vtx1(txdp, *pkt, flags); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do 4 at a time while possible, in bursts */ @@ -1188,7 +1188,7 @@ /* do any last ones */ while (nb_pkts) { idpf_singleq_vtx1(txdp, *pkt, flags); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } @@ -1301,7 +1301,7 @@ cq_qid = cq->tx_tail; - for (i = 0; i < IDPD_TXQ_SCAN_CQ_THRESH; i++) { + for (i = 0; i < IDPF_TXQ_SCAN_CQ_THRESH; i++) { if (cq_qid == cq->nb_tx_desc) { cq_qid = 0; cq->expected_gen_id ^= 1; @@ -1452,7 +1452,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { idpf_splitq_vtx1(txdp, *pkt, flags); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do 4 at a time while possible, in bursts */ @@ -1490,7 +1490,7 @@ /* do any last ones */ while (nb_pkts) { idpf_splitq_vtx1(txdp, *pkt, flags); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_common_os.c dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_common_os.c --- dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_common_os.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_common_os.c 2026-10-14 13:10:05.000000000 +0000 @@ -555,6 +555,14 @@ #endif /* HAVE_IBV_FLOW_DV_SUPPORT */ } +static bool +pci_addr_partial_match(const struct rte_pci_addr *addr1, const struct rte_pci_addr *addr2) +{ + return addr1->domain == addr2->domain && + addr1->bus == addr2->bus && + addr1->devid == addr2->devid; +} + static struct ibv_device * mlx5_os_get_ibv_device(const struct rte_pci_device *pci_dev) { @@ -576,17 +584,23 @@ } ret1 = mlx5_get_device_guid(addr, guid1, sizeof(guid1)); while (n-- > 0) { + bool pci_partial_match; + bool guid_match; + bool bond_match; + DRV_LOG(DEBUG, "Checking device \"%s\"..", ibv_list[n]->name); if (mlx5_get_pci_addr(ibv_list[n]->ibdev_path, &paddr) != 0) continue; if (ret1 > 0) ret2 = mlx5_get_device_guid(&paddr, guid2, sizeof(guid2)); + guid_match = ret1 > 0 && ret2 > 0 && memcmp(guid1, guid2, sizeof(guid1)) == 0; + pci_partial_match = pci_addr_partial_match(addr, &paddr); /* Bond device can bond secondary PCIe */ - if ((strstr(ibv_list[n]->name, "bond") && !is_vf_dev && - ((ret1 > 0 && ret2 > 0 && !memcmp(guid1, guid2, sizeof(guid1))) || - (addr->domain == paddr.domain && addr->bus == paddr.bus && - addr->devid == paddr.devid))) || - !rte_pci_addr_cmp(addr, &paddr)) { + bond_match = !is_vf_dev && + mlx5_os_is_device_bond(ibv_list[n]) && + (guid_match || pci_partial_match); + /* IB device matches either through bond or directly. */ + if (bond_match || !rte_pci_addr_cmp(addr, &paddr)) { ibv_match = ibv_list[n]; break; } @@ -1149,3 +1163,64 @@ mlx5_intr_callback_unregister(intr_handle, cb, cb_arg); rte_intr_instance_free(intr_handle); } + +bool +mlx5_os_is_device_bond(const void *dev) +{ + const struct ibv_device *ibdev; + char path[PATH_MAX]; + struct dirent *e; + DIR *net_dir; + bool result; + int ret; + + if (dev == NULL) + return false; + ibdev = dev; + + DRV_LOG(DEBUG, "Checking if %s ibdev belongs to bond", ibdev->name); + + ret = snprintf(path, sizeof(path), "%s/device/net", ibdev->ibdev_path); + if (ret < 0 || ret >= (int)sizeof(path)) { + DRV_LOG(DEBUG, "Unable to get netdevs path for IB device %s", ibdev->name); + return false; + } + + net_dir = opendir(path); + if (net_dir == NULL) { + DRV_LOG(DEBUG, "Unable to open directory %s (%s)", path, rte_strerror(errno)); + return false; + } + + result = false; + while ((e = readdir(net_dir)) != NULL) { + if (e->d_name[0] == '.') + continue; + + DRV_LOG(DEBUG, "Checking if %s netdev related to %s ibdev belongs to bond", + e->d_name, ibdev->name); + + ret = snprintf(path, sizeof(path), "/sys/class/net/%s/master/bonding", e->d_name); + if (ret < 0 || ret >= (int)sizeof(path)) { + DRV_LOG(DEBUG, "Unable to get bond path for %s netdev", e->d_name); + continue; + } + + if (access(path, F_OK) == 0) { + /* At least one associated netdev is part of a bond. */ + DRV_LOG(DEBUG, "Bonding path exists for %s netdev", e->d_name); + result = true; + goto end; + } + + DRV_LOG(DEBUG, "Unable to access bond path for %s netdev (%s)", + e->d_name, rte_strerror(errno)); + } + + DRV_LOG(DEBUG, "No bonded netdev related to %s ibdev found", + ibdev->name); + +end: + closedir(net_dir); + return result; +} diff -Nru dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_common_os.h dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_common_os.h --- dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_common_os.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_common_os.h 2026-10-14 13:10:05.000000000 +0000 @@ -311,4 +311,13 @@ mlx5_os_interrupt_handler_destroy(struct rte_intr_handle *intr_handle, rte_intr_callback_fn cb, void *cb_arg); +/** + * Return true if given IB device is associated with a networking bond. + * + * @param dev[in] + * Pointer to IB device. + */ +__rte_internal +bool mlx5_os_is_device_bond(const void *dev); + #endif /* RTE_PMD_MLX5_COMMON_OS_H_ */ diff -Nru dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_nl.c dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_nl.c --- dpdk-24.11.4/drivers/common/mlx5/linux/mlx5_nl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/linux/mlx5_nl.c 2026-10-14 13:10:05.000000000 +0000 @@ -577,8 +577,8 @@ } req = { .hdr = { .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), - .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | - NLM_F_EXCL | NLM_F_ACK, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | + (add ? NLM_F_CREATE | NLM_F_EXCL : 0), .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH, }, .ndm = { @@ -608,7 +608,6 @@ goto error; return 0; error: -#ifdef RTE_LIBRTE_MLX5_DEBUG { char m[RTE_ETHER_ADDR_FMT_SIZE]; @@ -618,7 +617,6 @@ iface_idx, add ? "add" : "remove", m, strerror(rte_errno)); } -#endif return -rte_errno; } diff -Nru dpdk-24.11.4/drivers/common/mlx5/mlx5_devx_cmds.c dpdk-24.11.8/drivers/common/mlx5/mlx5_devx_cmds.c --- dpdk-24.11.4/drivers/common/mlx5/mlx5_devx_cmds.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/mlx5_devx_cmds.c 2026-10-14 13:10:05.000000000 +0000 @@ -1594,12 +1594,11 @@ } ret = mlx5_glue->devx_obj_modify(rq->obj, in, sizeof(in), out, sizeof(out)); - if (ret) { - DRV_LOG(ERR, "Failed to modify RQ using DevX"); - rte_errno = errno; - return -errno; + if (ret || MLX5_FW_STATUS(out)) { + DEVX_DRV_LOG(ERR, out, "RQ modify", "rq_id", rq->id); + return MLX5_DEVX_ERR_RC(ret); } - return ret; + return 0; } /* @@ -2029,12 +2028,11 @@ MLX5_SET(sqc, sq_ctx, hairpin_peer_vhca, sq_attr->hairpin_peer_vhca); ret = mlx5_glue->devx_obj_modify(sq->obj, in, sizeof(in), out, sizeof(out)); - if (ret) { - DRV_LOG(ERR, "Failed to modify SQ using DevX"); - rte_errno = errno; - return -rte_errno; + if (ret || MLX5_FW_STATUS(out)) { + DEVX_DRV_LOG(ERR, out, "SQ modify", "sq_id", sq->id); + return MLX5_DEVX_ERR_RC(ret); } - return ret; + return 0; } /* diff -Nru dpdk-24.11.4/drivers/common/mlx5/mlx5_prm.h dpdk-24.11.8/drivers/common/mlx5/mlx5_prm.h --- dpdk-24.11.4/drivers/common/mlx5/mlx5_prm.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/mlx5_prm.h 2026-10-14 13:10:05.000000000 +0000 @@ -5443,8 +5443,8 @@ uint16_t checksum; uint16_t flow_tag_high; struct { - uint8_t reserved; uint8_t hdr_type; + uint8_t reserved; }; }; uint16_t stride_idx; diff -Nru dpdk-24.11.4/drivers/common/mlx5/version.map dpdk-24.11.8/drivers/common/mlx5/version.map --- dpdk-24.11.4/drivers/common/mlx5/version.map 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/version.map 2026-10-14 13:10:05.000000000 +0000 @@ -149,6 +149,7 @@ mlx5_nl_get_mtu_bounds; # WINDOWS_NO_EXPORT mlx5_os_get_physical_device_ctx; + mlx5_os_is_device_bond; # WINDOWS_NO_EXPORT mlx5_os_umem_dereg; mlx5_os_umem_reg; diff -Nru dpdk-24.11.4/drivers/common/mlx5/windows/mlx5_glue.h dpdk-24.11.8/drivers/common/mlx5/windows/mlx5_glue.h --- dpdk-24.11.4/drivers/common/mlx5/windows/mlx5_glue.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/mlx5/windows/mlx5_glue.h 2026-10-14 13:10:05.000000000 +0000 @@ -16,7 +16,7 @@ #endif #ifndef HAVE_MLX5DV_DR -enum mlx5dv_dr_domain_type { unused, }; +enum mlx5dv_dr_domain_type { MLX5_UNUSED_DOMAIN_TYPE }; struct mlx5dv_dr_domain; struct mlx5dv_dr_action; #endif diff -Nru dpdk-24.11.4/drivers/common/sfc_efx/base/ef10_mac.c dpdk-24.11.8/drivers/common/sfc_efx/base/ef10_mac.c --- dpdk-24.11.4/drivers/common/sfc_efx/base/ef10_mac.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/common/sfc_efx/base/ef10_mac.c 2026-10-14 13:10:05.000000000 +0000 @@ -273,6 +273,7 @@ efx_mcdi_req_t req; EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_MAC_IN_LEN, MC_CMD_SET_MAC_OUT_LEN); + uint32_t fcntl; efx_rc_t rc; req.emr_cmd = MC_CMD_SET_MAC; @@ -299,13 +300,29 @@ SET_MAC_IN_REJECT_UNCST, 0, SET_MAC_IN_REJECT_BRDCST, 0); - /* - * Flow control, whether it is auto-negotiated or not, - * is set via the PHY advertised capabilities. When set to - * automatic the MAC will use the PHY settings to determine - * the flow control settings. - */ - MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, MC_CMD_FCNTL_AUTO); + if (epp->ep_fcntl_autoneg != B_FALSE) { + fcntl = MC_CMD_FCNTL_AUTO; + } else { + switch (epp->ep_fcntl) { + case 0: + fcntl = MC_CMD_FCNTL_OFF; + break; + case EFX_FCNTL_RESPOND: + fcntl = MC_CMD_FCNTL_RESPOND; + break; + case EFX_FCNTL_GENERATE: + fcntl = MC_CMD_FCNTL_GENERATE; + break; + case EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE: + fcntl = MC_CMD_FCNTL_BIDIR; + break; + default: + rc = EINVAL; + goto fail1; + } + } + + MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, fcntl); /* Include the Ethernet frame checksum in RX packets if it's required */ MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_IN_FLAGS, @@ -321,7 +338,7 @@ */ if (req.emr_rc != EACCES) { rc = req.emr_rc; - goto fail1; + goto fail2; } } @@ -338,6 +355,8 @@ return (0); +fail2: + EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); diff -Nru dpdk-24.11.4/drivers/crypto/cnxk/cnxk_ae.h dpdk-24.11.8/drivers/crypto/cnxk/cnxk_ae.h --- dpdk-24.11.4/drivers/crypto/cnxk/cnxk_ae.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/cnxk/cnxk_ae.h 2026-10-14 13:10:05.000000000 +0000 @@ -1591,9 +1591,10 @@ break; case RTE_CRYPTO_ASYM_OP_VERIFY: if (rsa_ctx->padding.type == RTE_CRYPTO_RSA_PADDING_NONE) { - rsa->sign.length = rsa_ctx->n.length; - if (memcmp(rptr, rsa->message.data, rsa->message.length)) - cop->status = RTE_CRYPTO_OP_STATUS_ERROR; + /* Application compares decrypted data with message for SW padding schemes + */ + rsa->cipher.length = rsa_ctx->n.length; + memcpy(rsa->cipher.data, rptr, rsa->cipher.length); } else { /* Get length of signed output */ rsa->sign.length = rte_cpu_to_be_16(*((uint16_t *)rptr)); diff -Nru dpdk-24.11.4/drivers/crypto/cnxk/cnxk_cryptodev_ops.c dpdk-24.11.8/drivers/crypto/cnxk/cnxk_cryptodev_ops.c --- dpdk-24.11.4/drivers/crypto/cnxk/cnxk_cryptodev_ops.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/cnxk/cnxk_cryptodev_ops.c 2026-10-14 13:10:05.000000000 +0000 @@ -52,6 +52,9 @@ (RTE_ALIGN_CEIL(ROC_MAX_SG_IN_OUT_CNT, 4) >> 2) * ROC_SG_ENTRY_SIZE), 8); + /* Space for discarding AAD bytes from output stream in GCM OOP */ + len += ROC_SE_MAX_AAD_SIZE; + return len; } diff -Nru dpdk-24.11.4/drivers/crypto/cnxk/cnxk_se.h dpdk-24.11.8/drivers/crypto/cnxk/cnxk_se.h --- dpdk-24.11.4/drivers/crypto/cnxk/cnxk_se.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/cnxk/cnxk_se.h 2026-10-14 13:10:05.000000000 +0000 @@ -403,8 +403,28 @@ if (unlikely(req_flags & ROC_SE_SINGLE_BUF_INPLACE)) { i = fill_sg_comp_from_buf_min(scatter_comp, i, params->bufs, &size); } else { - i = fill_sg_comp_from_iov(scatter_comp, i, params->dst_iov, 0, - &size, aad_buf, aad_offset); + uint32_t dst_offset = 0; + + if (passthrough_len) { + if (unlikely(passthrough_len > ROC_SE_MAX_AAD_SIZE)) { + plt_dp_err( + "Passthrough length %u exceeds reserved space %u", + passthrough_len, ROC_SE_MAX_AAD_SIZE); + return -1; + } + uint64_t meta_passthrough = + (uint64_t)params->meta_buf.vaddr + + params->meta_buf.size - ROC_SE_MAX_AAD_SIZE; + i = fill_sg_comp(scatter_comp, i, meta_passthrough, + passthrough_len); + size -= passthrough_len; + dst_offset = passthrough_len; + aad_offset = 0; + } + if (size) + i = fill_sg_comp_from_iov(scatter_comp, i, params->dst_iov, + dst_offset, &size, aad_buf, + aad_offset); } if (unlikely(size)) { plt_dp_err("Insufficient buffer space," @@ -426,8 +446,28 @@ if (unlikely(req_flags & ROC_SE_SINGLE_BUF_INPLACE)) { i = fill_sg_comp_from_buf_min(scatter_comp, i, params->bufs, &size); } else { - i = fill_sg_comp_from_iov(scatter_comp, i, params->dst_iov, 0, - &size, aad_buf, aad_offset); + uint32_t dst_offset = 0; + + if (passthrough_len) { + if (unlikely(passthrough_len > ROC_SE_MAX_AAD_SIZE)) { + plt_dp_err( + "Passthrough length %u exceeds reserved space %u", + passthrough_len, ROC_SE_MAX_AAD_SIZE); + return -1; + } + uint64_t meta_passthrough = + (uint64_t)params->meta_buf.vaddr + + params->meta_buf.size - ROC_SE_MAX_AAD_SIZE; + i = fill_sg_comp(scatter_comp, i, meta_passthrough, + passthrough_len); + size -= passthrough_len; + dst_offset = passthrough_len; + aad_offset = 0; + } + if (size) + i = fill_sg_comp_from_iov(scatter_comp, i, params->dst_iov, + dst_offset, &size, aad_buf, + aad_offset); } if (unlikely(size)) { @@ -601,8 +641,28 @@ i = fill_sg2_comp_from_buf_min(scatter_comp, i, params->bufs, &size); } else { - i = fill_sg2_comp_from_iov(scatter_comp, i, params->dst_iov, 0, - &size, aad_buf, aad_offset); + uint32_t dst_offset = 0; + + if (passthrough_len) { + if (unlikely(passthrough_len > ROC_SE_MAX_AAD_SIZE)) { + plt_dp_err( + "Passthrough length %u exceeds reserved space %u", + passthrough_len, ROC_SE_MAX_AAD_SIZE); + return -1; + } + uint64_t meta_passthrough = + (uint64_t)params->meta_buf.vaddr + + params->meta_buf.size - ROC_SE_MAX_AAD_SIZE; + i = fill_sg2_comp(scatter_comp, i, meta_passthrough, + passthrough_len); + size -= passthrough_len; + dst_offset = passthrough_len; + aad_offset = 0; + } + if (size) + i = fill_sg2_comp_from_iov(scatter_comp, i, params->dst_iov, + dst_offset, &size, aad_buf, + aad_offset); } if (unlikely(size)) { plt_dp_err("Insufficient buffer space," @@ -625,8 +685,28 @@ i = fill_sg2_comp_from_buf_min(scatter_comp, i, params->bufs, &size); } else { - i = fill_sg2_comp_from_iov(scatter_comp, i, params->dst_iov, 0, - &size, aad_buf, aad_offset); + uint32_t dst_offset = 0; + + if (passthrough_len) { + if (unlikely(passthrough_len > ROC_SE_MAX_AAD_SIZE)) { + plt_dp_err( + "Passthrough length %u exceeds reserved space %u", + passthrough_len, ROC_SE_MAX_AAD_SIZE); + return -1; + } + uint64_t meta_passthrough = + (uint64_t)params->meta_buf.vaddr + + params->meta_buf.size - ROC_SE_MAX_AAD_SIZE; + i = fill_sg2_comp(scatter_comp, i, meta_passthrough, + passthrough_len); + size -= passthrough_len; + dst_offset = passthrough_len; + aad_offset = 0; + } + if (size) + i = fill_sg2_comp_from_iov(scatter_comp, i, params->dst_iov, + dst_offset, &size, aad_buf, + aad_offset); } if (unlikely(size)) { @@ -2201,9 +2281,14 @@ return -1; } - if (c_form->key.length < cipher_key_len) { - plt_dp_err("Invalid cipher params keylen %u", - c_form->key.length); + if (enc_type == ROC_SE_DES3_CBC || enc_type == ROC_SE_DES3_ECB || + enc_type == ROC_SE_DES_DOCSISBPI) { + if (c_form->key.length != cipher_key_len) { + plt_dp_err("Invalid cipher params keylen %u", c_form->key.length); + return -1; + } + } else if (c_form->key.length < cipher_key_len) { + plt_dp_err("Invalid cipher params keylen %u", c_form->key.length); return -1; } diff -Nru dpdk-24.11.4/drivers/crypto/ipsec_mb/pmd_snow3g.c dpdk-24.11.8/drivers/crypto/ipsec_mb/pmd_snow3g.c --- dpdk-24.11.4/drivers/crypto/ipsec_mb/pmd_snow3g.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/ipsec_mb/pmd_snow3g.c 2026-10-14 13:10:05.000000000 +0000 @@ -157,7 +157,8 @@ for (i = 0; i < num_ops; i++) { if ((session->op == IPSEC_MB_OP_HASH_VERIFY_THEN_DECRYPT || session->op == IPSEC_MB_OP_HASH_GEN_THEN_ENCRYPT) && - ops[i]->sym->m_dst != NULL) { + ops[i]->sym->m_dst != NULL && + ops[i]->sym->m_dst != ops[i]->sym->m_src) { digest_appended[i] = snow3g_digest_appended_in_src(ops[i]); /* Clear unencrypted digest from diff -Nru dpdk-24.11.4/drivers/crypto/openssl/rte_openssl_pmd_ops.c dpdk-24.11.8/drivers/crypto/openssl/rte_openssl_pmd_ops.c --- dpdk-24.11.4/drivers/crypto/openssl/rte_openssl_pmd_ops.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/openssl/rte_openssl_pmd_ops.c 2026-10-14 13:10:05.000000000 +0000 @@ -1470,6 +1470,12 @@ goto err_sm2; } + if (xform->ec.q.x.length >= sizeof(pubkey) || + xform->ec.q.y.length >= + sizeof(pubkey) - xform->ec.q.x.length) { + OPENSSL_LOG(ERR, "SM2 public key coordinates too large"); + goto err_sm2; + } memset(pubkey, 0, sizeof(pubkey)); pubkey[0] = 0x04; len += 1; diff -Nru dpdk-24.11.4/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h dpdk-24.11.8/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h --- dpdk-24.11.4/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/qat/dev/qat_crypto_pmd_gens.h 2026-10-14 13:10:05.000000000 +0000 @@ -443,6 +443,21 @@ n_dst > QAT_SYM_SGL_MAX_NUMBER)) return -1; + /* For crypto API only: try to align the in-place buffers*/ + if (op != NULL && likely(n_dst == 0) && likely(!is_sgl)) { + rte_iova_t offset = src_vec[0].iova & RTE_CACHE_LINE_MASK; + if (offset) { + rte_iova_t buff_addr = rte_mbuf_iova_get(op->sym->m_src); + /* make sure src_data_start is still within the buffer */ + if (src_vec[0].iova - offset >= buff_addr) { + src_vec[0].iova -= offset; + src_vec[0].len += offset; + ofs->ofs.auth.head += offset; + ofs->ofs.cipher.head += offset; + } + } + } + if (likely(!is_sgl)) { src_data_start = src_vec[0].iova; tl_src = total_len_src = @@ -503,24 +518,6 @@ dst_data_start = src_data_start; } - /* For crypto API only try to align the in-place buffers*/ - if (op != NULL && likely(n_dst == 0)) { - uint16_t offset = src_data_start & RTE_CACHE_LINE_MASK; - if (offset) { - rte_iova_t buff_addr = rte_mbuf_iova_get(op->sym->m_src); - /* make sure src_data_start is still within the buffer */ - if (src_data_start - offset >= buff_addr) { - src_data_start -= offset; - dst_data_start = src_data_start; - ofs->ofs.auth.head += offset; - ofs->ofs.cipher.head += offset; - tl_src += offset; - total_len_src = tl_src; - total_len_dst = tl_src; - } - } - } - req->comn_mid.src_data_addr = src_data_start; req->comn_mid.dest_data_addr = dst_data_start; req->comn_mid.src_length = total_len_src; diff -Nru dpdk-24.11.4/drivers/crypto/scheduler/scheduler_multicore.c dpdk-24.11.8/drivers/crypto/scheduler/scheduler_multicore.c --- dpdk-24.11.4/drivers/crypto/scheduler/scheduler_multicore.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/scheduler/scheduler_multicore.c 2026-10-14 13:10:05.000000000 +0000 @@ -191,11 +191,11 @@ worker->qp_id, &enq_ops[pending_enq_ops_idx], pending_enq_ops); - if (processed_ops < pending_deq_ops) + if (processed_ops < pending_enq_ops) scheduler_retrieve_sessions( &enq_ops[pending_enq_ops_idx + processed_ops], - pending_deq_ops - processed_ops); + pending_enq_ops - processed_ops); pending_enq_ops -= processed_ops; pending_enq_ops_idx += processed_ops; inflight_ops += processed_ops; diff -Nru dpdk-24.11.4/drivers/crypto/virtio/virtio_cryptodev.c dpdk-24.11.8/drivers/crypto/virtio/virtio_cryptodev.c --- dpdk-24.11.4/drivers/crypto/virtio/virtio_cryptodev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/crypto/virtio/virtio_cryptodev.c 2026-10-14 13:10:05.000000000 +0000 @@ -295,8 +295,6 @@ unsigned int vq_size, size; struct virtio_crypto_hw *hw = dev->data->dev_private; struct virtqueue *vq = NULL; - uint32_t i = 0; - uint32_t j; PMD_INIT_FUNC_TRACE(); @@ -358,17 +356,6 @@ "Cannot create mempool"); goto mpool_create_err; } - for (i = 0; i < vq_size; i++) { - vq->vq_descx[i].cookie = - rte_zmalloc("crypto PMD op cookie pointer", - sizeof(struct virtio_crypto_op_cookie), - RTE_CACHE_LINE_SIZE); - if (vq->vq_descx[i].cookie == NULL) { - VIRTIO_CRYPTO_DRV_LOG_ERR("Failed to " - "alloc mem for cookie"); - goto cookie_alloc_err; - } - } } vq->hw = hw; @@ -432,12 +419,6 @@ vring_addr_err: rte_memzone_free(mz); mz_reserve_err: -cookie_alloc_err: - rte_mempool_free(vq->mpool); - if (i != 0) { - for (j = 0; j < i; j++) - rte_free(vq->vq_descx[j].cookie); - } mpool_create_err: rte_free(vq); return -ENOMEM; diff -Nru dpdk-24.11.4/drivers/dma/cnxk/cnxk_dmadev.c dpdk-24.11.8/drivers/dma/cnxk/cnxk_dmadev.c --- dpdk-24.11.4/drivers/dma/cnxk/cnxk_dmadev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/dma/cnxk/cnxk_dmadev.c 2026-10-14 13:10:05.000000000 +0000 @@ -581,6 +581,9 @@ dmadev->fp_obj->completed_status = cnxk_dmadev_completed_status; dmadev->fp_obj->burst_capacity = cnxk_damdev_burst_capacity; + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return 0; + if (roc_model_is_cn10k()) { dpivf->is_cn10k = true; dmadev->fp_obj->copy = cn10k_dmadev_copy; diff -Nru dpdk-24.11.4/drivers/dma/dpaa/dpaa_qdma.c dpdk-24.11.8/drivers/dma/dpaa/dpaa_qdma.c --- dpdk-24.11.4/drivers/dma/dpaa/dpaa_qdma.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/dma/dpaa/dpaa_qdma.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2021-2024 NXP + * Copyright 2021-2026 NXP */ #include @@ -827,6 +827,11 @@ } } + if (num == 0 || num > FSL_QDMA_SG_MAX_ENTRY) { + DPAA_QDMA_ERR("Invalid scatter-gather entry count: num=%u", num); + return -EINVAL; + } + ft->desc_ssge[num - 1].final = 1; ft->desc_dsge[num - 1].final = 1; csgf_src->length = total_len; diff -Nru dpdk-24.11.4/drivers/dma/dpaa2/dpaa2_qdma.c dpdk-24.11.8/drivers/dma/dpaa2/dpaa2_qdma.c --- dpdk-24.11.4/drivers/dma/dpaa2/dpaa2_qdma.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/dma/dpaa2/dpaa2_qdma.c 2026-10-14 13:10:05.000000000 +0000 @@ -1740,7 +1740,7 @@ if (ret) DPAA2_QDMA_ERR("Device cleanup failed"); - return 0; + return ret; } static struct rte_dpaa2_driver rte_dpaa2_qdma_pmd; diff -Nru dpdk-24.11.4/drivers/dma/odm/odm_dmadev.c dpdk-24.11.8/drivers/dma/odm/odm_dmadev.c --- dpdk-24.11.4/drivers/dma/odm/odm_dmadev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/dma/odm/odm_dmadev.c 2026-10-14 13:10:05.000000000 +0000 @@ -108,6 +108,9 @@ vq = &odm->vq[vchan]; + if (unlikely(!length)) + return -EINVAL; + h = length; h |= ((uint64_t)length << 32); @@ -259,14 +262,20 @@ pending_submit_len = vq->pending_submit_len; pending_submit_cnt = vq->pending_submit_cnt; - if (unlikely(nb_src > 4 || nb_dst > 4)) + if (unlikely(!nb_src || nb_src > 4 || !nb_dst || nb_dst > 4)) return -EINVAL; - for (i = 0; i < nb_src; i++) + for (i = 0; i < nb_src; i++) { + if (unlikely(!src[i].length)) + return -EINVAL; s_sz += src[i].length; + } - for (i = 0; i < nb_dst; i++) + for (i = 0; i < nb_dst; i++) { + if (unlikely(!dst[i].length)) + return -EINVAL; d_sz += dst[i].length; + } if (s_sz != d_sz) return -EINVAL; @@ -339,6 +348,9 @@ .s.nlst = 1, }; + if (unlikely(!length)) + return -EINVAL; + h = (uint64_t)length; switch (pattern) { diff -Nru dpdk-24.11.4/drivers/event/cnxk/cn10k_eventdev.c dpdk-24.11.8/drivers/event/cnxk/cn10k_eventdev.c --- dpdk-24.11.4/drivers/event/cnxk/cn10k_eventdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/event/cnxk/cn10k_eventdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -663,7 +663,7 @@ struct rte_eventdev *event_dev = cnxk_eth_dev->evdev_priv; struct cnxk_sso_evdev *evdev = cnxk_sso_pmd_priv(event_dev); - evdev->rx_offloads |= flags; + evdev->rx_offloads |= (uint64_t)flags; if (ptp_en) evdev->tstamp[port_id] = &cnxk_eth_dev->tstamp; else @@ -678,8 +678,12 @@ struct rte_eth_dev *dev = &rte_eth_devices[port_id]; struct cnxk_eth_dev *cnxk_eth_dev = dev->data->dev_private; struct rte_eventdev *event_dev = cnxk_eth_dev->evdev_priv; - struct cnxk_sso_evdev *evdev = cnxk_sso_pmd_priv(event_dev); + struct cnxk_sso_evdev *evdev; + + if (event_dev == NULL) + return; + evdev = cnxk_sso_pmd_priv(event_dev); evdev->rx_offloads |= flags; cn10k_sso_fp_fns_set((struct rte_eventdev *)(uintptr_t)event_dev); eventdev_fops_update(event_dev); diff -Nru dpdk-24.11.4/drivers/event/cnxk/cnxk_eventdev.c dpdk-24.11.8/drivers/event/cnxk/cnxk_eventdev.c --- dpdk-24.11.4/drivers/event/cnxk/cnxk_eventdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/event/cnxk/cnxk_eventdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -566,7 +566,7 @@ else if (*s == ']') end = s; - if (start && start < end) { + if (start && end && start < end) { *end = 0; fn(start + 1, opaque); s = end; diff -Nru dpdk-24.11.4/drivers/event/cnxk/cnxk_eventdev_adptr.c dpdk-24.11.8/drivers/event/cnxk/cnxk_eventdev_adptr.c --- dpdk-24.11.4/drivers/event/cnxk/cnxk_eventdev_adptr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/event/cnxk/cnxk_eventdev_adptr.c 2026-10-14 13:10:05.000000000 +0000 @@ -275,7 +275,7 @@ return rc; } - dev->rx_offloads |= cnxk_eth_dev->rx_offload_flags; + dev->rx_offloads |= (uint64_t)cnxk_eth_dev->rx_offload_flags; return 0; } @@ -312,7 +312,7 @@ { struct cnxk_eth_dev *cnxk_eth_dev = eth_dev->data->dev_private; struct cnxk_sso_evdev *dev = cnxk_sso_pmd_priv(event_dev); - dev->rx_offloads |= cnxk_eth_dev->rx_offload_flags; + dev->rx_offloads |= (uint64_t)cnxk_eth_dev->rx_offload_flags; return 0; } diff -Nru dpdk-24.11.4/drivers/event/cnxk/cnxk_tim_evdev.c dpdk-24.11.8/drivers/event/cnxk/cnxk_tim_evdev.c --- dpdk-24.11.4/drivers/event/cnxk/cnxk_tim_evdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/event/cnxk/cnxk_tim_evdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -508,7 +508,7 @@ else continue; - if (start && start < end) { + if (start && end && start < end) { *end = 0; cnxk_tim_parse_ring_param(start + 1, opaque); start = end; diff -Nru dpdk-24.11.4/drivers/ml/cnxk/cn10k_ml_ops.c dpdk-24.11.8/drivers/ml/cnxk/cn10k_ml_ops.c --- dpdk-24.11.4/drivers/ml/cnxk/cn10k_ml_ops.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/ml/cnxk/cn10k_ml_ops.c 2026-10-14 13:10:05.000000000 +0000 @@ -671,9 +671,6 @@ rte_memcpy(&layer->glow.metadata, buffer, sizeof(struct cn10k_ml_model_metadata)); cn10k_ml_model_metadata_update(&layer->glow.metadata); - /* Set layer name */ - rte_memcpy(layer->name, layer->glow.metadata.model.name, MRVL_ML_MODEL_NAME_LEN); - /* Enable support for batch_size of 256 */ if (layer->glow.metadata.model.batch_size == 0) layer->batch_size = 256; diff -Nru dpdk-24.11.4/drivers/net/af_packet/rte_eth_af_packet.c dpdk-24.11.8/drivers/net/af_packet/rte_eth_af_packet.c --- dpdk-24.11.4/drivers/net/af_packet/rte_eth_af_packet.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/af_packet/rte_eth_af_packet.c 2026-10-14 13:10:05.000000000 +0000 @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include #include #include @@ -75,7 +77,7 @@ }; struct pmd_internals { - unsigned nb_queues; + unsigned int nb_queues; int if_index; char *if_name; @@ -500,7 +502,7 @@ static int eth_link_update(struct rte_eth_dev *dev, - int wait_to_complete __rte_unused) + int wait_to_complete __rte_unused) { const struct pmd_internals *internals = dev->data->dev_private; struct rte_eth_link *dev_link = &dev->data->dev_link; @@ -520,11 +522,11 @@ static int eth_rx_queue_setup(struct rte_eth_dev *dev, - uint16_t rx_queue_id, - uint16_t nb_rx_desc __rte_unused, - unsigned int socket_id __rte_unused, - const struct rte_eth_rxconf *rx_conf __rte_unused, - struct rte_mempool *mb_pool) + uint16_t rx_queue_id, + uint16_t nb_rx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_rxconf *rx_conf __rte_unused, + struct rte_mempool *mb_pool) { struct pmd_internals *internals = dev->data->dev_private; struct pkt_rx_queue *pkt_q = &internals->rx_queue[rx_queue_id]; @@ -555,10 +557,10 @@ static int eth_tx_queue_setup(struct rte_eth_dev *dev, - uint16_t tx_queue_id, - uint16_t nb_tx_desc __rte_unused, - unsigned int socket_id __rte_unused, - const struct rte_eth_txconf *tx_conf __rte_unused) + uint16_t tx_queue_id, + uint16_t nb_tx_desc __rte_unused, + unsigned int socket_id __rte_unused, + const struct rte_eth_txconf *tx_conf __rte_unused) { struct pmd_internals *internals = dev->data->dev_private; @@ -575,7 +577,7 @@ int ret; int s; unsigned int data_size = internals->req.tp_frame_size - - TPACKET2_HDRLEN; + TPACKET2_HDRLEN + sizeof(struct sockaddr_ll); if (mtu > data_size) return -EINVAL; @@ -685,8 +687,8 @@ */ static int open_packet_iface(const char *key __rte_unused, - const char *value __rte_unused, - void *extra_args) + const char *value __rte_unused, + void *extra_args) { int *sockfd = extra_args; @@ -702,16 +704,16 @@ static int rte_pmd_init_internals(struct rte_vdev_device *dev, - const int sockfd, - const unsigned nb_queues, - unsigned int blocksize, - unsigned int blockcnt, - unsigned int framesize, - unsigned int framecnt, + const int sockfd, + const unsigned int nb_queues, + unsigned int blocksize, + unsigned int blockcnt, + unsigned int framesize, + unsigned int framecnt, unsigned int qdisc_bypass, - struct pmd_internals **internals, - struct rte_eth_dev **eth_dev, - struct rte_kvargs *kvlist) + struct pmd_internals **internals, + struct rte_eth_dev **eth_dev, + struct rte_kvargs *kvlist) { const char *name = rte_vdev_device_name(dev); const unsigned int numa_node = dev->device.numa_node; @@ -739,7 +741,7 @@ if (pair == NULL) { PMD_LOG(ERR, "%s: no interface specified for AF_PACKET ethdev", - name); + name); return -1; } @@ -748,7 +750,7 @@ name, numa_node); *internals = rte_zmalloc_socket(name, sizeof(**internals), - 0, numa_node); + 0, numa_node); if (*internals == NULL) return -1; @@ -988,10 +990,46 @@ return -1; } +/* Parse an unsigned integer device argument. */ +static int +parse_uint(const char *key, const char *value, + unsigned int *out, unsigned long limit) +{ + unsigned long val; + char *endptr; + + if (value == NULL) { + PMD_LOG(ERR, "no value for argument \"%s\"", key); + return -1; + } + + /* Skip leading whitespace so a leading sign can be detected. */ + while (isspace((unsigned char)*value)) + value++; + + /* strtoul() silently accepts and negates a leading '-'. */ + if (*value == '\0' || *value == '-') { + PMD_LOG(ERR, "invalid value \"%s\" for argument \"%s\"", + value, key); + return -1; + } + + errno = 0; + val = strtoul(value, &endptr, 10); + if (errno != 0 || *endptr != '\0' || val > limit) { + PMD_LOG(ERR, "invalid value \"%s\" for argument \"%s\"", + value, key); + return -1; + } + + *out = (unsigned int)val; + return 0; +} + static int rte_eth_from_packet(struct rte_vdev_device *dev, - int const *sockfd, - struct rte_kvargs *kvlist) + int const *sockfd, + struct rte_kvargs *kvlist) { const char *name = rte_vdev_device_name(dev); struct pmd_internals *internals = NULL; @@ -1017,53 +1055,53 @@ for (k_idx = 0; k_idx < kvlist->count; k_idx++) { pair = &kvlist->pairs[k_idx]; if (strstr(pair->key, ETH_AF_PACKET_NUM_Q_ARG) != NULL) { - qpairs = atoi(pair->value); + if (parse_uint(pair->key, pair->value, + &qpairs, RTE_MAX_QUEUES_PER_PORT) < 0) + return -1; if (qpairs < 1) { PMD_LOG(ERR, "%s: invalid qpairs value", - name); + name); return -1; } continue; } if (strstr(pair->key, ETH_AF_PACKET_BLOCKSIZE_ARG) != NULL) { - blocksize = atoi(pair->value); + if (parse_uint(pair->key, pair->value, &blocksize, UINT_MAX) < 0) + return -1; if (!blocksize) { PMD_LOG(ERR, "%s: invalid blocksize value", - name); + name); return -1; } continue; } if (strstr(pair->key, ETH_AF_PACKET_FRAMESIZE_ARG) != NULL) { - framesize = atoi(pair->value); + if (parse_uint(pair->key, pair->value, &framesize, UINT_MAX) < 0) + return -1; if (!framesize) { PMD_LOG(ERR, "%s: invalid framesize value", - name); + name); return -1; } continue; } if (strstr(pair->key, ETH_AF_PACKET_FRAMECOUNT_ARG) != NULL) { - framecount = atoi(pair->value); + if (parse_uint(pair->key, pair->value, &framecount, UINT_MAX) < 0) + return -1; if (!framecount) { PMD_LOG(ERR, "%s: invalid framecount value", - name); + name); return -1; } continue; } if (strstr(pair->key, ETH_AF_PACKET_QDISC_BYPASS_ARG) != NULL) { - qdisc_bypass = atoi(pair->value); - if (qdisc_bypass > 1) { - PMD_LOG(ERR, - "%s: invalid bypass value", - name); + if (parse_uint(pair->key, pair->value, &qdisc_bypass, 1) < 0) return -1; - } continue; } } @@ -1071,7 +1109,7 @@ if (framesize > blocksize) { PMD_LOG(ERR, "%s: AF_PACKET MMAP frame size exceeds block size!", - name); + name); return -1; } @@ -1140,7 +1178,7 @@ if (rte_kvargs_count(kvlist, ETH_AF_PACKET_IFACE_ARG) == 1) { ret = rte_kvargs_process(kvlist, ETH_AF_PACKET_IFACE_ARG, - &open_packet_iface, &sockfd); + &open_packet_iface, &sockfd); if (ret < 0) goto exit; } diff -Nru dpdk-24.11.4/drivers/net/af_xdp/rte_eth_af_xdp.c dpdk-24.11.8/drivers/net/af_xdp/rte_eth_af_xdp.c --- dpdk-24.11.4/drivers/net/af_xdp/rte_eth_af_xdp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/af_xdp/rte_eth_af_xdp.c 2026-10-14 13:10:05.000000000 +0000 @@ -558,7 +558,7 @@ for (i = 0; i < nb_pkts; i++) { mbuf = bufs[i]; - if (mbuf->pool == umem->mb_pool) { + if (RTE_MBUF_DIRECT(mbuf) && mbuf->pool == umem->mb_pool) { if (!xsk_ring_prod__reserve(&txq->tx, 1, &idx_tx)) { kick_tx(txq, cq); if (!xsk_ring_prod__reserve(&txq->tx, 1, @@ -1025,12 +1025,10 @@ if (rte_atomic_fetch_sub_explicit(&rxq->umem->refcnt, 1, rte_memory_order_acquire) - 1 == 0) xdp_umem_destroy(rxq->umem); - - /* free pkt_tx_queue */ - rte_free(rxq->pair); - rte_free(rxq); } - + /* Free Tx and Rx queue arrays */ + rte_free(internals->tx_queues); + rte_free(internals->rx_queues); /* * MAC is not allocated dynamically, setting it to NULL would prevent * from releasing it in rte_eth_dev_release_port. diff -Nru dpdk-24.11.4/drivers/net/ark/ark_ethdev.c dpdk-24.11.8/drivers/net/ark/ark_ethdev.c --- dpdk-24.11.4/drivers/net/ark/ark_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ark/ark_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -439,6 +439,10 @@ sizeof(struct ark_adapter), RTE_CACHE_LINE_SIZE, rte_socket_id()); + if (eth_dev->data->dev_private == NULL) { + ARK_PMD_LOG(ERR, "Memory allocation for dev_private failed\n"); + goto error; + } memcpy(eth_dev->data->dev_private, ark, sizeof(struct ark_adapter)); diff -Nru dpdk-24.11.4/drivers/net/ark/ark_pktchkr.c dpdk-24.11.8/drivers/net/ark/ark_pktchkr.c --- dpdk-24.11.4/drivers/net/ark/ark_pktchkr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ark/ark_pktchkr.c 2026-10-14 13:10:05.000000000 +0000 @@ -4,9 +4,12 @@ #include #include +#include +#include #include #include +#include #include "ark_pktchkr.h" #include "ark_logs.h" @@ -374,12 +377,11 @@ static int32_t parse_ipv4_string(char const *ip_address) { - unsigned int ip[4]; + struct in_addr addr; - if (sscanf(ip_address, "%u.%u.%u.%u", - &ip[0], &ip[1], &ip[2], &ip[3]) != 4) + if (inet_pton(AF_INET, ip_address, &addr) != 1) return 0; - return ip[3] + ip[2] * 0x100 + ip[1] * 0x10000ul + ip[0] * 0x1000000ul; + return rte_be_to_cpu_32(addr.s_addr); } void diff -Nru dpdk-24.11.4/drivers/net/ark/ark_pktgen.c dpdk-24.11.8/drivers/net/ark/ark_pktgen.c --- dpdk-24.11.4/drivers/net/ark/ark_pktgen.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ark/ark_pktgen.c 2026-10-14 13:10:05.000000000 +0000 @@ -4,9 +4,12 @@ #include #include +#include +#include #include #include +#include #include #include "ark_pktgen.h" @@ -355,12 +358,11 @@ static int32_t parse_ipv4_string(char const *ip_address) { - unsigned int ip[4]; + struct in_addr addr; - if (sscanf(ip_address, "%u.%u.%u.%u", - &ip[0], &ip[1], &ip[2], &ip[3]) != 4) + if (inet_pton(AF_INET, ip_address, &addr) != 1) return 0; - return ip[3] + ip[2] * 0x100 + ip[1] * 0x10000ul + ip[0] * 0x1000000ul; + return rte_be_to_cpu_32(addr.s_addr); } static void diff -Nru dpdk-24.11.4/drivers/net/atlantic/atl_ethdev.c dpdk-24.11.8/drivers/net/atlantic/atl_ethdev.c --- dpdk-24.11.4/drivers/net/atlantic/atl_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/atlantic/atl_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -5,6 +5,7 @@ #include #include #include +#include #include "atl_ethdev.h" #include "atl_common.h" @@ -405,7 +406,7 @@ hw->aq_nic_cfg = &adapter->hw_cfg; - pthread_mutex_init(&hw->mbox_mutex, NULL); + rte_thread_mutex_init_shared(&hw->mbox_mutex); /* disable interrupt */ atl_disable_intr(hw); diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_common.h dpdk-24.11.8/drivers/net/axgbe/axgbe_common.h --- dpdk-24.11.4/drivers/net/axgbe/axgbe_common.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_common.h 2026-10-14 13:10:05.000000000 +0000 @@ -488,7 +488,7 @@ #define MAC_SSIR_SSINC_INDEX 16 #define MAC_SSIR_SSINC_WIDTH 8 #define MAC_TCR_SS_INDEX 29 -#define MAC_TCR_SS_WIDTH 2 +#define MAC_TCR_SS_WIDTH 3 #define MAC_TCR_TE_INDEX 0 #define MAC_TCR_TE_WIDTH 1 #define MAC_TSCR_AV8021ASMEN_INDEX 28 diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_dev.c dpdk-24.11.8/drivers/net/axgbe/axgbe_dev.c --- dpdk-24.11.4/drivers/net/axgbe/axgbe_dev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_dev.c 2026-10-14 13:10:05.000000000 +0000 @@ -301,6 +301,9 @@ case SPEED_10: ss = 0x07; break; + case SPEED_100: + ss = 0x04; + break; case SPEED_1000: ss = 0x03; break; diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_ethdev.c dpdk-24.11.8/drivers/net/axgbe/axgbe_ethdev.c --- dpdk-24.11.4/drivers/net/axgbe/axgbe_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -12,6 +12,7 @@ #include "eal_filesystem.h" +#include #include #ifdef RTE_ARCH_X86 @@ -2248,7 +2249,7 @@ edx == CPUID_VENDOR_AuthenticAMD_edx && ecx == CPUID_VENDOR_AuthenticAMD_ecx) { int unknown_cpu = 0; - eax = 0, ebx = 0, ecx = 0, edx = 0; + eax = 0; ebx = 0; ecx = 0; edx = 0; __cpuid(0x1, eax, ebx, ecx, edx); @@ -2396,10 +2397,10 @@ pdata->tx_desc_count = AXGBE_MAX_RING_DESC; pdata->rx_desc_count = AXGBE_MAX_RING_DESC; - pthread_mutex_init(&pdata->xpcs_mutex, NULL); - pthread_mutex_init(&pdata->i2c_mutex, NULL); - pthread_mutex_init(&pdata->an_mutex, NULL); - pthread_mutex_init(&pdata->phy_mutex, NULL); + rte_thread_mutex_init_shared(&pdata->xpcs_mutex); + rte_thread_mutex_init_shared(&pdata->i2c_mutex); + rte_thread_mutex_init_shared(&pdata->an_mutex); + rte_thread_mutex_init_shared(&pdata->phy_mutex); ret = pdata->phy_if.phy_init(pdata); if (ret) { diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_ethdev.h dpdk-24.11.8/drivers/net/axgbe/axgbe_ethdev.h --- dpdk-24.11.4/drivers/net/axgbe/axgbe_ethdev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_ethdev.h 2026-10-14 13:10:05.000000000 +0000 @@ -113,12 +113,12 @@ #define AXGBE_LINK_TIMEOUT 5 #define AXGBE_KR_TRAINING_WAIT_ITER 50 -#define AXGBE_SGMII_AN_LINK_STATUS BIT(1) +#define AXGBE_SGMII_AN_LINK_STATUS BIT(4) #define AXGBE_SGMII_AN_LINK_SPEED (BIT(2) | BIT(3)) #define AXGBE_SGMII_AN_LINK_SPEED_10 0x00 #define AXGBE_SGMII_AN_LINK_SPEED_100 0x04 #define AXGBE_SGMII_AN_LINK_SPEED_1000 0x08 -#define AXGBE_SGMII_AN_LINK_DUPLEX BIT(4) +#define AXGBE_SGMII_AN_LINK_DUPLEX BIT(1) /* ECC correctable error notification window (seconds) */ #define AXGBE_ECC_LIMIT 60 diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_mdio.c dpdk-24.11.8/drivers/net/axgbe/axgbe_mdio.c --- dpdk-24.11.4/drivers/net/axgbe/axgbe_mdio.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_mdio.c 2026-10-14 13:10:05.000000000 +0000 @@ -155,8 +155,8 @@ static void axgbe_sgmii_100_mode(struct axgbe_port *pdata) { - /* Set MAC to 1G speed */ - pdata->hw_if.set_speed(pdata, SPEED_1000); + /* Set MAC to 100M speed */ + pdata->hw_if.set_speed(pdata, SPEED_100); /* Call PHY implementation support to complete rate change */ pdata->phy_if.phy_impl.set_mode(pdata, AXGBE_MODE_SGMII_100); diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_phy.h dpdk-24.11.8/drivers/net/axgbe/axgbe_phy.h --- dpdk-24.11.4/drivers/net/axgbe/axgbe_phy.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_phy.h 2026-10-14 13:10:05.000000000 +0000 @@ -168,7 +168,7 @@ #define ADVERTISED_1000baseKX_Full (1 << 17) #define ADVERTISED_1000baseT_Full (1 << 5) #define ADVERTISED_100baseT_Full (1 << 3) -#define ADVERTISED_10baseT_Full (1 << 2) +#define ADVERTISED_10baseT_Full (1 << 1) #define ADVERTISED_TP (1 << 7) #define ADVERTISED_FIBRE (1 << 10) #define ADVERTISED_Backplane (1 << 16) @@ -176,8 +176,8 @@ #define SUPPORTED_1000baseKX_Full (1 << 17) #define SUPPORTED_10000baseKR_Full (1 << 19) #define SUPPORTED_2500baseX_Full (1 << 15) -#define SUPPORTED_10baseT_Full (1 << 3) -#define SUPPORTED_100baseT_Full (1 << 2) +#define SUPPORTED_10baseT_Full (1 << 1) +#define SUPPORTED_100baseT_Full (1 << 3) #define SUPPORTED_1000baseT_Full (1 << 5) #define SUPPORTED_10000baseT_Full (1 << 12) #define SUPPORTED_2500baseX_Full (1 << 15) diff -Nru dpdk-24.11.4/drivers/net/axgbe/axgbe_phy_impl.c dpdk-24.11.8/drivers/net/axgbe/axgbe_phy_impl.c --- dpdk-24.11.4/drivers/net/axgbe/axgbe_phy_impl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/axgbe/axgbe_phy_impl.c 2026-10-14 13:10:05.000000000 +0000 @@ -1497,6 +1497,18 @@ phy_data->cur_mode = AXGBE_MODE_SGMII_1000; } +static void axgbe_phy_sgmii_100_mode(struct axgbe_port *pdata) +{ + struct axgbe_phy_data *phy_data = pdata->phy_data; + + axgbe_phy_set_redrv_mode(pdata); + + /* 100M/SGMII */ + axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_1G, AXGBE_MB_SUBCMD_100MBITS); + + phy_data->cur_mode = AXGBE_MODE_SGMII_100; +} + static void axgbe_phy_sgmii_10_mode(struct axgbe_port *pdata) { struct axgbe_phy_data *phy_data = pdata->phy_data; @@ -1694,6 +1706,9 @@ case AXGBE_MODE_SGMII_1000: axgbe_phy_sgmii_1000_mode(pdata); break; + case AXGBE_MODE_SGMII_100: + axgbe_phy_sgmii_100_mode(pdata); + break; case AXGBE_MODE_SGMII_10: axgbe_phy_sgmii_10_mode(pdata); break; diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt.h dpdk-24.11.8/drivers/net/bnxt/bnxt.h --- dpdk-24.11.4/drivers/net/bnxt/bnxt.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt.h 2026-10-14 13:10:05.000000000 +0000 @@ -88,6 +88,8 @@ #define HWRM_VERSION_1_9_1 0x10901 #define HWRM_VERSION_1_9_2 0x10903 #define HWRM_VERSION_1_10_2_13 0x10a020d +/* Minimum spec version that supports AUTONEG_PAUSE bit in auto_pause field */ +#define HWRM_SPEC_CODE_AUTONEG_PAUSE 0x10201 #define BNXT_MAX_MTU 9574 #define BNXT_NUM_VLANS 2 @@ -331,6 +333,14 @@ uint8_t active_lanes; uint8_t option_flags; uint16_t pmd_speed_lanes; + /* Bitmask tracking which autoneg modes are active */ + uint8_t autoneg; +#define BNXT_AUTONEG_SPEED 1 /* speed autoneg enabled */ +#define BNXT_AUTONEG_FLOW_CTRL 2 /* pause/flow-ctrl autoneg enabled */ + /* True after autoneg->forced FC transition; cleared once set_pause + * sends the combined pause+link HWRM request successfully. + */ + bool link_reconfig_needed; }; #define BNXT_COS_QUEUE_COUNT 8 @@ -404,6 +414,8 @@ uint64_t current_time; uint64_t old_time; rte_spinlock_t ptp_lock; + /* On P7, the Tx timestamp is present in the Tx completion record */ + uint64_t tx_timestamp; }; struct bnxt_coal { @@ -425,8 +437,10 @@ #define DBR_TYPE_SQ (0x0ULL << 60) #define DBR_TYPE_SRQ (0x2ULL << 60) #define DBR_TYPE_CQ (0x4ULL << 60) +#define DBR_TYPE_CQ_ARMALL (0x6ULL << 60) #define DBR_TYPE_NQ (0xaULL << 60) #define DBR_TYPE_NQ_ARM (0xbULL << 60) +#define DBR_TYPE_NQ_MASK (0xeULL << 60) #define DB_PF_OFFSET 0x10000 #define DB_VF_OFFSET 0x4000 @@ -866,6 +880,7 @@ #define BNXT_FW_CAP_TX_COAL_CMPL BIT(10) #define BNXT_FW_CAP_RX_ALL_PKT_TS BIT(11) #define BNXT_FW_CAP_BACKING_STORE_V2 BIT(12) +#define BNXT_FW_CAP_TIMED_TX_PACING BIT(15) #define BNXT_FW_CAP_RX_RATE_PROFILE BIT(17) #define BNXT_FW_BACKING_STORE_V2_EN(bp) \ ((bp)->fw_cap & BNXT_FW_CAP_BACKING_STORE_V2) @@ -874,6 +889,7 @@ (bp)->hwrm_spec_code >= HWRM_VERSION_1_9_2 && \ !BNXT_VF((bp))) #define BNXT_FW_CAP_UDP_GSO BIT(13) +#define BNXT_FW_CAP_TX_TS_CMP BIT(16) #define BNXT_TRUFLOW_EN(bp) ((bp)->fw_cap & BNXT_FW_CAP_TRUFLOW_EN &&\ (bp)->app_id != 0xFF) @@ -1248,6 +1264,7 @@ #define BNXT_LINK_SPEEDS_V2(bp) (((bp)->link_info) && (((bp)->link_info->support_speeds_v2) || \ BNXT_LINK_SPEEDS_V2_VF((bp)))) #define BNXT_MAX_SPEED_LANES 8 +#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_P5_P7(bp) || (bp)->max_tpa_v2) extern const struct rte_flow_ops bnxt_ulp_rte_flow_ops; int32_t bnxt_ulp_port_init(struct bnxt *bp); void bnxt_ulp_port_deinit(struct bnxt *bp); diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_cpr.c dpdk-24.11.8/drivers/net/bnxt/bnxt_cpr.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_cpr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_cpr.c 2026-10-14 13:10:05.000000000 +0000 @@ -13,6 +13,106 @@ #include "hsi_struct_def_dpdk.h" #include "tfc_vf2pf_msg.h" +void bnxt_process_async_msg(struct bnxt *bp, struct tx_cmpl *cmpl) +{ + uint16_t type = cmpl->flags_type & TX_CMPL_TYPE_MASK; + + switch (type) { + case HWRM_CMPL_TYPE_HWRM_DONE: + break; + case HWRM_ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT: + bnxt_handle_async_event(bp, (struct cmpl_base *)cmpl); + break; + default: + PMD_DRV_LOG_LINE(ERR, "Port: %d Unhandled async message %x", + bp->eth_dev->data->port_id, type); + break; + } +} + +void bnxt_process_nq(struct bnxt *bp, struct bnxt_cp_ring_info *nqr, + struct bnxt_cp_ring_info *rx_cpr) +{ + struct nqe_cn *nqcmps = (struct nqe_cn *)nqr->cp_desc_ring; + uint32_t ring_mask = nqr->cp_ring_struct->ring_mask; + uint32_t raw_cons = nqr->cp_raw_cons; + uint16_t nq_type, nqe_cnt = 0; + bool v_bit = nqr->valid; + uint32_t cons = RING_CMPL(ring_mask, raw_cons); + + while (1) { + if (!CMPL_VALID(&nqcmps[cons], v_bit)) { + if (nqe_cnt) { + nqr->cp_raw_cons = raw_cons; + nqr->valid = v_bit; + } + return; + } + + nq_type = NQ_CN_TYPE_MASK & nqcmps[cons].type; + + if (CMP_TYPE((struct cmpl_base *)&nqcmps[cons]) != NQ_CN_TYPE_CQ_NOTIFICATION) + bnxt_process_async_msg(bp, (struct tx_cmpl *)&nqcmps[cons]); + else + rx_cpr->toggle = NQE_CN_TOGGLE((uint64_t)nqcmps[cons].type); + + NEXT_CMPL(nqr, cons, v_bit, 1); + raw_cons++; + if (nq_type) + nqe_cnt++; + } +} + +/* Arms/disarms the given NQ for Thor/Thor2, with P5+ represening the ASIC family */ +void bnxt_arm_nq_p5p(struct bnxt_cp_ring_info *nqr, bool enable_irq) +{ + uint32_t raw_cons = nqr->cp_raw_cons; + uint64_t db_msg = 0; + uint32_t toggle = 0; + + if (enable_irq == 1) + toggle = nqr->toggle; + + db_msg = nqr->cp_db.db_key64 | (raw_cons & nqr->cp_db.db_ring_mask) + | DB_EPOCH(&nqr->cp_db, raw_cons) | DB_TOGGLE(toggle); + + if (enable_irq) + db_msg |= DBR_TYPE_NQ_ARM; + else + db_msg |= DBR_TYPE_NQ_MASK; + + rte_compiler_barrier(); + rte_write64(db_msg, nqr->cp_db.doorbell); + rte_compiler_barrier(); +} + +/* Arms/disarms the given CQ for Thor/Thor2, with P5+ represening the ASIC family */ +void bnxt_arm_rx_cq_p5p(struct bnxt_cp_ring_info *cpr, bool enable_irq) +{ + uint32_t raw_cons = cpr->cp_raw_cons; + uint64_t db_msg = 0; + uint32_t toggle = 0; + + if (raw_cons == UINT32_MAX) + raw_cons = 0; + + if (enable_irq == 1) + toggle = cpr->toggle; + + db_msg = cpr->cp_db.db_key64 | (raw_cons & cpr->cp_db.db_ring_mask) + | DB_EPOCH(&cpr->cp_db, raw_cons) | DB_TOGGLE(toggle); + + if (enable_irq) + db_msg |= DBR_TYPE_CQ_ARMALL; + else + db_msg |= DBR_TYPE_CQ; + + rte_compiler_barrier(); + rte_write64(db_msg, cpr->cp_db.doorbell); + rte_compiler_barrier(); +} + + void bnxt_wait_for_device_shutdown(struct bnxt *bp) { uint32_t val, timeout; diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_cpr.h dpdk-24.11.8/drivers/net/bnxt/bnxt_cpr.h --- dpdk-24.11.4/drivers/net/bnxt/bnxt_cpr.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_cpr.h 2026-10-14 13:10:05.000000000 +0000 @@ -30,6 +30,14 @@ #define RING_CMPL(ring_mask, idx) ((idx) & (ring_mask)) #define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1)) +#define DBR_TOGGLE_SFT 25 +#define DB_TOGGLE(tgl) ((tgl) << DBR_TOGGLE_SFT) + +#define NQ_CN_TOGGLE_MASK 0xc0UL +#define NQ_CN_TOGGLE_SFT 6 +#define NQE_CN_TOGGLE(type) (((type) & NQ_CN_TOGGLE_MASK) >> \ + NQ_CN_TOGGLE_SFT) + #define DB_CP_REARM_FLAGS (DB_KEY_CP | DB_IDX_VALID) #define DB_CP_FLAGS (DB_KEY_CP | DB_IDX_VALID | DB_IRQ_DIS) @@ -73,6 +81,21 @@ #define DB_RING_IDX(db, idx) (((idx) & (db)->db_ring_mask) | \ DB_EPOCH(db, idx)) +struct nqe_cn { + rte_le16_t type; + #define NQ_CN_TYPE_MASK 0x3fUL + #define NQ_CN_TYPE_SFT 0 + #define NQ_CN_TYPE_CQ_NOTIFICATION 0x30UL + #define NQ_CN_TYPE_LAST NQ_CN_TYPE_CQ_NOTIFICATION + #define NQ_CN_TOGGLE_MASK 0xc0UL + #define NQ_CN_TOGGLE_SFT 6 + rte_le16_t reserved16; + rte_le32_t cq_handle_low; + rte_le32_t v; + #define NQ_CN_V 0x1UL + rte_le32_t cq_handle_high; +}; + struct bnxt_ring; struct bnxt_cp_ring_info { uint32_t cp_raw_cons; @@ -89,6 +112,8 @@ struct bnxt_ring *cp_ring_struct; bool valid; uint32_t epoch; + uint32_t toggle; + }; #define RX_CMP_L2_ERRORS \ @@ -100,6 +125,11 @@ int bnxt_event_hwrm_resp_handler(struct bnxt *bp, struct cmpl_base *cmp); void bnxt_dev_reset_and_resume(void *arg); void bnxt_wait_for_device_shutdown(struct bnxt *bp); +void bnxt_arm_nq_p5p(struct bnxt_cp_ring_info *nqr, bool enable_irq); +void bnxt_arm_rx_cq_p5p(struct bnxt_cp_ring_info *cpr, bool enable_irq); +void bnxt_process_async_msg(struct bnxt *bp, struct tx_cmpl *cmpl); +void bnxt_process_nq(struct bnxt *bp, struct bnxt_cp_ring_info *nqr, + struct bnxt_cp_ring_info *rx_cpr); #define EVENT_DATA1_REASON_CODE_FW_EXCEPTION_FATAL \ HWRM_ASYNC_EVENT_CMPL_RESET_NOTIFY_EVENT_DATA1_REASON_CODE_FW_EXCEPTION_FATAL @@ -153,4 +183,5 @@ } return false; } + #endif diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_ethdev.c dpdk-24.11.8/drivers/net/bnxt/bnxt_ethdev.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -785,7 +785,7 @@ return rc; } -static void bnxt_free_prev_ring_stats(struct bnxt *bp) +static void bnxt_free_prev_ring_stats_ext(struct bnxt *bp) { /* tpa v2 devices use ext variant local struct */ if (BNXT_TPA_V2_P7(bp)) { @@ -795,6 +795,10 @@ bp->prev_tx_ring_stats_ext = NULL; return; } +} + +static void bnxt_free_prev_ring_stats(struct bnxt *bp) +{ rte_free(bp->prev_rx_ring_stats); rte_free(bp->prev_tx_ring_stats); bp->prev_rx_ring_stats = NULL; @@ -803,17 +807,19 @@ static int bnxt_alloc_prev_ring_ext_stats(struct bnxt *bp) { - bp->prev_rx_ring_stats_ext = rte_zmalloc("bnxt_prev_rx_ring_stats_ext", - sizeof(struct bnxt_ring_stats_ext) * - bp->rx_cp_nr_rings, - 0); + if (bp->prev_rx_ring_stats_ext == NULL) + bp->prev_rx_ring_stats_ext = rte_zmalloc("bnxt_prev_rx_ring_stats_ext", + sizeof(struct bnxt_ring_stats_ext) * + bp->rx_cp_nr_rings, + 0); if (bp->prev_rx_ring_stats_ext == NULL) return -ENOMEM; - bp->prev_tx_ring_stats_ext = rte_zmalloc("bnxt_prev_tx_ring_stats_ext", - sizeof(struct bnxt_ring_stats_ext) * - bp->tx_cp_nr_rings, - 0); + if (bp->prev_tx_ring_stats_ext == NULL) + bp->prev_tx_ring_stats_ext = rte_zmalloc("bnxt_prev_tx_ring_stats_ext", + sizeof(struct bnxt_ring_stats_ext) * + bp->tx_cp_nr_rings, + 0); if (bp->tx_cp_nr_rings > 0 && bp->prev_tx_ring_stats_ext == NULL) goto error; @@ -830,24 +836,26 @@ if (BNXT_TPA_V2_P7(bp)) return bnxt_alloc_prev_ring_ext_stats(bp); - bp->prev_rx_ring_stats = rte_zmalloc("bnxt_prev_rx_ring_stats", - sizeof(struct bnxt_ring_stats) * - bp->rx_cp_nr_rings, - 0); + if (bp->prev_rx_ring_stats == NULL) + bp->prev_rx_ring_stats = rte_zmalloc("bnxt_prev_rx_ring_stats", + sizeof(struct bnxt_ring_stats) * + bp->rx_cp_nr_rings, + 0); if (bp->prev_rx_ring_stats == NULL) return -ENOMEM; - bp->prev_tx_ring_stats = rte_zmalloc("bnxt_prev_tx_ring_stats", - sizeof(struct bnxt_ring_stats) * - bp->tx_cp_nr_rings, - 0); + if (bp->prev_tx_ring_stats == NULL) + bp->prev_tx_ring_stats = rte_zmalloc("bnxt_prev_tx_ring_stats", + sizeof(struct bnxt_ring_stats) * + bp->tx_cp_nr_rings, + 0); if (bp->tx_cp_nr_rings > 0 && bp->prev_tx_ring_stats == NULL) goto error; return 0; error: - bnxt_free_prev_ring_stats(bp); + bnxt_free_prev_ring_stats_ext(bp); return -ENOMEM; } @@ -1424,6 +1432,9 @@ for (i = 0; i < eth_dev->data->nb_rx_queues; i++) { struct bnxt_rx_queue *rxq = eth_dev->data->rx_queues[i]; + if (rxq == NULL) + continue; + buf_size = (uint16_t)(rte_pktmbuf_data_room_size(rxq->mb_pool) - RTE_PKTMBUF_HEADROOM); if (eth_dev->data->mtu + overhead > buf_size) @@ -1756,7 +1767,6 @@ bnxt_shutdown_nic(bp); bnxt_hwrm_if_change(bp, false); - bnxt_free_prev_ring_stats(bp); rte_free(bp->mark_table); bp->mark_table = NULL; @@ -1947,6 +1957,8 @@ if (eth_dev->data->dev_started) ret = bnxt_dev_stop(eth_dev); + bnxt_free_prev_ring_stats_ext(bp); + bnxt_free_prev_ring_stats(bp); bnxt_uninit_resources(bp, false); bnxt_drv_uninit(bp); @@ -2482,7 +2494,7 @@ return rc; memset(fc_conf, 0, sizeof(*fc_conf)); - if (bp->link_info->auto_pause) + if (bp->link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) fc_conf->autoneg = 1; switch (bp->link_info->pause) { case 0: @@ -2518,6 +2530,14 @@ return -ENOTSUP; } + if (fc_conf->autoneg) { + bp->link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; + } else { + if (bp->link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) + bp->link_info->link_reconfig_needed = true; + bp->link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL; + } + switch (fc_conf->mode) { case RTE_ETH_FC_NONE: bp->link_info->auto_pause = 0; @@ -2559,7 +2579,7 @@ } break; } - return bnxt_set_hwrm_link_config(bp, true); + return bnxt_hwrm_set_pause(bp); } /* Add UDP tunneling port */ @@ -3676,148 +3696,6 @@ return ptypes; } -static int bnxt_map_regs(struct bnxt *bp, uint32_t *reg_arr, int count, - int reg_win) -{ - uint32_t reg_base = *reg_arr & 0xfffff000; - uint32_t win_off; - int i; - - for (i = 0; i < count; i++) { - if ((reg_arr[i] & 0xfffff000) != reg_base) - return -ERANGE; - } - win_off = BNXT_GRCPF_REG_WINDOW_BASE_OUT + (reg_win - 1) * 4; - rte_write32(reg_base, (uint8_t *)bp->bar0 + win_off); - return 0; -} - -static int bnxt_map_ptp_regs(struct bnxt *bp) -{ - struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - uint32_t *reg_arr; - int rc, i; - - reg_arr = ptp->rx_regs; - rc = bnxt_map_regs(bp, reg_arr, BNXT_PTP_RX_REGS, 5); - if (rc) - return rc; - - reg_arr = ptp->tx_regs; - rc = bnxt_map_regs(bp, reg_arr, BNXT_PTP_TX_REGS, 6); - if (rc) - return rc; - - for (i = 0; i < BNXT_PTP_RX_REGS; i++) - ptp->rx_mapped_regs[i] = 0x5000 + (ptp->rx_regs[i] & 0xfff); - - for (i = 0; i < BNXT_PTP_TX_REGS; i++) - ptp->tx_mapped_regs[i] = 0x6000 + (ptp->tx_regs[i] & 0xfff); - - return 0; -} - -static void bnxt_unmap_ptp_regs(struct bnxt *bp) -{ - rte_write32(0, (uint8_t *)bp->bar0 + - BNXT_GRCPF_REG_WINDOW_BASE_OUT + 16); - rte_write32(0, (uint8_t *)bp->bar0 + - BNXT_GRCPF_REG_WINDOW_BASE_OUT + 20); -} - -static uint64_t bnxt_cc_read(struct bnxt *bp) -{ - uint64_t ns; - - ns = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - BNXT_GRCPF_REG_SYNC_TIME)); - ns |= (uint64_t)(rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - BNXT_GRCPF_REG_SYNC_TIME + 4))) << 32; - return ns; -} - -static int bnxt_get_tx_ts(struct bnxt *bp, uint64_t *ts) -{ - struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - uint32_t fifo; - - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->tx_mapped_regs[BNXT_PTP_TX_FIFO])); - if (fifo & BNXT_PTP_TX_FIFO_EMPTY) - return -EAGAIN; - - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->tx_mapped_regs[BNXT_PTP_TX_FIFO])); - *ts = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->tx_mapped_regs[BNXT_PTP_TX_TS_L])); - *ts |= (uint64_t)rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->tx_mapped_regs[BNXT_PTP_TX_TS_H])) << 32; - rte_read32((uint8_t *)bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_SEQ]); - - return 0; -} - -static int bnxt_clr_rx_ts(struct bnxt *bp, uint64_t *last_ts) -{ - struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - struct bnxt_pf_info *pf = bp->pf; - uint16_t port_id; - int i = 0; - uint32_t fifo; - - if (!ptp || (bp->flags & BNXT_FLAG_CHIP_P5)) - return -EINVAL; - - port_id = pf->port_id; - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO])); - while ((fifo & BNXT_PTP_RX_FIFO_PENDING) && (i < BNXT_PTP_RX_PND_CNT)) { - rte_write32(1 << port_id, (uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO_ADV]); - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO])); - *last_ts = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_TS_L])); - *last_ts |= (uint64_t)rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_TS_H])) << 32; - i++; - } - - if (i >= BNXT_PTP_RX_PND_CNT) - return -EBUSY; - - return 0; -} - -static int bnxt_get_rx_ts(struct bnxt *bp, uint64_t *ts) -{ - struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - struct bnxt_pf_info *pf = bp->pf; - uint16_t port_id; - uint32_t fifo; - - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO])); - if (!(fifo & BNXT_PTP_RX_FIFO_PENDING)) - return -EAGAIN; - - port_id = pf->port_id; - rte_write32(1 << port_id, (uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO_ADV]); - - fifo = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO])); - if (fifo & BNXT_PTP_RX_FIFO_PENDING) - return bnxt_clr_rx_ts(bp, ts); - - *ts = rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_TS_L])); - *ts |= (uint64_t)rte_le_to_cpu_32(rte_read32((uint8_t *)bp->bar0 + - ptp->rx_mapped_regs[BNXT_PTP_RX_TS_H])) << 32; - - return 0; -} - static int bnxt_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *ts) { @@ -3848,12 +3726,9 @@ if (!ptp) return -ENOTSUP; - /* TODO Revisit for Thor 2 */ if (BNXT_CHIP_P5(bp)) rc = bnxt_hwrm_port_ts_query(bp, BNXT_PTP_FLAGS_CURRENT_TIME, &systime_cycles); - else - systime_cycles = bnxt_cc_read(bp); ns = rte_timecounter_update(&ptp->tc, systime_cycles); *ts = rte_ns_to_timespec(ns); @@ -3898,13 +3773,7 @@ ptp->tx_tstamp_tc.cc_shift = shift; ptp->tx_tstamp_tc.nsec_mask = (1ULL << shift) - 1; - /* TODO Revisit for Thor 2 */ - if (!BNXT_CHIP_P5(bp)) - bnxt_map_ptp_regs(bp); - else - rc = bnxt_ptp_start(bp); - - return rc; + return bnxt_ptp_start(bp); } static int @@ -3923,12 +3792,8 @@ bnxt_hwrm_ptp_cfg(bp); - /* TODO Revisit for Thor 2 */ bp->ptp_all_rx_tstamp = 0; - if (!BNXT_CHIP_P5(bp)) - bnxt_unmap_ptp_regs(bp); - else - bnxt_ptp_stop(bp); + bnxt_ptp_stop(bp); return 0; } @@ -3946,11 +3811,7 @@ if (!ptp) return -ENOTSUP; - /* TODO Revisit for Thor 2 */ - if (BNXT_CHIP_P5(bp)) - rx_tstamp_cycles = ptp->rx_timestamp; - else - bnxt_get_rx_ts(bp, &rx_tstamp_cycles); + rx_tstamp_cycles = ptp->rx_timestamp; ns = rte_timecounter_update(&ptp->rx_tstamp_tc, rx_tstamp_cycles); *timestamp = rte_ns_to_timespec(ns); @@ -3970,12 +3831,11 @@ if (!ptp) return -ENOTSUP; - /* TODO Revisit for Thor 2 */ - if (BNXT_CHIP_P5(bp)) + if (BNXT_CHIP_P7(bp)) + tx_tstamp_cycles = ptp->tx_timestamp; + else rc = bnxt_hwrm_port_ts_query(bp, BNXT_PTP_FLAGS_PATH_TX, &tx_tstamp_cycles); - else - rc = bnxt_get_tx_ts(bp, &tx_tstamp_cycles); ns = rte_timecounter_update(&ptp->tx_tstamp_tc, tx_tstamp_cycles); *timestamp = rte_ns_to_timespec(ns); @@ -5331,11 +5191,11 @@ if (ctxm->type == HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_CQ) entries = ctxm->cq_l2_entries; else if (ctxm->type == HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_QP) - entries = ctxm->qp_l2_entries; + entries = ctxm->qp_l2_entries + ctxm->qp_qp1_entries; else if (ctxm->type == HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_MRAV) entries = ctxm->mrav_av_entries; else if (ctxm->type == HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_TIM) - entries = ctx2->qp_l2_entries; + entries = ctx2->qp_l2_entries + ctx2->qp_qp1_entries; entries = clamp_t(uint32_t, entries, ctxm->min_entries, ctxm->max_entries); ctx_pg[i].entries = entries; @@ -5821,31 +5681,12 @@ static int bnxt_init_locks(struct bnxt *bp) { - int err; - - err = pthread_mutex_init(&bp->flow_lock, NULL); - if (err) { - PMD_DRV_LOG_LINE(ERR, "Unable to initialize flow_lock"); - return err; - } - - err = pthread_mutex_init(&bp->def_cp_lock, NULL); - if (err) { - PMD_DRV_LOG_LINE(ERR, "Unable to initialize def_cp_lock"); - return err; - } + rte_thread_mutex_init_shared(&bp->flow_lock); + rte_thread_mutex_init_shared(&bp->def_cp_lock); + rte_thread_mutex_init_shared(&bp->health_check_lock); + rte_thread_mutex_init_shared(&bp->err_recovery_lock); - err = pthread_mutex_init(&bp->health_check_lock, NULL); - if (err) { - PMD_DRV_LOG_LINE(ERR, "Unable to initialize health_check_lock"); - return err; - } - - err = pthread_mutex_init(&bp->err_recovery_lock, NULL); - if (err) - PMD_DRV_LOG_LINE(ERR, "Unable to initialize err_recovery_lock"); - - return err; + return 0; } /* This should be called after we have queried trusted VF cap */ @@ -6746,7 +6587,7 @@ static int bnxt_init_rep_info(struct bnxt *bp) { - int i = 0, rc; + int i = 0; if (bp->rep_info) return 0; @@ -6770,14 +6611,8 @@ for (i = 0; i < BNXT_MAX_CFA_CODE; i++) bp->cfa_code_map[i] = BNXT_VF_IDX_INVALID; - rc = pthread_mutex_init(&bp->rep_info->vfr_start_lock, NULL); - if (rc) { - PMD_DRV_LOG_LINE(ERR, "Unable to initialize vfr_start_lock"); - bnxt_free_rep_info(bp); - return rc; - } - - return rc; + rte_thread_mutex_init_shared(&bp->rep_info->vfr_start_lock); + return 0; } static int bnxt_rep_port_probe(struct rte_pci_device *pci_dev, diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_hwrm.c dpdk-24.11.8/drivers/net/bnxt/bnxt_hwrm.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_hwrm.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_hwrm.c 2026-10-14 13:10:05.000000000 +0000 @@ -1027,14 +1027,9 @@ HWRM_CHECK_RESULT(); - /* TODO Revisit for Thor 2 */ - if (BNXT_CHIP_P5(bp)) { - if (!(resp->flags & HWRM_PORT_MAC_PTP_QCFG_OUTPUT_FLAGS_HWRM_ACCESS)) - return 0; - } else { - if (!(resp->flags & HWRM_PORT_MAC_PTP_QCFG_OUTPUT_FLAGS_DIRECT_ACCESS)) - return 0; - } + if (!BNXT_CHIP_P7(bp) && + !(resp->flags & HWRM_PORT_MAC_PTP_QCFG_OUTPUT_FLAGS_HWRM_ACCESS)) + return 0; if (resp->flags & HWRM_PORT_MAC_PTP_QCFG_OUTPUT_FLAGS_ONE_STEP_TX_TS) bp->flags |= BNXT_FLAG_FW_CAP_ONE_STEP_TX_TS; @@ -1043,27 +1038,6 @@ if (!ptp) return -ENOMEM; - if (!BNXT_CHIP_P5(bp)) { - ptp->rx_regs[BNXT_PTP_RX_TS_L] = - rte_le_to_cpu_32(resp->rx_ts_reg_off_lower); - ptp->rx_regs[BNXT_PTP_RX_TS_H] = - rte_le_to_cpu_32(resp->rx_ts_reg_off_upper); - ptp->rx_regs[BNXT_PTP_RX_SEQ] = - rte_le_to_cpu_32(resp->rx_ts_reg_off_seq_id); - ptp->rx_regs[BNXT_PTP_RX_FIFO] = - rte_le_to_cpu_32(resp->rx_ts_reg_off_fifo); - ptp->rx_regs[BNXT_PTP_RX_FIFO_ADV] = - rte_le_to_cpu_32(resp->rx_ts_reg_off_fifo_adv); - ptp->tx_regs[BNXT_PTP_TX_TS_L] = - rte_le_to_cpu_32(resp->tx_ts_reg_off_lower); - ptp->tx_regs[BNXT_PTP_TX_TS_H] = - rte_le_to_cpu_32(resp->tx_ts_reg_off_upper); - ptp->tx_regs[BNXT_PTP_TX_SEQ] = - rte_le_to_cpu_32(resp->tx_ts_reg_off_seq_id); - ptp->tx_regs[BNXT_PTP_TX_FIFO] = - rte_le_to_cpu_32(resp->tx_ts_reg_off_fifo); - } - ptp->bp = bp; bp->ptp_cfg = ptp; @@ -1198,15 +1172,6 @@ if (BNXT_PF(bp)) bp->pf->total_vnics = rte_le_to_cpu_16(resp->max_vnics); - if (flags & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_PTP_SUPPORTED) { - if (BNXT_CHIP_P5(bp) || BNXT_PF(bp)) { - bp->flags |= BNXT_FLAG_PTP_SUPPORTED; - PMD_DRV_LOG_LINE(DEBUG, "PTP SUPPORTED"); - HWRM_UNLOCK(); - bnxt_hwrm_ptp_qcfg(bp); - } - } - if (flags & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT_STATS_SUPPORTED) bp->flags |= BNXT_FLAG_EXT_STATS_SUPPORTED; @@ -1260,9 +1225,23 @@ bp->fw_cap |= BNXT_FW_CAP_RX_ALL_PKT_TS; if (flags_ext2 & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT2_UDP_GSO_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_UDP_GSO; + if (flags_ext2 & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT2_TX_PKT_TS_CMPL_SUPPORTED) + bp->fw_cap |= BNXT_FW_CAP_TX_TS_CMP; if (flags_ext3 & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT3_RX_RATE_PROFILE_SEL_SUPPORTED) bp->fw_cap |= BNXT_FW_CAP_RX_RATE_PROFILE; + /* This block should be kept at the end of this function because it + * sends another hwrm msg. + */ + if (flags & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_PTP_SUPPORTED) { + if (BNXT_CHIP_P5(bp) || BNXT_PF(bp)) { + bp->flags |= BNXT_FLAG_PTP_SUPPORTED; + PMD_DRV_LOG_LINE(DEBUG, "PTP SUPPORTED"); + HWRM_UNLOCK(); + bnxt_hwrm_ptp_qcfg(bp); + } + } + unlock: HWRM_UNLOCK(); @@ -1870,6 +1849,26 @@ link_info->auto_pause = resp->auto_pause; link_info->force_pause = resp->force_pause; link_info->auto_mode = resp->auto_mode; + + if (link_info->auto_mode != HWRM_PORT_PHY_QCFG_OUTPUT_AUTO_MODE_NONE) { + link_info->autoneg = BNXT_AUTONEG_SPEED; + if (bp->hwrm_spec_code >= HWRM_SPEC_CODE_AUTONEG_PAUSE) { + if (link_info->auto_pause & + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE) + link_info->autoneg |= + BNXT_AUTONEG_FLOW_CTRL; + } else { + /* Firmware < HWRM_SPEC_CODE_AUTONEG_PAUSE does not + * expose the AUTONEG_PAUSE bit. Infer flow-ctrl + * autoneg from any non-zero auto_pause configuration. + */ + if (link_info->auto_pause) + link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL; + } + } else { + link_info->autoneg = 0; + } + link_info->phy_type = resp->phy_type; link_info->media_type = resp->media_type; @@ -2213,6 +2212,9 @@ if (stats_ctx_id != INVALID_STATS_CTX_ID) enables |= HWRM_RING_ALLOC_INPUT_ENABLES_STAT_CTX_ID_VALID; + if (bp->fw_cap & BNXT_FW_CAP_TX_TS_CMP && bp->ptp_cfg) + req.flags = + rte_cpu_to_le_16(HWRM_RING_ALLOC_INPUT_FLAGS_TX_PKT_TS_CMPL_ENABLE); break; case HWRM_RING_ALLOC_INPUT_RING_TYPE_RX: req.ring_type = ring_type; @@ -2982,8 +2984,22 @@ req.hash_mode_flags = BNXT_HASH_MODE_INNERMOST; else req.hash_mode_flags = vnic->hash_mode; - req.vnic_id = rte_cpu_to_le_16(BNXT_DFLT_VNIC_ID_INVALID); - req.rss_ctx_idx = rte_cpu_to_le_16(BNXT_RSS_CTX_IDX_INVALID); + + /* VFs must use actual vnic_id for per-VNIC configuration. + * PFs can use INVALID vnic_id for global configuration. + * This is because VFs don't have permission to configure + * global hash mode, even if they're trusted. + */ + if (BNXT_VF(bp)) { + req.vnic_id = rte_cpu_to_le_16(vnic->fw_vnic_id); + req.rss_ctx_idx = rte_cpu_to_le_16(vnic->fw_grp_ids[0]); + PMD_DRV_LOG_LINE(DEBUG, "VF using per-VNIC RSS config (vnic_id=%u)", + vnic->fw_vnic_id); + } else { + req.vnic_id = rte_cpu_to_le_16(BNXT_DFLT_VNIC_ID_INVALID); + req.rss_ctx_idx = rte_cpu_to_le_16(BNXT_RSS_CTX_IDX_INVALID); + PMD_DRV_LOG_LINE(DEBUG, "PF using global RSS config"); + } PMD_DRV_LOG_LINE(DEBUG, "RSS CFG: Hash level %d", req.hash_mode_flags); rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), @@ -3139,10 +3155,10 @@ return -ENOTSUP; } - if ((BNXT_CHIP_P5(bp) || BNXT_CHIP_P7(bp)) && !bp->max_tpa_v2) { + if (!BNXT_SUPPORTS_TPA(bp)) { if (enable) PMD_DRV_LOG_LINE(ERR, "No HW support for LRO"); - return -ENOTSUP; + return 0; } if (vnic->fw_vnic_id == INVALID_HW_RING_ID) { @@ -3348,6 +3364,9 @@ for (i = 0; i < bp->rx_cp_nr_rings; i++) { + if (bp->rx_queues[i] == NULL) + continue; + cpr = bp->rx_queues[i]->cp_ring; if (BNXT_HAS_RING_GRPS(bp)) bp->grp_info[i].fw_stats_ctx = -1; @@ -4061,6 +4080,206 @@ return rc; } +static void +bnxt_hwrm_set_pause_common(struct bnxt *bp, + struct hwrm_port_phy_cfg_input *req) +{ + struct bnxt_link_info *link_info = bp->link_info; + + if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) { + if (bp->hwrm_spec_code >= HWRM_SPEC_CODE_AUTONEG_PAUSE) + req->auto_pause = + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_AUTONEG_PAUSE; + if (link_info->auto_pause & + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX) + req->auto_pause |= + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_RX; + if (link_info->auto_pause & + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_TX) + req->auto_pause |= + HWRM_PORT_PHY_CFG_INPUT_AUTO_PAUSE_TX; + req->enables |= + rte_cpu_to_le_32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE); + } else { + if (link_info->force_pause & + HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX) + req->force_pause |= + HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_RX; + if (link_info->force_pause & + HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX) + req->force_pause |= + HWRM_PORT_PHY_CFG_INPUT_FORCE_PAUSE_TX; + req->enables |= + rte_cpu_to_le_32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE); + if (bp->hwrm_spec_code >= HWRM_SPEC_CODE_AUTONEG_PAUSE) { + req->auto_pause = req->force_pause; + req->enables |= + rte_cpu_to_le_32(HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE); + } + } +} + +static int +bnxt_hwrm_set_link_common(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req) +{ + struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf; + struct bnxt_link_info *link_info = bp->link_info; + uint16_t autoneg, speed; + uint32_t en = 0; + + autoneg = bnxt_check_eth_link_autoneg(dev_conf->link_speeds); + + if (BNXT_CHIP_P5_P7(bp) && + dev_conf->link_speeds & RTE_ETH_LINK_SPEED_40G) + autoneg = 0; + + if (autoneg == 1 && BNXT_CHIP_P5(bp) && + link_info->auto_mode == 0 && + link_info->force_pam4_link_speed == + HWRM_PORT_PHY_CFG_INPUT_FORCE_PAM4_LINK_SPEED_200GB) + autoneg = 0; + + speed = bnxt_parse_eth_link_speed(bp, dev_conf->link_speeds, + link_info); + req->flags |= + rte_cpu_to_le_32(HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY); + + if (autoneg == 0 && + (link_info->phy_type == HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASET || + link_info->phy_type == HWRM_PORT_PHY_QCFG_OUTPUT_PHY_TYPE_BASETE || + link_info->media_type == HWRM_PORT_PHY_QCFG_OUTPUT_MEDIA_TYPE_TP)) { + PMD_DRV_LOG_LINE(ERR, "10GBase-T devices must autoneg"); + return -EINVAL; + } + + if (BNXT_LINK_SPEEDS_V2(bp)) { + /* speeds-v2 firmware uses a separate field layout */ + if (autoneg == 1) { + req->flags |= rte_cpu_to_le_32 + (HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG); + req->auto_mode = + HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_SPEED_MASK; + req->auto_link_speeds2_mask = rte_cpu_to_le_16 + (bnxt_parse_eth_link_speed_mask(bp, + dev_conf->link_speeds)); + en |= HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_LINK_SPEEDS2_MASK | + HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE; + } else { + req->flags |= rte_cpu_to_le_32 + (HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE); + if (speed) { + req->force_link_speeds2 = + rte_cpu_to_le_16(speed); + en |= HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_LINK_SPEEDS2; + } + } + } else if (autoneg == 1 && + (link_info->support_auto_speeds || + link_info->support_pam4_auto_speeds)) { + req->flags |= rte_cpu_to_le_32 + (HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG); + req->auto_link_speed_mask = rte_cpu_to_le_16 + (bnxt_parse_eth_link_speed_mask(bp, + dev_conf->link_speeds)); + req->auto_link_pam4_speed_mask = + rte_cpu_to_le_16(link_info->auto_pam4_link_speed_mask); + en |= HWRM_PORT_PHY_CFG_IN_EN_AUTO_LINK_SPEED_MASK | + HWRM_PORT_PHY_CFG_IN_EN_AUTO_PAM4_LINK_SPD_MASK | + HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE; + req->auto_mode = HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_SPEED_MASK; + } else { + req->flags |= rte_cpu_to_le_32 + (HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE); + + /* No requested speed: keep the PHY's current speed rather + * than forcing 0. + */ + if (!speed) { + if (link_info->force_pam4_link_speed) + speed = link_info->force_pam4_link_speed; + else if (link_info->force_link_speed) + speed = link_info->force_link_speed; + else if (link_info->auto_pam4_link_speed_mask) + speed = link_info->auto_pam4_link_speed_mask; + else if (link_info->support_pam4_speeds) + speed = link_info->support_pam4_speeds; + else + speed = link_info->auto_link_speed; + /* Auto PAM4 link speed is zero, but auto_link_speed is + * not. Use the auto_link_speed. + */ + if (link_info->auto_link_speed != 0 && + link_info->auto_pam4_link_speed_mask == 0) + speed = link_info->auto_link_speed; + } + + if (speed) { + if (link_info->link_signal_mode) { + req->force_pam4_link_speed = + rte_cpu_to_le_16(speed); + en |= HWRM_PORT_PHY_CFG_IN_EN_FORCE_PAM4_LINK_SPEED; + } else { + req->force_link_speed = + rte_cpu_to_le_16(speed); + } + } + } + + req->auto_duplex = bnxt_parse_eth_link_duplex(dev_conf->link_speeds); + en |= HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX; + req->enables |= rte_cpu_to_le_32(en); + + return 0; +} + +int bnxt_hwrm_set_pause(struct bnxt *bp) +{ + struct hwrm_port_phy_cfg_input req = {0}; + struct hwrm_port_phy_cfg_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_link_info *link_info = bp->link_info; + bool reconfig; + int rc; + + /* Full reprogram on FC autoneg, or the autoneg->forced transition */ + reconfig = (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) || + link_info->link_reconfig_needed; + + /* Validate speeds up front, as bnxt_set_hwrm_link_config() does */ + if (reconfig) { + rc = bnxt_validate_link_speed(bp); + if (rc) + return rc; + } + + HWRM_PREP(&req, HWRM_PORT_PHY_CFG, BNXT_USE_CHIMP_MB); + + bnxt_hwrm_set_pause_common(bp, &req); + + if (reconfig) { + rc = bnxt_hwrm_set_link_common(bp, &req); + if (rc) { + HWRM_UNLOCK(); + return rc; + } + } + + rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB); + + /* HWRM_CHECK_RESULT() returns on any transport or firmware error, + * so the state updates below are reached only on success. + */ + HWRM_CHECK_RESULT(); + + if (!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)) { + link_info->pause = link_info->force_pause; + link_info->auto_pause = 0; + } + link_info->link_reconfig_needed = false; + + HWRM_UNLOCK(); + return rc; +} + static int bnxt_set_hwrm_link_config_v2(struct bnxt *bp, bool link_up) { struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf; @@ -4331,6 +4550,9 @@ bool tpa_flags = 0; int rc, i; + if (!BNXT_SUPPORTS_TPA(bp)) + return 0; + tpa_flags = (rx_offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) ? true : false; for (i = 0; i < bp->max_vnics; i++) { struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; @@ -5377,13 +5599,54 @@ *prev_cntr = *cntr; } +static void bnxt_get_prev_tx_stats(struct bnxt_ring_stats *ring_stats, + struct bnxt_ring_stats *prev_stats) +{ + ring_stats->tx_ucast_pkts = prev_stats->tx_ucast_pkts; + ring_stats->tx_mcast_pkts = prev_stats->tx_mcast_pkts; + ring_stats->tx_bcast_pkts = prev_stats->tx_bcast_pkts; + ring_stats->tx_ucast_bytes = prev_stats->tx_ucast_bytes; + ring_stats->tx_mcast_bytes = prev_stats->tx_mcast_bytes; + ring_stats->tx_bcast_bytes = prev_stats->tx_bcast_bytes; + ring_stats->tx_discard_pkts = prev_stats->tx_discard_pkts; +} + +static void bnxt_get_prev_rx_stats(struct bnxt_ring_stats *ring_stats, + struct bnxt_ring_stats *prev_stats) +{ + ring_stats->rx_ucast_pkts = prev_stats->rx_ucast_pkts; + ring_stats->rx_mcast_pkts = prev_stats->rx_mcast_pkts; + ring_stats->rx_bcast_pkts = prev_stats->rx_bcast_pkts; + ring_stats->rx_ucast_bytes = prev_stats->rx_ucast_bytes; + ring_stats->rx_mcast_bytes = prev_stats->rx_mcast_bytes; + ring_stats->rx_bcast_bytes = prev_stats->rx_bcast_bytes; + ring_stats->rx_discard_pkts = prev_stats->rx_discard_pkts; + ring_stats->rx_error_pkts = prev_stats->rx_error_pkts; + ring_stats->rx_agg_pkts = prev_stats->rx_agg_pkts; + ring_stats->rx_agg_bytes = prev_stats->rx_agg_bytes; + ring_stats->rx_agg_events = prev_stats->rx_agg_events; + ring_stats->rx_agg_aborts = prev_stats->rx_agg_aborts; +} + int bnxt_hwrm_ring_stats(struct bnxt *bp, uint32_t cid, int idx, struct bnxt_ring_stats *ring_stats, bool rx) { int rc = 0; struct hwrm_stat_ctx_query_input req = {.req_type = 0}; struct hwrm_stat_ctx_query_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_ring_stats *prev_stats = &bp->prev_rx_ring_stats[idx]; + + if (!rx) + prev_stats = &bp->prev_tx_ring_stats[idx]; + if (!bp->eth_dev->data->dev_started) { + if (rx) + bnxt_get_prev_rx_stats(ring_stats, prev_stats); + else + bnxt_get_prev_tx_stats(ring_stats, prev_stats); + + return 0; + } HWRM_PREP(&req, HWRM_STAT_CTX_QUERY, BNXT_USE_CHIMP_MB); req.stat_ctx_id = rte_cpu_to_le_32(cid); @@ -5393,8 +5656,6 @@ HWRM_CHECK_RESULT(); if (rx) { - struct bnxt_ring_stats *prev_stats = &bp->prev_rx_ring_stats[idx]; - ring_stats->rx_ucast_pkts = rte_le_to_cpu_64(resp->rx_ucast_pkts); bnxt_update_prev_stat(&ring_stats->rx_ucast_pkts, &prev_stats->rx_ucast_pkts); @@ -5443,8 +5704,6 @@ bnxt_update_prev_stat(&ring_stats->rx_agg_aborts, &prev_stats->rx_agg_aborts); } else { - struct bnxt_ring_stats *prev_stats = &bp->prev_tx_ring_stats[idx]; - ring_stats->tx_ucast_pkts = rte_le_to_cpu_64(resp->tx_ucast_pkts); bnxt_update_prev_stat(&ring_stats->tx_ucast_pkts, &prev_stats->tx_ucast_pkts); @@ -5479,6 +5738,38 @@ return rc; } +static void bnxt_get_prev_rx_stats_ext(struct bnxt_ring_stats_ext *ring_stats, + struct bnxt_ring_stats_ext *prev_stats) +{ + ring_stats->rx_ucast_pkts = prev_stats->rx_ucast_pkts; + ring_stats->rx_mcast_pkts = prev_stats->rx_mcast_pkts; + ring_stats->rx_bcast_pkts = prev_stats->rx_bcast_pkts; + ring_stats->rx_ucast_bytes = prev_stats->rx_ucast_bytes; + ring_stats->rx_mcast_bytes = prev_stats->rx_mcast_bytes; + ring_stats->rx_bcast_bytes = prev_stats->rx_bcast_bytes; + ring_stats->rx_discard_pkts = prev_stats->rx_discard_pkts; + ring_stats->rx_error_pkts = prev_stats->rx_error_pkts; + ring_stats->rx_tpa_eligible_pkt = prev_stats->rx_tpa_eligible_pkt; + ring_stats->rx_tpa_eligible_bytes = prev_stats->rx_tpa_eligible_bytes; + ring_stats->rx_tpa_pkt = prev_stats->rx_tpa_pkt; + ring_stats->rx_tpa_bytes = prev_stats->rx_tpa_bytes; + ring_stats->rx_tpa_errors = prev_stats->rx_tpa_errors; + ring_stats->rx_tpa_events = prev_stats->rx_tpa_events; +} + +static void bnxt_get_prev_tx_stats_ext(struct bnxt_ring_stats_ext *ring_stats, + struct bnxt_ring_stats_ext *prev_stats) +{ + ring_stats->tx_ucast_pkts = prev_stats->tx_ucast_pkts; + ring_stats->tx_mcast_pkts = prev_stats->tx_mcast_pkts; + ring_stats->tx_bcast_pkts = prev_stats->tx_bcast_pkts; + ring_stats->tx_ucast_bytes = prev_stats->tx_ucast_bytes; + ring_stats->tx_mcast_bytes = prev_stats->tx_mcast_bytes; + ring_stats->tx_bcast_bytes = prev_stats->tx_bcast_bytes; + ring_stats->tx_discard_pkts = prev_stats->tx_discard_pkts; + ring_stats->tx_error_pkts = prev_stats->tx_error_pkts; +} + int bnxt_hwrm_ring_stats_ext(struct bnxt *bp, uint32_t cid, int idx, struct bnxt_ring_stats_ext *ring_stats, bool rx) { @@ -5486,6 +5777,19 @@ struct hwrm_stat_ext_ctx_query_input req = {.req_type = 0}; struct hwrm_stat_ext_ctx_query_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_ring_stats_ext *prev_stats = &bp->prev_rx_ring_stats_ext[idx]; + + if (!rx) + prev_stats = &bp->prev_tx_ring_stats_ext[idx]; + + if (!bp->eth_dev->data->dev_started) { + if (rx) + bnxt_get_prev_rx_stats_ext(ring_stats, prev_stats); + else + bnxt_get_prev_tx_stats_ext(ring_stats, prev_stats); + + return 0; + } HWRM_PREP(&req, HWRM_STAT_EXT_CTX_QUERY, BNXT_USE_CHIMP_MB); req.stat_ctx_id = rte_cpu_to_le_32(cid); @@ -5494,8 +5798,6 @@ HWRM_CHECK_RESULT(); if (rx) { - struct bnxt_ring_stats_ext *prev_stats = &bp->prev_rx_ring_stats_ext[idx]; - ring_stats->rx_ucast_pkts = rte_le_to_cpu_64(resp->rx_ucast_pkts); bnxt_update_prev_stat(&ring_stats->rx_ucast_pkts, &prev_stats->rx_ucast_pkts); @@ -5552,8 +5854,6 @@ bnxt_update_prev_stat(&ring_stats->rx_tpa_events, &prev_stats->rx_tpa_events); } else { - struct bnxt_ring_stats_ext *prev_stats = &bp->prev_tx_ring_stats_ext[idx]; - ring_stats->tx_ucast_pkts = rte_le_to_cpu_64(resp->tx_ucast_pkts); bnxt_update_prev_stat(&ring_stats->tx_ucast_pkts, &prev_stats->tx_ucast_pkts); @@ -6528,7 +6828,10 @@ flags = rte_le_to_cpu_32(resp->flags); type = rte_le_to_cpu_16(resp->next_valid_type); - if (!(flags & HWRM_FUNC_BACKING_STORE_QCAPS_V2_OUTPUT_FLAGS_TYPE_VALID)) { + if (!(flags & HWRM_FUNC_BACKING_STORE_QCAPS_V2_OUTPUT_FLAGS_TYPE_VALID) || + (rte_le_to_cpu_16(req.type) == + HWRM_FUNC_BACKING_STORE_QCAPS_V2_INPUT_TYPE_TTX_PACING_TQM_RING && + !(bp->fw_cap & BNXT_FW_CAP_TIMED_TX_PACING))) { cnt = false; goto next; } @@ -6605,7 +6908,10 @@ type = rte_le_to_cpu_16(resp->next_valid_type); HWRM_UNLOCK(); - if (flags & HWRM_FUNC_BACKING_STORE_QCAPS_V2_OUTPUT_FLAGS_TYPE_VALID) { + if ((flags & HWRM_FUNC_BACKING_STORE_QCAPS_V2_OUTPUT_FLAGS_TYPE_VALID) && + !(rte_le_to_cpu_16(req.type) == + HWRM_FUNC_BACKING_STORE_QCAPS_V2_INPUT_TYPE_TTX_PACING_TQM_RING && + !(bp->fw_cap & BNXT_FW_CAP_TIMED_TX_PACING))) { PMD_DRV_LOG_LINE(DEBUG, "Valid types 0x%x", req.type); types++; } diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_hwrm.h dpdk-24.11.8/drivers/net/bnxt/bnxt_hwrm.h --- dpdk-24.11.4/drivers/net/bnxt/bnxt_hwrm.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_hwrm.h 2026-10-14 13:10:05.000000000 +0000 @@ -261,6 +261,7 @@ int bnxt_alloc_hwrm_resources(struct bnxt *bp); int bnxt_get_hwrm_link_config(struct bnxt *bp, struct rte_eth_link *link); int bnxt_set_hwrm_link_config(struct bnxt *bp, bool link_up); +int bnxt_hwrm_set_pause(struct bnxt *bp); int bnxt_hwrm_func_qcfg(struct bnxt *bp, uint16_t *mtu); int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp); int bnxt_hwrm_func_reserve_vf_resc(struct bnxt *bp, bool test); diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_ring.c dpdk-24.11.8/drivers/net/bnxt/bnxt_ring.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_ring.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_ring.c 2026-10-14 13:10:05.000000000 +0000 @@ -696,6 +696,9 @@ for (i = 0; i < bp->rx_cp_nr_rings; i++) { rxq = bp->rx_queues[i]; + + if (rxq == NULL) + continue; /* Rx-compl */ cp_ring = rxq->cp_ring->cp_ring_struct; cp_ring->fw_ring_id = INVALID_HW_RING_ID; @@ -738,9 +741,15 @@ for (i = 0; i < bp->rx_cp_nr_rings; i++) { unsigned int soc_id = bp->eth_dev->device->numa_node; struct bnxt_rx_queue *rxq = bp->rx_queues[i]; - struct bnxt_rx_ring_info *rxr = rxq->rx_ring; + struct bnxt_rx_ring_info *rxr; struct bnxt_ring *ring; + + if (rxq == NULL) + return -EINVAL; + + rxr = rxq->rx_ring; + if (bnxt_need_agg_ring(bp->eth_dev)) { ring = rxr->ag_ring_struct; if (ring == NULL) { diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_rxq.c dpdk-24.11.8/drivers/net/bnxt/bnxt_rxq.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_rxq.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_rxq.c 2026-10-14 13:10:05.000000000 +0000 @@ -38,7 +38,8 @@ RTE_ETH_RX_OFFLOAD_VLAN_EXTEND); - if (!bnxt_compressed_rx_cqe_mode_enabled(bp)) + if (!bnxt_compressed_rx_cqe_mode_enabled(bp) && + BNXT_SUPPORTS_TPA(bp)) rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TCP_LRO; if (bp->flags & BNXT_FLAG_PTP_SUPPORTED) rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP; @@ -461,7 +462,14 @@ return -EINVAL; cpr = rxq->cp_ring; - B_CP_DB_REARM(cpr, cpr->cp_raw_cons); + if (BNXT_CHIP_P5_P7(bp)) { + struct bnxt_cp_ring_info *nqr = bp->rxtx_nq_ring; + + bnxt_arm_nq_p5p(nqr, 1); + bnxt_arm_rx_cq_p5p(rxq->cp_ring, 1); + } else { + B_CP_DB_ARM(cpr); + } } return rc; } @@ -484,7 +492,43 @@ return -EINVAL; cpr = rxq->cp_ring; - B_CP_DB_DISARM(cpr); + if (BNXT_CHIP_P5_P7(bp)) { + struct bnxt_cp_ring_info *nqr = bp->rxtx_nq_ring; + struct bnxt_cp_ring_info *rx_cpr; + + bnxt_arm_nq_p5p(nqr, 0); + /* Loops through all RXQs and finds the one that + * received a packet if any + */ + uint32_t cons = RING_CMPL(nqr->cp_ring_struct->ring_mask, + nqr->cp_raw_cons); + struct cmpl_base *cmpl = &((nqr->cp_desc_ring)[cons]); + + if (CMPL_VALID(cmpl, nqr->valid)) { + unsigned int rxid = 0; + + rx_cpr = rxq->cp_ring; + for (; rxid < bp->rx_nr_rings; rxid++) { + rxq = bp->rx_queues[rxid]; + rx_cpr = rxq->cp_ring; + cons = RING_CMPL(rx_cpr->cp_ring_struct->ring_mask, + rx_cpr->cp_raw_cons); + cmpl = &((rx_cpr->cp_desc_ring)[cons]); + /* Because the valid bit in the rx + * completion queue is not updated the + * cmp valid using raw cons is used + */ + if (bnxt_cpr_cmp_valid(cmpl, + rx_cpr->cp_raw_cons, + rx_cpr->cp_ring_struct->ring_size)) { + break; + } + } + bnxt_process_nq(bp, nqr, rx_cpr); + } + } else { + B_CP_DB_DISARM(cpr); + } } return rc; } diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_rxr.c dpdk-24.11.8/drivers/net/bnxt/bnxt_rxr.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_rxr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_rxr.c 2026-10-14 13:10:05.000000000 +0000 @@ -727,14 +727,26 @@ mbuf->ol_flags = ol_flags; } +static void bnxt_get_rx_ts(struct bnxt *bp) +{ + struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; + + if (!ptp) + return; + + rte_spinlock_lock(&ptp->ptp_lock); + ptp->rx_timestamp = ptp->old_time; + rte_spinlock_unlock(&ptp->ptp_lock); +} + static void -bnxt_get_rx_ts_p5(struct bnxt *bp, uint32_t rx_ts_cmpl) +bnxt_get_rx_ts_p5_p7(struct bnxt *bp, uint32_t rx_ts_cmpl) { struct bnxt_ptp_cfg *ptp = bp->ptp_cfg; - uint64_t last_hwrm_time = 0; + uint64_t last_hwrm_time; uint64_t pkt_time = 0; - if (!BNXT_CHIP_P5(bp) || !ptp) + if (!ptp) return; /* On P5, Rx timestamps are provided directly in the @@ -1115,6 +1127,7 @@ uint16_t cmp_type; uint32_t vfr_flag = 0, mark_id = 0; struct bnxt *bp = rxq->bp; + struct bnxt_vnic_info *vnic = rxq->vnic; rxcmp = (struct rx_pkt_cmpl *) &cpr->cp_desc_ring[cp_cons]; @@ -1189,16 +1202,30 @@ mbuf->data_len = mbuf->pkt_len; mbuf->port = rxq->port_id; - if (unlikely((rte_le_to_cpu_16(rxcmp->flags_type) & - RX_PKT_CMPL_FLAGS_MASK) == - RX_PKT_CMPL_FLAGS_ITYPE_PTP_W_TIMESTAMP) || - bp->ptp_all_rx_tstamp) - bnxt_get_rx_ts_p5(rxq->bp, rxcmp1->reorder); + /* Extract the hardware timestamp from the completion record if: + * 1. The packet is explicitly classified as a PTP packet (with or + * without timestamp), OR + * 2. Promiscuous timestamping is enabled (ptp_all_rx_tstamp), which + * instructs the hardware to timestamp all packets, including + * non-PTP traffic (e.g., IPv6). + */ + if (unlikely(((rte_le_to_cpu_16(rxcmp->flags_type) & + RX_PKT_CMPL_FLAGS_MASK) == + RX_PKT_CMPL_FLAGS_ITYPE_PTP_W_TIMESTAMP) || + ((rte_le_to_cpu_16(rxcmp->flags_type) & + RX_PKT_CMPL_FLAGS_MASK) == + RX_PKT_CMPL_FLAGS_ITYPE_PTP_WO_TIMESTAMP) || + bp->ptp_all_rx_tstamp)) { + if (BNXT_CHIP_P5_P7(bp)) + bnxt_get_rx_ts_p5_p7(rxq->bp, rxcmp1->reorder); + else + bnxt_get_rx_ts(rxq->bp); + } if (cmp_type == CMPL_BASE_TYPE_RX_L2_V3) { bnxt_parse_csum_v3(mbuf, rxcmp1); bnxt_parse_pkt_type_v3(mbuf, rxcmp, rxcmp1); - bnxt_rx_vlan_v3(mbuf, rxcmp, rxcmp1); + bnxt_rx_vlan_v3(mbuf, rxcmp, rxcmp1, vnic->vlan_strip); if (BNXT_TRUFLOW_EN(bp)) mark_id = bnxt_ulp_set_mark_in_mbuf_v3(rxq->bp, rxcmp1, mbuf, &vfr_flag); @@ -1451,7 +1478,7 @@ int i; struct bnxt_rx_queue *rxq; - if (!bp->rx_queues) + if (!bp->rx_queues || !bp->eth_dev->data->rx_queues) return; for (i = 0; i < (int)bp->rx_nr_rings; i++) { diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_rxr.h dpdk-24.11.8/drivers/net/bnxt/bnxt_rxr.h --- dpdk-24.11.4/drivers/net/bnxt/bnxt_rxr.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_rxr.h 2026-10-14 13:10:05.000000000 +0000 @@ -474,11 +474,14 @@ static inline void bnxt_rx_vlan_v3(struct rte_mbuf *mbuf, struct rx_pkt_cmpl *rxcmp, - struct rx_pkt_cmpl_hi *rxcmp1) + struct rx_pkt_cmpl_hi *rxcmp1, + bool stripped) { if (RX_CMP_V3_VLAN_VALID(rxcmp)) { mbuf->vlan_tci = RX_CMP_V3_METADATA0_VID(rxcmp1); - mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED; + mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN; + if (stripped) + mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN_STRIPPED; } } diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_stats.c dpdk-24.11.8/drivers/net/bnxt/bnxt_stats.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_stats.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_stats.c 2026-10-14 13:10:05.000000000 +0000 @@ -547,15 +547,20 @@ { int i; - for (i = 0; i < (int)bp->tx_cp_nr_rings; i++) { - struct bnxt_tx_queue *txq = bp->tx_queues[i]; + if (bp->tx_queues && bp->eth_dev->data->tx_queues) { + for (i = 0; i < (int)bp->tx_cp_nr_rings; i++) { + struct bnxt_tx_queue *txq = bp->tx_queues[i]; - bnxt_free_txq_stats(txq); + bnxt_free_txq_stats(txq); + } } - for (i = 0; i < (int)bp->rx_cp_nr_rings; i++) { - struct bnxt_rx_queue *rxq = bp->rx_queues[i]; - bnxt_free_rxq_stats(rxq); + if (bp->rx_queues && bp->eth_dev->data->rx_queues) { + for (i = 0; i < (int)bp->rx_cp_nr_rings; i++) { + struct bnxt_rx_queue *rxq = bp->rx_queues[i]; + + bnxt_free_rxq_stats(rxq); + } } } @@ -675,6 +680,9 @@ struct bnxt_cp_ring_info *cpr = txq->cp_ring; struct bnxt_ring_stats_ext ring_stats = {0}; + bnxt_stats->oerrors += rte_atomic_load_explicit(&txq->tx_mbuf_drop, + rte_memory_order_relaxed); + if (!txq->tx_started) continue; @@ -701,9 +709,6 @@ if (rc) return rc; - if (!eth_dev->data->dev_started) - return -EIO; - if (BNXT_TPA_V2_P7(bp)) return bnxt_stats_get_ext(eth_dev, bnxt_stats); diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_txq.c dpdk-24.11.8/drivers/net/bnxt/bnxt_txq.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_txq.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_txq.c 2026-10-14 13:10:05.000000000 +0000 @@ -198,11 +198,7 @@ goto err; } - rc = pthread_mutex_init(&txq->txq_lock, NULL); - if (rc != 0) { - PMD_DRV_LOG_LINE(ERR, "TxQ mutex init failed!"); - goto err; - } + rte_thread_mutex_init_shared(&txq->txq_lock); return 0; err: bnxt_tx_queue_release_op(eth_dev, queue_idx); diff -Nru dpdk-24.11.4/drivers/net/bnxt/bnxt_txr.c dpdk-24.11.8/drivers/net/bnxt/bnxt_txr.c --- dpdk-24.11.4/drivers/net/bnxt/bnxt_txr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/bnxt_txr.c 2026-10-14 13:10:05.000000000 +0000 @@ -24,6 +24,9 @@ { int i; + if (!bp->tx_queues || !bp->eth_dev->data->tx_queues) + return; + for (i = 0; i < (int)bp->tx_nr_rings; i++) { struct bnxt_tx_queue *txq = bp->tx_queues[i]; @@ -111,8 +114,7 @@ static bool bnxt_xmit_need_long_bd(struct rte_mbuf *tx_pkt, struct bnxt_tx_queue *txq) { - if (tx_pkt->ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_TCP_CKSUM | - RTE_MBUF_F_TX_UDP_CKSUM | RTE_MBUF_F_TX_IP_CKSUM | + if (tx_pkt->ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_OUTER_IP_CKSUM | RTE_MBUF_F_TX_TUNNEL_GRE | RTE_MBUF_F_TX_TUNNEL_VXLAN | RTE_MBUF_F_TX_TUNNEL_GENEVE | RTE_MBUF_F_TX_IEEE1588_TMST | @@ -233,15 +235,17 @@ uint16_t *coal_pkts, struct tx_bd_long **last_txbd) { + struct tx_bd_long *last_txbd_save = *last_txbd; struct bnxt_tx_ring_info *txr = txq->tx_ring; struct bnxt_ring *ring = txr->tx_ring_struct; + uint16_t tx_raw_prod_save = txr->tx_raw_prod; uint32_t outer_tpid_bd = 0; struct tx_bd_long *txbd; struct tx_bd_long_hi *txbd1 = NULL; uint32_t vlan_tag_flags; bool long_bd = false; unsigned short nr_bds; - uint16_t prod; + uint16_t prod, idx; bool pkt_needs_ts = 0; struct rte_mbuf *m_seg; struct rte_mbuf **tx_buf; @@ -325,7 +329,10 @@ txbd->flags_type |= TX_BD_LONG_FLAGS_LHINT_GTE2K; else txbd->flags_type |= lhint_arr[tx_pkt->pkt_len >> 9]; - txbd->address = rte_cpu_to_le_64(rte_mbuf_data_iova(tx_pkt)); + if (tx_pkt->ol_flags & RTE_MBUF_F_EXTERNAL) + txbd->address = rte_cpu_to_le_64(rte_pktmbuf_mtod_offset(tx_pkt, uint64_t, 0)); + else + txbd->address = rte_cpu_to_le_64(rte_mbuf_data_iova(tx_pkt)); *last_txbd = txbd; if (long_bd) { @@ -482,7 +489,12 @@ *tx_buf = m_seg; txbd = &txr->tx_desc_ring[prod]; - txbd->address = rte_cpu_to_le_64(rte_mbuf_data_iova(m_seg)); + if (m_seg->ol_flags & RTE_MBUF_F_EXTERNAL) + txbd->address = rte_cpu_to_le_64(rte_pktmbuf_mtod_offset(m_seg, + uint64_t, + 0)); + else + txbd->address = rte_cpu_to_le_64(rte_mbuf_data_iova(m_seg)); txbd->flags_type = TX_BD_SHORT_TYPE_TX_BD_SHORT; txbd->len = m_seg->data_len; @@ -495,16 +507,71 @@ return 0; drop: + /* Roll back any descriptors and tx_buf_ring slots that were written + * for this packet before the failure was detected. Walking from the + * saved producer index up to (but not including) the current one is + * safe because we hold the Tx lock and the HW has not been notified + * (the doorbell is only rung after bnxt_start_xmit() returns + * successfully). + */ + idx = tx_raw_prod_save; + + while (idx != txr->tx_raw_prod) { + uint16_t slot = RING_IDX(ring, idx); + + txr->tx_buf_ring[slot] = NULL; + txr->tx_desc_ring[slot].address = 0; + idx = RING_NEXT(idx); + } + txr->tx_raw_prod = tx_raw_prod_save; + *last_txbd = last_txbd_save; rte_pktmbuf_free(tx_pkt); ret: return rc; } +static void bnxt_tx_coal_cmp_fast(struct bnxt_tx_queue *txq, int nr_cons) +{ + struct bnxt_tx_ring_info *txr = txq->tx_ring; + struct bnxt_ring *ring = txr->tx_ring_struct; + struct rte_mbuf **free = txq->free; + uint16_t raw_cons = txr->tx_raw_cons; + unsigned int blk = 0; + int cons, bds; + + for (cons = 0; cons < nr_cons; cons++) { + struct rte_mbuf **tx_buf; + unsigned short nr_bds; + + tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)]; + nr_bds = (*tx_buf)->nb_segs + + bnxt_xmit_need_long_bd(*tx_buf, txq); + for (bds = 0; bds < nr_bds; bds++) { + if (*tx_buf) { + free[blk++] = *tx_buf; + /* + * Each BD also tracks a consumer index. + * Update cons, otherwise it will fall behind. + */ + cons++; + *tx_buf = NULL; + } + raw_cons = RING_NEXT(raw_cons); + tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)]; + } + } + if (blk) + rte_mempool_put_bulk(free[0]->pool, (void *)free, blk); + + txr->tx_raw_cons = raw_cons; +} + /* * Transmit completion function for use when RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE * is enabled. */ -static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts) +static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nb_tx, + bool tx_coal_cmp) { struct bnxt_tx_ring_info *txr = txq->tx_ring; struct bnxt_ring *ring = txr->tx_ring_struct; @@ -513,7 +580,10 @@ unsigned int blk = 0; int i, j; - for (i = 0; i < nr_pkts; i++) { + if (tx_coal_cmp) + return bnxt_tx_coal_cmp_fast(txq, nb_tx); + + for (i = 0; i < nb_tx; i++) { struct rte_mbuf **tx_buf; unsigned short nr_bds; @@ -536,7 +606,72 @@ txr->tx_raw_cons = raw_cons; } -static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts) +static void bnxt_tx_coal_cmp(struct bnxt_tx_queue *txq, int nr_cons) +{ + struct bnxt_tx_ring_info *txr = txq->tx_ring; + struct bnxt_ring *ring = txr->tx_ring_struct; + struct rte_mempool *pool = NULL; + struct rte_mbuf **free = txq->free; + uint16_t raw_cons = txr->tx_raw_cons; + unsigned int blk = 0; + int cons, bds; + + for (cons = 0; cons < nr_cons; cons++) { + struct rte_mbuf *mbuf; + struct rte_mbuf **tx_buf; + unsigned short nr_bds; + + tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)]; + nr_bds = txr->nr_bds[RING_IDX(ring, raw_cons)]; + /* Clear the now stale number of buffer descriptors */ + txr->nr_bds[RING_IDX(ring, raw_cons)] = 0; + + for (bds = 0; bds < nr_bds; bds++) { + mbuf = *tx_buf; + *tx_buf = NULL; + raw_cons = RING_NEXT(raw_cons); + /* + * Each BD also tracks a consumer index. So update the cons. + * Otherwise the cons will fall behind. + */ + cons++; + tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)]; + if (!mbuf) /* long_bd's tx_buf ? */ + continue; + + mbuf = rte_pktmbuf_prefree_seg(mbuf); + if (unlikely(!mbuf)) + continue; + + /* EW - no need to unmap DMA memory? */ + + if (likely(mbuf->pool == pool)) { + /* Add mbuf to the bulk free array */ + free[blk++] = mbuf; + } else { + /* Found an mbuf from a different pool. Free + * mbufs accumulated so far to the previous + * pool + */ + if (likely(pool != NULL)) + rte_mempool_put_bulk(pool, + (void *)free, + blk); + + /* Start accumulating mbufs in a new pool */ + free[0] = mbuf; + pool = mbuf->pool; + blk = 1; + } + } + } + if (blk) + rte_mempool_put_bulk(pool, (void *)free, blk); + + txr->tx_raw_cons = raw_cons; +} + +static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nb_tx, bool tx_coal_cmp) { struct bnxt_tx_ring_info *txr = txq->tx_ring; struct bnxt_ring *ring = txr->tx_ring_struct; @@ -546,13 +681,19 @@ unsigned int blk = 0; int i, j; - for (i = 0; i < nr_pkts; i++) { + if (tx_coal_cmp) + return bnxt_tx_coal_cmp(txq, nb_tx); + + for (i = 0; i < nb_tx; i++) { struct rte_mbuf *mbuf; struct rte_mbuf **tx_buf; unsigned short nr_bds; tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)]; nr_bds = txr->nr_bds[RING_IDX(ring, raw_cons)]; + /* Clear the now stale number of buffer descriptors */ + txr->nr_bds[RING_IDX(ring, raw_cons)] = 0; + for (j = 0; j < nr_bds; j++) { mbuf = *tx_buf; *tx_buf = NULL; @@ -600,12 +741,28 @@ type == CMPL_BASE_TYPE_TX_L2); } +static void bnxt_get_tx_ts_p7(struct bnxt *bp, struct tx_cmpl_packet_timestamp *txcmp) +{ + uint64_t tx_timestamp; + + if (!(bp->fw_cap & BNXT_FW_CAP_TX_TS_CMP)) + return; + + if (!bp->ptp_cfg || !bp->ieee_1588) + return; + + tx_timestamp = rte_le_to_cpu_16(txcmp->ts_ns_mid); + bp->ptp_cfg->tx_timestamp = (tx_timestamp << 32) | rte_le_to_cpu_32(txcmp->ts_ns_lo); +} + static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq) { uint32_t nb_tx_pkts = 0, cons, ring_mask, opaque; struct bnxt_cp_ring_info *cpr = txq->cp_ring; uint32_t raw_cons = cpr->cp_raw_cons; struct bnxt_ring *cp_ring_struct; + uint32_t tx_ring_mask; + bool tx_coal_cmp = false; struct tx_cmpl *txcmp; if (bnxt_tx_bds_in_hw(txq) < txq->tx_free_thresh) @@ -613,6 +770,7 @@ cp_ring_struct = cpr->cp_ring_struct; ring_mask = cp_ring_struct->ring_mask; + tx_ring_mask = txq->tx_ring->tx_ring_struct->ring_mask; do { cons = RING_CMPL(ring_mask, raw_cons); @@ -621,6 +779,16 @@ if (!bnxt_cpr_cmp_valid(txcmp, raw_cons, ring_mask + 1)) break; + if (CMP_TYPE(txcmp) == CMPL_BASE_TYPE_TX_L2_COAL) { + struct tx_cmpl_coal *txcmp_c = (struct tx_cmpl_coal *)txcmp; + + nb_tx_pkts = (rte_le_to_cpu_32(txcmp_c->sq_cons_idx) - + (txq->tx_ring->tx_raw_cons & tx_ring_mask)) & tx_ring_mask; + raw_cons = NEXT_RAW_CMP(raw_cons); + tx_coal_cmp = true; + break; + } + opaque = rte_le_to_cpu_32(txcmp->opaque); if (bnxt_is_tx_cmpl_type(CMP_TYPE(txcmp))) @@ -629,14 +797,16 @@ RTE_LOG_DP_LINE(ERR, BNXT, "Unhandled CMP type %02x", CMP_TYPE(txcmp)); + if (CMP_TYPE(txcmp) == CMPL_BASE_TYPE_TX_L2_PKT_TS) + bnxt_get_tx_ts_p7(txq->bp, (struct tx_cmpl_packet_timestamp *)txcmp); raw_cons = NEXT_RAW_CMP(raw_cons); } while (nb_tx_pkts < ring_mask); if (nb_tx_pkts) { if (txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) - bnxt_tx_cmp_fast(txq, nb_tx_pkts); + bnxt_tx_cmp_fast(txq, nb_tx_pkts, tx_coal_cmp); else - bnxt_tx_cmp(txq, nb_tx_pkts); + bnxt_tx_cmp(txq, nb_tx_pkts, tx_coal_cmp); cpr->cp_raw_cons = raw_cons; bnxt_db_cq(cpr); } @@ -684,22 +854,28 @@ if (unlikely(rc)) { if (rc == -EINVAL) { + coal_pkts--; rte_atomic_fetch_add_explicit(&txq->tx_mbuf_drop, 1, rte_memory_order_relaxed); dropped++; + continue; } break; } } - if (likely(nb_tx_pkts)) { + /* last_txbd is used to check for if any packets have been sent in + * the burst as bnxt_start_xmit will update it to the most recent + * non-dropped buffer descriptor in the burst. + */ + if (likely(last_txbd != NULL)) { /* Request a completion on the last packet */ last_txbd->flags_type &= ~TX_BD_LONG_FLAGS_NO_CMPL; bnxt_db_write(&txq->tx_ring->tx_db, txq->tx_ring->tx_raw_prod); } - nb_tx_pkts += dropped; - return nb_tx_pkts; + return RTE_MIN((uint16_t)(nb_tx_pkts + dropped), nb_pkts); + } int bnxt_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id) diff -Nru dpdk-24.11.4/drivers/net/bnxt/hsi_struct_def_dpdk.h dpdk-24.11.8/drivers/net/bnxt/hsi_struct_def_dpdk.h --- dpdk-24.11.4/drivers/net/bnxt/hsi_struct_def_dpdk.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/hsi_struct_def_dpdk.h 2026-10-14 13:10:05.000000000 +0000 @@ -24457,6 +24457,9 @@ /* RoCE HWRM trace. */ #define HWRM_FUNC_BACKING_STORE_QCAPS_V2_INPUT_TYPE_ROCE_HWRM_TRACE \ UINT32_C(0x24) + /* TimedTx pacing TQM ring. */ + #define HWRM_FUNC_BACKING_STORE_QCAPS_V2_INPUT_TYPE_TTX_PACING_TQM_RING \ + UINT32_C(0x25) /* Invalid type. */ #define HWRM_FUNC_BACKING_STORE_QCAPS_V2_INPUT_TYPE_INVALID \ UINT32_C(0xffff) diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_core/cfa_tcam_mgr_session.c dpdk-24.11.8/drivers/net/bnxt/tf_core/cfa_tcam_mgr_session.c --- dpdk-24.11.4/drivers/net/bnxt/tf_core/cfa_tcam_mgr_session.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_core/cfa_tcam_mgr_session.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,390 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2021-2023 Broadcom - * All rights reserved. - */ - -#include -#include "hcapi_cfa_defs.h" -#include "tf_util.h" -#include "cfa_tcam_mgr.h" -#include "cfa_tcam_mgr_device.h" -#include "cfa_tcam_mgr_session.h" -#include "cfa_tcam_mgr_sbmp.h" -#include "tfp.h" -#include "cfa_tcam_mgr_p58.h" -#include "cfa_tcam_mgr_p4.h" - -struct cfa_tcam_mgr_session_data { - uint32_t session_id; - /* The following are per-session values */ - uint16_t max_entries[TF_DIR_MAX][CFA_TCAM_MGR_TBL_TYPE_MAX]; - uint16_t used_entries[TF_DIR_MAX][CFA_TCAM_MGR_TBL_TYPE_MAX]; -}; - -static struct cfa_tcam_mgr_session_data session_data[TF_TCAM_MAX_SESSIONS]; - -static uint16_t last_entry_id; - -static struct sbmp *session_bmp[TF_TCAM_MAX_SESSIONS]; - -int -cfa_tcam_mgr_session_init(int sess_idx, enum cfa_tcam_mgr_device_type type) -{ - int rc; - - switch (type) { - case CFA_TCAM_MGR_DEVICE_TYPE_P4: - case CFA_TCAM_MGR_DEVICE_TYPE_SR: - rc = cfa_tcam_mgr_sess_table_get_p4(sess_idx, &session_bmp[sess_idx]); - break; - case CFA_TCAM_MGR_DEVICE_TYPE_P5: - rc = cfa_tcam_mgr_sess_table_get_p58(sess_idx, &session_bmp[sess_idx]); - break; - default: - CFA_TCAM_MGR_LOG(ERR, "No such device %d\n", type); - rc = -CFA_TCAM_MGR_ERR_CODE(NODEV); - } - - return rc; -} - -int -cfa_tcam_mgr_get_session_from_context(struct cfa_tcam_mgr_context *context, - uint32_t *session_id) -{ - if (context == NULL) { - CFA_TCAM_MGR_LOG_0(ERR, "context passed as NULL pointer.\n"); - return -CFA_TCAM_MGR_ERR_CODE(INVAL); - } - - *session_id = context->tfp->session->session_id.id; - return 0; -} - -int -cfa_tcam_mgr_session_find(unsigned int session_id) -{ - unsigned int sess_idx; - - for (sess_idx = 0; sess_idx < ARRAY_SIZE(session_data); sess_idx++) { - if (session_data[sess_idx].session_id == session_id) - return sess_idx; - } - - return -CFA_TCAM_MGR_ERR_CODE(INVAL); -} - -int -cfa_tcam_mgr_session_empty(void) -{ - unsigned int sess_idx; - - for (sess_idx = 0; sess_idx < ARRAY_SIZE(session_data); sess_idx++) { - if (session_data[sess_idx].session_id) - return 0; - } - - return 1; -} - -int -cfa_tcam_mgr_session_add(unsigned int session_id) -{ - int sess_idx; - - sess_idx = cfa_tcam_mgr_session_find(session_id); - if (sess_idx >= 0) { - CFA_TCAM_MGR_LOG_0(ERR, "Session is already bound.\n"); - return -CFA_TCAM_MGR_ERR_CODE(BUSY); - } - - /* Session not found in table, find first empty entry. */ - for (sess_idx = 0; - sess_idx < (signed int)ARRAY_SIZE(session_data); - sess_idx++) { - if (session_data[sess_idx].session_id == 0) - break; - } - - if (sess_idx >= (signed int)ARRAY_SIZE(session_data)) { - /* No room in the session table */ - CFA_TCAM_MGR_LOG_0(ERR, "Session table is full.\n"); - return -CFA_TCAM_MGR_ERR_CODE(NOMEM); - } - - session_data[sess_idx].session_id = session_id; - - return sess_idx; -} - -int -cfa_tcam_mgr_session_free(unsigned int session_id, - struct cfa_tcam_mgr_context *context) -{ - struct cfa_tcam_mgr_free_parms free_parms; - int entry_id; - int sess_idx = cfa_tcam_mgr_session_find(session_id); - - if (sess_idx < 0) - return sess_idx; - - memset(&free_parms, 0, sizeof(free_parms)); - /* Since we are freeing all pending TCAM entries (which is typically - * done during tcam_unbind), we don't know the type of each entry. - * So we set the type to MAX as a hint to cfa_tcam_mgr_free() to - * figure out the actual type. We need to set it through each - * iteration in the loop below; otherwise, the type determined for - * the first entry would be used for subsequent entries that may or - * may not be of the same type, resulting in errors. - */ - for (entry_id = 0; entry_id < cfa_tcam_mgr_max_entries[sess_idx]; entry_id++) { - if (SBMP_MEMBER(session_bmp[sess_idx][entry_id], sess_idx)) { - SBMP_SESSION_REMOVE(session_bmp[sess_idx][entry_id], sess_idx); - - free_parms.id = entry_id; - free_parms.type = CFA_TCAM_MGR_TBL_TYPE_MAX; - cfa_tcam_mgr_free(context, &free_parms); - } - } - - memset(&session_data[sess_idx], 0, sizeof(session_data[sess_idx])); - return 0; -} - -int -cfa_tcam_mgr_session_cfg(unsigned int session_id, - uint16_t tcam_cnt[][CFA_TCAM_MGR_TBL_TYPE_MAX]) -{ - struct cfa_tcam_mgr_table_data *table_data; - struct cfa_tcam_mgr_session_data *session_entry; - unsigned int dir, type; - int sess_idx = cfa_tcam_mgr_session_find(session_id); - uint16_t requested_cnt; - - if (sess_idx < 0) - return sess_idx; - - session_entry = &session_data[sess_idx]; - - /* Validate session request */ - for (dir = 0; dir < ARRAY_SIZE(cfa_tcam_mgr_tables[sess_idx]); dir++) { - for (type = 0; - type < ARRAY_SIZE(cfa_tcam_mgr_tables[sess_idx][dir]); - type++) { - table_data = &cfa_tcam_mgr_tables[sess_idx][dir][type]; - requested_cnt = tcam_cnt[dir][type]; - /* - * Only check if table supported (max_entries > 0). - */ - if (table_data->max_entries > 0 && - requested_cnt > table_data->max_entries) { - CFA_TCAM_MGR_LOG_DIR_TYPE(ERR, dir, type, - "Requested %d, available %d.\n", - requested_cnt, - table_data->max_entries); - return -CFA_TCAM_MGR_ERR_CODE(NOSPC); - } - } - } - - memcpy(session_entry->max_entries, tcam_cnt, - sizeof(session_entry->max_entries)); - return 0; -} - -void -cfa_tcam_mgr_mv_session_used_entries_cnt(int sess_idx, enum tf_dir dir, - enum cfa_tcam_mgr_tbl_type dst_type, - enum cfa_tcam_mgr_tbl_type src_type) -{ - session_data[sess_idx].used_entries[dir][dst_type]++; - session_data[sess_idx].used_entries[dir][src_type]--; -} - -int -cfa_tcam_mgr_session_entry_alloc(unsigned int session_id, - enum tf_dir dir, - enum cfa_tcam_mgr_tbl_type type) -{ - int sess_idx; - - sess_idx = cfa_tcam_mgr_session_find(session_id); - if (sess_idx < 0) { - CFA_TCAM_MGR_LOG_0(ERR, "Session not found.\n"); - return -CFA_TCAM_MGR_ERR_CODE(NODEV); - } - - if (session_data[sess_idx].used_entries[dir][type] >= - session_data[sess_idx].max_entries[dir][type]) { - CFA_TCAM_MGR_LOG_0(ERR, "Table full (session).\n"); - return -CFA_TCAM_MGR_ERR_CODE(NOSPC); - } - - do { - last_entry_id++; - if (cfa_tcam_mgr_max_entries[sess_idx] <= last_entry_id) - last_entry_id = 0; - } while (!SBMP_IS_NULL(session_bmp[sess_idx][last_entry_id])); - - SBMP_SESSION_ADD(session_bmp[sess_idx][last_entry_id], sess_idx); - - session_data[sess_idx].used_entries[dir][type] += 1; - - return last_entry_id; -} - -int -cfa_tcam_mgr_session_entry_free(unsigned int session_id, - unsigned int entry_id, - enum tf_dir dir, - enum cfa_tcam_mgr_tbl_type type) -{ - int sess_idx; - - sess_idx = cfa_tcam_mgr_session_find(session_id); - if (sess_idx < 0) { - CFA_TCAM_MGR_LOG_0(ERR, "Session not found.\n"); - return -CFA_TCAM_MGR_ERR_CODE(NODEV); - } - - SBMP_SESSION_REMOVE(session_bmp[sess_idx][entry_id], sess_idx); - session_data[sess_idx].used_entries[dir][type] -= 1; - - return 0; -} - -#if SBMP_WORD_WIDTH == 16 -#define SBMP_FORMAT PRIX16 -#define SBMP_PRECISION "4" -#elif SBMP_WORD_WIDTH == 32 -#define SBMP_FORMAT PRIX32 -#define SBMP_PRECISION "8" -#elif SBMP_WORD_WIDTH == 64 -#define SBMP_FORMAT PRIX64 -#define SBMP_PRECISION "16" -#else -#error "Invalid value for SBMP_WORD_WIDTH." -#endif - -static void -cfa_tcam_mgr_session_bitmap_print(struct sbmp *session_bmp) -{ - unsigned int i; - - printf("0x"); - for (i = 0; - i < ARRAY_SIZE(session_bmp->bits); - i++) { - printf("%0" SBMP_PRECISION SBMP_FORMAT, - session_bmp->bits[i]); - } -} - -#define SESSION_DUMP_HEADER_1 " RX TX\n" -#define SESSION_DUMP_HEADER_2 \ - " Max Used Max Used\n" - -static void -cfa_tcam_mgr_session_printf(struct cfa_tcam_mgr_session_data *session, - enum cfa_tcam_mgr_tbl_type tbl_type) -{ - printf("%-22s: %5u %5u %5u %5u\n", - cfa_tcam_mgr_tbl_2_str(tbl_type), - session->max_entries[TF_DIR_RX][tbl_type], - session->used_entries[TF_DIR_RX][tbl_type], - session->max_entries[TF_DIR_TX][tbl_type], - session->used_entries[TF_DIR_TX][tbl_type]); -} - -void -cfa_tcam_mgr_sessions_dump(void) -{ - struct cfa_tcam_mgr_session_data *session; - unsigned int sess_idx; - bool sess_found = false; - enum cfa_tcam_mgr_tbl_type tbl_type; - - printf("\nTCAM Sessions Table:\n"); - for (sess_idx = 0; sess_idx < ARRAY_SIZE(session_data); sess_idx++) { - if (session_data[sess_idx].session_id != 0) { - session = &session_data[sess_idx]; - if (!sess_found) { - printf(SESSION_DUMP_HEADER_1); - printf(SESSION_DUMP_HEADER_2); - } - printf("Session 0x%08x:\n", - session->session_id); - for (tbl_type = CFA_TCAM_MGR_TBL_TYPE_START; - tbl_type < CFA_TCAM_MGR_TBL_TYPE_MAX; - tbl_type++) { - cfa_tcam_mgr_session_printf(session, tbl_type); - } - sess_found = true; - } - } - - if (!sess_found) - printf("No sessions found.\n"); -} - -/* This dumps all the sessions using an entry */ -void -cfa_tcam_mgr_entry_sessions_dump(int sess_idx, uint16_t id) -{ - bool session_found = false; - - if (id >= cfa_tcam_mgr_max_entries[sess_idx]) { - printf("Entry ID %u out of range for sess_idx %d. Max ID %u.\n", - id, sess_idx, cfa_tcam_mgr_max_entries[sess_idx] - 1); - return; - } - - if (!SBMP_IS_NULL(session_bmp[sess_idx][id])) { - printf("Sessions using entry ID %u:\n", id); - for (sess_idx = 0; sess_idx < SBMP_SESSION_MAX; sess_idx++) - if (SBMP_MEMBER(session_bmp[sess_idx][id], (sess_idx))) { - if (session_data[sess_idx].session_id != 0) { - printf("0x%08x (index %d)\n", - session_data[sess_idx].session_id, - sess_idx); - session_found = true; - } else { - printf("Error! Entry ID %u used by " - "session index %d which is not " - "in use.\n", - id, sess_idx); - } - } - if (!session_found) - printf("No sessions using entry ID %u.\n", id); - } else { - printf("Entry ID %u not in use.\n", - id); - return; - } -} - -/* This dumps all the entries in use by any session */ -void -cfa_tcam_mgr_session_entries_dump(int sess_idx) -{ - bool entry_found = false; - uint16_t id; - - printf("\nGlobal Maximum Entries for sess_idx %d: %d\n\n", - sess_idx, cfa_tcam_mgr_max_entries[sess_idx]); - printf("TCAM Session Entry Table:\n"); - for (id = 0; id < cfa_tcam_mgr_max_entries[sess_idx]; id++) { - if (!SBMP_IS_NULL(session_bmp[sess_idx][id])) { - if (!entry_found) - printf(" EID Session bitmap\n"); - printf("%5u ", id); - cfa_tcam_mgr_session_bitmap_print(&session_bmp[sess_idx][id]); - printf("\n"); - entry_found = true; - } - } - - if (!entry_found) - printf("No entries found.\n"); -} diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_core/tf_em_common.c dpdk-24.11.8/drivers/net/bnxt/tf_core/tf_em_common.c --- dpdk-24.11.4/drivers/net/bnxt/tf_core/tf_em_common.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_core/tf_em_common.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2019-2023 Broadcom - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include "tf_core.h" -#include "tf_util.h" -#include "tf_common.h" -#include "tf_em.h" -#include "tf_em_common.h" -#include "tf_msg.h" -#include "tfp.h" -#include "tf_device.h" -#include "tf_ext_flow_handle.h" -#include "hcapi_cfa.h" -#include "bnxt.h" - diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_core/tf_em_host.c dpdk-24.11.8/drivers/net/bnxt/tf_core/tf_em_host.c --- dpdk-24.11.4/drivers/net/bnxt/tf_core/tf_em_host.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_core/tf_em_host.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2019-2023 Broadcom - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -#include "tf_core.h" -#include "tf_util.h" -#include "tf_common.h" -#include "tf_em.h" -#include "tf_em_common.h" -#include "tf_msg.h" -#include "tfp.h" -#include "lookup3.h" -#include "tf_ext_flow_handle.h" - -#include "bnxt.h" diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_core/v3/tfc_cpm.c dpdk-24.11.8/drivers/net/bnxt/tf_core/v3/tfc_cpm.c --- dpdk-24.11.4/drivers/net/bnxt/tf_core/v3/tfc_cpm.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_core/v3/tfc_cpm.c 2026-10-14 13:10:05.000000000 +0000 @@ -92,6 +92,10 @@ /* Alloc new entry */ new_pool_use = rte_zmalloc("tf", sizeof(struct cpm_pool_use), 0); + if (new_pool_use == NULL) { + PMD_DRV_LOG_LINE(ERR, "Failed to allocate pool_use entry"); + return -ENOMEM; + } new_pool_use->pool_id = pool_id; new_pool_use->prev = NULL; new_pool_use->next = NULL; @@ -287,6 +291,7 @@ int tfc_cpm_set_cmm_inst(struct tfc_cpm *cpm, uint16_t pool_id, struct tfc_cmm *cmm) { struct cpm_pool_entry *pool; + int rc; if (cpm == NULL) { PMD_DRV_LOG_LINE(ERR, "CPM is NULL"); @@ -309,7 +314,12 @@ pool->valid = false; } else { pool->valid = true; - cpm_insert_pool_id(cpm, pool_id); + rc = cpm_insert_pool_id(cpm, pool_id); + if (rc) { + pool->cmm = NULL; + pool->valid = false; + return rc; + } } return 0; diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp.c 2026-10-14 13:10:05.000000000 +0000 @@ -188,7 +188,6 @@ struct rte_pci_device *pci_dev; struct rte_pci_addr *pci_addr; struct bnxt_ulp_session_state *session; - int rc = 0; if (!bp) return NULL; @@ -215,12 +214,7 @@ session->pci_info.domain = pci_addr->domain; session->pci_info.bus = pci_addr->bus; memcpy(session->dsn, bp->dsn, sizeof(session->dsn)); - rc = pthread_mutex_init(&session->bnxt_ulp_mutex, NULL); - if (rc) { - BNXT_DRV_DBG(ERR, "mutex create failed\n"); - pthread_mutex_unlock(&bnxt_ulp_global_mutex); - return NULL; - } + rte_thread_mutex_init_shared(&session->bnxt_ulp_mutex); STAILQ_INSERT_TAIL(&bnxt_ulp_session_list, session, next); } diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c 2026-10-14 13:10:05.000000000 +0000 @@ -1299,10 +1299,10 @@ struct tf *tfp; /* Initialize the params */ - parms.dir = dir, - parms.type = type, - parms.offset = offset, - parms.config = (uint8_t *)&global_cfg, + parms.dir = dir; + parms.type = type; + parms.offset = offset; + parms.config = (uint8_t *)&global_cfg; parms.config_sz_in_bytes = sizeof(global_cfg); tfp = bnxt_ulp_bp_tfp_get(bp, BNXT_ULP_SESSION_TYPE_DEFAULT); @@ -1472,11 +1472,7 @@ goto jump_to_error; } - rc = pthread_mutex_init(&bp->ulp_ctx->cfg_data->flow_db_lock, NULL); - if (rc) { - BNXT_DRV_DBG(ERR, "Unable to initialize flow db lock\n"); - goto jump_to_error; - } + rte_thread_mutex_init_shared(&bp->ulp_ctx->cfg_data->flow_db_lock); /* Initialize ulp dparms with values devargs passed */ rc = ulp_tf_dparms_init(bp, bp->ulp_ctx); diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c 2026-10-14 13:10:05.000000000 +0000 @@ -993,11 +993,7 @@ goto jump_to_error; } - rc = pthread_mutex_init(&bp->ulp_ctx->cfg_data->flow_db_lock, NULL); - if (rc) { - BNXT_DRV_DBG(ERR, "Unable to initialize flow db lock\n"); - goto jump_to_error; - } + rte_thread_mutex_init_shared(&bp->ulp_ctx->cfg_data->flow_db_lock); rc = ulp_tfc_dparms_init(bp, bp->ulp_ctx, ulp_dev_id); if (rc) { diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_mapper.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_mapper.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_mapper.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_mapper.c 2026-10-14 13:10:05.000000000 +0000 @@ -2459,6 +2459,11 @@ slice_width = dparms->wc_slice_width; clen = dparms->wc_ctl_size_bits; + if (clen > 32) { + BNXT_DRV_DBG(ERR, "Key size bits %d too large\n", clen); + return -EINVAL; + } + max_slices = dparms->wc_max_slices; blen = ulp_blob_data_len_get(key); diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_mapper_tfc.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_mapper_tfc.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_mapper_tfc.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_mapper_tfc.c 2026-10-14 13:10:05.000000000 +0000 @@ -91,6 +91,10 @@ slice_width = dparms->wc_slice_width; clen = dparms->wc_ctl_size_bits; + if (clen > 32) { + BNXT_DRV_DBG(ERR, "Key size bits %d too large\n", clen); + return -EINVAL; + } max_slices = dparms->wc_max_slices; blen = ulp_blob_data_len_get(key); diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c 2026-10-14 13:10:05.000000000 +0000 @@ -181,7 +181,7 @@ const struct bnxt_ulp_sc_core_ops *sc_ops = NULL; struct ulp_sc_tfc_stats_cache_entry *sce; struct ulp_sc_tfc_stats_cache_entry *sce_end; - struct tfc_mpc_batch_info_t batch_info; + struct tfc_mpc_batch_info_t batch_info = {0}; struct bnxt_ulp_sc_info *ulp_sc_info; struct bnxt_ulp_context *ctxt = NULL; uint16_t words = (ULP_TFC_CNTR_READ_BYTES + ULP_TFC_ACT_WORD_SZ - 1) / ULP_TFC_ACT_WORD_SZ; diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_utils.c dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_utils.c --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_utils.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_utils.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1100 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright(c) 2014-2023 Broadcom - * All rights reserved. - */ - -#include -#include "ulp_utils.h" -#include "bnxt_tf_common.h" - -/* - * Initialize the regfile structure for writing - * - * regfile [in] Ptr to a regfile instance - * - * returns zero on success - */ -int32_t -ulp_regfile_init(struct ulp_regfile *regfile) -{ - /* validate the arguments */ - if (!regfile) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - memset(regfile, 0, sizeof(struct ulp_regfile)); - return 0; /* Success */ -} - -/* - * Read a value from the regfile - * - * regfile [in] The regfile instance. Must be initialized prior to being used - * - * field [in] The field to be read within the regfile. - * - * data [in/out] - * - * returns zero on success - */ -int32_t -ulp_regfile_read(struct ulp_regfile *regfile, - enum bnxt_ulp_rf_idx field, - uint64_t *data) -{ - /* validate the arguments */ - if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - - *data = regfile->entry[field].data; - return 0; -} - -/* - * Write a value to the regfile - * - * regfile [in] The regfile instance. Must be initialized prior to being used - * - * field [in] The field to be written within the regfile. - * - * data [in] The value is written into this variable. It is going to be in the - * same byte order as it was written. - * - * size [in] The size in bytes of the value being written into this - * variable. - * - * returns 0 on success - */ -int32_t -ulp_regfile_write(struct ulp_regfile *regfile, - enum bnxt_ulp_rf_idx field, - uint64_t data) -{ - /* validate the arguments */ - if (!regfile || field >= BNXT_ULP_RF_IDX_LAST) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; /* failure */ - } - - regfile->entry[field].data = data; - return 0; /* Success */ -} - -static void -ulp_bs_put_msb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) -{ - uint8_t bitoffs = bitpos % 8; - uint16_t index = bitpos / 8; - uint8_t mask; - uint8_t tmp; - int8_t shift; - - tmp = bs[index]; - mask = ((uint8_t)-1 >> (8 - bitlen)); - shift = 8 - bitoffs - bitlen; - val &= mask; - - if (shift >= 0) { - tmp &= ~(mask << shift); - tmp |= val << shift; - bs[index] = tmp; - } else { - tmp &= ~((uint8_t)-1 >> bitoffs); - tmp |= val >> -shift; - bs[index++] = tmp; - - tmp = bs[index]; - tmp &= ((uint8_t)-1 >> (bitlen - (8 - bitoffs))); - tmp |= val << (8 + shift); - bs[index] = tmp; - } -} - -static void -ulp_bs_put_lsb(uint8_t *bs, uint16_t bitpos, uint8_t bitlen, uint8_t val) -{ - uint8_t bitoffs = bitpos % 8; - uint16_t index = bitpos / 8; - uint8_t mask; - uint8_t tmp; - uint8_t shift; - uint8_t partial; - - tmp = bs[index]; - shift = bitoffs; - - if (bitoffs + bitlen <= 8) { - mask = ((1 << bitlen) - 1) << shift; - tmp &= ~mask; - tmp |= ((val << shift) & mask); - bs[index] = tmp; - } else { - partial = 8 - bitoffs; - mask = ((1 << partial) - 1) << shift; - tmp &= ~mask; - tmp |= ((val << shift) & mask); - bs[index++] = tmp; - - val >>= partial; - partial = bitlen - partial; - mask = ((1 << partial) - 1); - tmp = bs[index]; - tmp &= ~mask; - tmp |= (val & mask); - bs[index] = tmp; - } -} - -/* - * Add data to the byte array in Little endian format. - * - * bs [in] The byte array where data is pushed - * - * pos [in] The offset where data is pushed - * - * len [in] The number of bits to be added to the data array. - * - * val [in] The data to be added to the data array. - * - * returns the number of bits pushed. - */ -uint32_t -ulp_bs_push_lsb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) -{ - int i; - int cnt = (len) / 8; - int tlen = len; - - if (cnt > 0 && !(len % 8)) - cnt -= 1; - - for (i = 0; i < cnt; i++) { - ulp_bs_put_lsb(bs, pos, 8, val[cnt - i]); - pos += 8; - tlen -= 8; - } - - /* Handle the remainder bits */ - if (tlen) - ulp_bs_put_lsb(bs, pos, tlen, val[0]); - return len; -} - -/* - * Add data to the byte array in Big endian format. - * - * bs [in] The byte array where data is pushed - * - * pos [in] The offset where data is pushed - * - * len [in] The number of bits to be added to the data array. - * - * val [in] The data to be added to the data array. - * - * returns the number of bits pushed. - */ -uint32_t -ulp_bs_push_msb(uint8_t *bs, uint16_t pos, uint8_t len, uint8_t *val) -{ - int i; - int cnt = (len + 7) / 8; - - /* Handle any remainder bits */ - int tmp = len % 8; - - if (!tmp) - tmp = 8; - - ulp_bs_put_msb(bs, pos, tmp, val[0]); - - pos += tmp; - - for (i = 1; i < cnt; i++) { - ulp_bs_put_msb(bs, pos, 8, val[i]); - pos += 8; - } - - return len; -} - -/* - * Initializes the blob structure for creating binary blob - * - * blob [in] The blob to be initialized - * - * bitlen [in] The bit length of the blob - * - * order [in] The byte order for the blob. Currently only supporting - * big endian. All fields are packed with this order. - * - * returns zero on success - * Notes - If bitlen is zero then set it to max. - */ -int32_t -ulp_blob_init(struct ulp_blob *blob, - uint16_t bitlen, - enum bnxt_ulp_byte_order order) -{ - /* validate the arguments */ - if (!blob || bitlen > (8 * sizeof(blob->data))) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - if (bitlen) - blob->bitlen = bitlen; - else - blob->bitlen = BNXT_ULP_FLMP_BLOB_SIZE_IN_BITS; - blob->byte_order = order; - blob->write_idx = 0; - memset(blob->data, 0, sizeof(blob->data)); - return 0; /* Success */ -} - -/* - * Add data to the binary blob at the current offset. - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * data [in] A pointer to bytes to be added to the blob. - * - * datalen [in] The number of bits to be added to the blob. - * - * The offset of the data is updated after each push of data. - * - * returns zero on success - */ -#define ULP_BLOB_BYTE 8 -#define ULP_BLOB_BYTE_HEX 0xFF -#define BLOB_MASK_CAL(x) ((0xFF << (x)) & 0xFF) -int32_t -ulp_blob_push(struct ulp_blob *blob, - uint8_t *data, - uint32_t datalen) -{ - uint32_t rc; - - /* validate the arguments */ - if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - - if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) - rc = ulp_bs_push_msb(blob->data, - blob->write_idx, - datalen, - data); - else - rc = ulp_bs_push_lsb(blob->data, - blob->write_idx, - datalen, - data); - if (!rc) { - BNXT_DRV_DBG(ERR, "Failed to write blob\n"); - return -EINVAL; - } - blob->write_idx += datalen; - return 0; -} - -/* - * Insert data into the binary blob at the given offset. - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * offset [in] The offset where the data needs to be inserted. - * - * data [in/out] A pointer to bytes to be added to the blob. - * - * datalen [in] The number of bits to be added to the blob. - * - * The offset of the data is updated after each push of data. - * - * returns zero on success - */ -int32_t -ulp_blob_insert(struct ulp_blob *blob, uint32_t offset, - uint8_t *data, uint32_t datalen) -{ - uint32_t rc; - uint8_t local_data[BNXT_ULP_FLMP_BLOB_SIZE]; - uint16_t mov_len; - - /* validate the arguments */ - if (!blob || datalen > (uint32_t)(blob->bitlen - blob->write_idx) || - offset > blob->write_idx) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - - mov_len = blob->write_idx - offset; - /* If offset and data len are not 8 bit aligned then return error */ - if (ULP_BITS_IS_BYTE_NOT_ALIGNED(offset) || - ULP_BITS_IS_BYTE_NOT_ALIGNED(datalen)) { - BNXT_DRV_DBG(ERR, "invalid argument, not aligned\n"); - return -EINVAL; - } - - /* copy the data so we can move the data */ - memcpy(local_data, &blob->data[ULP_BITS_2_BYTE_NR(offset)], - ULP_BITS_2_BYTE(mov_len)); - blob->write_idx = offset; - if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) - rc = ulp_bs_push_msb(blob->data, - blob->write_idx, - datalen, - data); - else - rc = ulp_bs_push_lsb(blob->data, - blob->write_idx, - datalen, - data); - if (!rc) { - BNXT_DRV_DBG(ERR, "Failed to write blob\n"); - return -EINVAL; - } - /* copy the previously stored data */ - memcpy(&blob->data[ULP_BITS_2_BYTE_NR(offset + datalen)], local_data, - ULP_BITS_2_BYTE(mov_len)); - blob->write_idx += (mov_len + datalen); - return 0; -} - -/* - * Add data to the binary blob at the current offset. - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * data [in] 64-bit value to be added to the blob. - * - * datalen [in] The number of bits to be added to the blob. - * - * The offset of the data is updated after each push of data. - * NULL returned on error, pointer pushed value otherwise. - */ -uint8_t * -ulp_blob_push_64(struct ulp_blob *blob, - uint64_t *data, - uint32_t datalen) -{ - uint8_t *val = (uint8_t *)data; - int rc; - - int size = (datalen + 7) / 8; - - if (!blob || !data || - datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return NULL; - } - - rc = ulp_blob_push(blob, &val[8 - size], datalen); - if (rc) - return NULL; - - return &val[8 - size]; -} - -/* - * Add data to the binary blob at the current offset. - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * data [in] 32-bit value to be added to the blob. - * - * datalen [in] The number of bits to be added to the blob. - * - * The offset of the data is updated after each push of data. - * NULL returned on error, pointer pushed value otherwise. - */ -uint8_t * -ulp_blob_push_32(struct ulp_blob *blob, - uint32_t *data, - uint32_t datalen) -{ - uint8_t *val = (uint8_t *)data; - uint32_t rc; - uint32_t size = ULP_BITS_2_BYTE(datalen); - - if (!data || size > sizeof(uint32_t)) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return NULL; - } - - rc = ulp_blob_push(blob, &val[sizeof(uint32_t) - size], datalen); - if (rc) - return NULL; - - return &val[sizeof(uint32_t) - size]; -} - -/* - * Add encap data to the binary blob at the current offset. - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * data [in] value to be added to the blob. - * - * datalen [in] The number of bits to be added to the blob. - * - * The offset of the data is updated after each push of data. - * NULL returned on error, pointer pushed value otherwise. - */ -int32_t -ulp_blob_push_encap(struct ulp_blob *blob, - uint8_t *data, - uint32_t datalen) -{ - uint8_t *val = (uint8_t *)data; - uint32_t initial_size, write_size = datalen; - uint32_t size = 0; - - if (!blob || !data || - datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -1; - } - - initial_size = ULP_BYTE_2_BITS(sizeof(uint64_t)) - - (blob->write_idx % ULP_BYTE_2_BITS(sizeof(uint64_t))); - while (write_size > 0) { - if (initial_size && write_size > initial_size) { - size = initial_size; - initial_size = 0; - } else if (initial_size && write_size <= initial_size) { - size = write_size; - initial_size = 0; - } else if (write_size > ULP_BYTE_2_BITS(sizeof(uint64_t))) { - size = ULP_BYTE_2_BITS(sizeof(uint64_t)); - } else { - size = write_size; - } - if (ulp_blob_push(blob, val, size)) { - BNXT_DRV_DBG(ERR, "push field failed\n"); - return -1; - } - val += ULP_BITS_2_BYTE(size); - write_size -= size; - } - return datalen; -} - -/* - * Adds pad to an initialized blob at the current offset - * - * blob [in] The blob that data is added to. The blob must - * be initialized prior to pushing data. - * - * datalen [in] The number of bits of pad to add - * - * returns the number of pad bits added, -1 on failure - */ -int32_t -ulp_blob_pad_push(struct ulp_blob *blob, - uint32_t datalen) -{ - if (datalen > (uint32_t)(blob->bitlen - blob->write_idx)) { - BNXT_DRV_DBG(ERR, "Pad too large for blob\n"); - return -1; - } - - blob->write_idx += datalen; - return datalen; -} - -/* - * Adds pad to an initialized blob at the current offset based on - * the alignment. - * - * blob [in] The blob that needs to be aligned - * - * align [in] Alignment in bits. - * - * returns the number of pad bits added, -1 on failure - */ -int32_t -ulp_blob_pad_align(struct ulp_blob *blob, - uint32_t align) -{ - int32_t pad = 0; - - pad = RTE_ALIGN(blob->write_idx, align) - blob->write_idx; - if (pad > (int32_t)(blob->bitlen - blob->write_idx)) { - BNXT_DRV_DBG(ERR, "Pad too large for blob\n"); - return -1; - } - blob->write_idx += pad; - return pad; -} - -/* Get data from src and put into dst using little-endian format */ -static void -ulp_bs_get_lsb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst) -{ - uint8_t bitoffs = bitpos % ULP_BLOB_BYTE; - uint16_t index = ULP_BITS_2_BYTE_NR(bitpos); - uint8_t mask, partial, shift; - - shift = bitoffs; - partial = ULP_BLOB_BYTE - bitoffs; - if (bitoffs + bitlen <= ULP_BLOB_BYTE) { - mask = ((1 << bitlen) - 1) << shift; - *dst = (src[index] & mask) >> shift; - } else { - mask = ((1 << partial) - 1) << shift; - *dst = (src[index] & mask) >> shift; - index++; - partial = bitlen - partial; - mask = ((1 << partial) - 1); - *dst |= (src[index] & mask) << (ULP_BLOB_BYTE - bitoffs); - } -} - -/* - * Get data from the byte array in Little endian format. - * - * src [in] The byte array where data is extracted from - * - * dst [out] The byte array where data is pulled into - * - * size [in] The size of dst array in bytes - * - * offset [in] The offset where data is pulled - * - * len [in] The number of bits to be extracted from the data array - * - * returns None. - */ -void -ulp_bs_pull_lsb(uint8_t *src, uint8_t *dst, uint32_t size, - uint32_t offset, uint32_t len) -{ - uint32_t idx; - uint32_t cnt = ULP_BITS_2_BYTE_NR(len); - - /* iterate bytewise to get data */ - for (idx = 0; idx < cnt; idx++) { - ulp_bs_get_lsb(src, offset, ULP_BLOB_BYTE, - &dst[size - 1 - idx]); - offset += ULP_BLOB_BYTE; - len -= ULP_BLOB_BYTE; - } - - /* Extract the last reminder data that is not 8 byte boundary */ - if (len) - ulp_bs_get_lsb(src, offset, len, &dst[size - 1 - idx]); -} - -/* Get data from src and put into dst using big-endian format */ -static void -ulp_bs_get_msb(uint8_t *src, uint16_t bitpos, uint8_t bitlen, uint8_t *dst) -{ - uint8_t bitoffs = bitpos % ULP_BLOB_BYTE; - uint16_t index = ULP_BITS_2_BYTE_NR(bitpos); - uint8_t mask; - int32_t shift; - - shift = ULP_BLOB_BYTE - bitoffs - bitlen; - if (shift >= 0) { - mask = 0xFF >> -bitlen; - *dst = (src[index] >> shift) & mask; - } else { - *dst = (src[index] & (0xFF >> bitoffs)) << -shift; - *dst |= src[index + 1] >> -shift; - } -} - -/* - * Get data from the byte array in Big endian format. - * - * src [in] The byte array where data is extracted from - * - * dst [out] The byte array where data is pulled into - * - * offset [in] The offset where data is pulled - * - * len [in] The number of bits to be extracted from the data array - * - * returns None. - */ -void -ulp_bs_pull_msb(uint8_t *src, uint8_t *dst, - uint32_t offset, uint32_t len) -{ - uint32_t idx; - uint32_t cnt = ULP_BITS_2_BYTE_NR(len); - - /* iterate bytewise to get data */ - for (idx = 0; idx < cnt; idx++) { - ulp_bs_get_msb(src, offset, ULP_BLOB_BYTE, &dst[idx]); - offset += ULP_BLOB_BYTE; - len -= ULP_BLOB_BYTE; - } - - /* Extract the last reminder data that is not 8 byte boundary */ - if (len) - ulp_bs_get_msb(src, offset, len, &dst[idx]); -} - -/* - * Extract data from the binary blob using given offset. - * - * blob [in] The blob that data is extracted from. The blob must - * be initialized prior to pulling data. - * - * data [in] A pointer to put the data. - * data_size [in] size of the data buffer in bytes. - *offset [in] - Offset in the blob to extract the data in bits format. - * len [in] The number of bits to be pulled from the blob. - * - * Output: zero on success, -1 on failure - */ -int32_t -ulp_blob_pull(struct ulp_blob *blob, uint8_t *data, uint32_t data_size, - uint16_t offset, uint16_t len) -{ - /* validate the arguments */ - if (!blob || (offset + len) > blob->bitlen || - ULP_BYTE_2_BITS(data_size) < len) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -1; /* failure */ - } - - if (blob->byte_order == BNXT_ULP_BYTE_ORDER_BE) - ulp_bs_pull_msb(blob->data, data, offset, len); - else - ulp_bs_pull_lsb(blob->data, data, data_size, offset, len); - return 0; -} - -/* - * Get the data portion of the binary blob. - * - * blob [in] The blob's data to be retrieved. The blob must be - * initialized prior to pushing data. - * - * datalen [out] The number of bits that are filled. - * - * Returns a byte array of the blob data or NULL on error. - */ -uint8_t * -ulp_blob_data_get(struct ulp_blob *blob, - uint16_t *datalen) -{ - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return NULL; /* failure */ - } - *datalen = blob->write_idx; - return blob->data; -} - -/* - * Get the data length of the binary blob. - * - * blob [in] The blob's data len to be retrieved. - * - * returns length of the binary blob - */ -uint16_t -ulp_blob_data_len_get(struct ulp_blob *blob) -{ - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return 0; /* failure */ - } - return blob->write_idx; -} - -/* - * Set the encap swap start index of the binary blob. - * - * blob [in] The blob's data to be retrieved. The blob must be - * initialized prior to pushing data. - * - * returns void. - */ -void -ulp_blob_encap_swap_idx_set(struct ulp_blob *blob) -{ - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return; /* failure */ - } - blob->encap_swap_idx = blob->write_idx; -} - -/* - * Perform the encap buffer swap to 64 bit reversal. - * - * blob [in] The blob's data to be used for swap. - * - * returns void. - */ -void -ulp_blob_perform_encap_swap(struct ulp_blob *blob) -{ - uint32_t i, idx = 0, end_idx = 0, roundoff; - uint8_t temp_val_1, temp_val_2; - - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return; /* failure */ - } - idx = ULP_BITS_2_BYTE_NR(blob->encap_swap_idx); - end_idx = ULP_BITS_2_BYTE(blob->write_idx); - roundoff = ULP_BYTE_2_BITS(ULP_BITS_2_BYTE(end_idx)); - if (roundoff > end_idx) { - blob->write_idx += ULP_BYTE_2_BITS(roundoff - end_idx); - end_idx = roundoff; - } - while (idx <= end_idx) { - for (i = 0; i < 4; i = i + 2) { - temp_val_1 = blob->data[idx + i]; - temp_val_2 = blob->data[idx + i + 1]; - blob->data[idx + i] = blob->data[idx + 6 - i]; - blob->data[idx + i + 1] = blob->data[idx + 7 - i]; - blob->data[idx + 7 - i] = temp_val_2; - blob->data[idx + 6 - i] = temp_val_1; - } - idx += 8; - } -} - -/* - * Perform the blob buffer reversal byte wise. - * This api makes the first byte the last and - * vice-versa. - * - * blob [in] The blob's data to be used for swap. - * chunk_size[in] the swap is done within the chunk in bytes - * - * returns void. - */ -void -ulp_blob_perform_byte_reverse(struct ulp_blob *blob, - uint32_t chunk_size) -{ - uint32_t idx = 0, jdx = 0, num = 0; - uint8_t xchar; - uint8_t *buff; - - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return; /* failure */ - } - - buff = blob->data; - num = ULP_BITS_2_BYTE(blob->write_idx) / chunk_size; - for (idx = 0; idx < num; idx++) { - for (jdx = 0; jdx < chunk_size / 2; jdx++) { - xchar = buff[jdx]; - buff[jdx] = buff[(chunk_size - 1) - jdx]; - buff[(chunk_size - 1) - jdx] = xchar; - } - buff += chunk_size; - } -} - -/* - * Perform the blob buffer 64 bit word swap. - * This api makes the first 4 bytes the last in - * a given 64 bit value and vice-versa. - * - * blob [in] The blob's data to be used for swap. - * - * returns void. - */ -void -ulp_blob_perform_64B_word_swap(struct ulp_blob *blob) -{ - uint32_t i, j, num; - uint8_t xchar; - uint32_t word_size = ULP_64B_IN_BYTES / 2; - - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return; /* failure */ - } - num = ULP_BITS_2_BYTE(blob->write_idx); - for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) { - for (j = 0; j < word_size; j++) { - xchar = blob->data[i + j]; - blob->data[i + j] = blob->data[i + j + word_size]; - blob->data[i + j + word_size] = xchar; - } - } -} - -/* - * Perform the blob buffer 64 bit byte swap. - * This api makes the first byte the last in - * a given 64 bit value and vice-versa. - * - * blob [in] The blob's data to be used for swap. - * - * returns void. - */ -void -ulp_blob_perform_64B_byte_swap(struct ulp_blob *blob) -{ - uint32_t i, j, num; - uint8_t xchar; - uint32_t offset = ULP_64B_IN_BYTES - 1; - - /* validate the arguments */ - if (!blob) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return; /* failure */ - } - num = ULP_BITS_2_BYTE(blob->write_idx); - for (i = 0; i < num; i = i + ULP_64B_IN_BYTES) { - for (j = 0; j < (ULP_64B_IN_BYTES / 2); j++) { - xchar = blob->data[i + j]; - blob->data[i + j] = blob->data[i + offset - j]; - blob->data[i + offset - j] = xchar; - } - } -} - -static int32_t -ulp_blob_msb_block_merge(struct ulp_blob *dst, struct ulp_blob *src, - uint32_t block_size, uint32_t pad) -{ - uint32_t i, k, write_bytes, remaining; - uint16_t num; - uint8_t *src_buf = ulp_blob_data_get(src, &num); - uint8_t bluff; - - for (i = 0; i < num;) { - if (((dst->write_idx % block_size) + (num - i)) > block_size) - write_bytes = block_size - - (dst->write_idx % block_size); - else - write_bytes = num - i; - for (k = 0; k < ULP_BITS_2_BYTE_NR(write_bytes); k++) { - ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, - *src_buf); - dst->write_idx += ULP_BLOB_BYTE; - src_buf++; - } - remaining = write_bytes % ULP_BLOB_BYTE; - if (remaining) { - bluff = (*src_buf) & ((uint8_t)-1 << - (ULP_BLOB_BYTE - remaining)); - ulp_bs_put_msb(dst->data, dst->write_idx, - ULP_BLOB_BYTE, bluff); - dst->write_idx += remaining; - } - if (write_bytes != (num - i)) { - /* add the padding */ - ulp_blob_pad_push(dst, pad); - if (remaining) { - ulp_bs_put_msb(dst->data, dst->write_idx, - ULP_BLOB_BYTE - remaining, - *src_buf); - dst->write_idx += ULP_BLOB_BYTE - remaining; - src_buf++; - } - } - i += write_bytes; - } - return 0; -} - -/* - * Perform the blob buffer merge. - * This api makes the src blob merged to the dst blob. - * The block size and pad size help in padding the dst blob - * - * dst [in] The destination blob, the blob to be merged. - * src [in] The src blob. - * block_size [in] The size of the block in bytes after which padding gets - * applied. - * pad [in] The size of the pad to be applied. - * - * returns 0 on success. - */ -int32_t -ulp_blob_block_merge(struct ulp_blob *dst, struct ulp_blob *src, - uint32_t block_size, uint32_t pad) -{ - if (dst->byte_order == BNXT_ULP_BYTE_ORDER_BE && - src->byte_order == BNXT_ULP_BYTE_ORDER_BE) - return ulp_blob_msb_block_merge(dst, src, block_size, pad); - - BNXT_DRV_DBG(ERR, "block merge not implemented yet\n"); - return -EINVAL; -} - -int32_t -ulp_blob_append(struct ulp_blob *dst, struct ulp_blob *src, - uint16_t src_offset, uint16_t src_len) -{ - uint32_t k, remaining = 0; - uint16_t num; - uint8_t bluff; - uint8_t *src_buf = ulp_blob_data_get(src, &num); - - if ((src_offset + src_len) > num) - return -EINVAL; - - /* Only supporting BE for now */ - if (src->byte_order != BNXT_ULP_BYTE_ORDER_BE || - dst->byte_order != BNXT_ULP_BYTE_ORDER_BE) - return -EINVAL; - - /* Handle if the source offset is not on a byte boundary */ - remaining = src_offset % ULP_BLOB_BYTE; - if (remaining) { - bluff = src_buf[src_offset / ULP_BLOB_BYTE] & ((uint8_t)-1 >> - (ULP_BLOB_BYTE - remaining)); - ulp_bs_put_msb(dst->data, dst->write_idx, - ULP_BLOB_BYTE, bluff); - dst->write_idx += remaining; - src_offset += remaining; - } - - src_buf += ULP_BITS_2_BYTE_NR(src_offset); - - /* Push the byte aligned pieces */ - for (k = 0; k < ULP_BITS_2_BYTE_NR(src_len); k++) { - ulp_bs_put_msb(dst->data, dst->write_idx, ULP_BLOB_BYTE, - *src_buf); - dst->write_idx += ULP_BLOB_BYTE; - src_buf++; - } - - /* Handle the remaining if length is not a byte boundary */ - if (src_len > remaining) - remaining = (src_len - remaining) % ULP_BLOB_BYTE; - else - remaining = 0; - if (remaining) { - bluff = (*src_buf) & ((uint8_t)-1 << - (ULP_BLOB_BYTE - remaining)); - ulp_bs_put_msb(dst->data, dst->write_idx, - ULP_BLOB_BYTE, bluff); - dst->write_idx += remaining; - } - - return 0; -} - -/* - * Perform the blob buffer copy. - * This api makes the src blob merged to the dst blob. - * - * dst [in] The destination blob, the blob to be merged. - * src [in] The src blob. - * - * returns 0 on success. - */ -int32_t -ulp_blob_buffer_copy(struct ulp_blob *dst, struct ulp_blob *src) -{ - if ((dst->write_idx + src->write_idx) > dst->bitlen) { - BNXT_DRV_DBG(ERR, "source buffer too large\n"); - return -EINVAL; - } - if (ULP_BITS_IS_BYTE_NOT_ALIGNED(dst->write_idx) || - ULP_BITS_IS_BYTE_NOT_ALIGNED(src->write_idx)) { - BNXT_DRV_DBG(ERR, "source buffer is not aligned\n"); - return -EINVAL; - } - memcpy(&dst->data[ULP_BITS_2_BYTE_NR(dst->write_idx)], - src->data, ULP_BITS_2_BYTE_NR(src->write_idx)); - dst->write_idx += src->write_idx; - return 0; -} - -/* - * Read data from the operand - * - * operand [in] A pointer to a 16 Byte operand - * - * val [in/out] The variable to copy the operand to - * - * bytes [in] The number of bytes to read into val - * - * returns zero on success. - */ -int32_t -ulp_operand_read(uint8_t *operand, - uint8_t *val, - uint16_t bytes) -{ - /* validate the arguments */ - if (!operand || !val) { - BNXT_DRV_DBG(ERR, "invalid argument\n"); - return -EINVAL; - } - memcpy(val, operand, bytes); - return 0; -} - -/* - * Check the buffer is empty - * - * buf [in] The buffer - * size [in] The size of the buffer - * - */ -int32_t ulp_buffer_is_empty(const uint8_t *buf, uint32_t size) -{ - return buf[0] == 0 && !memcmp(buf, buf + 1, size - 1); -} - -/* Function to check if bitmap is zero.Return 1 on success */ -uint32_t ulp_bitmap_is_zero(uint8_t *bitmap, int32_t size) -{ - while (size-- > 0) { - if (*bitmap != 0) - return 0; - bitmap++; - } - return 1; -} - -/* Function to check if bitmap is ones. Return 1 on success */ -uint32_t ulp_bitmap_is_ones(uint8_t *bitmap, int32_t size) -{ - while (size-- > 0) { - if (*bitmap != 0xFF) - return 0; - bitmap++; - } - return 1; -} - -/* Function to check if bitmap is not zero. Return 1 on success */ -uint32_t ulp_bitmap_notzero(const uint8_t *bitmap, int32_t size) -{ - while (size-- > 0) { - if (*bitmap != 0) - return 1; - bitmap++; - } - return 0; -} - -/* returns 0 if input is power of 2 */ -int32_t ulp_util_is_power_of_2(uint64_t x) -{ - if (((x - 1) & x)) - return -1; - return 0; -} diff -Nru dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_utils.h dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_utils.h --- dpdk-24.11.4/drivers/net/bnxt/tf_ulp/ulp_utils.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bnxt/tf_ulp/ulp_utils.h 2026-10-14 13:10:05.000000000 +0000 @@ -1106,6 +1106,8 @@ uint8_t bluff; uint8_t *src_buf = ulp_blob_data_get(src, &num); + if (unlikely(src_buf == NULL)) + return -EINVAL; if (unlikely((src_offset + src_len) > num)) return -EINVAL; diff -Nru dpdk-24.11.4/drivers/net/bonding/rte_eth_bond_8023ad.c dpdk-24.11.8/drivers/net/bonding/rte_eth_bond_8023ad.c --- dpdk-24.11.4/drivers/net/bonding/rte_eth_bond_8023ad.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bonding/rte_eth_bond_8023ad.c 2026-10-14 13:10:05.000000000 +0000 @@ -1715,7 +1715,6 @@ int rte_eth_bond_8023ad_dedicated_queues_enable(uint16_t port) { - int retval = 0; struct rte_eth_dev *dev; struct bond_dev_private *internals; @@ -1732,16 +1731,18 @@ if (dev->data->dev_started) return -1; + if (internals->mode != BONDING_MODE_8023AD) + return -1; + internals->mode4.dedicated_queues.enabled = 1; bond_ethdev_mode_set(dev, internals->mode); - return retval; + return 0; } int rte_eth_bond_8023ad_dedicated_queues_disable(uint16_t port) { - int retval = 0; struct rte_eth_dev *dev; struct bond_dev_private *internals; @@ -1755,9 +1756,12 @@ if (dev->data->dev_started) return -1; + if (internals->mode != BONDING_MODE_8023AD) + return -1; + internals->mode4.dedicated_queues.enabled = 0; bond_ethdev_mode_set(dev, internals->mode); - return retval; + return 0; } diff -Nru dpdk-24.11.4/drivers/net/bonding/rte_eth_bond_pmd.c dpdk-24.11.8/drivers/net/bonding/rte_eth_bond_pmd.c --- dpdk-24.11.4/drivers/net/bonding/rte_eth_bond_pmd.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/bonding/rte_eth_bond_pmd.c 2026-10-14 13:10:05.000000000 +0000 @@ -57,6 +57,33 @@ } static uint16_t +bond_ethdev_rx_secondary(void *queue __rte_unused, + struct rte_mbuf **bufs __rte_unused, uint16_t nb_pkts __rte_unused) +{ + static bool once = true; + + if (once) { + /* once per process is enough of a notice */ + RTE_BOND_LOG(ERR, "receive not supported in secondary"); + once = false; + } + return 0; +} + +static uint16_t +bond_ethdev_tx_secondary(void *queue __rte_unused, struct rte_mbuf **bufs, uint16_t nb_pkts) +{ + static bool once = true; + + if (once) { + RTE_BOND_LOG(ERR, "transmit not supported in secondary"); + once = false; + } + rte_pktmbuf_free_bulk(bufs, nb_pkts); + return nb_pkts; +} + +static uint16_t bond_ethdev_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { struct bond_dev_private *internals; @@ -1599,6 +1626,11 @@ { struct bond_dev_private *internals; + if (rte_eal_process_type() == RTE_PROC_SECONDARY) { + RTE_BOND_LOG(ERR, "Setting mode in secondary not allowed"); + return -1; + } + internals = eth_dev->data->dev_private; switch (mode) { @@ -1701,11 +1733,18 @@ if (member_info.rx_desc_lim.nb_min != 0) nb_rx_desc = member_info.rx_desc_lim.nb_min; - /* Configure slow Rx queue */ + /* Configure slow Rx queue. + * Use explicit conf rather than NULL so we can clamp rx_free_thresh: + * with a minimum-sized ring the default rx_free_thresh may be too large + * for some drivers to work correctly, so clamp it to ring_size / 4. + */ + struct rte_eth_rxconf slow_rx_conf = member_info.default_rxconf; + if (slow_rx_conf.rx_free_thresh > nb_rx_desc / 4) + slow_rx_conf.rx_free_thresh = nb_rx_desc / 4; errval = rte_eth_rx_queue_setup(member_eth_dev->data->port_id, internals->mode4.dedicated_queues.rx_qid, nb_rx_desc, rte_eth_dev_socket_id(member_eth_dev->data->port_id), - NULL, port->slow_pool); + &slow_rx_conf, port->slow_pool); if (errval != 0) { RTE_BOND_LOG(ERR, "rte_eth_rx_queue_setup: port=%d queue_id %d, err (%d)", @@ -3790,9 +3829,18 @@ RTE_BOND_LOG(ERR, "Failed to probe %s", name); return -1; } - /* TODO: request info from primary to set up Rx and Tx */ + eth_dev->dev_ops = &default_dev_ops; eth_dev->device = &dev->device; + + /* + * Propagation of bond mode would require adding + * MP client/server support and lots of error handling. + * + * For now just install a black hole. + */ + eth_dev->tx_pkt_burst = bond_ethdev_tx_secondary; + eth_dev->rx_pkt_burst = bond_ethdev_rx_secondary; rte_eth_dev_probing_finish(eth_dev); return 0; } diff -Nru dpdk-24.11.4/drivers/net/cnxk/cn10k_tx.h dpdk-24.11.8/drivers/net/cnxk/cn10k_tx.h --- dpdk-24.11.4/drivers/net/cnxk/cn10k_tx.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cnxk/cn10k_tx.h 2026-10-14 13:10:05.000000000 +0000 @@ -1132,10 +1132,8 @@ if (flags & NIX_TX_NEED_EXT_HDR && flags & NIX_TX_OFFLOAD_TSO_F && (ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { uint16_t lso_sb; - uint64_t mask; - mask = -(!w1.il3type); - lso_sb = (mask & w1.ol4ptr) + (~mask & w1.il4ptr) + m->l4_len; + lso_sb = (w1.il3type ? w1.il4ptr : w1.ol4ptr) + m->l4_len; send_hdr_ext->w0.lso_sb = lso_sb; send_hdr_ext->w0.lso = 1; @@ -1760,13 +1758,11 @@ const uint64_t flags, const uint64_t lso_tun_fmt) { uint16_t lso_sb; - uint64_t mask; if (!(ol_flags & RTE_MBUF_F_TX_TCP_SEG)) return; - mask = -(!w1->il3type); - lso_sb = (mask & w1->ol4ptr) + (~mask & w1->il4ptr) + m->l4_len; + lso_sb = (w1->il3type ? w1->il4ptr : w1->ol4ptr) + m->l4_len; w0->u |= BIT(14); w0->lso_sb = lso_sb; diff -Nru dpdk-24.11.4/drivers/net/cnxk/cn20k_tx.h dpdk-24.11.8/drivers/net/cnxk/cn20k_tx.h --- dpdk-24.11.4/drivers/net/cnxk/cn20k_tx.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cnxk/cn20k_tx.h 2026-10-14 13:10:05.000000000 +0000 @@ -1105,10 +1105,8 @@ if (flags & NIX_TX_NEED_EXT_HDR && flags & NIX_TX_OFFLOAD_TSO_F && (ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { uint16_t lso_sb; - uint64_t mask; - mask = -(!w1.il3type); - lso_sb = (mask & w1.ol4ptr) + (~mask & w1.il4ptr) + m->l4_len; + lso_sb = (w1.il3type ? w1.il4ptr : w1.ol4ptr) + m->l4_len; send_hdr_ext->w0.lso_sb = lso_sb; send_hdr_ext->w0.lso = 1; @@ -1720,13 +1718,11 @@ uint64_t ol_flags, const uint64_t flags, const uint64_t lso_tun_fmt) { uint16_t lso_sb; - uint64_t mask; if (!(ol_flags & RTE_MBUF_F_TX_TCP_SEG)) return; - mask = -(!w1->il3type); - lso_sb = (mask & w1->ol4ptr) + (~mask & w1->il4ptr) + m->l4_len; + lso_sb = (w1->il3type ? w1->il4ptr : w1->ol4ptr) + m->l4_len; w0->u |= BIT(14); w0->lso_sb = lso_sb; diff -Nru dpdk-24.11.4/drivers/net/cnxk/cn9k_tx.h dpdk-24.11.8/drivers/net/cnxk/cn9k_tx.h --- dpdk-24.11.4/drivers/net/cnxk/cn9k_tx.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cnxk/cn9k_tx.h 2026-10-14 13:10:05.000000000 +0000 @@ -477,10 +477,8 @@ if (flags & NIX_TX_OFFLOAD_TSO_F && (ol_flags & RTE_MBUF_F_TX_TCP_SEG)) { uint16_t lso_sb; - uint64_t mask; - mask = -(!w1.il3type); - lso_sb = (mask & w1.ol4ptr) + (~mask & w1.il4ptr) + m->l4_len; + lso_sb = (w1.il3type ? w1.il4ptr : w1.ol4ptr) + m->l4_len; send_hdr_ext->w0.lso_sb = lso_sb; send_hdr_ext->w0.lso = 1; @@ -876,13 +874,11 @@ uint64_t flags) { uint16_t lso_sb; - uint64_t mask; if (!(ol_flags & RTE_MBUF_F_TX_TCP_SEG)) return; - mask = -(!w1->il3type); - lso_sb = (mask & w1->ol4ptr) + (~mask & w1->il4ptr) + m->l4_len; + lso_sb = (w1->il3type ? w1->il4ptr : w1->ol4ptr) + m->l4_len; w0->u |= BIT(14); w0->lso_sb = lso_sb; diff -Nru dpdk-24.11.4/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c dpdk-24.11.8/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c --- dpdk-24.11.4/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cnxk/cnxk_ethdev_sec_telemetry.c 2026-10-14 13:10:05.000000000 +0000 @@ -211,33 +211,30 @@ static int parse_params(const char *params, uint32_t *vals, size_t n_vals) { - char dlim[2] = ","; - char *params_args; size_t count = 0; - char *token; - if (vals == NULL || params == NULL || strlen(params) == 0) + if (params == NULL || !isdigit((unsigned char)params[0])) return -1; - /* strtok expects char * and param is const char *. Hence on using - * params as "const char *" compiler throws warning. - */ - params_args = strdup(params); - if (params_args == NULL) - return -1; + while (count < n_vals) { + char *end; + unsigned long v; - token = strtok(params_args, dlim); - while (token && isdigit(*token) && count < n_vals) { - vals[count++] = strtoul(token, NULL, 10); - token = strtok(NULL, dlim); - } + errno = 0; + v = strtoul(params, &end, 10); + if (errno != 0 || v > UINT32_MAX) + return -EINVAL; + vals[count++] = v; - free(params_args); + if (*end == '\0') + break; - if (count < n_vals) - return -1; + if (*end != ',' || !isdigit((unsigned char)end[1])) + return -EINVAL; + params = end + 1; + } - return 0; + return count == n_vals ? 0 : -EINVAL; } static int @@ -252,13 +249,13 @@ uint32_t i; int ret; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) - return -EINVAL; - if (parse_params(params, vals, RTE_DIM(vals)) < 0) return -EINVAL; port_id = vals[0]; + if (port_id >= RTE_MAX_ETHPORTS) + return -EINVAL; + sa_idx = vals[1]; if (!rte_eth_dev_is_valid_port(port_id)) { @@ -320,12 +317,13 @@ struct cnxk_eth_sec_sess *eth_sec, *tvar; struct rte_eth_dev *eth_dev; struct cnxk_eth_dev *dev; - uint16_t port_id; + unsigned long port_id; char *end_p; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || !isdigit((unsigned char)*params)) return -EINVAL; + errno = 0; port_id = strtoul(params, &end_p, 0); if (errno != 0) return -EINVAL; @@ -333,8 +331,8 @@ if (*end_p != '\0') plt_err("Extra parameters passed to telemetry, ignoring it"); - if (!rte_eth_dev_is_valid_port(port_id)) { - plt_err("Invalid port id %u", port_id); + if (port_id >= RTE_MAX_ETHPORTS || !rte_eth_dev_is_valid_port(port_id)) { + plt_err("Invalid port id %lu", port_id); return -EINVAL; } diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_ethdev.c dpdk-24.11.8/drivers/net/cpfl/cpfl_ethdev.c --- dpdk-24.11.4/drivers/net/cpfl/cpfl_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -2315,7 +2315,7 @@ hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id; adapter->host_id = get_running_host_id(); - strncpy(adapter->name, pci_dev->device.name, PCI_PRI_STR_SIZE); + strlcpy(adapter->name, pci_dev->device.name, sizeof(adapter->name)); rte_memcpy(&base->caps, &req_caps, sizeof(struct virtchnl2_get_capabilities)); diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_flow_engine_fxp.c dpdk-24.11.8/drivers/net/cpfl/cpfl_flow_engine_fxp.c --- dpdk-24.11.4/drivers/net/cpfl/cpfl_flow_engine_fxp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_flow_engine_fxp.c 2026-10-14 13:10:05.000000000 +0000 @@ -386,8 +386,6 @@ } if (mr_action) { - uint32_t i; - for (i = 0; i < rim->mr_num; i++) if (cpfl_parse_mod_content(itf->adapter, rinfo, &rim->rules[rim->pr_num + i], diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_flow_parser.c dpdk-24.11.8/drivers/net/cpfl/cpfl_flow_parser.c --- dpdk-24.11.4/drivers/net/cpfl/cpfl_flow_parser.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_flow_parser.c 2026-10-14 13:10:05.000000000 +0000 @@ -211,7 +211,7 @@ PMD_DRV_LOG(ERR, "The 'name' is too long."); goto err; } - strncpy(js_field->fields[i].name, name, CPFL_JS_STR_SIZE - 1); + strlcpy(js_field->fields[i].name, name, CPFL_JS_STR_SIZE); if (js_field->type == RTE_FLOW_ITEM_TYPE_ETH || js_field->type == RTE_FLOW_ITEM_TYPE_IPV4) { @@ -647,8 +647,7 @@ PMD_DRV_LOG(ERR, "The 'name' is too long."); goto err; } - strncpy(js_mr_key->actions[i].prog.name, name, - CPFL_JS_STR_SIZE - 1); + strlcpy(js_mr_key->actions[i].prog.name, name, CPFL_JS_STR_SIZE); } ob_param = json_object_get(object, "parameters"); @@ -673,8 +672,8 @@ PMD_DRV_LOG(ERR, "The 'name' is too long."); goto err; } - strncpy(js_mr_key->actions[i].prog.params[j].name, name, - CPFL_JS_STR_SIZE - 1); + strlcpy(js_mr_key->actions[i].prog.params[j].name, name, + CPFL_JS_STR_SIZE); } ret = cpfl_json_t_to_uint16(subobject, "size", &value); if (ret < 0) { @@ -741,7 +740,7 @@ PMD_DRV_LOG(ERR, "The 'hint' is too long."); goto err; } - strncpy(js_mod->layout[i].hint, hint, CPFL_JS_STR_SIZE - 1); + strlcpy(js_mod->layout[i].hint, hint, CPFL_JS_STR_SIZE); } return 0; @@ -787,7 +786,7 @@ PMD_DRV_LOG(ERR, "The 'type' is too long."); goto err; } - strncpy(js_mod->content.fields[i].type, type, CPFL_JS_STR_SIZE - 1); + strlcpy(js_mod->content.fields[i].type, type, CPFL_JS_STR_SIZE); ret = cpfl_json_t_to_uint16(object, "start", &start); if (ret < 0) { PMD_DRV_LOG(ERR, "Can not parse 'start'."); @@ -1098,12 +1097,12 @@ fv[2 * offset] = (uint8_t)(temp_fv >> 8); fv[2 * offset + 1] = (uint8_t)(temp_fv & 0x00ff); } else if (type == CPFL_FV_TYPE_METADATA) { - uint16_t type, v_offset, mask; + uint16_t v_offset, mask; - type = js_fv->meta.type; v_offset = js_fv->meta.offset; mask = js_fv->meta.mask; - temp_fv = cpfl_metadata_read16(&itf->adapter->meta, type, v_offset) & mask; + temp_fv = cpfl_metadata_read16(&itf->adapter->meta, js_fv->meta.type, + v_offset) & mask; fv[2 * offset] = (uint8_t)(temp_fv & 0x00ff); fv[2 * offset + 1] = (uint8_t)(temp_fv >> 8); } else if (type == CPFL_FV_TYPE_PROTOCOL) { @@ -1722,8 +1721,7 @@ return -EINVAL; if (param->has_name) { mr_key_prog->has_name = TRUE; - strncpy(mr_key_prog->name[param->index], param->name, - CPFL_JS_STR_SIZE - 1); + strlcpy(mr_key_prog->name[param->index], param->name, CPFL_JS_STR_SIZE); } } diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_fxp_rule.h dpdk-24.11.8/drivers/net/cpfl/cpfl_fxp_rule.h --- dpdk-24.11.4/drivers/net/cpfl/cpfl_fxp_rule.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_fxp_rule.h 2026-10-14 13:10:05.000000000 +0000 @@ -53,8 +53,6 @@ }; }; -extern struct cpfl_vport_ext *vport; - int cpfl_rule_process(struct cpfl_itf *itf, struct idpf_ctlq_info *tx_cq, struct idpf_ctlq_info *rx_cq, diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_representor.h dpdk-24.11.8/drivers/net/cpfl/cpfl_representor.h --- dpdk-24.11.4/drivers/net/cpfl/cpfl_representor.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_representor.h 2026-10-14 13:10:05.000000000 +0000 @@ -21,7 +21,7 @@ struct cpfl_vport_info *vport_info; }; -extern struct cpfl_devargs *devargs; +struct cpfl_devargs; int cpfl_repr_devargs_process(struct cpfl_adapter_ext *adapter, struct cpfl_devargs *devargs); int cpfl_repr_create(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *adapter); diff -Nru dpdk-24.11.4/drivers/net/cpfl/cpfl_rxtx.c dpdk-24.11.8/drivers/net/cpfl/cpfl_rxtx.c --- dpdk-24.11.4/drivers/net/cpfl/cpfl_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/cpfl/cpfl_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -621,6 +621,7 @@ return 0; err_complq_setup: + rte_free(txq->sw_ring); err_sw_ring_alloc: cpfl_dma_zone_release(mz); err_mz_reserve: diff -Nru dpdk-24.11.4/drivers/net/dpaa/dpaa_ethdev.c dpdk-24.11.8/drivers/net/dpaa/dpaa_ethdev.c --- dpdk-24.11.4/drivers/net/dpaa/dpaa_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa/dpaa_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -133,7 +133,7 @@ offsetof(struct dpaa_if_stats, terr)}, {"tx_vlan_frame", offsetof(struct dpaa_if_stats, tvlan)}, - {"rx_undersized", + {"tx_undersized", offsetof(struct dpaa_if_stats, tund)}, {"rx_frame_counter", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rfrc)}, @@ -143,13 +143,13 @@ offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rlfc)}, {"rx_filter_frames_count", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rffc)}, - {"rx_frame_discrad_count", + {"rx_frame_discard_count", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rfdc)}, {"rx_frame_list_dma_err_count", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rfldec)}, - {"rx_out_of_buffer_discard ", + {"rx_out_of_buffer_discard", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rodc)}, - {"rx_buf_diallocate", + {"rx_buf_deallocate", offsetof(struct dpaa_if_rx_bmi_stats, fmbm_rbdc)}, }; @@ -415,8 +415,6 @@ RTE_PTYPE_L4_TCP, RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_FRAG, - RTE_PTYPE_L4_TCP, - RTE_PTYPE_L4_UDP, RTE_PTYPE_L4_SCTP, RTE_PTYPE_TUNNEL_ESP, RTE_PTYPE_TUNNEL_GRE, @@ -570,7 +568,7 @@ } ret = rte_intr_callback_unregister(intr_handle, dpaa_interrupt_handler, (void *)dev); - if (ret) { + if (ret < 0) { DPAA_PMD_WARN("%s: unregister interrupt failed(%d)", dev->data->name, ret); } @@ -954,7 +952,8 @@ values[i] = values_copy[dpaa_xstats_strings[i].offset / 8]; - fman_if_bmi_stats_get_all(dev->process_private, values); + /* i continues from previous loop; BMI stats fill values[i..stat_cnt-1] */ + fman_if_bmi_stats_get_all(dev->process_private, values_copy); for (j = 0; i < stat_cnt; i++, j++) values[i] = values_copy[j]; @@ -1332,7 +1331,7 @@ rxq->nb_desc = nb_desc; /* Enable tail drop with cgr on this queue */ qm_cgr_cs_thres_set64(&cgr_opts.cgr.cs_thres, nb_desc, 0); - ret = qman_modify_cgr(dpaa_intf->cgr_rx, 0, &cgr_opts); + ret = qman_modify_cgr(&dpaa_intf->cgr_rx[queue_idx], 0, &cgr_opts); if (ret) { DPAA_PMD_WARN( "rx taildrop modify fail on fqid %d (ret=%d)", @@ -2709,18 +2708,20 @@ rte_dpaa_remove(struct rte_dpaa_device *dpaa_dev) { struct rte_eth_dev *eth_dev; - int ret; + int ret = 0; PMD_INIT_FUNC_TRACE(); eth_dev = dpaa_dev->eth_dev; - dpaa_eth_dev_close(eth_dev); - ret = rte_eth_dev_release_port(eth_dev); + ret = dpaa_eth_dev_close(eth_dev); + if (eth_dev->state != RTE_ETH_DEV_UNUSED) { + dpaa_eth_dev_close(eth_dev); + ret = rte_eth_dev_release_port(eth_dev); + } dpaa_valid_dev--; - if (!dpaa_valid_dev) { + if (!dpaa_valid_dev) rte_mempool_free(dpaa_tx_sg_pool); - dpaa_finish(); - } + return ret; } diff -Nru dpdk-24.11.4/drivers/net/dpaa/dpaa_flow.c dpdk-24.11.8/drivers/net/dpaa/dpaa_flow.c --- dpdk-24.11.4/drivers/net/dpaa/dpaa_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa/dpaa_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -81,6 +81,10 @@ devid = fm_model.device_order[i]; /* FM Port Open */ fm_model.fm_port_params[devid].h_fm = fm_info.fman_handle; + if (dpaa_intf.port_handle) { + fm_port_close(dpaa_intf.port_handle); + dpaa_intf.port_handle = NULL; + } dpaa_intf.port_handle = fm_port_open(&fm_model.fm_port_params[devid]); dpaa_intf.scheme_handle[0] = create_device(fm_info.pcd_handle, diff -Nru dpdk-24.11.4/drivers/net/dpaa/dpaa_rxtx.c dpdk-24.11.8/drivers/net/dpaa/dpaa_rxtx.c --- dpdk-24.11.4/drivers/net/dpaa/dpaa_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa/dpaa_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -375,6 +375,10 @@ struct rte_ipv6_hdr *ipv6_hdr = (struct rte_ipv6_hdr *)l3_hdr; DPAA_DP_LOG(DEBUG, "Calculating checksum for mbuf: %p", mbuf); + if (mbuf->l3_len == 0) { + DPAA_DP_LOG(WARNING, "l3_len is 0, skipping checksum for mbuf: %p", mbuf); + return; + } if (((mbuf->packet_type & RTE_PTYPE_L3_MASK) == RTE_PTYPE_L3_IPV4) || ((mbuf->packet_type & RTE_PTYPE_L3_MASK) == @@ -993,6 +997,7 @@ if (temp->buf_len < ((mbuf->nb_segs * sizeof(struct qm_sg_entry)) + temp->data_off)) { DPAA_PMD_ERR("Insufficient space in mbuf for SG entries"); + rte_pktmbuf_free(temp); return -1; } diff -Nru dpdk-24.11.4/drivers/net/dpaa/fmlib/fm_lib.c dpdk-24.11.8/drivers/net/dpaa/fmlib/fm_lib.c --- dpdk-24.11.4/drivers/net/dpaa/fmlib/fm_lib.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa/fmlib/fm_lib.c 2026-10-14 13:10:05.000000000 +0000 @@ -305,6 +305,9 @@ _fml_dbg("Calling..."); + if (p_dev == NULL) + return E_NO_DEVICE; + p_pcd_dev = (t_device *)p_dev->h_user_priv; id.obj = UINT_TO_PTR(p_dev->id); diff -Nru dpdk-24.11.4/drivers/net/dpaa2/base/dpaa2_hw_dpni.c dpdk-24.11.8/drivers/net/dpaa2/base/dpaa2_hw_dpni.c --- dpdk-24.11.4/drivers/net/dpaa2/base/dpaa2_hw_dpni.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa2/base/dpaa2_hw_dpni.c 2026-10-14 13:10:05.000000000 +0000 @@ -226,7 +226,7 @@ uint32_t loop = 0, i = 0; uint64_t dist_field = 0; int l2_configured = 0, l3_configured = 0; - int l4_configured = 0, sctp_configured = 0; + int l4_configured = 0; int mpls_configured = 0; int vlan_configured = 0; int esp_configured = 0; @@ -405,6 +405,8 @@ case RTE_ETH_RSS_NONFRAG_IPV6_UDP: case RTE_ETH_RSS_IPV6_TCP_EX: case RTE_ETH_RSS_IPV6_UDP_EX: + case RTE_ETH_RSS_NONFRAG_IPV4_SCTP: + case RTE_ETH_RSS_NONFRAG_IPV6_SCTP: if (l4_configured) break; @@ -423,35 +425,7 @@ kg_cfg->extracts[i].extract.from_hdr.prot = NET_PROT_TCP; kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_TCP_PORT_SRC; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - break; - - case RTE_ETH_RSS_NONFRAG_IPV4_SCTP: - case RTE_ETH_RSS_NONFRAG_IPV6_SCTP: - - if (sctp_configured) - break; - sctp_configured = 1; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_SCTP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_SCTP_PORT_SRC; - kg_cfg->extracts[i].type = - DPKG_EXTRACT_FROM_HDR; - kg_cfg->extracts[i].extract.from_hdr.type = - DPKG_FULL_FIELD; - i++; - - kg_cfg->extracts[i].extract.from_hdr.prot = - NET_PROT_SCTP; - kg_cfg->extracts[i].extract.from_hdr.field = - NH_FLD_SCTP_PORT_DST; + NH_FLD_TCP_PORT_DST; kg_cfg->extracts[i].type = DPKG_EXTRACT_FROM_HDR; kg_cfg->extracts[i].extract.from_hdr.type = diff -Nru dpdk-24.11.4/drivers/net/dpaa2/dpaa2_ethdev.c dpdk-24.11.8/drivers/net/dpaa2/dpaa2_ethdev.c --- dpdk-24.11.4/drivers/net/dpaa2/dpaa2_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa2/dpaa2_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -77,8 +77,9 @@ bool dpaa2_print_parser_result; -#define MAX_NB_RX_DESC 11264 -int total_nb_rx_desc; +/* Rx descriptor limit when DPNI loads PFDRs in PEB */ +#define MAX_NB_RX_DESC_IN_PEB 11264 +static int total_nb_rx_desc; int dpaa2_valid_dev; struct rte_mempool *dpaa2_tx_sg_pool; @@ -294,34 +295,18 @@ __rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode) { - struct rte_eth_conf *eth_conf = &dev->data->dev_conf; - int ret = -EINVAL; - unsigned int i; - const struct burst_info { - uint64_t flags; - const char *output; - } rx_offload_map[] = { - {RTE_ETH_RX_OFFLOAD_CHECKSUM, " Checksum,"}, - {RTE_ETH_RX_OFFLOAD_SCTP_CKSUM, " SCTP csum,"}, - {RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM, " Outer IPV4 csum,"}, - {RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM, " Outer UDP csum,"}, - {RTE_ETH_RX_OFFLOAD_VLAN_STRIP, " VLAN strip,"}, - {RTE_ETH_RX_OFFLOAD_VLAN_FILTER, " VLAN filter,"}, - {RTE_ETH_RX_OFFLOAD_TIMESTAMP, " Timestamp,"}, - {RTE_ETH_RX_OFFLOAD_RSS_HASH, " RSS,"}, - {RTE_ETH_RX_OFFLOAD_SCATTER, " Scattered,"} - }; + eth_rx_burst_t pkt_burst = dev->rx_pkt_burst; - /* Update Rx offload info */ - for (i = 0; i < RTE_DIM(rx_offload_map); i++) { - if (eth_conf->rxmode.offloads & rx_offload_map[i].flags) { - snprintf(mode->info, sizeof(mode->info), "%s", - rx_offload_map[i].output); - ret = 0; - break; - } - } - return ret; + if (pkt_burst == dpaa2_dev_prefetch_rx) + snprintf(mode->info, sizeof(mode->info), "%s", "Scalar Prefetch"); + else if (pkt_burst == dpaa2_dev_rx) + snprintf(mode->info, sizeof(mode->info), "%s", "Scalar"); + else if (pkt_burst == dpaa2_dev_loopback_rx) + snprintf(mode->info, sizeof(mode->info), "%s", "Loopback"); + else + return -EINVAL; + + return 0; } static int @@ -329,34 +314,18 @@ __rte_unused uint16_t queue_id, struct rte_eth_burst_mode *mode) { - struct rte_eth_conf *eth_conf = &dev->data->dev_conf; - int ret = -EINVAL; - unsigned int i; - const struct burst_info { - uint64_t flags; - const char *output; - } tx_offload_map[] = { - {RTE_ETH_TX_OFFLOAD_VLAN_INSERT, " VLAN Insert,"}, - {RTE_ETH_TX_OFFLOAD_IPV4_CKSUM, " IPV4 csum,"}, - {RTE_ETH_TX_OFFLOAD_UDP_CKSUM, " UDP csum,"}, - {RTE_ETH_TX_OFFLOAD_TCP_CKSUM, " TCP csum,"}, - {RTE_ETH_TX_OFFLOAD_SCTP_CKSUM, " SCTP csum,"}, - {RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM, " Outer IPV4 csum,"}, - {RTE_ETH_TX_OFFLOAD_MT_LOCKFREE, " MT lockfree,"}, - {RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE, " MBUF free disable,"}, - {RTE_ETH_TX_OFFLOAD_MULTI_SEGS, " Scattered,"} - }; + eth_tx_burst_t pkt_burst = dev->tx_pkt_burst; - /* Update Tx offload info */ - for (i = 0; i < RTE_DIM(tx_offload_map); i++) { - if (eth_conf->txmode.offloads & tx_offload_map[i].flags) { - snprintf(mode->info, sizeof(mode->info), "%s", - tx_offload_map[i].output); - ret = 0; - break; - } - } - return ret; + if (pkt_burst == dpaa2_dev_tx) + snprintf(mode->info, sizeof(mode->info), "%s", "Scalar"); + else if (pkt_burst == dpaa2_dev_tx_ordered) + snprintf(mode->info, sizeof(mode->info), "%s", "Ordered"); + else if (pkt_burst == rte_eth_pkt_burst_dummy) + snprintf(mode->info, sizeof(mode->info), "%s", "Dummy"); + else + return -EINVAL; + + return 0; } static int @@ -743,10 +712,14 @@ dev, rx_queue_id, mb_pool, rx_conf); total_nb_rx_desc += nb_rx_desc; - if (total_nb_rx_desc > MAX_NB_RX_DESC) { - DPAA2_PMD_WARN("Total nb_rx_desc exceeds %d limit. Please use Normal buffers", - MAX_NB_RX_DESC); - DPAA2_PMD_WARN("To use Normal buffers, run 'export DPNI_NORMAL_BUF=1' before running dynamic_dpl.sh script"); + if (total_nb_rx_desc > MAX_NB_RX_DESC_IN_PEB && + (priv->options & DPNI_OPT_V1_PFDR_IN_PEB)) { + DPAA2_PMD_WARN("RX descriptor exceeds limit(%d) to load PFDR in PEB", + MAX_NB_RX_DESC_IN_PEB); + DPAA2_PMD_WARN("Suggest removing 0x%08x from DPNI creating options(0x%08x)", + DPNI_OPT_V1_PFDR_IN_PEB, priv->options); + DPAA2_PMD_WARN("Or reduce RX descriptor number(%d) per queue", + nb_rx_desc); } /* Rx deferred start is not supported */ @@ -1239,9 +1212,6 @@ return ret; } - /* Power up the phy. Needed to make the link go UP */ - dpaa2_dev_set_link_up(dev); - for (i = 0; i < data->nb_rx_queues; i++) { dpaa2_q = data->rx_queues[i]; ret = dpni_get_queue(dpni, CMD_PRI_LOW, priv->token, @@ -1308,6 +1278,12 @@ dpaa2_eth_setup_irqs(dev, 1); } + /* Power up the phy. Needed to make the link go UP. + * Called after LSC interrupt setup so that the link-up + * event is not missed if the MAC negotiates quickly. + */ + dpaa2_dev_set_link_up(dev); + /* Change the tx burst function if ordered queues are used */ if (priv->en_ordered) dev->tx_pkt_burst = dpaa2_dev_tx_ordered; @@ -2806,6 +2782,7 @@ } eth_dev->dev_ops = &dpaa2_ethdev_ops; + eth_dev->rx_queue_count = dpaa2_dev_rx_queue_count; if (dpaa2_get_devargs(dev->devargs, DRIVER_LOOPBACK_MODE)) { eth_dev->rx_pkt_burst = dpaa2_dev_loopback_rx; @@ -2862,7 +2839,7 @@ if (ret < 0) { DPAA2_PMD_ERR(" Error(%d) in loading softparser", ret); - return ret; + goto init_err; } ret = dpaa2_eth_enable_wriop_soft_parser(priv, @@ -2870,7 +2847,7 @@ if (ret < 0) { DPAA2_PMD_ERR(" Error(%d) in enabling softparser", ret); - return ret; + goto init_err; } } diff -Nru dpdk-24.11.4/drivers/net/dpaa2/dpaa2_rxtx.c dpdk-24.11.8/drivers/net/dpaa2/dpaa2_rxtx.c --- dpdk-24.11.4/drivers/net/dpaa2/dpaa2_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa2/dpaa2_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -202,8 +202,13 @@ if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L3CE)) mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD; - else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CE)) + else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L3CV)) + mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD; + + if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CE)) mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD; + else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CV)) + mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD; if (BIT_ISSET_AT_POS(annotation->word4, L3_IP_1_FIRST_FRAGMENT | L3_IP_1_MORE_FRAGMENT | @@ -211,24 +216,18 @@ L3_IP_N_MORE_FRAGMENT)) { pkt_type |= RTE_PTYPE_L4_FRAG; goto parse_done; - } else { - pkt_type |= RTE_PTYPE_L4_NONFRAG; } if (BIT_ISSET_AT_POS(annotation->word4, L3_PROTO_UDP_PRESENT)) pkt_type |= RTE_PTYPE_L4_UDP; - else if (BIT_ISSET_AT_POS(annotation->word4, L3_PROTO_TCP_PRESENT)) pkt_type |= RTE_PTYPE_L4_TCP; - else if (BIT_ISSET_AT_POS(annotation->word4, L3_PROTO_SCTP_PRESENT)) pkt_type |= RTE_PTYPE_L4_SCTP; - else if (BIT_ISSET_AT_POS(annotation->word4, L3_PROTO_ICMP_PRESENT)) pkt_type |= RTE_PTYPE_L4_ICMP; - - else if (BIT_ISSET_AT_POS(annotation->word4, L3_IP_UNKNOWN_PROTOCOL)) - pkt_type |= RTE_PTYPE_UNKNOWN; + else + pkt_type |= RTE_PTYPE_L4_NONFRAG; parse_done: return pkt_type; @@ -245,8 +244,13 @@ if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L3CE)) mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD; - else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CE)) + else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L3CV)) + mbuf->ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD; + + if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CE)) mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD; + else if (BIT_ISSET_AT_POS(annotation->word1, DPAA2_ETH_FAS_L4CV)) + mbuf->ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD; if (unlikely(dpaa2_print_parser_result)) dpaa2_print_parse_result(annotation); @@ -330,7 +334,7 @@ (void **)&first_seg, 1, 1); #endif cur_seg = first_seg; - while (!DPAA2_SG_IS_FINAL(sge)) { + while (!DPAA2_SG_IS_FINAL(sge) && i < DPAA2_MAX_SGS) { sge = &sgt[i++]; sg_addr = (size_t)DPAA2_IOVA_TO_VADDR( DPAA2_GET_FLE_ADDR(sge)); @@ -633,7 +637,7 @@ const struct qbman_fd *fd; struct qbman_pull_desc pulldesc; struct rte_eth_dev_data *eth_data = dpaa2_q->eth_data; - uint32_t lcore_id = rte_lcore_id(), i = 0; + uint32_t lcore_id = rte_lcore_id(); void *v_addr, *hw_annot_addr; struct dpaa2_fas *fas; struct rte_mbuf *mbuf; @@ -708,24 +712,27 @@ DPAA2_GET_FD_OFFSET(fd), DPAA2_GET_FD_ERR(fd), fas->status); - if (mbuf) + if (mbuf) { __rte_mbuf_sanity_check(mbuf, 1); - if (mbuf->nb_segs > 1) { - while (mbuf) { - sprintf(title, "Payload seg[%d]", i); - rte_hexdump(stderr, title, + if (mbuf->nb_segs > 1) { + struct rte_mbuf *seg = mbuf; + int i = 0; + + while (seg) { + sprintf(title, "Payload seg[%d]", i); + rte_hexdump(stderr, title, + (char *)seg->buf_addr + seg->data_off, + seg->data_len); + seg = seg->next; + i++; + } + } else { + rte_hexdump(stderr, "Payload", (char *)mbuf->buf_addr + mbuf->data_off, mbuf->data_len); - mbuf = mbuf->next; - i++; } - } else { - rte_hexdump(stderr, "Payload", - (char *)mbuf->buf_addr + mbuf->data_off, - mbuf->data_len); + rte_pktmbuf_free(mbuf); } - - rte_pktmbuf_free(mbuf); dq_storage++; num_rx++; } while (pending); @@ -1349,10 +1356,8 @@ priv->bp_list->dpaa2_ops_index && (*bufs)->nb_segs == 1 && rte_mbuf_refcnt_read((*bufs)) == 1)) { - if (unlikely(((*bufs)->ol_flags - & RTE_MBUF_F_TX_VLAN) || - (eth_data->dev_conf.txmode.offloads - & RTE_ETH_TX_OFFLOAD_VLAN_INSERT))) { + if (unlikely((*bufs)->ol_flags + & RTE_MBUF_F_TX_VLAN)) { ret = rte_vlan_insert(bufs); if (ret) goto send_n_return; @@ -1405,9 +1410,7 @@ goto send_n_return; } - if (unlikely(((*bufs)->ol_flags & RTE_MBUF_F_TX_VLAN) || - (eth_data->dev_conf.txmode.offloads - & RTE_ETH_TX_OFFLOAD_VLAN_INSERT))) { + if (unlikely((*bufs)->ol_flags & RTE_MBUF_F_TX_VLAN)) { int ret = rte_vlan_insert(bufs); if (ret) goto send_n_return; @@ -1517,21 +1520,15 @@ return num_tx; sw_td: - loop = 0; - while (loop < num_tx) { - if (unlikely(RTE_MBUF_HAS_EXTBUF(*bufs))) - rte_pktmbuf_free(*bufs); - bufs++; - loop++; + for (loop = 0; loop < free_count; loop++) { + if (buf_to_free[loop].pkt_id < num_tx) + rte_pktmbuf_free_seg(buf_to_free[loop].seg); } /* free the pending buffers */ - while (nb_pkts) { - rte_pktmbuf_free(*bufs); - bufs++; - nb_pkts--; - num_tx++; - } + rte_pktmbuf_free_bulk(bufs, nb_pkts); + + num_tx += nb_pkts; dpaa2_q->tx_pkts += num_tx; return num_tx; diff -Nru dpdk-24.11.4/drivers/net/dpaa2/mc/fsl_dpni.h dpdk-24.11.8/drivers/net/dpaa2/mc/fsl_dpni.h --- dpdk-24.11.4/drivers/net/dpaa2/mc/fsl_dpni.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/dpaa2/mc/fsl_dpni.h 2026-10-14 13:10:05.000000000 +0000 @@ -121,6 +121,12 @@ * The stashing is enabled by default. */ #define DPNI_OPT_STASHING_DIS 0x002000 +/* + * PFDR in PEB mode (v1 layout). + * The total number of Rx descriptors is limited to 11264 in this mode. + * When not set, PFDRs are stored in DDR and there is no such limit. + */ +#define DPNI_OPT_V1_PFDR_IN_PEB 0x80000000 /** * Software sequence maximum layout size */ diff -Nru dpdk-24.11.4/drivers/net/e1000/base/e1000_82575.c dpdk-24.11.8/drivers/net/e1000/base/e1000_82575.c --- dpdk-24.11.4/drivers/net/e1000/base/e1000_82575.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/base/e1000_82575.c 2026-10-14 13:10:05.000000000 +0000 @@ -2403,7 +2403,7 @@ DEBUGFUNC("e1000_validate_nvm_checksum_with_offset"); - for (i = offset; i < ((NVM_CHECKSUM_REG + offset) + 1); i++) { + for (i = offset; i < (u16)((NVM_CHECKSUM_REG + offset) + 1); i++) { ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); if (ret_val) { DEBUGOUT("NVM Read Error\n"); @@ -2440,7 +2440,7 @@ DEBUGFUNC("e1000_update_nvm_checksum_with_offset"); - for (i = offset; i < (NVM_CHECKSUM_REG + offset); i++) { + for (i = offset; i < (u16)(NVM_CHECKSUM_REG + offset); i++) { ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); if (ret_val) { DEBUGOUT("NVM Read Error while updating checksum.\n"); diff -Nru dpdk-24.11.4/drivers/net/e1000/base/e1000_ich8lan.c dpdk-24.11.8/drivers/net/e1000/base/e1000_ich8lan.c --- dpdk-24.11.4/drivers/net/e1000/base/e1000_ich8lan.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/base/e1000_ich8lan.c 2026-10-14 13:10:05.000000000 +0000 @@ -2585,6 +2585,8 @@ e1000_phy_sw_reset_generic(hw); ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, 0x3140); + if (ret_val) + return ret_val; } } @@ -4064,7 +4066,7 @@ usec_delay(100); - /* Write the data to the new bank. Offset in words*/ + /* Write the data to the new bank. Offset in words */ act_offset = i + new_bank_offset; ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); @@ -4087,7 +4089,7 @@ */ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; - /*offset in words but we read dword*/ + /* offset in words but we read dword */ --act_offset; ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); @@ -4100,7 +4102,7 @@ if (ret_val) goto release; - /* offset in words but we read dword*/ + /* offset in words but we read dword */ act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1; ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); diff -Nru dpdk-24.11.4/drivers/net/e1000/base/e1000_mac.c dpdk-24.11.8/drivers/net/e1000/base/e1000_mac.c --- dpdk-24.11.4/drivers/net/e1000/base/e1000_mac.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/base/e1000_mac.c 2026-10-14 13:10:05.000000000 +0000 @@ -1954,7 +1954,7 @@ (mode == E1000_LEDCTL_MODE_LED_OFF))) { ledctl_blink &= ~(E1000_LEDCTL_LED0_MODE_MASK << i); - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK | + ledctl_blink |= (u32)(E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_MODE_LED_ON) << i; } } diff -Nru dpdk-24.11.4/drivers/net/e1000/base/e1000_manage.c dpdk-24.11.8/drivers/net/e1000/base/e1000_manage.c --- dpdk-24.11.4/drivers/net/e1000/base/e1000_manage.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/base/e1000_manage.c 2026-10-14 13:10:05.000000000 +0000 @@ -129,7 +129,7 @@ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; for (i = 0; i < len; i++) - *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, + buffer[i] = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i); hdr_csum = hdr->checksum; hdr->checksum = 0; @@ -173,7 +173,7 @@ /* Write the relevant command block into the ram area. */ for (i = 0; i < length; i++) { E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, - *((u32 *) hdr + i)); + ((u32 *)hdr)[i]); E1000_WRITE_FLUSH(hw); } diff -Nru dpdk-24.11.4/drivers/net/e1000/igb_ethdev.c dpdk-24.11.8/drivers/net/e1000/igb_ethdev.c --- dpdk-24.11.4/drivers/net/e1000/igb_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/igb_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1981,8 +1981,9 @@ PMD_INIT_LOG(ERR, "id value isn't valid"); return -1; } - strcpy(xstats_names[i].name, - xstats_names_copy[ids[i]].name); + strlcpy(xstats_names[i].name, + xstats_names_copy[ids[i]].name, + sizeof(xstats_names[i].name)); } return limit; } @@ -4203,7 +4204,8 @@ flex_filter->filter_info.len = filter->len; flex_filter->filter_info.priority = filter->priority; memcpy(flex_filter->filter_info.dwords, filter->bytes, filter->len); - for (i = 0; i < RTE_ALIGN(filter->len, CHAR_BIT) / CHAR_BIT; i++) { + for (i = 0; i < RTE_ALIGN(filter->len, CHAR_BIT) / CHAR_BIT && + i < E1000_FLEX_FILTERS_MASK_SIZE; i++) { mask = 0; /* reverse bits in flex filter's mask*/ for (shift = 0; shift < CHAR_BIT; shift++) { diff -Nru dpdk-24.11.4/drivers/net/e1000/igb_rxtx.c dpdk-24.11.8/drivers/net/e1000/igb_rxtx.c --- dpdk-24.11.4/drivers/net/e1000/igb_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/e1000/igb_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -2035,13 +2035,14 @@ hash_key = rss_conf->rss_key; if (hash_key != NULL) { /* Return RSS hash key */ - for (i = 0; i < 10; i++) { + for (i = 0; i < IGB_HKEY_MAX_INDEX; i++) { rss_key = E1000_READ_REG_ARRAY(hw, E1000_RSSRK(0), i); hash_key[(i * 4)] = rss_key & 0x000000FF; hash_key[(i * 4) + 1] = (rss_key >> 8) & 0x000000FF; hash_key[(i * 4) + 2] = (rss_key >> 16) & 0x000000FF; hash_key[(i * 4) + 3] = (rss_key >> 24) & 0x000000FF; } + rss_conf->rss_key_len = IGB_HKEY_MAX_INDEX * sizeof(uint32_t); } /* Get RSS functions configured in MRQC register */ diff -Nru dpdk-24.11.4/drivers/net/enetc/base/enetc_hw.h dpdk-24.11.8/drivers/net/enetc/base/enetc_hw.h --- dpdk-24.11.4/drivers/net/enetc/base/enetc_hw.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/enetc/base/enetc_hw.h 2026-10-14 13:10:05.000000000 +0000 @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2020 NXP + * Copyright 2018-2026 NXP */ #ifndef _ENETC_HW_H_ @@ -188,8 +188,7 @@ #define ENETC_TX_ADDR(txq, addr) ((void *)((txq)->enetc_txbdr + (addr))) -#define ENETC_TXBD_FLAGS_IE BIT(13) -#define ENETC_TXBD_FLAGS_F BIT(15) +#define ENETC_TXBD_FLAGS_F BIT(7) /* ENETC Parsed values (Little Endian) */ #define ENETC_PARSE_ERROR 0x8000 @@ -249,7 +248,7 @@ uint16_t buf_len; uint16_t frm_len; uint16_t err_csum; - uint16_t flags; + uint8_t flags; }; /* RX buffer descriptor */ diff -Nru dpdk-24.11.4/drivers/net/enetc/enetc_rxtx.c dpdk-24.11.8/drivers/net/enetc/enetc_rxtx.c --- dpdk-24.11.4/drivers/net/enetc/enetc_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/enetc/enetc_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright 2018-2020 NXP + * Copyright 2018-2026 NXP */ #include @@ -99,7 +99,7 @@ tx_swbd = &tx_ring->q_swbd[i]; txbd->frm_len = tx_pkts[start]->pkt_len; txbd->buf_len = txbd->frm_len; - txbd->flags = rte_cpu_to_le_16(ENETC_TXBD_FLAGS_F); + txbd->flags = ENETC_TXBD_FLAGS_F; txbd->addr = (uint64_t)(uintptr_t) rte_cpu_to_le_64((size_t)tx_swbd->buffer_addr->buf_iova + tx_swbd->buffer_addr->data_off); diff -Nru dpdk-24.11.4/drivers/net/enic/enic_flow.c dpdk-24.11.8/drivers/net/enic/enic_flow.c --- dpdk-24.11.4/drivers/net/enic/enic_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/enic/enic_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -407,7 +407,7 @@ /* check that the supplied mask exactly matches capability */ if (!mask_exact_match((const uint8_t *)&supported_mask, - (const uint8_t *)item->mask, sizeof(*mask))) { + (const uint8_t *)mask, sizeof(*mask))) { ENICPMD_LOG(ERR, "IPv4 exact match mask"); return ENOTSUP; } @@ -445,7 +445,7 @@ /* check that the supplied mask exactly matches capability */ if (!mask_exact_match((const uint8_t *)&supported_mask, - (const uint8_t *)item->mask, sizeof(*mask))) { + (const uint8_t *)mask, sizeof(*mask))) { ENICPMD_LOG(ERR, "UDP exact match mask"); return ENOTSUP; } @@ -484,7 +484,7 @@ /* check that the supplied mask exactly matches capability */ if (!mask_exact_match((const uint8_t *)&supported_mask, - (const uint8_t *)item->mask, sizeof(*mask))) { + (const uint8_t *)mask, sizeof(*mask))) { ENICPMD_LOG(ERR, "TCP exact match mask"); return ENOTSUP; } diff -Nru dpdk-24.11.4/drivers/net/failsafe/failsafe.c dpdk-24.11.8/drivers/net/failsafe/failsafe.c --- dpdk-24.11.4/drivers/net/failsafe/failsafe.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/failsafe/failsafe.c 2026-10-14 13:10:05.000000000 +0000 @@ -144,15 +144,24 @@ /* Allow mutex relocks for the thread holding the mutex. */ ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); if (ret) { - ERROR("Cannot set mutex type - %s", strerror(ret)); - return ret; + ERROR("Cannot set mutex recursive - %s", strerror(ret)); + goto out; + } + /* Allow mutex to be shared between processes. */ + ret = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + if (ret) { + ERROR("Cannot set mutex pshared - %s", strerror(ret)); + goto out; } ret = pthread_mutex_init(&priv->hotplug_mutex, &attr); if (ret) { ERROR("Cannot initiate mutex - %s", strerror(ret)); - return ret; + goto out; } - return 0; + +out: + pthread_mutexattr_destroy(&attr); + return ret; } static int diff -Nru dpdk-24.11.4/drivers/net/gve/base/gve_adminq.c dpdk-24.11.8/drivers/net/gve/base/gve_adminq.c --- dpdk-24.11.4/drivers/net/gve/base/gve_adminq.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/base/gve_adminq.c 2026-10-14 13:10:05.000000000 +0000 @@ -589,9 +589,9 @@ GVE_RAW_ADDRESSING_QPL_ID : rxq->qpl->id; cmd.create_rx_queue.rx_desc_ring_addr = - cpu_to_be64(rxq->mz->iova), + cpu_to_be64(rxq->mz->iova); cmd.create_rx_queue.rx_data_ring_addr = - cpu_to_be64(rxq->data_mz->iova), + cpu_to_be64(rxq->data_mz->iova); cmd.create_rx_queue.index = cpu_to_be32(queue_index); cmd.create_rx_queue.queue_page_list_id = cpu_to_be32(qpl_id); cmd.create_rx_queue.packet_buffer_size = cpu_to_be16(rxq->rx_buf_len); @@ -732,15 +732,20 @@ gve_set_max_desc_cnt(struct gve_priv *priv, const struct gve_device_option_modify_ring *modify_ring) { + priv->max_rx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.rx); + priv->max_tx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.tx); + if (priv->queue_format == GVE_DQO_RDA_FORMAT) { PMD_DRV_LOG(DEBUG, "Overriding max ring size from device for DQ " "queue format to 4096."); priv->max_rx_desc_cnt = GVE_MAX_QUEUE_SIZE_DQO; priv->max_tx_desc_cnt = GVE_MAX_QUEUE_SIZE_DQO; - return; + } else if (priv->queue_format == GVE_GQI_QPL_FORMAT) { + priv->max_rx_desc_cnt = RTE_MIN(priv->max_rx_desc_cnt, + GVE_MAX_RING_SIZE_GQ_QPL); + priv->max_tx_desc_cnt = RTE_MIN(priv->max_tx_desc_cnt, + GVE_MAX_RING_SIZE_GQ_QPL); } - priv->max_rx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.rx); - priv->max_tx_desc_cnt = be16_to_cpu(modify_ring->max_ring_size.tx); } static void gve_enable_supported_features(struct gve_priv *priv, diff -Nru dpdk-24.11.4/drivers/net/gve/base/gve_osdep.h dpdk-24.11.8/drivers/net/gve/base/gve_osdep.h --- dpdk-24.11.4/drivers/net/gve/base/gve_osdep.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/base/gve_osdep.h 2026-10-14 13:10:05.000000000 +0000 @@ -159,14 +159,14 @@ static inline void * gve_alloc_dma_mem(struct gve_dma_mem *mem, u64 size) { - static RTE_ATOMIC(uint16_t) gve_dma_memzone_id; + static RTE_ATOMIC(uint64_t) gve_dma_memzone_id; const struct rte_memzone *mz = NULL; char z_name[RTE_MEMZONE_NAMESIZE]; if (!mem) return NULL; - snprintf(z_name, sizeof(z_name), "gve_dma_%u", + snprintf(z_name, sizeof(z_name), "gve_dma_%" PRIu64, rte_atomic_fetch_add_explicit(&gve_dma_memzone_id, 1, rte_memory_order_relaxed)); mz = rte_memzone_reserve_aligned(z_name, size, SOCKET_ID_ANY, RTE_MEMZONE_IOVA_CONTIG, diff -Nru dpdk-24.11.4/drivers/net/gve/gve_ethdev.c dpdk-24.11.8/drivers/net/gve/gve_ethdev.c --- dpdk-24.11.4/drivers/net/gve/gve_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/gve_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -291,6 +291,8 @@ if (!priv->stats_report_mem) return -ENOMEM; + memset(priv->stats_report_mem->addr, 0, priv->stats_report_mem->len); + /* offset by skipping stats written by gve. */ priv->stats_start_idx = (GVE_TX_STATS_REPORT_NUM * nb_tx_queues) + (GVE_RX_STATS_REPORT_NUM * nb_rx_queues); diff -Nru dpdk-24.11.4/drivers/net/gve/gve_ethdev.h dpdk-24.11.8/drivers/net/gve/gve_ethdev.h --- dpdk-24.11.4/drivers/net/gve/gve_ethdev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/gve_ethdev.h 2026-10-14 13:10:05.000000000 +0000 @@ -16,6 +16,7 @@ #define DQO_TX_MULTIPLIER 4 #define GVE_DEFAULT_MAX_RING_SIZE 1024 +#define GVE_MAX_RING_SIZE_GQ_QPL 2048 #define GVE_DEFAULT_MIN_RX_RING_SIZE 512 #define GVE_DEFAULT_MIN_TX_RING_SIZE 256 diff -Nru dpdk-24.11.4/drivers/net/gve/gve_rx.c dpdk-24.11.8/drivers/net/gve/gve_rx.c --- dpdk-24.11.4/drivers/net/gve/gve_rx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/gve_rx.c 2026-10-14 13:10:05.000000000 +0000 @@ -152,6 +152,7 @@ rxe = rxq->sw_ring[rx_id]; gve_rx_mbuf(rxq, rxe, frag_size, rx_id); + rxq->sw_ring[rx_id] = NULL; rxq->stats.bytes += frag_size; if (is_first_frag) { @@ -204,6 +205,8 @@ if (gve_rx(rxq, rxd, rx_id)) { if (!ctx->drop_pkt) rx_pkts[nb_rx++] = ctx->mbuf_head; + else if (ctx->mbuf_head != NULL) + rte_pktmbuf_free(ctx->mbuf_head); rxq->nb_avail += ctx->total_frags; gve_rx_ctx_clear(ctx); } diff -Nru dpdk-24.11.4/drivers/net/gve/gve_rx_dqo.c dpdk-24.11.8/drivers/net/gve/gve_rx_dqo.c --- dpdk-24.11.4/drivers/net/gve/gve_rx_dqo.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/gve_rx_dqo.c 2026-10-14 13:10:05.000000000 +0000 @@ -152,6 +152,7 @@ if (rx_id_bufq == rxq->nb_rx_desc) rx_id_bufq = 0; rxq->nb_rx_hold++; + rxq->sw_ring[rx_id_bufq] = NULL; rxm->pkt_len = pkt_len; rxm->data_len = pkt_len; diff -Nru dpdk-24.11.4/drivers/net/gve/gve_tx.c dpdk-24.11.8/drivers/net/gve/gve_tx.c --- dpdk-24.11.4/drivers/net/gve/gve_tx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/gve/gve_tx.c 2026-10-14 13:10:05.000000000 +0000 @@ -255,10 +255,10 @@ struct rte_mbuf **sw_ring = txq->sw_ring; uint16_t mask = txq->nb_tx_desc - 1; uint16_t tx_id = txq->tx_tail & mask; - uint64_t ol_flags, addr, fifo_addr; uint32_t tx_tail = txq->tx_tail; struct rte_mbuf *tx_pkt, *first; uint16_t sw_id = txq->sw_tail; + uint64_t ol_flags, fifo_addr; uint16_t nb_used, i; uint64_t bytes = 0; uint16_t nb_tx = 0; @@ -273,6 +273,9 @@ gve_tx_clean_swr_qpl(txq); for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { + const void *mbuf_header_addr; + void *qpl_write_addr; + tx_pkt = *tx_pkts++; ol_flags = tx_pkt->ol_flags; @@ -301,13 +304,11 @@ (uint32_t)(tx_offload.l2_len + tx_offload.l3_len + tx_offload.l4_len) : tx_pkt->pkt_len; - sw_ring[sw_id] = tx_pkt; if (!is_fifo_avail(txq, hlen)) { gve_tx_clean(txq); if (!is_fifo_avail(txq, hlen)) goto end_of_tx; } - addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off; fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, hlen); /* For TSO, check if there's enough fifo space for data first */ @@ -318,39 +319,46 @@ goto end_of_tx; } } - if (tx_pkt->nb_segs == 1 || ol_flags & RTE_MBUF_F_TX_TCP_SEG) - rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base), - (void *)(size_t)addr, hlen); - else - rte_pktmbuf_read(tx_pkt, 0, hlen, - (void *)(size_t)(fifo_addr + txq->fifo_base)); + + qpl_write_addr = (void *)(size_t)(fifo_addr + txq->fifo_base); + mbuf_header_addr = rte_pktmbuf_read(tx_pkt, 0, hlen, qpl_write_addr); + + /* Header data is linear in the mbuf head. Copy directly. */ + if (mbuf_header_addr != qpl_write_addr) + rte_memcpy(qpl_write_addr, mbuf_header_addr, hlen); + gve_tx_fill_pkt_desc(txd, tx_pkt, nb_used, hlen, fifo_addr); if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + const void *mbuf_payload_addr; + tx_id = (tx_id + 1) & mask; txd = &txr[tx_id]; - addr = (uint64_t)(tx_pkt->buf_addr) + tx_pkt->data_off + hlen; fifo_addr = gve_tx_alloc_from_fifo(txq, tx_id, tx_pkt->pkt_len - hlen); - if (tx_pkt->nb_segs == 1) - rte_memcpy((void *)(size_t)(fifo_addr + txq->fifo_base), - (void *)(size_t)addr, + qpl_write_addr = (void *)(size_t)(txq->fifo_base + fifo_addr); + mbuf_payload_addr = rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen, + qpl_write_addr); + + /* Payload data is contiguous. Take the offset from the + * read request and copy from there. + */ + if (mbuf_payload_addr != qpl_write_addr) + rte_memcpy(qpl_write_addr, mbuf_payload_addr, tx_pkt->pkt_len - hlen); - else - rte_pktmbuf_read(tx_pkt, hlen, tx_pkt->pkt_len - hlen, - (void *)(size_t)(fifo_addr + txq->fifo_base)); gve_tx_fill_seg_desc(txd, ol_flags, tx_offload, tx_pkt->pkt_len - hlen, fifo_addr); } /* record mbuf in sw_ring for free */ - for (i = 1; i < first->nb_segs; i++) { + for (i = 0; i < first->nb_segs; i++) { + if (!tx_pkt) + break; + sw_ring[sw_id] = tx_pkt; sw_id = (sw_id + 1) & mask; tx_pkt = tx_pkt->next; - sw_ring[sw_id] = tx_pkt; } - sw_id = (sw_id + 1) & mask; tx_id = (tx_id + 1) & mask; txq->nb_free -= nb_used; diff -Nru dpdk-24.11.4/drivers/net/hinic/base/hinic_compat.h dpdk-24.11.8/drivers/net/hinic/base/hinic_compat.h --- dpdk-24.11.4/drivers/net/hinic/base/hinic_compat.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/hinic/base/hinic_compat.h 2026-10-14 13:10:05.000000000 +0000 @@ -19,6 +19,7 @@ #include #include #include +#include typedef uint8_t u8; typedef int8_t s8; @@ -198,15 +199,10 @@ } static inline int hinic_mutex_init(pthread_mutex_t *pthreadmutex, - const pthread_mutexattr_t *mattr) + __rte_unused const pthread_mutexattr_t *mattr) { - int err; - - err = pthread_mutex_init(pthreadmutex, mattr); - if (unlikely(err)) - PMD_DRV_LOG(ERR, "Fail to initialize mutex, error: %d", err); - - return err; + rte_thread_mutex_init_shared(pthreadmutex); + return 0; } static inline int hinic_mutex_destroy(pthread_mutex_t *pthreadmutex) diff -Nru dpdk-24.11.4/drivers/net/hns3/hns3_rxtx.c dpdk-24.11.8/drivers/net/hns3/hns3_rxtx.c --- dpdk-24.11.4/drivers/net/hns3/hns3_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/hns3/hns3_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -3985,12 +3985,17 @@ if (txq->simple_bd_enable && !(m->ol_flags & RTE_MBUF_F_TX_IP_CKSUM) && !(m->ol_flags & RTE_MBUF_F_TX_TCP_SEG) && !(m->ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM) && + !(m->ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM) && ((m->ol_flags & RTE_MBUF_F_TX_L4_MASK) == RTE_MBUF_F_TX_TCP_CKSUM || - (m->ol_flags & RTE_MBUF_F_TX_L4_MASK) == RTE_MBUF_F_TX_UDP_CKSUM)) { + (m->ol_flags & RTE_MBUF_F_TX_L4_MASK) == RTE_MBUF_F_TX_UDP_CKSUM)) { /* set checksum start and offset, defined in 2 Bytes */ + uint32_t l4_start = m->l2_len + m->l3_len; + if (m->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) + l4_start += m->outer_l2_len + m->outer_l3_len; + hns3_set_field(desc->tx.type_cs_vlan_tso_len, HNS3_TXD_L4_START_M, HNS3_TXD_L4_START_S, - (m->l2_len + m->l3_len) >> HNS3_SIMPLE_BD_UNIT); + l4_start >> HNS3_SIMPLE_BD_UNIT); hns3_set_field(desc->tx.ol_type_vlan_len_msec, HNS3_TXD_L4_CKS_OFFSET_M, HNS3_TXD_L4_CKS_OFFSET_S, (m->ol_flags & RTE_MBUF_F_TX_L4_MASK) == diff -Nru dpdk-24.11.4/drivers/net/i40e/base/i40e_dcb.c dpdk-24.11.8/drivers/net/i40e/base/i40e_dcb.c --- dpdk-24.11.4/drivers/net/i40e/base/i40e_dcb.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/base/i40e_dcb.c 2026-10-14 13:10:05.000000000 +0000 @@ -364,7 +364,7 @@ { u16 length, typelength, offset = 0; struct i40e_cee_app_prio *app; - u8 i; + u32 i; typelength = I40E_NTOHS(tlv->hdr.typelen); length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> @@ -1169,9 +1169,9 @@ struct i40e_dcbx_config *dcbcfg) { u16 typelength, length, offset = 0; - u8 priority, selector, i = 0; u8 *buf = tlv->tlvinfo; - u32 ouisubtype; + u32 ouisubtype, i = 0; + u8 priority, selector; /* No APP TLVs then just return */ if (dcbcfg->numapps == 0) diff -Nru dpdk-24.11.4/drivers/net/i40e/base/i40e_nvm.c dpdk-24.11.8/drivers/net/i40e/base/i40e_nvm.c --- dpdk-24.11.4/drivers/net/i40e/base/i40e_nvm.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/base/i40e_nvm.c 2026-10-14 13:10:05.000000000 +0000 @@ -50,6 +50,20 @@ } /** + * get_elapsed_time - Compute elapsed hardware timer ticks + * @from: The start timer value + * @to: The current timer value + * + * Returns the elapsed time as the difference between the current and start + * timer values. The subtraction is wrap-safe for unsigned 32-bit values, + * meaning it correctly handles timer wrap-around. + **/ +static u32 get_elapsed_time(u32 from, u32 to) +{ + return (u32)(to - from); /* wrap-safe */ +} + +/** * i40e_acquire_nvm - Generic request for acquiring the NVM ownership * @hw: pointer to the HW structure * @access: NVM access type (read or write) @@ -61,7 +75,7 @@ enum i40e_aq_resource_access_type access) { enum i40e_status_code ret_code = I40E_SUCCESS; - u32 gtime, timeout; + u32 gtime_start, gtime_current, timeout, elapsed; u32 time_left = 0; DEBUGFUNC("i40e_acquire_nvm"); @@ -72,10 +86,12 @@ ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time_left, NULL); /* Reading the Global Device Timer */ - gtime = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_start = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_current = gtime_start; + elapsed = 0; /* Store the timeout */ - hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; + hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime_start; if (ret_code) i40e_debug(hw, I40E_DEBUG_NVM, @@ -84,17 +100,20 @@ if (ret_code && time_left) { /* Poll until the current NVM owner timeouts */ - timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; - while ((s32)(gtime - timeout) < 0 && time_left) { + timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT); + + while (elapsed < timeout && time_left) { i40e_msec_delay(10); - gtime = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_current = rd32(hw, I40E_GLVFGEN_TIMER); + elapsed = get_elapsed_time(gtime_start, gtime_current); ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time_left, NULL); if (ret_code == I40E_SUCCESS) { hw->nvm.hw_semaphore_timeout = - I40E_MS_TO_GTIME(time_left) + gtime; + I40E_MS_TO_GTIME(time_left) + + gtime_current; break; } } @@ -110,7 +129,6 @@ return ret_code; } - /** * i40e_acquire_nvm_ex - Specific request only for * OID_INTEL_FLASH_INFO_TIMEOUT for acquiring the NVM ownership @@ -121,13 +139,12 @@ * This function will request NVM ownership for reading * via the proper Admin Command. **/ - enum i40e_status_code i40e_acquire_nvm_ex(struct i40e_hw *hw, enum i40e_aq_resource_access_type access, u32 custom_timeout) { enum i40e_status_code ret_code = I40E_SUCCESS; - u32 gtime, timeout; + u32 gtime_start, gtime_current, timeout, elapsed; u32 time_left = 0; DEBUGFUNC("i40e_acquire_nvm"); @@ -138,10 +155,12 @@ ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time_left, NULL); /* Reading the Global Device Timer */ - gtime = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_start = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_current = gtime_start; + elapsed = 0; /* Store the timeout */ - hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime; + hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time_left) + gtime_start; if (ret_code) i40e_debug(hw, I40E_DEBUG_NVM, @@ -151,17 +170,20 @@ if (ret_code && time_left) { /* Poll until the current NVM owner timeouts */ - timeout = I40E_MS_TO_GTIME(custom_timeout) + gtime; - while ((gtime < timeout) && time_left) { + timeout = I40E_MS_TO_GTIME(custom_timeout); + + while (elapsed < timeout && time_left) { i40e_msec_delay(10); - gtime = rd32(hw, I40E_GLVFGEN_TIMER); + gtime_current = rd32(hw, I40E_GLVFGEN_TIMER); + elapsed = get_elapsed_time(gtime_start, gtime_current); ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time_left, NULL); if (ret_code == I40E_SUCCESS) { hw->nvm.hw_semaphore_timeout = - I40E_MS_TO_GTIME(time_left) + gtime; + I40E_MS_TO_GTIME(time_left) + + gtime_current; break; } } @@ -245,7 +267,7 @@ * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. **/ STATIC enum i40e_status_code i40e_read_nvm_word_srctl(struct i40e_hw *hw, - u16 offset, + u32 offset, u16 *data) { enum i40e_status_code ret_code = I40E_ERR_TIMEOUT; @@ -516,11 +538,12 @@ * method. The buffer read is preceded by the NVM ownership take * and followed by the release. **/ -STATIC enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u16 offset, +STATIC enum i40e_status_code i40e_read_nvm_buffer_srctl(struct i40e_hw *hw, u32 offset, u16 *words, u16 *data) { enum i40e_status_code ret_code = I40E_SUCCESS; - u16 index, word; + u32 index; + u16 word; DEBUGFUNC("i40e_read_nvm_buffer_srctl"); @@ -549,7 +572,7 @@ * method. The buffer read is preceded by the NVM ownership take * and followed by the release. **/ -STATIC enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u16 offset, +STATIC enum i40e_status_code i40e_read_nvm_buffer_aq(struct i40e_hw *hw, u32 offset, u16 *words, u16 *data) { enum i40e_status_code ret_code; @@ -608,7 +631,7 @@ * method. **/ enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw, - u16 offset, + u32 offset, u16 *words, u16 *data) { if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) @@ -767,7 +790,7 @@ u16 checksum_local = 0; u16 vpd_module = 0; u16 *data; - u16 i = 0; + u32 i = 0; DEBUGFUNC("i40e_calc_nvm_checksum"); diff -Nru dpdk-24.11.4/drivers/net/i40e/base/i40e_prototype.h dpdk-24.11.8/drivers/net/i40e/base/i40e_prototype.h --- dpdk-24.11.4/drivers/net/i40e/base/i40e_prototype.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/base/i40e_prototype.h 2026-10-14 13:10:05.000000000 +0000 @@ -482,7 +482,7 @@ bool last_command); enum i40e_status_code __i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data); -enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, +enum i40e_status_code __i40e_read_nvm_buffer(struct i40e_hw *hw, u32 offset, u16 *words, u16 *data); enum i40e_status_code __i40e_write_nvm_word(struct i40e_hw *hw, u32 offset, void *data); diff -Nru dpdk-24.11.4/drivers/net/i40e/base/i40e_type.h dpdk-24.11.8/drivers/net/i40e/base/i40e_type.h --- dpdk-24.11.4/drivers/net/i40e/base/i40e_type.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/base/i40e_type.h 2026-10-14 13:10:05.000000000 +0000 @@ -449,7 +449,7 @@ struct i40e_nvm_info { u32 hw_semaphore_timeout; /* usec global time (GTIME resolution) */ u32 timeout; /* [ms] */ - u16 sr_size; /* Shadow RAM size in words */ + u32 sr_size; /* Shadow RAM size in words */ bool blank_nvm_mode; /* is NVM empty (no FW present)*/ u16 version; /* NVM package version */ u32 eetrack; /* NVM data version */ diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_ethdev.c dpdk-24.11.8/drivers/net/i40e/i40e_ethdev.c --- dpdk-24.11.4/drivers/net/i40e/i40e_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -2565,17 +2565,27 @@ I40E_AQ_EVENT_MEDIA_NA), NULL); if (ret != I40E_SUCCESS) PMD_DRV_LOG(WARNING, "Fail to set phy mask"); - - /* Call get_link_info aq command to enable/disable LSE */ - i40e_dev_link_update(dev, 1); } if (dev->data->dev_conf.intr_conf.rxq == 0) { + i40e_dev_link_update(dev, 0); + pf->mac_config_on_link_up = !dev->data->dev_link.link_status; rte_eal_alarm_set(I40E_ALARM_INTERVAL, i40e_dev_alarm_handler, dev); } else { + /* Block if no interrupt handler can process link-up events, to help + * ensure that MAC config is applied when the link is up. + */ + i40e_dev_link_update(dev, !rte_intr_allow_others(intr_handle)); + pf->mac_config_on_link_up = !dev->data->dev_link.link_status; /* enable uio intr after callback register */ - rte_intr_enable(intr_handle); + if (rte_intr_enable(intr_handle) != 0) { + if (rte_eal_alarm_set(I40E_ALARM_INTERVAL, + i40e_dev_alarm_handler, dev) != 0) + PMD_DRV_LOG(WARNING, "Failed to set alarm"); + else + pf->use_aq_polling = true; + } } i40e_filter_restore(pf); @@ -2621,6 +2631,9 @@ if (dev->data->dev_conf.intr_conf.rxq == 0) { rte_eal_alarm_cancel(i40e_dev_alarm_handler, dev); rte_intr_enable(intr_handle); + } else if (pf->use_aq_polling) { + rte_eal_alarm_cancel(i40e_dev_alarm_handler, dev); + pf->use_aq_polling = false; } /* Disable all queues */ @@ -4149,6 +4162,16 @@ i40e_vsi_config_vlan_stripping(vsi, TRUE); else i40e_vsi_config_vlan_stripping(vsi, FALSE); + + /* When VLAN strip is enabled/disabled + * after enabling outer VLAN stripping, + * outer VLAN stripping gets disabled + * as the register gets overridden by + * VLAN's strip vsi param update. + * Hence, re-enable outer VLAN stripping. + */ + if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_QINQ_STRIP) + i40e_vsi_config_outer_vlan_stripping(vsi, TRUE); } if (mask & RTE_ETH_VLAN_EXTEND_MASK) { @@ -5097,16 +5120,14 @@ if (pool == NULL) return; - for (entry = LIST_FIRST(&pool->alloc_list); - entry && (next_entry = LIST_NEXT(entry, next), 1); - entry = next_entry) { + for (entry = LIST_FIRST(&pool->alloc_list); entry; entry = next_entry) { + next_entry = LIST_NEXT(entry, next); LIST_REMOVE(entry, next); rte_free(entry); } - for (entry = LIST_FIRST(&pool->free_list); - entry && (next_entry = LIST_NEXT(entry, next), 1); - entry = next_entry) { + for (entry = LIST_FIRST(&pool->free_list); entry; entry = next_entry) { + next_entry = LIST_NEXT(entry, next); LIST_REMOVE(entry, next); rte_free(entry); } @@ -6884,6 +6905,7 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev) { struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); struct i40e_arq_event_info info; uint16_t pending, opcode; int ret; @@ -6919,9 +6941,21 @@ break; case i40e_aqc_opc_get_link_status: ret = i40e_dev_link_update(dev, 0); - if (!ret) + /* Some devices require MAC config to be applied when the link comes up. */ + if (!ret) { + if (pf->mac_config_on_link_up && dev->data->dev_link.link_status) { + uint16_t max_frame_size; + + max_frame_size = dev->data->mtu ? + dev->data->mtu + I40E_ETH_OVERHEAD : + I40E_FRAME_SIZE_MAX; + i40e_aq_set_mac_config(hw, max_frame_size, TRUE, + false, 0, NULL); + pf->mac_config_on_link_up = false; + } rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL); + } break; default: PMD_DRV_LOG(DEBUG, "Request %u is not supported yet", @@ -7266,9 +7300,7 @@ if (ret != I40E_SUCCESS) { /* Do not report as an error when firmware returns ENOENT */ - if (aq_status == I40E_AQ_RC_ENOENT) { - ret = I40E_SUCCESS; - } else { + if (aq_status != I40E_AQ_RC_ENOENT) { PMD_DRV_LOG(ERR, "Failed to remove macvlan filter"); goto DONE; } @@ -11415,7 +11447,8 @@ { struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); uint16_t *data = eeprom->data; - uint16_t offset, length, cnt_words; + uint32_t offset, length; + uint16_t cnt_words; int ret_code; offset = eeprom->offset >> 1; @@ -11974,8 +12007,7 @@ for (n = 0; n < proto_num; n++) { if (proto[n].proto_id != proto_id) continue; - memset(name, 0, sizeof(name)); - strcpy(name, proto[n].name); + strlcpy(name, proto[n].name, sizeof(name)); PMD_DRV_LOG(INFO, "name = %s", name); if (!strncasecmp(name, "PPPOE", 5)) ptype_mapping[i].sw_ptype |= diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_ethdev.h dpdk-24.11.8/drivers/net/i40e/i40e_ethdev.h --- dpdk-24.11.4/drivers/net/i40e/i40e_ethdev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_ethdev.h 2026-10-14 13:10:05.000000000 +0000 @@ -91,11 +91,11 @@ #define I40E_WRITE_GLB_REG(hw, reg, value) \ do { \ uint32_t ori_val; \ - struct rte_eth_dev *dev; \ - struct rte_eth_dev_data *dev_data; \ + struct rte_eth_dev *_dev; \ + struct rte_eth_dev_data *_dev_data; \ ori_val = I40E_READ_REG((hw), (reg)); \ - dev_data = ((struct i40e_adapter *)hw->back)->pf.dev_data; \ - dev = &rte_eth_devices[dev_data->port_id]; \ + _dev_data = ((struct i40e_adapter *)hw->back)->pf.dev_data; \ + _dev = &rte_eth_devices[_dev_data->port_id]; \ I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((hw), \ (reg)), (value)); \ if (ori_val != value) \ @@ -103,7 +103,7 @@ "i40e device %s changed global " \ "register [0x%08x]. original: 0x%08x, " \ "new: 0x%08x ", \ - (dev->device->name), (reg), \ + (_dev->device->name), (reg), \ (ori_val), (value)); \ } while (0) @@ -1190,6 +1190,10 @@ /* When firmware > 8.3, the enable flag for outer VLAN processing */ bool fw8_3gt; + /* MAC config needs re-applying when link first comes up */ + bool mac_config_on_link_up; + /* true when interrupt path unavailable */ + bool use_aq_polling; struct i40e_vf_msg_cfg vf_msg_cfg; uint64_t prev_rx_bytes; diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_fdir.c dpdk-24.11.8/drivers/net/i40e/i40e_fdir.c --- dpdk-24.11.4/drivers/net/i40e/i40e_fdir.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_fdir.c 2026-10-14 13:10:05.000000000 +0000 @@ -1232,12 +1232,12 @@ flex_mask.word_mask |= I40E_FLEX_WORD_MASK(i / sizeof(uint16_t)); if (mask_tmp != UINT16_MAX) { + if (nb_bitmask >= I40E_FDIR_BITMASK_NUM_WORD) + return -1; flex_mask.bitmask[nb_bitmask].mask = ~mask_tmp; flex_mask.bitmask[nb_bitmask].offset = i / sizeof(uint16_t); nb_bitmask++; - if (nb_bitmask > I40E_FDIR_BITMASK_NUM_WORD) - return -1; } } } @@ -1491,15 +1491,17 @@ } } - if (cfg_flex_pit) - i40e_flow_set_fdir_flex_pit(pf, layer_idx, - filter->input.flow_ext.raw_id); - /* Store flex mask to SW */ for (i = 0; i < I40E_FDIR_MAX_FLEX_LEN; i++) flex_mask[i] = filter->input.flow_ext.flex_mask[i]; + /* Validate the flex mask before writing any hardware + * register. i40e_flow_set_fdir_flex_pit() below programs + * the global GLQF_ORT register, which is shared by all + * PFs on the NIC, so it must not be touched for a rule + * that is going to be rejected. + */ ret = i40e_flow_store_flex_mask(pf, pctype, flex_mask); if (ret == -1) { PMD_DRV_LOG(ERR, "Exceed maximal" @@ -1509,9 +1511,14 @@ PMD_DRV_LOG(ERR, "Conflict with the" " first flexible rule"); return -EINVAL; - } else if (ret == 0) { - i40e_flow_set_fdir_flex_msk(pf, pctype); } + + if (cfg_flex_pit) + i40e_flow_set_fdir_flex_pit(pf, layer_idx, + filter->input.flow_ext.raw_id); + + if (ret == 0) + i40e_flow_set_fdir_flex_msk(pf, pctype); } ret = i40e_sw_fdir_filter_insert(pf, &check_filter); diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_flow.c dpdk-24.11.8/drivers/net/i40e/i40e_flow.c --- dpdk-24.11.4/drivers/net/i40e/i40e_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -29,9 +29,6 @@ #define I40E_IPV6_FRAG_HEADER 44 #define I40E_TENANT_ARRAY_NUM 3 #define I40E_VLAN_TCI_MASK 0xFFFF -#define I40E_VLAN_PRI_MASK 0xE000 -#define I40E_VLAN_CFI_MASK 0x1000 -#define I40E_VLAN_VID_MASK 0x0FFF static int i40e_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr, @@ -1770,22 +1767,19 @@ RTE_ASSERT(!(input_set & I40E_INSET_LAST_ETHER_TYPE)); if (vlan_spec && vlan_mask) { - if (vlan_mask->hdr.vlan_tci != - rte_cpu_to_be_16(I40E_VLAN_TCI_MASK) && + if (vlan_mask->hdr.vlan_tci != 0 && vlan_mask->hdr.vlan_tci != - rte_cpu_to_be_16(I40E_VLAN_PRI_MASK) && - vlan_mask->hdr.vlan_tci != - rte_cpu_to_be_16(I40E_VLAN_CFI_MASK) && - vlan_mask->hdr.vlan_tci != - rte_cpu_to_be_16(I40E_VLAN_VID_MASK)) { + rte_cpu_to_be_16(I40E_VLAN_TCI_MASK)) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Unsupported TCI mask."); + return -rte_errno; + } + if (vlan_mask->hdr.vlan_tci != 0) { + input_set |= I40E_INSET_VLAN_INNER; + filter->input.flow_ext.vlan_tci = vlan_spec->hdr.vlan_tci; } - input_set |= I40E_INSET_VLAN_INNER; - filter->input.flow_ext.vlan_tci = - vlan_spec->hdr.vlan_tci; } if (vlan_spec && vlan_mask && vlan_mask->hdr.eth_proto) { if (vlan_mask->hdr.eth_proto != RTE_BE16(0xffff)) { @@ -2350,6 +2344,23 @@ return -rte_errno; } + if (raw_spec->length != 0) { + if (raw_spec->pattern == NULL) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "NULL RAW spec pattern"); + return -rte_errno; + } + if (raw_mask->pattern == NULL) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "NULL RAW mask pattern"); + return -rte_errno; + } + } + for (i = 0; i < raw_spec->length; i++) { j = i + next_dst_off; if (j >= RTE_ETH_FDIR_MAX_FLEXLEN || @@ -2552,9 +2563,7 @@ struct rte_flow_error *error, union i40e_filter_t *filter) { - struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct i40e_fdir_filter_conf *fdir_filter = - &filter->fdir_filter; + struct i40e_fdir_filter_conf *fdir_filter = &filter->fdir_filter; int ret; ret = i40e_flow_parse_fdir_pattern(dev, pattern, error, fdir_filter); @@ -2571,32 +2580,7 @@ cons_filter_type = RTE_ETH_FILTER_FDIR; - if (pf->fdir.fdir_vsi == NULL) { - /* Enable fdir when fdir flow is added at first time. */ - ret = i40e_fdir_setup(pf); - if (ret != I40E_SUCCESS) { - rte_flow_error_set(error, ENOTSUP, - RTE_FLOW_ERROR_TYPE_HANDLE, - NULL, "Failed to setup fdir."); - return -rte_errno; - } - ret = i40e_fdir_configure(dev); - if (ret < 0) { - rte_flow_error_set(error, ENOTSUP, - RTE_FLOW_ERROR_TYPE_HANDLE, - NULL, "Failed to configure fdir."); - goto err; - } - } - - /* If create the first fdir rule, enable fdir check for rx queues */ - if (TAILQ_EMPTY(&pf->fdir.fdir_list)) - i40e_fdir_rx_proc_enable(dev, 1); - return 0; -err: - i40e_fdir_teardown(pf); - return -rte_errno; } /* Parse to get the action info of a tunnel filter @@ -3608,6 +3592,19 @@ return -rte_errno; } break; + case RTE_FLOW_ITEM_TYPE_IPV6: + filter->ip_type = I40E_TUNNEL_IPTYPE_IPV6; + /* IPv6 is used to describe protocol, + * spec and mask should be NULL. + */ + if (item->spec || item->mask) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, + "Invalid IPv6 item"); + return -rte_errno; + } + break; case RTE_FLOW_ITEM_TYPE_UDP: if (item->spec || item->mask) { rte_flow_error_set(error, EINVAL, @@ -3922,6 +3919,28 @@ return NULL; if (cons_filter_type == RTE_ETH_FILTER_FDIR) { + /* if this is the first time we're creating an fdir flow */ + if (pf->fdir.fdir_vsi == NULL) { + ret = i40e_fdir_setup(pf); + if (ret != I40E_SUCCESS) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, "Failed to setup fdir."); + return NULL; + } + ret = i40e_fdir_configure(dev); + if (ret < 0) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_HANDLE, + NULL, "Failed to configure fdir."); + i40e_fdir_teardown(pf); + return NULL; + } + } + /* If create the first fdir rule, enable fdir check for rx queues */ + if (TAILQ_EMPTY(&pf->fdir.fdir_list)) + i40e_fdir_rx_proc_enable(dev, 1); + flow = i40e_fdir_entry_pool_get(fdir_info); if (flow == NULL) { rte_flow_error_set(error, ENOBUFS, diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_rxtx.c dpdk-24.11.8/drivers/net/i40e/i40e_rxtx.c --- dpdk-24.11.4/drivers/net/i40e/i40e_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -74,7 +74,8 @@ #define I40E_TX_OFFLOAD_SIMPLE_SUP_MASK (RTE_MBUF_F_TX_IPV4 | \ RTE_MBUF_F_TX_IPV6 | \ RTE_MBUF_F_TX_OUTER_IPV4 | \ - RTE_MBUF_F_TX_OUTER_IPV6) + RTE_MBUF_F_TX_OUTER_IPV6 | \ + RTE_MBUF_F_TX_TUNNEL_MASK) #define I40E_TX_OFFLOAD_SIMPLE_NOTSUP_MASK \ (RTE_MBUF_F_TX_OFFLOAD_MASK ^ I40E_TX_OFFLOAD_SIMPLE_SUP_MASK) diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_rxtx_vec_avx2.c dpdk-24.11.8/drivers/net/i40e/i40e_rxtx_vec_avx2.c --- dpdk-24.11.4/drivers/net/i40e/i40e_rxtx_vec_avx2.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_rxtx_vec_avx2.c 2026-10-14 13:10:05.000000000 +0000 @@ -708,7 +708,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { vtx1(txdp, *pkt, flags); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do two at a time while possible, in bursts */ @@ -735,7 +735,7 @@ /* do any last ones */ while (nb_pkts) { vtx1(txdp, *pkt, flags); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/net/i40e/i40e_rxtx_vec_avx512.c dpdk-24.11.8/drivers/net/i40e/i40e_rxtx_vec_avx512.c --- dpdk-24.11.4/drivers/net/i40e/i40e_rxtx_vec_avx512.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/i40e_rxtx_vec_avx512.c 2026-10-14 13:10:05.000000000 +0000 @@ -915,7 +915,7 @@ /* do any last ones */ while (nb_pkts) { vtx1(txdp, *pkt, flags); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/net/i40e/rte_pmd_i40e.c dpdk-24.11.8/drivers/net/i40e/rte_pmd_i40e.c --- dpdk-24.11.4/drivers/net/i40e/rte_pmd_i40e.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/i40e/rte_pmd_i40e.c 2026-10-14 13:10:05.000000000 +0000 @@ -1883,6 +1883,11 @@ return I40E_SUCCESS; } + if (!i40e_seg_hdr) { + PMD_DRV_LOG(ERR, "Failed to find i40e segment header"); + return -EINVAL; + } + /* get i40e segment header info */ if (type == RTE_PMD_I40E_PKG_INFO_HEADER) { struct rte_pmd_i40e_profile_info *info = @@ -1898,11 +1903,6 @@ return -EINVAL; } - if (!i40e_seg_hdr) { - PMD_DRV_LOG(ERR, "Failed to find i40e segment header"); - return -EINVAL; - } - memset(info, 0, sizeof(struct rte_pmd_i40e_profile_info)); info->owner = RTE_PMD_I40E_DDP_OWNER_UNKNOWN; info->track_id = diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf.h dpdk-24.11.8/drivers/net/iavf/iavf.h --- dpdk-24.11.4/drivers/net/iavf/iavf.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf.h 2026-10-14 13:10:05.000000000 +0000 @@ -284,6 +284,8 @@ struct rte_eth_dev *eth_dev; bool in_reset_recovery; + bool reset_pending; + bool pf_reset_in_progress; uint32_t ptp_caps; rte_spinlock_t phc_time_aq_lock; @@ -383,6 +385,7 @@ enum iavf_tx_burst_type tx_burst_type; uint16_t fdir_ref_cnt; struct iavf_devargs devargs; + bool mac_primary_set; }; /* IAVF_DEV_PRIVATE_TO */ diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_ethdev.c dpdk-24.11.8/drivers/net/iavf/iavf_ethdev.c --- dpdk-24.11.4/drivers/net/iavf/iavf_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -100,6 +100,7 @@ static int iavf_dev_stop(struct rte_eth_dev *dev); static int iavf_dev_close(struct rte_eth_dev *dev); static int iavf_dev_reset(struct rte_eth_dev *dev); +static bool iavf_is_reset_detected(struct iavf_adapter *adapter); static int iavf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); static const uint32_t *iavf_dev_supported_ptypes_get(struct rte_eth_dev *dev, @@ -1069,6 +1070,9 @@ /* Set all mac addrs */ iavf_add_del_all_mac_addr(adapter, true); + if (!adapter->mac_primary_set) + adapter->mac_primary_set = true; + /* Set all multicast addresses */ iavf_add_del_mc_addr_list(adapter, vf->mc_addrs, vf->mc_addrs_num, true); @@ -1125,12 +1129,18 @@ struct iavf_adapter *adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); struct iavf_info *vf = &adapter->vf; + uint16_t max_queue_pairs; if (adapter->closed) return -EIO; - dev_info->max_rx_queues = IAVF_MAX_NUM_QUEUES_LV; - dev_info->max_tx_queues = IAVF_MAX_NUM_QUEUES_LV; + if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_LARGE_NUM_QPAIRS) + max_queue_pairs = IAVF_MAX_NUM_QUEUES_LV; + else + max_queue_pairs = IAVF_MAX_NUM_QUEUES_DFLT; + + dev_info->max_rx_queues = max_queue_pairs; + dev_info->max_tx_queues = max_queue_pairs; dev_info->min_rx_bufsize = IAVF_BUF_SIZE_MIN; dev_info->max_rx_pktlen = IAVF_FRAME_SIZE_MAX; dev_info->max_mtu = dev_info->max_rx_pktlen - IAVF_ETH_OVERHEAD; @@ -1177,7 +1187,8 @@ if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_CRC) dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_KEEP_CRC; - if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_PTP) + if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_PTP && + vf->ptp_caps & VIRTCHNL_1588_PTP_CAP_RX_TSTAMP) dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP; if (iavf_ipsec_crypto_supported(adapter)) { @@ -1734,11 +1745,13 @@ if (rte_is_same_ether_addr(old_addr, mac_addr)) return 0; - ret = iavf_add_del_eth_addr(adapter, old_addr, false, VIRTCHNL_ETHER_ADDR_PRIMARY); - if (ret) - PMD_DRV_LOG(ERR, "Fail to delete old MAC:" - RTE_ETHER_ADDR_PRT_FMT, - RTE_ETHER_ADDR_BYTES(old_addr)); + if (adapter->mac_primary_set) { /* delete old PRIMARY MAC only if set */ + ret = iavf_add_del_eth_addr(adapter, old_addr, false, VIRTCHNL_ETHER_ADDR_PRIMARY); + if (ret) + PMD_DRV_LOG(ERR, "Fail to delete old MAC:" + RTE_ETHER_ADDR_PRT_FMT, + RTE_ETHER_ADDR_BYTES(old_addr)); + } ret = iavf_add_del_eth_addr(adapter, mac_addr, true, VIRTCHNL_ETHER_ADDR_PRIMARY); if (ret) @@ -1749,6 +1762,9 @@ if (ret) return -EIO; + if (!adapter->mac_primary_set) + adapter->mac_primary_set = true; + rte_ether_addr_copy(mac_addr, (struct rte_ether_addr *)hw->mac.addr); return 0; } @@ -1809,8 +1825,16 @@ RTE_ETH_RX_OFFLOAD_KEEP_CRC) ? 0 : RTE_ETHER_CRC_LEN; iavf_update_stats(vsi, pstats); - stats->ipackets = pstats->rx_unicast + pstats->rx_multicast + - pstats->rx_broadcast - pstats->rx_discards; + stats->ipackets = pstats->rx_unicast + pstats->rx_multicast + pstats->rx_broadcast; + /* + * Unicast/multicast/broadcast counters include discarded packets, so subtract + * rx_discards to report only the packets delivered to the application. The + * counters are sampled from separate sources and can be momentarily inconsistent + * under load. If rx_discards exceeds their sum then essentially nothing was + * delivered, so saturate at zero rather than underflow. + */ + stats->ipackets = stats->ipackets >= pstats->rx_discards ? + stats->ipackets - pstats->rx_discards : 0; stats->opackets = pstats->tx_broadcast + pstats->tx_multicast + pstats->tx_unicast; stats->imissed = pstats->rx_discards; @@ -2662,6 +2686,10 @@ rte_free(vf->qos_cap); vf->qos_cap = NULL; + free(vf->qtc_map); + vf->qtc_map = NULL; + rte_free(vf->proto_xtr); + vf->proto_xtr = NULL; rte_free(vf->rss_lut); vf->rss_lut = NULL; @@ -2810,8 +2838,9 @@ hw->back = IAVF_DEV_PRIVATE_TO_ADAPTER(eth_dev->data->dev_private); adapter->dev_data = eth_dev->data; adapter->stopped = 1; + adapter->mac_primary_set = false; - if (iavf_dev_event_handler_init()) + if (!vf->in_reset_recovery && iavf_dev_event_handler_init()) goto init_vf_err; if (iavf_init_vf(eth_dev) != 0) { @@ -2880,6 +2909,14 @@ } } + /* Get PTP caps early to verify device capabilities */ + if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_PTP) { + if (iavf_get_ptp_cap(adapter)) { + PMD_INIT_LOG(ERR, "Failed to get ptp capability"); + goto security_init_err; + } + } + iavf_default_rss_disable(adapter); iavf_dev_stats_reset(eth_dev); @@ -2938,15 +2975,28 @@ ret = iavf_dev_stop(dev); /* - * Release redundant queue resource when close the dev - * so that other vfs can re-use the queues. + * Prevent sending close-time virtchnl messages to the AdminQ + * during PF-initiated reset recovery. */ - if (vf->lv_enabled) { - ret = iavf_request_queues(dev, IAVF_MAX_NUM_QUEUES_DFLT); - if (ret) - PMD_DRV_LOG(ERR, "Reset the num of queues failed"); + if (!vf->pf_reset_in_progress) { - vf->max_rss_qregion = IAVF_MAX_NUM_QUEUES_DFLT; + /* + * Release redundant queue resource when close the dev + * so that other vfs can re-use the queues. + */ + if (vf->lv_enabled) { + ret = iavf_request_queues(dev, IAVF_MAX_NUM_QUEUES_DFLT); + if (ret) + PMD_DRV_LOG(ERR, "Reset the num of queues failed"); + vf->max_rss_qregion = IAVF_MAX_NUM_QUEUES_DFLT; + } + + /* + * Disable promiscuous mode before resetting the VF. This is to avoid + * potential issues when the PF is bound to the kernel driver. + */ + if (vf->promisc_unicast_enabled || vf->promisc_multicast_enabled) + iavf_config_promisc(adapter, false, false); } adapter->closed = true; @@ -2958,14 +3008,19 @@ iavf_flow_uninit(adapter); /* - * disable promiscuous mode before reset vf - * it is a workaround solution when work with kernel driver - * and it is not the normal way + * Prevent sending VIRTCHNL_OP_RESET_VF during PF-initiated + * reset recovery. */ - if (vf->promisc_unicast_enabled || vf->promisc_multicast_enabled) - iavf_config_promisc(adapter, false, false); - - iavf_vf_reset(hw); + if (!vf->pf_reset_in_progress) + iavf_vf_reset(hw); + /* + * If a reset is pending, wait for the PF to disable the VF's admin + * receive queue (its first reset action) before we shut it down + * ourselves. This ensures iavf_check_vf_reset_done() does not see + * a stale VFACTIVE value on the re-init path. + */ + if (vf->reset_pending) + iavf_is_reset_detected(adapter); iavf_shutdown_adminq(hw); if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR) { /* disable uio intr before callback unregister */ @@ -2993,6 +3048,9 @@ } } + rte_free(vf->proto_xtr); + vf->proto_xtr = NULL; + rte_free(vf->vf_res); vf->vsi_res = NULL; vf->vf_res = NULL; @@ -3045,6 +3103,7 @@ struct iavf_adapter *adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); struct iavf_hw *hw = IAVF_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); /* * Check whether the VF reset has been done and inform application, * to avoid calling the virtual channel command, which may cause @@ -3057,8 +3116,10 @@ } iavf_set_no_poll(adapter, false); + vf->reset_pending = true; PMD_DRV_LOG(DEBUG, "Start dev_reset ..."); ret = iavf_dev_uninit(dev); + vf->reset_pending = false; if (ret) return ret; @@ -3107,6 +3168,7 @@ } vf->in_reset_recovery = true; + vf->pf_reset_in_progress = true; iavf_set_no_poll(adapter, false); ret = iavf_dev_reset(dev); @@ -3129,9 +3191,10 @@ goto exit; error: - PMD_DRV_LOG(DEBUG, "RESET recover with error code=%dn", ret); + PMD_DRV_LOG(DEBUG, "RESET recover with error code=%d", ret); exit: vf->in_reset_recovery = false; + vf->pf_reset_in_progress = false; iavf_set_no_poll(adapter, false); return; diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_fsub.c dpdk-24.11.8/drivers/net/iavf/iavf_fsub.c --- dpdk-24.11.4/drivers/net/iavf/iavf_fsub.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_fsub.c 2026-10-14 13:10:05.000000000 +0000 @@ -306,11 +306,11 @@ if (ipv4_mask->hdr.src_addr) { *input |= IAVF_INSET_IPV4_SRC; - input_set_byte += 2; + input_set_byte += 4; } if (ipv4_mask->hdr.dst_addr) { *input |= IAVF_INSET_IPV4_DST; - input_set_byte += 2; + input_set_byte += 4; } if (ipv4_mask->hdr.time_to_live) { *input |= IAVF_INSET_IPV4_TTL; diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_generic_flow.c dpdk-24.11.8/drivers/net/iavf/iavf_generic_flow.c --- dpdk-24.11.4/drivers/net/iavf/iavf_generic_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_generic_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -1859,6 +1859,11 @@ TAILQ_REMOVE(&vf->dist_parser_list, p_parser, node); rte_free(p_parser); } + + while ((p_parser = TAILQ_FIRST(&vf->ipsec_crypto_parser_list))) { + TAILQ_REMOVE(&vf->ipsec_crypto_parser_list, p_parser, node); + rte_free(p_parser); + } } int @@ -1899,6 +1904,7 @@ list = &vf->dist_parser_list; TAILQ_INSERT_HEAD(list, parser_node, node); } else { + rte_free(parser_node); return -EINVAL; } @@ -1920,6 +1926,8 @@ else if ((parser->engine->type == IAVF_FLOW_ENGINE_FDIR) || (parser->engine->type == IAVF_FLOW_ENGINE_FSUB)) list = &vf->dist_parser_list; + else if (parser->engine->type == IAVF_FLOW_ENGINE_IPSEC_CRYPTO) + list = &vf->ipsec_crypto_parser_list; if (list == NULL) return; @@ -2265,8 +2273,10 @@ } /* Special case for inline crypto egress flows */ - if (attr->egress && actions[0].type == RTE_FLOW_ACTION_TYPE_SECURITY) - goto free_flow; + if (attr->egress && actions[0].type == RTE_FLOW_ACTION_TYPE_SECURITY) { + flow->is_ipsec_egress_flow = true; + goto tailq_insert; + } ret = iavf_flow_process_filter(dev, flow, attr, pattern, actions, &engine, iavf_parse_engine_create, error); @@ -2278,6 +2288,7 @@ } flow->engine = engine; +tailq_insert: rte_spinlock_lock(&vf->flow_ops_lock); TAILQ_INSERT_TAIL(&vf->flow_list, flow, node); rte_spinlock_unlock(&vf->flow_ops_lock); @@ -2293,7 +2304,14 @@ struct iavf_flow_engine *engine; void *temp; - if (flow && flow->engine) { + if (flow == NULL) + return false; + + /* these flows don't use engines */ + if (flow->is_ipsec_egress_flow) + return true; + + if (flow->engine) { RTE_TAILQ_FOREACH_SAFE(engine, &engine_list, node, temp) { if (engine == flow->engine) return true; @@ -2311,18 +2329,26 @@ struct iavf_adapter *ad = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(ad); + bool need_destroy; int ret = 0; - if (!iavf_flow_is_valid(flow) || !flow->engine->destroy) { + if (!iavf_flow_is_valid(flow)) { rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Invalid flow destroy"); return -rte_errno; } + need_destroy = !flow->is_ipsec_egress_flow; - rte_spinlock_lock(&vf->flow_ops_lock); + if (need_destroy && flow->engine->destroy == NULL) { + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, + "Invalid flow destroy"); + } - ret = flow->engine->destroy(ad, flow, error); + rte_spinlock_lock(&vf->flow_ops_lock); + if (need_destroy) + ret = flow->engine->destroy(ad, flow, error); if (!ret) { TAILQ_REMOVE(&vf->flow_list, flow, node); diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_generic_flow.h dpdk-24.11.8/drivers/net/iavf/iavf_generic_flow.h --- dpdk-24.11.4/drivers/net/iavf/iavf_generic_flow.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_generic_flow.h 2026-10-14 13:10:05.000000000 +0000 @@ -517,6 +517,7 @@ /* Struct to store flow created. */ struct rte_flow { TAILQ_ENTRY(rte_flow) node; + bool is_ipsec_egress_flow; struct iavf_flow_engine *engine; void *rule; }; diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_ipsec_crypto.c dpdk-24.11.8/drivers/net/iavf/iavf_ipsec_crypto.c --- dpdk-24.11.4/drivers/net/iavf/iavf_ipsec_crypto.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_ipsec_crypto.c 2026-10-14 13:10:05.000000000 +0000 @@ -1574,6 +1574,8 @@ return -ENODEV; /* free and reset security data structures */ + rte_free(iavf_sctx->crypto_capabilities); + iavf_sctx->crypto_capabilities = NULL; rte_free(iavf_sctx); rte_free(sctx); @@ -1601,7 +1603,7 @@ } response_len = sizeof(struct inline_ipsec_msg) + - sizeof(struct virtchnl_ipsec_cap); + sizeof(struct virtchnl_ipsec_status); response = rte_malloc("iavf-device-status-response", response_len, 0); if (response == NULL) { diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_rxtx.c dpdk-24.11.8/drivers/net/iavf/iavf_rxtx.c --- dpdk-24.11.4/drivers/net/iavf/iavf_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -1550,16 +1550,6 @@ rx_ring = rxq->rx_ring; ptype_tbl = rxq->vsi->adapter->ptype_tbl; - if (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { - uint64_t sw_cur_time = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); - - if (sw_cur_time - rxq->hw_time_update > 4) { - if (iavf_get_phc_time(rxq)) - PMD_DRV_LOG(ERR, "get physical time failed"); - rxq->hw_time_update = sw_cur_time; - } - } - while (nb_rx < nb_pkts) { rxdp = (volatile union iavf_rx_flex_desc *)&rx_ring[rx_id]; rx_stat_err0 = rte_le_to_cpu_16(rxdp->wb.status_error0); @@ -1628,7 +1618,6 @@ rte_le_to_cpu_32(rxd.wb.flex_ts.ts_high)); rxq->phc_time = ts_ns; - rxq->hw_time_update = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); *RTE_MBUF_DYNFIELD(rxm, iavf_timestamp_dynfield_offset, @@ -1670,16 +1659,6 @@ volatile union iavf_rx_flex_desc *rxdp; const uint32_t *ptype_tbl = rxq->vsi->adapter->ptype_tbl; - if (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { - uint64_t sw_cur_time = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); - - if (sw_cur_time - rxq->hw_time_update > 4) { - if (iavf_get_phc_time(rxq)) - PMD_DRV_LOG(ERR, "get physical time failed"); - rxq->hw_time_update = sw_cur_time; - } - } - while (nb_rx < nb_pkts) { rxdp = (volatile union iavf_rx_flex_desc *)&rx_ring[rx_id]; rx_stat_err0 = rte_le_to_cpu_16(rxdp->wb.status_error0); @@ -1780,6 +1759,14 @@ rxm->data_len = (uint16_t)(rx_packet_len - RTE_ETHER_CRC_LEN); } + } else if (unlikely(rx_packet_len == 0)) { + /* + * NIC split CRC bytes into a trailing segment which is + * now empty after hardware CRC stripping. Free it. + */ + rte_pktmbuf_free_seg(rxm); + first_seg->nb_segs--; + last_seg->next = NULL; } first_seg->port = rxq->port_id; @@ -1798,7 +1785,6 @@ rte_le_to_cpu_32(rxd.wb.flex_ts.ts_high)); rxq->phc_time = ts_ns; - rxq->hw_time_update = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); *RTE_MBUF_DYNFIELD(first_seg, iavf_timestamp_dynfield_offset, @@ -1949,6 +1935,14 @@ } else rxm->data_len = (uint16_t)(rx_packet_len - RTE_ETHER_CRC_LEN); + } else if (unlikely(rx_packet_len == 0)) { + /* + * NIC split CRC bytes into a trailing segment which is + * now empty after hardware CRC stripping. Free it. + */ + rte_pktmbuf_free_seg(rxm); + first_seg->nb_segs--; + last_seg->next = NULL; } first_seg->port = rxq->port_id; @@ -2012,16 +2006,6 @@ if (!(stat_err0 & (1 << IAVF_RX_FLEX_DESC_STATUS0_DD_S))) return 0; - if (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { - uint64_t sw_cur_time = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); - - if (sw_cur_time - rxq->hw_time_update > 4) { - if (iavf_get_phc_time(rxq)) - PMD_DRV_LOG(ERR, "get physical time failed"); - rxq->hw_time_update = sw_cur_time; - } - } - /* Scan LOOK_AHEAD descriptors at a time to determine which * descriptors reference packets that are ready to be received. */ @@ -2084,8 +2068,6 @@ rte_le_to_cpu_32(rxdp[j].wb.flex_ts.ts_high)); rxq->phc_time = ts_ns; - rxq->hw_time_update = rte_get_timer_cycles() / - (rte_get_timer_hz() / 1000); *RTE_MBUF_DYNFIELD(mb, iavf_timestamp_dynfield_offset, @@ -3666,9 +3648,9 @@ m = tx_pkts[i]; ol_flags = m->ol_flags; - /* Check condition for nb_segs > IAVF_TX_MAX_MTU_SEG. */ + /* Validate segment count and packet length. */ if (!(ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG))) { - if (m->nb_segs > IAVF_TX_MAX_MTU_SEG) { + if (m->nb_segs > IAVF_TX_MAX_MTU_SEG || m->pkt_len > IAVF_FRAME_SIZE_MAX) { rte_errno = EINVAL; return i; } diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_rxtx_vec_avx2.c dpdk-24.11.8/drivers/net/iavf/iavf_rxtx_vec_avx2.c --- dpdk-24.11.4/drivers/net/iavf/iavf_rxtx_vec_avx2.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_rxtx_vec_avx2.c 2026-10-14 13:10:05.000000000 +0000 @@ -529,18 +529,10 @@ rte_cpu_to_le_32(1 << IAVF_RX_FLEX_DESC_STATUS0_DD_S))) return 0; #ifndef RTE_LIBRTE_IAVF_16BYTE_RX_DESC - bool is_tsinit = false; uint8_t inflection_point = 0; __m256i hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, rxq->phc_time); if (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { - uint64_t sw_cur_time = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); - - if (unlikely(sw_cur_time - rxq->hw_time_update > 4)) { - hw_low_last = _mm256_setzero_si256(); - is_tsinit = 1; - } else { - hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, rxq->phc_time); - } + hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, rxq->phc_time); } #endif @@ -1169,10 +1161,8 @@ *RTE_MBUF_DYNFIELD(rx_pkts[i + 7], iavf_timestamp_dynfield_offset, uint32_t *) = _mm256_extract_epi32(ts_low1, 7); - if (unlikely(is_tsinit)) { + { uint32_t in_timestamp; - if (iavf_get_phc_time(rxq)) - PMD_DRV_LOG(ERR, "get physical time failed"); in_timestamp = *RTE_MBUF_DYNFIELD(rx_pkts[i + 0], iavf_timestamp_dynfield_offset, uint32_t *); rxq->phc_time = iavf_tstamp_convert_32b_64b(rxq->phc_time, in_timestamp); @@ -1407,8 +1397,6 @@ PMD_DRV_LOG(ERR, "invalid inflection point for rx timestamp"); break; } - - rxq->hw_time_update = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); } #endif if (burst != IAVF_DESCS_PER_LOOP_AVX) @@ -1677,7 +1665,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { iavf_vtx1(txdp, *pkt, flags, offload); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do two at a time while possible, in bursts */ @@ -1726,7 +1714,7 @@ /* do any last ones */ while (nb_pkts) { iavf_vtx1(txdp, *pkt, flags, offload); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_rxtx_vec_avx512.c dpdk-24.11.8/drivers/net/iavf/iavf_rxtx_vec_avx512.c --- dpdk-24.11.4/drivers/net/iavf/iavf_rxtx_vec_avx512.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_rxtx_vec_avx512.c 2026-10-14 13:10:05.000000000 +0000 @@ -623,18 +623,10 @@ #ifndef RTE_LIBRTE_IAVF_16BYTE_RX_DESC #ifdef IAVF_RX_TS_OFFLOAD uint8_t inflection_point = 0; - bool is_tsinit = false; __m256i hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (uint32_t)rxq->phc_time); if (rxq->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { - uint64_t sw_cur_time = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); - - if (unlikely(sw_cur_time - rxq->hw_time_update > 4)) { - hw_low_last = _mm256_setzero_si256(); - is_tsinit = 1; - } else { - hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (uint32_t)rxq->phc_time); - } + hw_low_last = _mm256_set_epi32(0, 0, 0, 0, 0, 0, 0, (uint32_t)rxq->phc_time); } #endif #endif @@ -1353,11 +1345,9 @@ *RTE_MBUF_DYNFIELD(rx_pkts[i + 7], iavf_timestamp_dynfield_offset, uint32_t *) = _mm256_extract_epi32(ts_low1, 7); - if (unlikely(is_tsinit)) { + { uint32_t in_timestamp; - if (iavf_get_phc_time(rxq)) - PMD_DRV_LOG(ERR, "get physical time failed"); in_timestamp = *RTE_MBUF_DYNFIELD(rx_pkts[i + 0], iavf_timestamp_dynfield_offset, uint32_t *); rxq->phc_time = iavf_tstamp_convert_32b_64b(rxq->phc_time, in_timestamp); @@ -1596,8 +1586,6 @@ PMD_DRV_LOG(ERR, "invalid inflection point for rx timestamp"); break; } - - rxq->hw_time_update = rte_get_timer_cycles() / (rte_get_timer_hz() / 1000); } #endif #endif @@ -1999,7 +1987,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { iavf_vtx1(txdp, *pkt, flags, offload); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do 4 at a time while possible, in bursts */ @@ -2043,7 +2031,7 @@ /* do any last ones */ while (nb_pkts) { iavf_vtx1(txdp, *pkt, flags, offload); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } @@ -2239,7 +2227,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { ctx_vtx1(txdp, *pkt, flags, offload, vlan_flag); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } for (; nb_pkts > 1; txdp += 4, pkt += 2, nb_pkts -= 2) { diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_tm.c dpdk-24.11.8/drivers/net/iavf/iavf_tm.c --- dpdk-24.11.4/drivers/net/iavf/iavf_tm.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_tm.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2017 Intel Corporation */ +#include + #include #include "iavf.h" @@ -95,6 +97,9 @@ shaper_profile, node); rte_free(shaper_profile); } + + free(vf->qtc_map); + vf->qtc_map = NULL; } static inline struct iavf_tm_node * @@ -178,12 +183,6 @@ RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES; error->message = "SP priority not supported"; return -EINVAL; - } else if (params->nonleaf.wfq_weight_mode && - !(*params->nonleaf.wfq_weight_mode)) { - error->type = - RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE; - error->message = "WFP should be byte mode"; - return -EINVAL; } return 0; @@ -801,11 +800,12 @@ struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private); struct iavf_adapter *adapter = IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); - struct virtchnl_queue_tc_mapping *q_tc_mapping; - struct virtchnl_queues_bw_cfg *q_bw; + struct virtchnl_queue_tc_mapping *q_tc_mapping = NULL; + struct virtchnl_queues_bw_cfg *q_bw = NULL; struct iavf_tm_node_list *queue_list = &vf->tm_conf.queue_list; struct iavf_tm_node *tm_node; - struct iavf_qtc_map *qtc_map; + struct iavf_qtc_map *qtc_map = NULL; + struct iavf_qtc_map *old_qtc_map = vf->qtc_map; /* to free memory if new map assigned */ uint16_t size, size_q; int index = 0, node_committed = 0; int i, ret_val = IAVF_SUCCESS; @@ -832,7 +832,7 @@ size = sizeof(*q_tc_mapping) + sizeof(q_tc_mapping->tc[0]) * (vf->qos_cap->num_elem - 1); - q_tc_mapping = rte_zmalloc("q_tc", size, 0); + q_tc_mapping = calloc(1, size); if (!q_tc_mapping) { ret_val = IAVF_ERR_NO_MEMORY; goto fail_clear; @@ -840,7 +840,7 @@ size_q = sizeof(*q_bw) + sizeof(q_bw->cfg[0]) * (vf->num_queue_pairs - 1); - q_bw = rte_zmalloc("q_bw", size_q, 0); + q_bw = calloc(1, size_q); if (!q_bw) { ret_val = IAVF_ERR_NO_MEMORY; goto fail_clear; @@ -887,10 +887,11 @@ goto fail_clear; /* store the queue TC mapping info */ - qtc_map = rte_zmalloc("qtc_map", - sizeof(struct iavf_qtc_map) * q_tc_mapping->num_tc, 0); - if (!qtc_map) - return IAVF_ERR_NO_MEMORY; + qtc_map = calloc(q_tc_mapping->num_tc, sizeof(struct iavf_qtc_map)); + if (!qtc_map) { + ret_val = IAVF_ERR_NO_MEMORY; + goto fail_clear; + } for (i = 0; i < q_tc_mapping->num_tc; i++) { q_tc_mapping->tc[i].req.start_queue_id = index; @@ -906,7 +907,10 @@ goto fail_clear; vf->qtc_map = qtc_map; + free(old_qtc_map); vf->tm_conf.committed = true; + free(q_bw); + free(q_tc_mapping); return ret_val; fail_clear: @@ -916,5 +920,8 @@ iavf_tm_conf_init(dev); } err: + free(q_bw); + free(q_tc_mapping); + free(qtc_map); return ret_val; } diff -Nru dpdk-24.11.4/drivers/net/iavf/iavf_vchnl.c dpdk-24.11.8/drivers/net/iavf/iavf_vchnl.c --- dpdk-24.11.4/drivers/net/iavf/iavf_vchnl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/iavf/iavf_vchnl.c 2026-10-14 13:10:05.000000000 +0000 @@ -216,6 +216,67 @@ return speed; } +/* + * iavf_handle_link_change_event: common handler for VIRTCHNL link change events + * + * @dev: pointer to rte_eth_dev for this VF + * @vpe: pointer to the virtchnl_pf_event payload received from the PF + * + * Handle PF link-change event: decode adv/legacy link info, update VF + * link state, sync no-poll/watchdog behavior & notify app via LSC event. + */ +static void +iavf_handle_link_change_event(struct rte_eth_dev *dev, + struct virtchnl_pf_event *vpe) +{ + struct iavf_adapter *adapter = + IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); + struct iavf_info *vf = &adapter->vf; + bool adv_link_speed; + + adv_link_speed = (vf->vf_res != NULL) && + ((vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) != 0); + + if (adv_link_speed) { + vf->link_up = vpe->event_data.link_event_adv.link_status; + vf->link_speed = vpe->event_data.link_event_adv.link_speed; + } else { + enum virtchnl_link_speed speed; + + vf->link_up = vpe->event_data.link_event.link_status; + speed = vpe->event_data.link_event.link_speed; + vf->link_speed = iavf_convert_link_speed(speed); + } + + iavf_dev_link_update(dev, 0); + + /* + * Update watchdog/no_poll state BEFORE notifying the application via + * the LSC event. Otherwise the application's link-up callback could + * race with stale (link-down) no_poll/watchdog state and either + * continue to drop traffic or trigger a spurious reset detection. + * + * Keeping the watchdog enabled whenever the link cannot be trusted + * (link is down or a VF reset is in progress); the watchdog drives + * auto-reset recovery, so it must remain armed in those cases. + */ + if (vf->link_up && !vf->vf_reset) + iavf_dev_watchdog_disable(adapter); + else + iavf_dev_watchdog_enable(adapter); + + if (adapter->devargs.no_poll_on_link_down) { + iavf_set_no_poll(adapter, true); + PMD_DRV_LOG(DEBUG, "VF no poll turned %s", + adapter->no_poll ? "on" : "off"); + } + + iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0); + + PMD_DRV_LOG(INFO, "Link status update:%s", + vf->link_up ? "up" : "down"); +} + /* Read data in admin queue to get msg from pf driver */ static enum iavf_aq_result iavf_read_msg_from_pf(struct iavf_adapter *adapter, uint16_t buf_len, @@ -253,39 +314,24 @@ result = IAVF_MSG_SYS; switch (vpe->event) { case VIRTCHNL_EVENT_LINK_CHANGE: - vf->link_up = - vpe->event_data.link_event.link_status; - if (vf->vf_res != NULL && - vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) { - vf->link_speed = - vpe->event_data.link_event_adv.link_speed; - } else { - enum virtchnl_link_speed speed; - speed = vpe->event_data.link_event.link_speed; - vf->link_speed = iavf_convert_link_speed(speed); - } - iavf_dev_link_update(vf->eth_dev, 0); - iavf_dev_event_post(vf->eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0); - if (vf->link_up && !vf->vf_reset) { - iavf_dev_watchdog_disable(adapter); - } else { - if (!vf->link_up) - iavf_dev_watchdog_enable(adapter); - } - if (adapter->devargs.no_poll_on_link_down) { - iavf_set_no_poll(adapter, true); - if (adapter->no_poll) - PMD_DRV_LOG(DEBUG, "VF no poll turned on"); - else - PMD_DRV_LOG(DEBUG, "VF no poll turned off"); - } - PMD_DRV_LOG(INFO, "Link status update:%s", - vf->link_up ? "up" : "down"); + iavf_handle_link_change_event(vf->eth_dev, vpe); break; case VIRTCHNL_EVENT_RESET_IMPENDING: - vf->vf_reset = true; - iavf_set_no_poll(adapter, false); - PMD_DRV_LOG(INFO, "VF is resetting"); + /* + * Force link down on impending reset to drop + * the cached link-up state; a fresh LSC up + * event will be re-issued by the PF once the + * VF is reinitialised. + */ + vf->link_up = false; + if (!vf->vf_reset) { + vf->vf_reset = true; + iavf_set_no_poll(adapter, false); + iavf_dev_event_post(vf->eth_dev, + RTE_ETH_EVENT_INTR_RESET, + NULL, 0); + } + PMD_DRV_LOG(DEBUG, "VF is resetting"); break; case VIRTCHNL_EVENT_PF_DRIVER_CLOSE: vf->dev_closed = true; @@ -467,30 +513,7 @@ break; case VIRTCHNL_EVENT_LINK_CHANGE: PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_LINK_CHANGE event"); - vf->link_up = pf_msg->event_data.link_event.link_status; - if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_CAP_ADV_LINK_SPEED) { - vf->link_speed = - pf_msg->event_data.link_event_adv.link_speed; - } else { - enum virtchnl_link_speed speed; - speed = pf_msg->event_data.link_event.link_speed; - vf->link_speed = iavf_convert_link_speed(speed); - } - iavf_dev_link_update(dev, 0); - if (vf->link_up && !vf->vf_reset) { - iavf_dev_watchdog_disable(adapter); - } else { - if (!vf->link_up) - iavf_dev_watchdog_enable(adapter); - } - if (adapter->devargs.no_poll_on_link_down) { - iavf_set_no_poll(adapter, true); - if (adapter->no_poll) - PMD_DRV_LOG(DEBUG, "VF no poll turned on"); - else - PMD_DRV_LOG(DEBUG, "VF no poll turned off"); - } - iavf_dev_event_post(dev, RTE_ETH_EVENT_INTR_LSC, NULL, 0); + iavf_handle_link_change_event(dev, pf_msg); break; case VIRTCHNL_EVENT_PF_DRIVER_CLOSE: PMD_DRV_LOG(DEBUG, "VIRTCHNL_EVENT_PF_DRIVER_CLOSE event"); @@ -524,8 +547,16 @@ ret = iavf_clean_arq_element(hw, &info, &pending); if (ret != IAVF_SUCCESS) { - PMD_DRV_LOG(INFO, "Failed to read msg from AdminQ," - "ret: %d", ret); + /* + * IAVF_ERR_ADMIN_QUEUE_NO_WORK (-57) means AQ is empty + * and is a normal way to terminate the drain loop. + * Log error only for genuine other failure codes. + * Incorrect logging like this during VF resets might + * mislead into chasing a non-existent AQ failure. + */ + if (ret != IAVF_ERR_ADMIN_QUEUE_NO_WORK) + PMD_DRV_LOG(INFO, "Failed to read msg from AdminQ," + "ret: %d", ret); break; } aq_opc = rte_le_to_cpu_16(info.desc.opcode); diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_acl_ctrl.c dpdk-24.11.8/drivers/net/ice/base/ice_acl_ctrl.c --- dpdk-24.11.4/drivers/net/ice/base/ice_acl_ctrl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_acl_ctrl.c 2026-10-14 13:10:05.000000000 +0000 @@ -494,7 +494,7 @@ * is available. */ p = dir > 0 ? i : ICE_AQC_MAX_TCAM_ALLOC_UNITS - i - 1; - for (w = row; w < row + width && avail; w++) { + for (w = row; w < (u16)(row + width) && avail; w++) { u16 b; b = (w * ICE_AQC_MAX_TCAM_ALLOC_UNITS) + p; @@ -644,7 +644,7 @@ * For each TCAM, there will be (ICE_AQC_ACL_TCAM_DEPTH * / ICE_ACL_ENTRY_ALLOC_UNIT) or 8 chunks. */ - for (i = tcam_idx; i < tcam_idx + num_cscd; i++) + for (i = tcam_idx; i < (u16)(tcam_idx + num_cscd); i++) scen_buf->tcam_cfg[i].chnk_msk |= BIT(chnk_offst); chnk_offst = (chnk_offst + 1) % ICE_AQC_MAX_TCAM_ALLOC_UNITS; @@ -799,7 +799,7 @@ ICE_AQC_ACL_ALLOC_SCE_START_CMP; /* cascade TCAMs up to the width of the scenario */ - for (i = k; i < cascade_cnt + k; i++) { + for (i = k; i < (u8)(cascade_cnt + k); i++) { ice_acl_fill_tcam_select(&scen_buf, scen, i, i - k); ice_acl_assign_act_mem_for_scen(hw->acl_tbl, scen, &scen_buf, diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_bitops.h dpdk-24.11.8/drivers/net/ice/base/ice_bitops.h --- dpdk-24.11.4/drivers/net/ice/base/ice_bitops.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_bitops.h 2026-10-14 13:10:05.000000000 +0000 @@ -188,7 +188,7 @@ u16 i; /* Handle all but the last chunk */ - for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) { + for (i = 0; i < (u16)(BITS_TO_CHUNKS(size) - 1); i++) { dst[i] = bmp1[i] & bmp2[i]; res |= dst[i]; } @@ -225,7 +225,7 @@ u16 i; /* Handle all but last chunk */ - for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) + for (i = 0; i < (u16)(BITS_TO_CHUNKS(size) - 1); i++) dst[i] = bmp1[i] | bmp2[i]; /* We want to only OR bits within the size. Furthermore, we also do @@ -256,7 +256,7 @@ u16 i; /* Handle all but last chunk */ - for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) + for (i = 0; i < (u16)(BITS_TO_CHUNKS(size) - 1); i++) dst[i] = bmp1[i] ^ bmp2[i]; /* We want to only XOR bits within the size. Furthermore, we also do @@ -287,7 +287,7 @@ u16 i; /* Handle all but last chunk */ - for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) + for (i = 0; i < (u16)(BITS_TO_CHUNKS(size) - 1); i++) dst[i] = bmp1[i] & ~bmp2[i]; /* We want to only clear bits within the size. Furthermore, we also do @@ -330,7 +330,7 @@ } /* Now we handle the remaining chunks, if any */ - for (i++; i < BITS_TO_CHUNKS(size); i++) { + for (i++; i < (u16)BITS_TO_CHUNKS(size); i++) { if (bitmap[i] != 0) { u16 off = i * BITS_PER_CHUNK; @@ -405,7 +405,7 @@ { u16 i; - for (i = pos; i < pos + num_bits; i++) + for (i = pos; i < (u16)(pos + num_bits); i++) ice_set_bit(i, dst); } @@ -447,7 +447,7 @@ u16 i; /* Handle all but last chunk */ - for (i = 0; i < BITS_TO_CHUNKS(size) - 1; i++) + for (i = 0; i < (u16)(BITS_TO_CHUNKS(size) - 1); i++) if (bmp1[i] != bmp2[i]) return false; diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_dcb.c dpdk-24.11.8/drivers/net/ice/base/ice_dcb.c --- dpdk-24.11.4/drivers/net/ice/base/ice_dcb.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_dcb.c 2026-10-14 13:10:05.000000000 +0000 @@ -465,7 +465,7 @@ { u16 len, typelen, offset = 0; struct ice_cee_app_prio *app; - u8 i; + u32 i; typelen = NTOHS(tlv->hdr.typelen); len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S); @@ -790,8 +790,8 @@ struct ice_port_info *pi) { u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status); - u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift; - u8 i, j, err, sync, oper, app_index, ice_app_sel_type; + u32 j, ice_aqc_cee_status_mask, ice_aqc_cee_status_shift; + u8 i, err, sync, oper, app_index, ice_app_sel_type; u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio); u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift; struct ice_dcbx_cfg *cmp_dcbcfg, *dcbcfg; @@ -1268,7 +1268,7 @@ * Bits:|23 21|20 19|18 16|15 0| * ----------------------------------------- */ - while (i < dcbcfg->numapps) { + while (i < (u8)dcbcfg->numapps) { priority = dcbcfg->app[i].priority & 0x7; selector = dcbcfg->app[i].selector & 0x7; buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector; diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_fdir.c dpdk-24.11.8/drivers/net/ice/base/ice_fdir.c --- dpdk-24.11.4/drivers/net/ice/base/ice_fdir.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_fdir.c 2026-10-14 13:10:05.000000000 +0000 @@ -3835,6 +3835,12 @@ u16 pos; u16 offset; + /* pkt = start of full packet buffer (outer Ethernet header, offset 0). + * loc = start of current protocol segment; equals pkt for non-tunnel + * flows, but points past the tunnel header for tunnel flows. + * Use pkt for outer L2 fields, loc for the active segment. + */ + if (input->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) { switch (input->ip.v4.proto) { case ICE_IP_PROTO_TCP: @@ -4593,16 +4599,16 @@ input->ip.v6.tc); break; case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_CONTROL: - ice_pkt_insert_mac_addr(loc, input->ext_data_outer.dst_mac); - ice_pkt_insert_mac_addr(loc + ETH_ALEN, + ice_pkt_insert_mac_addr(pkt, input->ext_data_outer.dst_mac); + ice_pkt_insert_mac_addr(pkt + ETH_ALEN, input->ext_data_outer.src_mac); ice_pkt_insert_u16(loc, ICE_IPV4_L2TPV2_LEN_SESS_ID_OFFSET, input->l2tpv2_data.session_id); break; case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2: case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV2_PPP: - ice_pkt_insert_mac_addr(loc, input->ext_data_outer.dst_mac); - ice_pkt_insert_mac_addr(loc + ETH_ALEN, + ice_pkt_insert_mac_addr(pkt, input->ext_data_outer.dst_mac); + ice_pkt_insert_mac_addr(pkt + ETH_ALEN, input->ext_data_outer.src_mac); flags_version = BE16_TO_CPU(input->l2tpv2_data.flags_version); if (flags_version & ICE_L2TPV2_FLAGS_LEN) { @@ -4616,16 +4622,16 @@ } break; case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_CONTROL: - ice_pkt_insert_mac_addr(loc, input->ext_data_outer.dst_mac); - ice_pkt_insert_mac_addr(loc + ETH_ALEN, + ice_pkt_insert_mac_addr(pkt, input->ext_data_outer.dst_mac); + ice_pkt_insert_mac_addr(pkt + ETH_ALEN, input->ext_data_outer.src_mac); ice_pkt_insert_u16(loc, ICE_IPV6_L2TPV2_LEN_SESS_ID_OFFSET, input->l2tpv2_data.session_id); break; case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2: case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV2_PPP: - ice_pkt_insert_mac_addr(loc, input->ext_data_outer.dst_mac); - ice_pkt_insert_mac_addr(loc + ETH_ALEN, + ice_pkt_insert_mac_addr(pkt, input->ext_data_outer.dst_mac); + ice_pkt_insert_mac_addr(pkt + ETH_ALEN, input->ext_data_outer.src_mac); flags_version = BE16_TO_CPU(input->l2tpv2_data.flags_version); if (flags_version & ICE_L2TPV2_FLAGS_LEN) { diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_ptp_hw.c dpdk-24.11.8/drivers/net/ice/base/ice_ptp_hw.c --- dpdk-24.11.4/drivers/net/ice/base/ice_ptp_hw.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_ptp_hw.c 2026-10-14 13:10:05.000000000 +0000 @@ -6086,7 +6086,7 @@ */ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj, bool lock_sbq) { - int err; + int err = 0; u8 tmr_idx; tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned; @@ -6104,8 +6104,8 @@ err = ice_ptp_prep_phy_adj_eth56g(hw, adj, lock_sbq); break; case ICE_PHY_E830: - /* E830 sync PHYs automatically after setting GLTSYN_SHADJ */ - return 0; + /* E830 sync PHYs automatically after setting cmd register */ + break; case ICE_PHY_E810: err = ice_ptp_prep_phy_adj_e810(hw, adj, lock_sbq); break; diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_sched.c dpdk-24.11.8/drivers/net/ice/base/ice_sched.c --- dpdk-24.11.4/drivers/net/ice/base/ice_sched.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_sched.c 2026-10-14 13:10:05.000000000 +0000 @@ -1247,7 +1247,8 @@ u8 num_branches; u16 num_elems; int status; - u8 i, j; + u8 i; + u16 j; if (!pi) return ICE_ERR_PARAM; diff -Nru dpdk-24.11.4/drivers/net/ice/base/ice_switch.c dpdk-24.11.8/drivers/net/ice/base/ice_switch.c --- dpdk-24.11.4/drivers/net/ice/base/ice_switch.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/base/ice_switch.c 2026-10-14 13:10:05.000000000 +0000 @@ -7395,7 +7395,7 @@ struct ice_fv_word *pr; bool found = false; u16 mask; - u8 j; + u16 j; pr = &rg->r_group.pairs[i]; mask = rg->r_group.mask[i]; diff -Nru dpdk-24.11.4/drivers/net/ice/ice_dcf_ethdev.c dpdk-24.11.8/drivers/net/ice/ice_dcf_ethdev.c --- dpdk-24.11.4/drivers/net/ice/ice_dcf_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_dcf_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1530,8 +1530,16 @@ ret = ice_dcf_query_stats(hw, &pstats); if (ret == 0) { ice_dcf_update_stats(&hw->eth_stats_offset, &pstats); - stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + - pstats.rx_broadcast - pstats.rx_discards; + stats->ipackets = pstats.rx_unicast + pstats.rx_multicast + pstats.rx_broadcast; + /* + * Unicast/multicast/broadcast counters include discarded packets, so subtract + * rx_discards to report only the packets delivered to the application. The + * counters are sampled from separate sources and can be momentarily inconsistent + * under load. If rx_discards exceeds their sum then essentially nothing was + * delivered, so saturate at zero rather than underflow. + */ + stats->ipackets = stats->ipackets >= pstats.rx_discards ? + stats->ipackets - pstats.rx_discards : 0; stats->opackets = pstats.tx_broadcast + pstats.tx_multicast + pstats.tx_unicast; stats->imissed = pstats.rx_discards; diff -Nru dpdk-24.11.4/drivers/net/ice/ice_dcf_sched.c dpdk-24.11.8/drivers/net/ice/ice_dcf_sched.c --- dpdk-24.11.4/drivers/net/ice/ice_dcf_sched.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_dcf_sched.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2017 Intel Corporation */ +#include + #include #include "base/ice_sched.h" @@ -746,8 +748,8 @@ { struct ice_dcf_adapter *adapter = dev->data->dev_private; struct ice_dcf_hw *hw = &adapter->real_hw; - struct virtchnl_dcf_bw_cfg_list *vf_bw; - struct virtchnl_dcf_bw_cfg_list *tc_bw; + struct virtchnl_dcf_bw_cfg_list *vf_bw = NULL; + struct virtchnl_dcf_bw_cfg_list *tc_bw = NULL; struct ice_dcf_tm_node_list *vsi_list = &hw->tm_conf.vsi_list; struct rte_tm_shaper_params *profile; struct ice_dcf_tm_node *tm_node; @@ -770,12 +772,12 @@ size = sizeof(struct virtchnl_dcf_bw_cfg_list) + sizeof(struct virtchnl_dcf_bw_cfg) * (hw->tm_conf.nb_tc_node - 1); - vf_bw = rte_zmalloc("vf_bw", size, 0); + vf_bw = calloc(1, size); if (!vf_bw) { ret_val = ICE_ERR_NO_MEMORY; goto fail_clear; } - tc_bw = rte_zmalloc("tc_bw", size, 0); + tc_bw = calloc(1, size); if (!tc_bw) { ret_val = ICE_ERR_NO_MEMORY; goto fail_clear; @@ -875,6 +877,11 @@ return ret_val; fail_clear: + if (vf_bw != NULL) + free(vf_bw); + if (tc_bw != NULL) + free(tc_bw); + /* clear all the traffic manager configuration */ if (clear_on_fail) { ice_dcf_tm_conf_uninit(dev); diff -Nru dpdk-24.11.4/drivers/net/ice/ice_diagnose.c dpdk-24.11.8/drivers/net/ice/ice_diagnose.c --- dpdk-24.11.4/drivers/net/ice/ice_diagnose.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_diagnose.c 2026-10-14 13:10:05.000000000 +0000 @@ -638,7 +638,7 @@ fprintf(stream, "\t\t\t\t\n"); fprintf(stream, "\t\t\t\t\t priority mode\n"); fprintf(stream, "\t\t\t\t\t"); - print_priority_mode(stream, ((data->data.generic >> 4) & 0x1) != 0); + print_priority_mode(stream, ((data->data.generic >> 4) & 0x1) == 0); fprintf(stream, "\n"); fprintf(stream, "\t\t\t\t\n"); diff -Nru dpdk-24.11.4/drivers/net/ice/ice_ethdev.c dpdk-24.11.8/drivers/net/ice/ice_ethdev.c --- dpdk-24.11.4/drivers/net/ice/ice_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -876,16 +876,14 @@ if (!pool) return; - for (entry = LIST_FIRST(&pool->alloc_list); - entry && (next_entry = LIST_NEXT(entry, next), 1); - entry = next_entry) { + for (entry = LIST_FIRST(&pool->alloc_list); entry; entry = next_entry) { + next_entry = LIST_NEXT(entry, next); LIST_REMOVE(entry, next); rte_free(entry); } - for (entry = LIST_FIRST(&pool->free_list); - entry && (next_entry = LIST_NEXT(entry, next), 1); - entry = next_entry) { + for (entry = LIST_FIRST(&pool->free_list); entry; entry = next_entry) { + next_entry = LIST_NEXT(entry, next); LIST_REMOVE(entry, next); rte_free(entry); } @@ -930,9 +928,9 @@ if (vsi->adapter->hw.func_caps.common_cap.num_msix_vectors < 2) { vsi->nb_qps = 0; } else { - vsi->nb_qps = RTE_MIN - ((uint16_t)vsi->adapter->hw.func_caps.common_cap.num_msix_vectors - 2, - RTE_MIN(vsi->nb_qps, ICE_MAX_Q_PER_TC)); + vsi->nb_qps = RTE_MIN(vsi->nb_qps, ICE_MAX_Q_PER_TC); + vsi->nb_qps = RTE_MIN(vsi->nb_qps, + (uint16_t)vsi->adapter->hw.func_caps.common_cap.num_msix_vectors - 2); /* cap max QPs to what the HW reports as num-children for each layer. * Multiply num_children for each layer from the entry_point layer to @@ -1844,7 +1842,7 @@ dv.minor_ver = 0; dv.build_ver = 0; dv.subbuild_ver = 0; - strncpy((char *)dv.driver_string, "dpdk", sizeof(dv.driver_string)); + strlcpy((char *)dv.driver_string, "dpdk", sizeof(dv.driver_string)); return ice_aq_send_driver_ver(hw, &dv, NULL); } @@ -1990,24 +1988,22 @@ if (!use_dsn) goto no_dsn; - strncpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_UPDATES, - ICE_MAX_PKG_FILENAME_SIZE); - strcat(pkg_file, opt_ddp_filename); + strlcpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_UPDATES, ICE_MAX_PKG_FILENAME_SIZE); + strlcat(pkg_file, opt_ddp_filename, ICE_MAX_PKG_FILENAME_SIZE); if (rte_firmware_read(pkg_file, &buf, &bufsz) == 0) goto load_fw; - strncpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_DEFAULT, - ICE_MAX_PKG_FILENAME_SIZE); - strcat(pkg_file, opt_ddp_filename); + strlcpy(pkg_file, ICE_PKG_FILE_SEARCH_PATH_DEFAULT, ICE_MAX_PKG_FILENAME_SIZE); + strlcat(pkg_file, opt_ddp_filename, ICE_MAX_PKG_FILENAME_SIZE); if (rte_firmware_read(pkg_file, &buf, &bufsz) == 0) goto load_fw; no_dsn: - strncpy(pkg_file, ICE_PKG_FILE_UPDATES, ICE_MAX_PKG_FILENAME_SIZE); + strlcpy(pkg_file, ICE_PKG_FILE_UPDATES, ICE_MAX_PKG_FILENAME_SIZE); if (rte_firmware_read(pkg_file, &buf, &bufsz) == 0) goto load_fw; - strncpy(pkg_file, ICE_PKG_FILE_DEFAULT, ICE_MAX_PKG_FILENAME_SIZE); + strlcpy(pkg_file, ICE_PKG_FILE_DEFAULT, ICE_MAX_PKG_FILENAME_SIZE); if (rte_firmware_read(pkg_file, &buf, &bufsz) < 0) { PMD_INIT_LOG(ERR, "failed to search file path"); return -1; @@ -4060,6 +4056,8 @@ for (i = 0; i < nb_txq; i++) ice_tx_queue_stop(dev, i); + pf->adapter_stopped = true; + return -EIO; } @@ -4609,7 +4607,8 @@ ice_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) { struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct ice_vlan vlan = ICE_VLAN(RTE_ETHER_TYPE_VLAN, vlan_id); + /* Use the configured outer_ethertype instead of hardcoded 0x8100 */ + struct ice_vlan vlan = ICE_VLAN(pf->outer_ethertype, vlan_id); struct ice_vsi *vsi = pf->main_vsi; int ret; @@ -6000,6 +5999,15 @@ struct ice_hw *hw = ICE_VSI_TO_HW(vsi); int idx = rte_le_to_cpu_16(vsi->vsi_id); + /* + * Unicast/multicast/broadcast counters include discarded packets. Received packets is + * calculated by deducting discards from unicast/multicast/broadcast. To prevent a + * potential underflow, read discards first to guarantee it is smaller than + * unicast/multicast/broadcast. + */ + ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded, + &oes->rx_discards, &nes->rx_discards); + ice_stat_update_40(hw, GLV_GORCH(idx), GLV_GORCL(idx), vsi->offset_loaded, &oes->rx_bytes, &nes->rx_bytes); @@ -6023,8 +6031,6 @@ nes->rx_bytes -= (nes->rx_unicast + nes->rx_multicast + nes->rx_broadcast) * RTE_ETHER_CRC_LEN; - ice_stat_update_32(hw, GLV_RDPC(idx), vsi->offset_loaded, - &oes->rx_discards, &nes->rx_discards); /* GLV_REPC not supported */ /* GLV_RMPC not supported */ ice_stat_update_32(hw, GLSWID_RUPP(idx), vsi->offset_loaded, diff -Nru dpdk-24.11.4/drivers/net/ice/ice_fdir_filter.c dpdk-24.11.8/drivers/net/ice/ice_fdir_filter.c --- dpdk-24.11.4/drivers/net/ice/ice_fdir_filter.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_fdir_filter.c 2026-10-14 13:10:05.000000000 +0000 @@ -1838,6 +1838,7 @@ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Not support range"); + return -rte_errno; } input_set = (tunnel_type && !is_outer) ? @@ -1929,7 +1930,7 @@ goto raw_error; } - u8 *pkt_buf = (u8 *)ice_malloc(&ad->hw, pkt_len + 1); + u8 *pkt_buf = (u8 *)rte_zmalloc("raw pkt buf", pkt_len + 1, 0); if (!pkt_buf) { ret_val = -ENOMEM; goto raw_error; @@ -2483,8 +2484,12 @@ if (ret) goto error; - if (meta) + /* if meta is NULL we're validating so the flow won't be stored */ + if (meta) { *meta = filter; + } else if (filter->pkt_buf != NULL) { + rte_free(filter->pkt_buf); + } rte_free(item); return ret; diff -Nru dpdk-24.11.4/drivers/net/ice/ice_rxtx_vec_avx2.c dpdk-24.11.8/drivers/net/ice/ice_rxtx_vec_avx2.c --- dpdk-24.11.4/drivers/net/ice/ice_rxtx_vec_avx2.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_rxtx_vec_avx2.c 2026-10-14 13:10:05.000000000 +0000 @@ -803,7 +803,7 @@ /* if unaligned on 32-bit boundary, do one to align */ if (((uintptr_t)txdp & 0x1F) != 0 && nb_pkts != 0) { ice_vtx1(txdp, *pkt, flags, offload); - nb_pkts--, txdp++, pkt++; + nb_pkts--; txdp++; pkt++; } /* do two at a time while possible, in bursts */ @@ -848,7 +848,7 @@ /* do any last ones */ while (nb_pkts) { ice_vtx1(txdp, *pkt, flags, offload); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/net/ice/ice_rxtx_vec_avx512.c dpdk-24.11.8/drivers/net/ice/ice_rxtx_vec_avx512.c --- dpdk-24.11.4/drivers/net/ice/ice_rxtx_vec_avx512.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_rxtx_vec_avx512.c 2026-10-14 13:10:05.000000000 +0000 @@ -1035,7 +1035,7 @@ /* do any last ones */ while (nb_pkts) { ice_vtx1(txdp, *pkt, flags, do_offload); - txdp++, pkt++, nb_pkts--; + txdp++; pkt++; nb_pkts--; } } diff -Nru dpdk-24.11.4/drivers/net/ice/ice_tm.c dpdk-24.11.8/drivers/net/ice/ice_tm.c --- dpdk-24.11.4/drivers/net/ice/ice_tm.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ice/ice_tm.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2022 Intel Corporation */ +#include + #include #include @@ -88,8 +90,11 @@ uint32_t priority, uint32_t weight, const struct rte_tm_node_params *params, bool is_leaf, + uint16_t nb_txq, struct rte_tm_error *error) { + uint32_t max_leaf_id = (nb_txq != 0) ? nb_txq : RTE_MAX_QUEUES_PER_PORT; + /* checked all the unsupported parameter */ if (node_id == RTE_TM_NODE_ID_NULL) { error->type = RTE_TM_ERROR_TYPE_NODE_ID; @@ -123,6 +128,11 @@ /* for non-leaf node */ if (!is_leaf) { + if (node_id < max_leaf_id) { + error->type = RTE_TM_ERROR_TYPE_NODE_ID; + error->message = "node ID is reserved for leaf nodes"; + return -EINVAL; + } if (params->nonleaf.wfq_weight_mode) { error->type = RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE; @@ -146,7 +156,7 @@ } /* for leaf node */ - if (node_id >= RTE_MAX_QUEUES_PER_PORT) { + if (node_id >= max_leaf_id) { error->type = RTE_TM_ERROR_TYPE_NODE_ID; error->message = "Node ID out of range for a leaf node."; return -EINVAL; @@ -440,7 +450,8 @@ return -EINVAL; } - ret = ice_node_param_check(node_id, priority, weight, params, false, error); + ret = ice_node_param_check(node_id, priority, weight, params, false, + dev->data->nb_tx_queues, error); if (ret) return ret; @@ -456,6 +467,8 @@ tm_node->parent = NULL; tm_node->reference_count = 0; tm_node->shaper_profile = shaper_profile; + if (shaper_profile != NULL) + shaper_profile->reference_count++; tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node)); tm_node->params = *params; pf->tm_conf.root = tm_node; @@ -479,7 +492,8 @@ } ret = ice_node_param_check(node_id, priority, weight, - params, level_id == ice_get_leaf_level(pf), error); + params, level_id == ice_get_leaf_level(pf), + dev->data->nb_tx_queues, error); if (ret) return ret; @@ -518,11 +532,14 @@ tm_node->parent = parent_node; tm_node->level = level_id; tm_node->shaper_profile = shaper_profile; + if (shaper_profile != NULL) + shaper_profile->reference_count++; tm_node->children = RTE_PTR_ADD(tm_node, sizeof(struct ice_tm_node)); tm_node->parent->children[tm_node->parent->reference_count++] = tm_node; tm_node->params = *params; - if (tm_node->priority != 0) + /* Priority cannot be configured for the root level */ + if (tm_node->priority != 0 && level_id == 0) PMD_DRV_LOG(WARNING, "priority != 0 not supported in level %d", level_id); if (tm_node->weight != 1 && level_id == 0) @@ -567,6 +584,8 @@ /* root node */ if (tm_node->level == 0) { + if (tm_node->shaper_profile != NULL) + tm_node->shaper_profile->reference_count--; rte_free(tm_node); pf->tm_conf.root = NULL; return 0; @@ -581,6 +600,8 @@ tm_node->parent->children[j] = tm_node->parent->children[j + 1]; tm_node->parent->reference_count--; + if (tm_node->shaper_profile != NULL) + tm_node->shaper_profile->reference_count--; rte_free(tm_node); return 0; @@ -695,7 +716,7 @@ uint8_t txqs_moved = 0; uint16_t buf_size = ice_struct_size(buf, txqs, 1); - buf = ice_malloc(hw, buf_size); + buf = calloc(1, buf_size); if (buf == NULL) return -ENOMEM; @@ -708,9 +729,9 @@ int ret = ice_aq_move_recfg_lan_txq(hw, 1, true, false, false, false, 50, NULL, buf, buf_size, &txqs_moved, NULL); + free(buf); if (ret || txqs_moved == 0) { PMD_DRV_LOG(ERR, "move lan queue %u failed", qid); - ice_free(hw, buf); return ICE_ERR_PARAM; } @@ -804,6 +825,19 @@ return 0; } +static void +reset_hw_node_recursive(struct ice_hw *hw, struct ice_sched_node *node) +{ + uint16_t i; + + for (i = 0; i < node->num_children; i++) { + reset_hw_node_recursive(hw, node->children[i]); + if (ice_cfg_hw_node(hw, NULL, node->children[i])) + PMD_DRV_LOG(WARNING, "Failed to reset node %u to default configuration", + node->children[i]->info.node_teid); + } +} + static int commit_new_hierarchy(struct rte_eth_dev *dev) { @@ -816,8 +850,20 @@ uint16_t nodes_created_per_level[ICE_TM_MAX_LAYERS] = {0}; uint8_t q_lvl = ice_get_leaf_level(pf); uint8_t qg_lvl = q_lvl - 1; - struct ice_sched_node *new_vsi_root = hw->vsi_ctx[pf->main_vsi->idx]->sched.vsi_node[0]; + + if (sw_root == NULL) { + if (!pf->tm_conf.committed) { + PMD_DRV_LOG(ERR, "No root node defined in TM hierarchy"); + return -EINVAL; + } + /* TM hierarchy deleted. Restore default scheduler state. */ + reset_hw_node_recursive(hw, hw->vsi_ctx[pf->main_vsi->idx]->sched.vsi_node[0]); + pf->main_vsi->nb_qps = pf->lan_nb_qps; + pf->tm_conf.committed = false; + return ice_alloc_lan_q_ctx(hw, 0, 0, pf->main_vsi->nb_qps); + } + /* handle case where VSI node needs to move DOWN the hierarchy */ while (new_vsi_root->tx_sched_layer < new_root_level) { if (new_vsi_root->num_children == 0) diff -Nru dpdk-24.11.4/drivers/net/idpf/idpf_ethdev.c dpdk-24.11.8/drivers/net/idpf/idpf_ethdev.c --- dpdk-24.11.4/drivers/net/idpf/idpf_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/idpf/idpf_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1201,7 +1201,7 @@ hw->device_id = pci_dev->id.device_id; hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id; - strncpy(adapter->name, pci_dev->device.name, PCI_PRI_STR_SIZE); + strlcpy(adapter->name, pci_dev->device.name, sizeof(adapter->name)); rte_memcpy(&base->caps, &req_caps, sizeof(struct virtchnl2_get_capabilities)); diff -Nru dpdk-24.11.4/drivers/net/idpf/idpf_rxtx.c dpdk-24.11.8/drivers/net/idpf/idpf_rxtx.c --- dpdk-24.11.4/drivers/net/idpf/idpf_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/idpf/idpf_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -495,6 +495,7 @@ return 0; err_complq_setup: + rte_free(txq->sw_ring); err_sw_ring_alloc: idpf_dma_zone_release(mz); err_mz_reserve: diff -Nru dpdk-24.11.4/drivers/net/igc/igc_ethdev.c dpdk-24.11.8/drivers/net/igc/igc_ethdev.c --- dpdk-24.11.4/drivers/net/igc/igc_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/igc/igc_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1309,14 +1309,14 @@ struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev); int retry = 0; - int ret = 0; + int retval = 0; PMD_INIT_FUNC_TRACE(); if (rte_eal_process_type() != RTE_PROC_PRIMARY) return 0; if (!adapter->stopped) - ret = eth_igc_stop(dev); + retval = eth_igc_stop(dev); igc_flow_flush(dev, NULL); igc_clear_all_filter(dev); @@ -1339,7 +1339,7 @@ /* Reset any pending lock */ igc_reset_swfw_lock(hw); - return ret; + return retval; } static void @@ -2552,6 +2552,7 @@ /* read RSS key from register */ for (i = 0; i < IGC_HKEY_MAX_INDEX; i++) hash_key[i] = IGC_READ_REG_LE_VALUE(hw, IGC_RSSRK(i)); + rss_conf->rss_key_len = IGC_HKEY_MAX_INDEX * sizeof(uint32_t); } /* get RSS functions configured in MRQC register */ @@ -2806,6 +2807,12 @@ { struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); + /* + * Reading the SYSTIML register latches the upper 32 bits to the SYSTIMH + * shadow register for coherent access. As long as we read SYSTIML first + * followed by SYSTIMH, we avoid race conditions where the time rolls + * over between the two register reads. + */ ts->tv_nsec = IGC_READ_REG(hw, IGC_SYSTIML); ts->tv_sec = IGC_READ_REG(hw, IGC_SYSTIMH); @@ -2965,10 +2972,10 @@ static int eth_igc_read_clock(__rte_unused struct rte_eth_dev *dev, uint64_t *clock) { - struct timespec system_time; + struct timespec ts; - clock_gettime(CLOCK_REALTIME, &system_time); - *clock = system_time.tv_sec * NSEC_PER_SEC + system_time.tv_nsec; + eth_igc_timesync_read_time(dev, &ts); + *clock = rte_timespec_to_ns(&ts); return 0; } diff -Nru dpdk-24.11.4/drivers/net/igc/igc_txrx.c dpdk-24.11.8/drivers/net/igc/igc_txrx.c --- dpdk-24.11.4/drivers/net/igc/igc_txrx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/igc/igc_txrx.c 2026-10-14 13:10:05.000000000 +0000 @@ -824,17 +824,20 @@ uint16_t i; /* Fill in redirection table. */ - for (i = 0; i < IGC_RSS_RDT_SIZD; i++) { - union igc_rss_reta_reg reta; - uint16_t q_idx, reta_idx; - - q_idx = (uint8_t)((dev->data->nb_rx_queues > 1) ? - i % dev->data->nb_rx_queues : 0); - reta_idx = i % sizeof(reta); - reta.bytes[reta_idx] = q_idx; - if (reta_idx == sizeof(reta) - 1) - IGC_WRITE_REG_LE_VALUE(hw, - IGC_RETA(i / sizeof(reta)), reta.dword); + for (i = 0; i < IGC_RSS_RDT_SIZD; i += IGC_RSS_RDT_REG_SIZE) { + union igc_rss_reta_reg reta = { .dword = 0 }; + uint16_t reta_idx; + + RTE_BUILD_BUG_ON(sizeof(reta.bytes) != IGC_RSS_RDT_REG_SIZE); + for (reta_idx = 0; reta_idx < IGC_RSS_RDT_REG_SIZE; reta_idx++) { + uint16_t q_idx; + + q_idx = (uint8_t)((dev->data->nb_rx_queues > 1) ? + (i + reta_idx) % dev->data->nb_rx_queues : 0); + reta.bytes[reta_idx] = q_idx; + } + IGC_WRITE_REG_LE_VALUE(hw, + IGC_RETA(i / IGC_RSS_RDT_REG_SIZE), reta.dword); } /* @@ -940,18 +943,18 @@ igc_rss_conf_set(rss_filter, &rss->conf); /* Fill in redirection table. */ - for (i = 0, j = 0; i < IGC_RSS_RDT_SIZD; i++, j++) { - union igc_rss_reta_reg reta; - uint16_t q_idx, reta_idx; - - if (j == rss->conf.queue_num) - j = 0; - q_idx = rss->conf.queue[j]; - reta_idx = i % sizeof(reta); - reta.bytes[reta_idx] = q_idx; - if (reta_idx == sizeof(reta) - 1) - IGC_WRITE_REG_LE_VALUE(hw, - IGC_RETA(i / sizeof(reta)), reta.dword); + for (i = 0, j = 0; i < IGC_RSS_RDT_SIZD; i += IGC_RSS_RDT_REG_SIZE) { + union igc_rss_reta_reg reta = { .dword = 0 }; + uint16_t reta_idx; + + RTE_BUILD_BUG_ON(sizeof(reta.bytes) != IGC_RSS_RDT_REG_SIZE); + for (reta_idx = 0; reta_idx < IGC_RSS_RDT_REG_SIZE; reta_idx++, j++) { + if (j == rss->conf.queue_num) + j = 0; + reta.bytes[reta_idx] = rss->conf.queue[j]; + } + IGC_WRITE_REG_LE_VALUE(hw, + IGC_RETA(i / IGC_RSS_RDT_REG_SIZE), reta.dword); } if (rss_conf.rss_key == NULL) @@ -1416,6 +1419,10 @@ { uint32_t curr = txq->ctx_curr; + /* Launch time feature always need a new context descriptor */ + if (flags & igc_tx_timestamp_dynflag) + return IGC_CTX_NUM; + /* If match with the current context */ if (likely(txq->ctx_cache[curr].flags == flags && txq->ctx_cache[curr].tx_offload.data == @@ -1621,7 +1628,8 @@ tx_last = (uint16_t)(tx_id + tx_pkt->nb_segs - 1); ol_flags = tx_pkt->ol_flags; - tx_ol_req = ol_flags & IGC_TX_OFFLOAD_MASK; + tx_ol_req = ol_flags & (IGC_TX_OFFLOAD_MASK | + igc_tx_timestamp_dynflag); /* If a Context Descriptor need be built . */ if (tx_ol_req) { @@ -1675,7 +1683,11 @@ * The "last descriptor" of the previously sent packet, if any, * which used the last descriptor to allocate. */ - tx_end = sw_ring[tx_last].last_id; + tx_end = (uint16_t)(tx_last); + if (tx_end >= txq->nb_tx_desc) + tx_end = (uint16_t)(tx_end - txq->nb_tx_desc); + + tx_end = sw_ring[tx_end].last_id; /* * The next descriptor following that "last descriptor" in the diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_bypass_api.h dpdk-24.11.8/drivers/net/ixgbe/ixgbe_bypass_api.h --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_bypass_api.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_bypass_api.h 2026-10-14 13:10:05.000000000 +0000 @@ -40,16 +40,10 @@ dir_sdo = IXGBE_ESDP_SDP6_DIR; break; case ixgbe_mac_X540: - sck = IXGBE_ESDP_SDP2; - sdi = IXGBE_ESDP_SDP0; - sdo = IXGBE_ESDP_SDP1; - dir_sck = IXGBE_ESDP_SDP2_DIR; - dir_sdi = IXGBE_ESDP_SDP0_DIR; - dir_sdo = IXGBE_ESDP_SDP1_DIR; - break; case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_X550EM_a: + case ixgbe_mac_E610: sck = IXGBE_ESDP_SDP2; sdi = IXGBE_ESDP_SDP0; sdo = IXGBE_ESDP_SDP1; diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ethdev.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ethdev.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -907,7 +907,8 @@ (hw->mac.type != ixgbe_mac_X540) && (hw->mac.type != ixgbe_mac_X550) && (hw->mac.type != ixgbe_mac_X550EM_x) && - (hw->mac.type != ixgbe_mac_X550EM_a)) + (hw->mac.type != ixgbe_mac_X550EM_a) && + (hw->mac.type != ixgbe_mac_E610)) return -ENOSYS; PMD_INIT_LOG(DEBUG, "Setting port %d, %s queue_id %d to stat index %d", @@ -1819,7 +1820,7 @@ representor.vf_id = eth_da.representor_ports[i]; representor.switch_domain_id = vfinfo->switch_domain_id; - representor.pf_ethdev = pf_ethdev; + representor.pf_port_id = pf_ethdev->data->port_id; /* representor port net_bdf_port */ snprintf(name, sizeof(name), "net_%s_representor_%d", @@ -2130,10 +2131,11 @@ ctrl |= IXGBE_EXTENDED_VLAN; IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl); - /* Clear pooling mode of PFVTCTL. It's required by X550. */ + /* Clear pooling mode of PFVTCTL. It's required by X550 and E610. */ if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a) { + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) { ctrl = IXGBE_READ_REG(hw, IXGBE_VT_CTL); ctrl &= ~IXGBE_VT_CTL_POOLING_MODE_MASK; IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, ctrl); @@ -2821,6 +2823,7 @@ case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_X550EM_a: + case ixgbe_mac_E610: speed = IXGBE_LINK_SPEED_X550_AUTONEG; break; default: @@ -3177,8 +3180,9 @@ uint64_t *total_missed_rx, uint64_t *total_qbrc, uint64_t *total_qprc, uint64_t *total_qprdc) { - uint32_t bprc, lxon, lxoff, total; - uint32_t delta_gprc = 0; + uint32_t bprc, lxon, lxoff; + uint64_t total; + uint64_t delta_gprc = 0; unsigned i; /* Workaround for RX byte count not including CRC bytes when CRC * strip is enabled. CRC bytes are removed from counters when crc_strip @@ -3233,7 +3237,7 @@ hw_stats->qbrc[i] += ((uint64_t)IXGBE_READ_REG(hw, IXGBE_QBRC_H(i)) << 32); if (crc_strip == 0) - hw_stats->qbrc[i] -= delta_qprc * RTE_ETHER_CRC_LEN; + hw_stats->qbrc[i] -= (uint64_t)delta_qprc * RTE_ETHER_CRC_LEN; hw_stats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i)); hw_stats->qbtc[i] += @@ -3306,7 +3310,7 @@ hw_stats->lxontxc += lxon; lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); hw_stats->lxofftxc += lxoff; - total = lxon + lxoff; + total = (uint64_t)lxon + lxoff; hw_stats->mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); hw_stats->ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); @@ -3618,8 +3622,9 @@ PMD_INIT_LOG(ERR, "id value isn't valid"); return -1; } - strcpy(xstats_names[i].name, - xstats_names_copy[ids[i]].name); + strlcpy(xstats_names[i].name, + xstats_names_copy[ids[i]].name, + sizeof(xstats_names[i].name)); } return limit; } @@ -4033,10 +4038,11 @@ if (hw->mac.type == ixgbe_mac_X540 || hw->mac.type == ixgbe_mac_X540_vf || hw->mac.type == ixgbe_mac_X550 || - hw->mac.type == ixgbe_mac_X550_vf) { + hw->mac.type == ixgbe_mac_X550_vf || + hw->mac.type == ixgbe_mac_E610) { dev_info->speed_capa |= RTE_ETH_LINK_SPEED_100M; } - if (hw->mac.type == ixgbe_mac_X550) { + if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_E610) { dev_info->speed_capa |= RTE_ETH_LINK_SPEED_2_5G; dev_info->speed_capa |= RTE_ETH_LINK_SPEED_5G; } @@ -7412,6 +7418,12 @@ if (rte_eal_process_type() != RTE_PROC_PRIMARY) return -E_RTE_SECONDARY; + if (hw->phy.media_type == ixgbe_media_type_copper) { + PMD_DRV_LOG(DEBUG, "Port %u is Base-T (copper), no SFF module info.", + dev->data->port_id); + return -ENOTSUP; + } + /* Check whether we support SFF-8472 or not */ status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_SFF_8472_COMP, @@ -7465,6 +7477,12 @@ if (rte_eal_process_type() != RTE_PROC_PRIMARY) return -E_RTE_SECONDARY; + if (hw->phy.media_type == ixgbe_media_type_copper) { + PMD_DRV_LOG(DEBUG, "Port %u is Base-T (copper), cannot read module EEPROM.", + dev->data->port_id); + return -ENOTSUP; + } + for (i = info->offset; i < info->offset + info->length; i++) { if (i < RTE_ETH_MODULE_SFF_8079_LEN) status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte); @@ -7659,7 +7677,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { return -ENOTSUP; } @@ -7680,7 +7699,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { return -ENOTSUP; } @@ -7703,7 +7723,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { return -ENOTSUP; } @@ -7739,7 +7760,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { return -ENOTSUP; } @@ -7926,7 +7948,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { return -ENOTSUP; } diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ethdev.h dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ethdev.h --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ethdev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ethdev.h 2026-10-14 13:10:05.000000000 +0000 @@ -165,6 +165,7 @@ uint32_t dst_ipv4_mask; uint16_t src_ipv6_mask; uint16_t dst_ipv6_mask; + uint8_t l4_proto_match; uint16_t src_port_mask; uint16_t dst_port_mask; uint16_t flex_bytes_mask; @@ -359,6 +360,8 @@ struct rte_flow { enum rte_filter_type filter_type; + /* security flows are not rte_filter_type */ + bool is_security; void *rule; }; @@ -518,7 +521,7 @@ struct ixgbe_vf_representor { uint16_t vf_id; uint16_t switch_domain_id; - struct rte_eth_dev *pf_ethdev; + uint16_t pf_port_id; }; int ixgbe_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params); diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_fdir.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_fdir.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_fdir.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_fdir.c 2026-10-14 13:10:05.000000000 +0000 @@ -67,8 +67,7 @@ #define IPV6_MASK_TO_ADDR(ipv6m, ipaddr) do { \ uint8_t ipv6_addr[16]; \ - uint8_t i; \ - for (i = 0; i < sizeof(ipv6_addr); i++) { \ + for (uint8_t i = 0; i < sizeof(ipv6_addr); i++) { \ if ((ipv6m) & (1 << i)) \ ipv6_addr[i] = UINT8_MAX; \ else \ @@ -80,8 +79,6 @@ #define IXGBE_FDIRIP6M_INNER_MAC_SHIFT 4 static int fdir_erase_filter_82599(struct ixgbe_hw *hw, uint32_t fdirhash); -static int fdir_set_input_mask(struct rte_eth_dev *dev, - const struct rte_eth_fdir_masks *input_mask); static int fdir_set_input_mask_82599(struct rte_eth_dev *dev); static int fdir_set_input_mask_x550(struct rte_eth_dev *dev); static int ixgbe_set_fdir_flex_conf(struct rte_eth_dev *dev, @@ -267,14 +264,8 @@ PMD_INIT_FUNC_TRACE(); - /* - * Program the relevant mask registers. If src/dst_port or src/dst_addr - * are zero, then assume a full mask for that field. Also assume that - * a VLAN of 0 is unspecified, so mask that out as well. L4type - * cannot be masked out in this implementation. - */ - if (info->mask.dst_port_mask == 0 && info->mask.src_port_mask == 0) - /* use the L4 protocol mask for raw IPv4/IPv6 traffic */ + if (!info->mask.l4_proto_match) + /* set L4P to ignore L4 protocol for IP traffic */ fdirm |= IXGBE_FDIRM_L4P; if (info->mask.vlan_tci_mask == rte_cpu_to_be_16(0x0FFF)) @@ -307,7 +298,12 @@ */ IXGBE_WRITE_REG(hw, IXGBE_FDIRTCPM, ~fdirtcpm); IXGBE_WRITE_REG(hw, IXGBE_FDIRUDPM, ~fdirtcpm); - IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm); + /* only certain MAC types have SCTP masking register */ + if (hw->mac.type == ixgbe_mac_X550 || + hw->mac.type == ixgbe_mac_X550EM_x || + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) + IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm); /* Store source and destination IPv4 masks (big-endian), * can not use IXGBE_WRITE_REG. @@ -426,62 +422,6 @@ return IXGBE_SUCCESS; } -static int -ixgbe_fdir_store_input_mask_82599(struct rte_eth_dev *dev, - const struct rte_eth_fdir_masks *input_mask) -{ - struct ixgbe_hw_fdir_info *info = - IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private); - uint16_t dst_ipv6m = 0; - uint16_t src_ipv6m = 0; - - memset(&info->mask, 0, sizeof(struct ixgbe_hw_fdir_mask)); - info->mask.vlan_tci_mask = input_mask->vlan_tci_mask; - info->mask.src_port_mask = input_mask->src_port_mask; - info->mask.dst_port_mask = input_mask->dst_port_mask; - info->mask.src_ipv4_mask = input_mask->ipv4_mask.src_ip; - info->mask.dst_ipv4_mask = input_mask->ipv4_mask.dst_ip; - IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.src_ip, src_ipv6m); - IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.dst_ip, dst_ipv6m); - info->mask.src_ipv6_mask = src_ipv6m; - info->mask.dst_ipv6_mask = dst_ipv6m; - - return IXGBE_SUCCESS; -} - -static int -ixgbe_fdir_store_input_mask_x550(struct rte_eth_dev *dev, - const struct rte_eth_fdir_masks *input_mask) -{ - struct ixgbe_hw_fdir_info *info = - IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private); - - memset(&info->mask, 0, sizeof(struct ixgbe_hw_fdir_mask)); - info->mask.vlan_tci_mask = input_mask->vlan_tci_mask; - info->mask.mac_addr_byte_mask = input_mask->mac_addr_byte_mask; - info->mask.tunnel_type_mask = input_mask->tunnel_type_mask; - info->mask.tunnel_id_mask = input_mask->tunnel_id_mask; - - return IXGBE_SUCCESS; -} - -static int -ixgbe_fdir_store_input_mask(struct rte_eth_dev *dev, - const struct rte_eth_fdir_masks *input_mask) -{ - enum rte_fdir_mode mode = IXGBE_DEV_FDIR_CONF(dev)->mode; - - if (mode >= RTE_FDIR_MODE_SIGNATURE && - mode <= RTE_FDIR_MODE_PERFECT) - return ixgbe_fdir_store_input_mask_82599(dev, input_mask); - else if (mode >= RTE_FDIR_MODE_PERFECT_MAC_VLAN && - mode <= RTE_FDIR_MODE_PERFECT_TUNNEL) - return ixgbe_fdir_store_input_mask_x550(dev, input_mask); - - PMD_DRV_LOG(ERR, "Not supported fdir mode - %d!", mode); - return -ENOTSUP; -} - int ixgbe_fdir_set_input_mask(struct rte_eth_dev *dev) { @@ -552,19 +492,6 @@ return 0; } -static int -fdir_set_input_mask(struct rte_eth_dev *dev, - const struct rte_eth_fdir_masks *input_mask) -{ - int ret; - - ret = ixgbe_fdir_store_input_mask(dev, input_mask); - if (ret) - return ret; - - return ixgbe_fdir_set_input_mask(dev); -} - /* * ixgbe_check_fdir_flex_conf -check if the flex payload and mask configuration * arguments are valid @@ -651,10 +578,11 @@ hw->mac.type != ixgbe_mac_E610) return -ENOSYS; - /* x550 supports mac-vlan and tunnel mode but other NICs not */ + /* x550 and E610 supports mac-vlan and tunnel mode but other NICs not */ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610 && mode != RTE_FDIR_MODE_SIGNATURE && mode != RTE_FDIR_MODE_PERFECT) return -ENOSYS; @@ -681,7 +609,7 @@ for (i = 1; i < 8; i++) IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0); - err = fdir_set_input_mask(dev, &IXGBE_DEV_FDIR_CONF(dev)->mask); + err = ixgbe_fdir_set_input_mask(dev); if (err < 0) { PMD_INIT_LOG(ERR, " Error on setting FD mask"); return err; @@ -1131,7 +1059,7 @@ return -ENOTSUP; /* - * Sanity check for x550. + * Sanity check for x550 and E610. * When adding a new filter with flow type set to IPv4, * the flow director mask should be configed before, * and the L4 protocol and ports are masked. @@ -1139,7 +1067,8 @@ if ((!del) && (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a) && + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) && (rule->ixgbe_fdir.formatted.flow_type == IXGBE_ATR_FLOW_TYPE_IPV4 || rule->ixgbe_fdir.formatted.flow_type == @@ -1282,7 +1211,7 @@ struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct ixgbe_hw_fdir_info *info = IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private); - uint32_t fdirctrl, max_num, i; + uint32_t fdirctrl, max_num; uint8_t offset; fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); @@ -1317,7 +1246,7 @@ fdir_info->flow_types_mask[0] = 0ULL; else fdir_info->flow_types_mask[0] = IXGBE_FDIR_FLOW_TYPES; - for (i = 1; i < RTE_FLOW_MASK_ARRAY_SIZE; i++) + for (uint32_t i = 1; i < RTE_FLOW_MASK_ARRAY_SIZE; i++) fdir_info->flow_types_mask[i] = 0ULL; fdir_info->flex_payload_unit = sizeof(uint16_t); @@ -1429,6 +1358,7 @@ int ixgbe_clear_all_fdir_filter(struct rte_eth_dev *dev) { + struct rte_eth_fdir_conf *fdir_conf = IXGBE_DEV_FDIR_CONF(dev); struct ixgbe_hw_fdir_info *fdir_info = IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private); struct ixgbe_fdir_filter *fdir_filter; @@ -1447,6 +1377,12 @@ rte_free(fdir_filter); } + /* reset internal FDIR state */ + fdir_info->mask = (struct ixgbe_hw_fdir_mask){0}; + fdir_info->flex_bytes_offset = 0; + fdir_info->mask_added = FALSE; + fdir_conf->mode = RTE_FDIR_MODE_NONE; + if (filter_flag != NULL) ret = ixgbe_fdir_flush(dev); diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_flow.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_flow.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -221,6 +221,13 @@ act = next_no_void_action(actions, NULL); if (act->type == RTE_FLOW_ACTION_TYPE_SECURITY) { const void *conf = act->conf; + + if (conf == NULL) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + act, "NULL security conf."); + return -rte_errno; + } /* check if the next not void item is END */ act = next_no_void_action(actions, act); if (act->type != RTE_FLOW_ACTION_TYPE_END) { @@ -244,6 +251,12 @@ } item = next_no_void_pattern(pattern, item); } + if (item->spec == NULL) { + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, item, + "NULL IP pattern."); + return -rte_errno; + } filter->proto = IPPROTO_ESP; return ixgbe_crypto_add_ingress_sa_from_flow(conf, item->spec, @@ -275,14 +288,10 @@ } /* if the first item is MAC, the content should be NULL */ - if ((item->spec || item->mask) && - (memcmp(eth_spec, ð_null, - sizeof(struct rte_flow_item_eth)) || - memcmp(eth_mask, ð_null, - sizeof(struct rte_flow_item_eth)))) { - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, "Not supported by ntuple filter"); + if ((item->spec != NULL && memcmp(eth_spec, ð_null, sizeof(eth_null)) != 0) || + (item->mask != NULL && memcmp(eth_mask, ð_null, sizeof(eth_null)) != 0)) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, + "Not supported by ntuple filter"); return -rte_errno; } /* check if the next not void item is IPv4 or Vlan */ @@ -308,15 +317,10 @@ return -rte_errno; } /* the content should be NULL */ - if ((item->spec || item->mask) && - (memcmp(vlan_spec, &vlan_null, - sizeof(struct rte_flow_item_vlan)) || - memcmp(vlan_mask, &vlan_null, - sizeof(struct rte_flow_item_vlan)))) { - - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, "Not supported by ntuple filter"); + if ((item->spec != NULL && memcmp(vlan_spec, &vlan_null, sizeof(vlan_null)) != 0) || + (item->mask != NULL && memcmp(vlan_mask, &vlan_null, sizeof(vlan_null)) != 0)) { + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, + "Not supported by ntuple filter"); return -rte_errno; } /* check if the next not void item is IPv4 */ @@ -1361,7 +1365,8 @@ if (hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { memset(l2_tn_filter, 0, sizeof(struct ixgbe_l2_tunnel_conf)); rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, @@ -1644,6 +1649,7 @@ memset(&rule->mask, 0xFF, sizeof(struct ixgbe_hw_fdir_mask)); rule->mask.vlan_tci_mask = 0; rule->mask.flex_bytes_mask = 0; + rule->mask.l4_proto_match = 0; rule->mask.dst_port_mask = 0; rule->mask.src_port_mask = 0; @@ -2111,57 +2117,55 @@ return -rte_errno; } - /* only some mac types support sctp port */ - if (hw->mac.type == ixgbe_mac_X550 || - hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a || - hw->mac.type == ixgbe_mac_E610) { - /** - * Only care about src & dst ports, - * others should be masked. - */ - if (!item->mask) { - memset(rule, 0, sizeof(struct ixgbe_fdir_rule)); - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, "Not supported by fdir filter"); - return -rte_errno; - } - rule->b_mask = TRUE; - sctp_mask = item->mask; - if (sctp_mask->hdr.tag || - sctp_mask->hdr.cksum) { - memset(rule, 0, sizeof(struct ixgbe_fdir_rule)); - rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ITEM, - item, "Not supported by fdir filter"); - return -rte_errno; - } - rule->mask.src_port_mask = sctp_mask->hdr.src_port; - rule->mask.dst_port_mask = sctp_mask->hdr.dst_port; + sctp_mask = item->mask; + if (sctp_mask != NULL) { + /* only some mac types support sctp port masking */ + if (hw->mac.type == ixgbe_mac_X550 || + hw->mac.type == ixgbe_mac_X550EM_x || + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) { + /** + * Only care about src & dst ports, + * others should be masked. + */ + rule->b_mask = TRUE; + if (sctp_mask->hdr.tag || + sctp_mask->hdr.cksum) { + memset(rule, 0, sizeof(struct ixgbe_fdir_rule)); + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, "Not supported by fdir filter"); + return -rte_errno; + } + rule->mask.src_port_mask = sctp_mask->hdr.src_port; + rule->mask.dst_port_mask = sctp_mask->hdr.dst_port; - if (item->spec) { - rule->b_spec = TRUE; - sctp_spec = item->spec; - rule->ixgbe_fdir.formatted.src_port = - sctp_spec->hdr.src_port; - rule->ixgbe_fdir.formatted.dst_port = - sctp_spec->hdr.dst_port; - } - /* others even sctp port is not supported */ - } else { - sctp_mask = item->mask; - if (sctp_mask && - (sctp_mask->hdr.src_port || - sctp_mask->hdr.dst_port || - sctp_mask->hdr.tag || - sctp_mask->hdr.cksum)) { + if (item->spec) { + rule->b_spec = TRUE; + sctp_spec = item->spec; + rule->ixgbe_fdir.formatted.src_port = + sctp_spec->hdr.src_port; + rule->ixgbe_fdir.formatted.dst_port = + sctp_spec->hdr.dst_port; + } + /* others even sctp port masking is not supported */ + } else if (sctp_mask->hdr.src_port || + sctp_mask->hdr.dst_port || + sctp_mask->hdr.tag || + sctp_mask->hdr.cksum) { memset(rule, 0, sizeof(struct ixgbe_fdir_rule)); rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item, "Not supported by fdir filter"); return -rte_errno; } + } else if (item->spec != NULL) { + /* No port mask means protocol-only match; spec is invalid. */ + memset(rule, 0, sizeof(struct ixgbe_fdir_rule)); + rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + item, "Not supported by fdir filter"); + return -rte_errno; } item = next_no_fuzzy_pattern(pattern, item); @@ -2258,6 +2262,10 @@ } } + /* L4 protocol matching is enabled when parser selected an L4 type. */ + rule->mask.l4_proto_match = + (rule->ixgbe_fdir.formatted.flow_type & IXGBE_ATR_L4TYPE_MASK) != 0; + return ixgbe_parse_fdir_act_attr(attr, actions, rule, error); } @@ -2785,12 +2793,6 @@ step_next: - if (hw->mac.type == ixgbe_mac_82599EB && - rule->fdirflags == IXGBE_FDIRCMD_DROP && - (rule->ixgbe_fdir.formatted.src_port != 0 || - rule->ixgbe_fdir.formatted.dst_port != 0)) - return -ENOTSUP; - if (fdir_conf->mode == RTE_FDIR_MODE_NONE) { fdir_conf->mode = rule->mode; ret = ixgbe_fdir_configure(dev); @@ -3061,8 +3063,12 @@ #ifdef RTE_LIB_SECURITY /* ESP flow not really a flow*/ - if (ntuple_filter.proto == IPPROTO_ESP) + if (ntuple_filter.proto == IPPROTO_ESP) { + if (ret != 0) + goto out; + flow->is_security = true; return flow; + } #endif if (!ret) { @@ -3351,6 +3357,12 @@ IXGBE_DEV_PRIVATE_TO_FDIR_INFO(dev->data->dev_private); struct ixgbe_rss_conf_ele *rss_filter_ptr; + /* Special case for SECURITY flows */ + if (flow->is_security) { + ret = 0; + goto free; + } + switch (filter_type) { case RTE_ETH_FILTER_NTUPLE: ntuple_filter_ptr = (struct ixgbe_ntuple_filter_ele *) @@ -3399,11 +3411,16 @@ sizeof(struct ixgbe_fdir_rule)); ret = ixgbe_fdir_filter_program(dev, &fdir_rule, TRUE, FALSE); if (!ret) { + struct rte_eth_fdir_conf *fdir_conf = IXGBE_DEV_FDIR_CONF(dev); TAILQ_REMOVE(&filter_fdir_list, fdir_rule_ptr, entries); rte_free(fdir_rule_ptr); - if (TAILQ_EMPTY(&filter_fdir_list)) + if (TAILQ_EMPTY(&filter_fdir_list)) { fdir_info->mask_added = false; + fdir_info->mask = (struct ixgbe_hw_fdir_mask){0}; + fdir_info->flex_bytes_offset = 0; + fdir_conf->mode = RTE_FDIR_MODE_NONE; + } } break; case RTE_ETH_FILTER_L2_TUNNEL: @@ -3443,6 +3460,7 @@ return ret; } +free: TAILQ_FOREACH(ixgbe_flow_mem_ptr, &ixgbe_flow_list, entries) { if (ixgbe_flow_mem_ptr->flow == pmd_flow) { TAILQ_REMOVE(&ixgbe_flow_list, diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ipsec.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ipsec.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ipsec.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ipsec.c 2026-10-14 13:10:05.000000000 +0000 @@ -88,10 +88,10 @@ static int ixgbe_crypto_add_sa(struct ixgbe_crypto_session *ic_session) { - struct rte_eth_dev *dev = ic_session->dev; - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_eth_dev_data *dev_data = ic_session->dev_data; + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev_data->dev_private); struct ixgbe_ipsec *priv = IXGBE_DEV_PRIVATE_TO_IPSEC( - dev->data->dev_private); + dev_data->dev_private); uint32_t reg_val; int sa_index = -1; @@ -405,7 +405,7 @@ memcpy(&ic_session->salt, &aead_xform->key.data[aead_xform->key.length], 4); ic_session->spi = conf->ipsec.spi; - ic_session->dev = eth_dev; + ic_session->dev_data = eth_dev->data; if (ic_session->op == IXGBE_OP_AUTHENTICATED_ENCRYPTION) { if (ixgbe_crypto_add_sa(ic_session)) { @@ -430,7 +430,7 @@ struct rte_eth_dev *eth_dev = device; struct ixgbe_crypto_session *ic_session = SECURITY_GET_SESS_PRIV(session); - if (eth_dev != ic_session->dev) { + if (eth_dev->data != ic_session->dev_data) { PMD_DRV_LOG(ERR, "Session not bound to this device"); return -ENODEV; } diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ipsec.h dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ipsec.h --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_ipsec.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_ipsec.h 2026-10-14 13:10:05.000000000 +0000 @@ -5,6 +5,7 @@ #ifndef IXGBE_IPSEC_H_ #define IXGBE_IPSEC_H_ +#include #include #define IPSRXIDX_RX_EN 0x00000001 @@ -69,7 +70,7 @@ uint32_t spi; struct ipaddr src_ip; struct ipaddr dst_ip; - struct rte_eth_dev *dev; + struct rte_eth_dev_data *dev_data; }; struct ixgbe_crypto_rx_ip_table { diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_pf.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_pf.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_pf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_pf.c 2026-10-14 13:10:05.000000000 +0000 @@ -558,11 +558,12 @@ uint32_t max_frs; uint32_t hlreg0; - /* X540 and X550 support jumbo frames in IOV mode */ + /* X540, X550, and E610 support jumbo frames in IOV mode */ if (hw->mac.type != ixgbe_mac_X540 && hw->mac.type != ixgbe_mac_X550 && hw->mac.type != ixgbe_mac_X550EM_x && - hw->mac.type != ixgbe_mac_X550EM_a) { + hw->mac.type != ixgbe_mac_X550EM_a && + hw->mac.type != ixgbe_mac_E610) { struct ixgbe_vf_info *vfinfo = *IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private); diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_rxtx.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_rxtx.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -2602,7 +2602,8 @@ if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a) + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) tx_offload_capa |= RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM; #ifdef RTE_LIB_SECURITY @@ -3059,7 +3060,8 @@ if (hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a) + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) offloads |= RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM; #ifdef RTE_LIB_SECURITY @@ -3129,7 +3131,7 @@ /* * The packet type in RX descriptor is different for different NICs. - * Some bits are used for x550 but reserved for other NICS. + * Some bits are used for x550 and E610 but reserved for other NICS. * So set different masks for different NICs. */ if (hw->mac.type == ixgbe_mac_X550 || @@ -3137,7 +3139,8 @@ hw->mac.type == ixgbe_mac_X550EM_a || hw->mac.type == ixgbe_mac_X550_vf || hw->mac.type == ixgbe_mac_X550EM_x_vf || - hw->mac.type == ixgbe_mac_X550EM_a_vf) + hw->mac.type == ixgbe_mac_X550EM_a_vf || + hw->mac.type == ixgbe_mac_E610) rxq->pkt_type_mask = IXGBE_PACKET_TYPE_MASK_X550; else rxq->pkt_type_mask = IXGBE_PACKET_TYPE_MASK_82599; @@ -3403,7 +3406,8 @@ if (hw->mac.type == ixgbe_mac_X540 || hw->mac.type == ixgbe_mac_X550 || hw->mac.type == ixgbe_mac_X550EM_x || - hw->mac.type == ixgbe_mac_X550EM_a) + hw->mac.type == ixgbe_mac_X550EM_a || + hw->mac.type == ixgbe_mac_E610) ixgbe_setup_loopback_link_x540_x550(hw, false); } } @@ -3658,13 +3662,14 @@ hash_key = rss_conf->rss_key; if (hash_key != NULL) { /* Return RSS hash key */ - for (i = 0; i < 10; i++) { + for (i = 0; i < IXGBE_HKEY_MAX_INDEX; i++) { rss_key = IXGBE_READ_REG_ARRAY(hw, rssrk_reg, i); hash_key[(i * 4)] = rss_key & 0x000000FF; hash_key[(i * 4) + 1] = (rss_key >> 8) & 0x000000FF; hash_key[(i * 4) + 2] = (rss_key >> 16) & 0x000000FF; hash_key[(i * 4) + 3] = (rss_key >> 24) & 0x000000FF; } + rss_conf->rss_key_len = IXGBE_HKEY_MAX_INDEX * sizeof(uint32_t); } if (!ixgbe_rss_enabled(hw)) { /* RSS is disabled */ diff -Nru dpdk-24.11.4/drivers/net/ixgbe/ixgbe_vf_representor.c dpdk-24.11.8/drivers/net/ixgbe/ixgbe_vf_representor.c --- dpdk-24.11.4/drivers/net/ixgbe/ixgbe_vf_representor.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ixgbe/ixgbe_vf_representor.c 2026-10-14 13:10:05.000000000 +0000 @@ -13,14 +13,27 @@ #include "ixgbe_rxtx.h" #include "rte_pmd_ixgbe.h" +static struct rte_eth_dev * +ixgbe_vf_representor_pf_get(const struct ixgbe_vf_representor *representor) +{ + if (!rte_eth_dev_is_valid_port(representor->pf_port_id)) + return NULL; + + return &rte_eth_devices[representor->pf_port_id]; +} + static int ixgbe_vf_representor_link_update(struct rte_eth_dev *ethdev, int wait_to_complete) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev = ixgbe_vf_representor_pf_get(representor); - return ixgbe_dev_link_update_share(representor->pf_ethdev, + if (pf_ethdev == NULL) + return -ENODEV; + + return ixgbe_dev_link_update_share(pf_ethdev, wait_to_complete, 0); } @@ -29,9 +42,13 @@ struct rte_ether_addr *mac_addr) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev = ixgbe_vf_representor_pf_get(representor); + + if (pf_ethdev == NULL) + return -ENODEV; return rte_pmd_ixgbe_set_vf_mac_addr( - representor->pf_ethdev->data->port_id, + pf_ethdev->data->port_id, representor->vf_id, mac_addr); } @@ -40,11 +57,14 @@ struct rte_eth_dev_info *dev_info) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev = ixgbe_vf_representor_pf_get(representor); - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW( - representor->pf_ethdev->data->dev_private); + if (pf_ethdev == NULL) + return -ENODEV; + + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(pf_ethdev->data->dev_private); - dev_info->device = representor->pf_ethdev->device; + dev_info->device = pf_ethdev->device; dev_info->min_rx_bufsize = 1024; /**< Minimum size of RX buffer. */ @@ -70,11 +90,11 @@ /**< Device TX offload capabilities. */ dev_info->speed_capa = - representor->pf_ethdev->data->dev_link.link_speed; + pf_ethdev->data->dev_link.link_speed; /**< Supported speeds bitmap (RTE_ETH_LINK_SPEED_). */ dev_info->switch_info.name = - representor->pf_ethdev->device->name; + pf_ethdev->device->name; dev_info->switch_info.domain_id = representor->switch_domain_id; dev_info->switch_info.port_id = representor->vf_id; @@ -123,10 +143,14 @@ uint16_t vlan_id, int on) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev = ixgbe_vf_representor_pf_get(representor); uint64_t vf_mask = 1ULL << representor->vf_id; + if (pf_ethdev == NULL) + return -ENODEV; + return rte_pmd_ixgbe_set_vf_vlan_filter( - representor->pf_ethdev->data->port_id, vlan_id, vf_mask, on); + pf_ethdev->data->port_id, vlan_id, vf_mask, on); } static void @@ -134,8 +158,12 @@ __rte_unused uint16_t rx_queue_id, int on) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev = ixgbe_vf_representor_pf_get(representor); - rte_pmd_ixgbe_set_vf_vlan_stripq(representor->pf_ethdev->data->port_id, + if (pf_ethdev == NULL) + return; + + rte_pmd_ixgbe_set_vf_vlan_stripq(pf_ethdev->data->port_id, representor->vf_id, on); } @@ -175,6 +203,7 @@ ixgbe_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params) { struct ixgbe_vf_representor *representor = ethdev->data->dev_private; + struct rte_eth_dev *pf_ethdev; struct ixgbe_vf_info *vf_data; struct rte_pci_device *pci_dev; @@ -187,17 +216,21 @@ ((struct ixgbe_vf_representor *)init_params)->vf_id; representor->switch_domain_id = ((struct ixgbe_vf_representor *)init_params)->switch_domain_id; - representor->pf_ethdev = - ((struct ixgbe_vf_representor *)init_params)->pf_ethdev; + representor->pf_port_id = + ((struct ixgbe_vf_representor *)init_params)->pf_port_id; + + pf_ethdev = ixgbe_vf_representor_pf_get(representor); + if (pf_ethdev == NULL) + return -ENODEV; - pci_dev = RTE_ETH_DEV_TO_PCI(representor->pf_ethdev); + pci_dev = RTE_ETH_DEV_TO_PCI(pf_ethdev); if (representor->vf_id >= pci_dev->max_vfs) return -ENODEV; ethdev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; ethdev->data->representor_id = representor->vf_id; - ethdev->data->backer_port_id = representor->pf_ethdev->data->port_id; + ethdev->data->backer_port_id = pf_ethdev->data->port_id; /* Set representor device ops */ ethdev->dev_ops = &ixgbe_vf_representor_dev_ops; @@ -214,13 +247,13 @@ /* Reference VF mac address from PF data structure */ vf_data = *IXGBE_DEV_PRIVATE_TO_P_VFDATA( - representor->pf_ethdev->data->dev_private); + pf_ethdev->data->dev_private); ethdev->data->mac_addrs = (struct rte_ether_addr *) vf_data[representor->vf_id].vf_mac_addresses; /* Link state. Inherited from PF */ - link = &representor->pf_ethdev->data->dev_link; + link = &pf_ethdev->data->dev_link; ethdev->data->dev_link.link_speed = link->link_speed; ethdev->data->dev_link.link_duplex = link->link_duplex; diff -Nru dpdk-24.11.4/drivers/net/mana/mana.c dpdk-24.11.8/drivers/net/mana/mana.c --- dpdk-24.11.4/drivers/net/mana/mana.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mana/mana.c 2026-10-14 13:10:05.000000000 +0000 @@ -282,6 +282,20 @@ if (ret) return ret; + if (priv->ib_parent_pd) { + int err = ibv_dealloc_pd(priv->ib_parent_pd); + if (err) + DRV_LOG(ERR, "Failed to deallocate parent PD: %d", err); + priv->ib_parent_pd = NULL; + } + + if (priv->ib_pd) { + int err = ibv_dealloc_pd(priv->ib_pd); + if (err) + DRV_LOG(ERR, "Failed to deallocate PD: %d", err); + priv->ib_pd = NULL; + } + ret = ibv_close_device(priv->ib_ctx); if (ret) { ret = errno; diff -Nru dpdk-24.11.4/drivers/net/mana/mana.h dpdk-24.11.8/drivers/net/mana/mana.h --- dpdk-24.11.4/drivers/net/mana/mana.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mana/mana.h 2026-10-14 13:10:05.000000000 +0000 @@ -442,7 +442,7 @@ /* desc_ring_head is where we put pending requests to ring, * completion pull off desc_ring_tail */ - uint32_t desc_ring_head, desc_ring_tail; + uint32_t desc_ring_head, desc_ring_tail, desc_ring_len; #ifdef RTE_ARCH_32 /* For storing wqe increment count btw each short doorbell ring */ diff -Nru dpdk-24.11.4/drivers/net/mana/mp.c dpdk-24.11.8/drivers/net/mana/mp.c --- dpdk-24.11.4/drivers/net/mana/mp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mana/mp.c 2026-10-14 13:10:05.000000000 +0000 @@ -145,6 +145,11 @@ dev->tx_pkt_burst = mana_tx_burst; dev->rx_pkt_burst = mana_rx_burst; + rte_eth_fp_ops[param->port_id].rx_pkt_burst = mana_rx_burst; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = mana_tx_burst; + rte_eth_fp_ops[param->port_id].rxq.data = dev->data->rx_queues; + rte_eth_fp_ops[param->port_id].txq.data = dev->data->tx_queues; + rte_mb(); res->result = 0; @@ -154,6 +159,9 @@ case MANA_MP_REQ_STOP_RXTX: DRV_LOG(INFO, "Port %u stopping datapath", dev->data->port_id); + rte_eth_fp_ops[param->port_id].rx_pkt_burst = mana_rx_burst_removed; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = mana_tx_burst_removed; + dev->tx_pkt_burst = mana_tx_burst_removed; dev->rx_pkt_burst = mana_rx_burst_removed; diff -Nru dpdk-24.11.4/drivers/net/mana/rx.c dpdk-24.11.8/drivers/net/mana/rx.c --- dpdk-24.11.4/drivers/net/mana/rx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mana/rx.c 2026-10-14 13:10:05.000000000 +0000 @@ -102,6 +102,7 @@ rxq->wqe_cnt_to_short_db += wqe_size_in_bu; #endif rxq->desc_ring_head = (rxq->desc_ring_head + 1) % rxq->num_desc; + rxq->desc_ring_len++; } else { DP_LOG(DEBUG, "failed to post recv ret %d", ret); return ret; @@ -215,7 +216,7 @@ } /* Drain and free posted WQEs */ - while (rxq->desc_ring_tail != rxq->desc_ring_head) { + while (rxq->desc_ring_len > 0) { struct mana_rxq_desc *desc = &rxq->desc_ring[rxq->desc_ring_tail]; @@ -223,9 +224,11 @@ rxq->desc_ring_tail = (rxq->desc_ring_tail + 1) % rxq->num_desc; + rxq->desc_ring_len--; } rxq->desc_ring_head = 0; rxq->desc_ring_tail = 0; + rxq->desc_ring_len = 0; memset(&rxq->gdma_rq, 0, sizeof(rxq->gdma_rq)); memset(&rxq->gdma_cq, 0, sizeof(rxq->gdma_cq)); @@ -560,6 +563,7 @@ rxq->desc_ring_tail = 0; rxq->gdma_rq.tail += desc->wqe_size_in_bu; + rxq->desc_ring_len--; /* Record the number of the RX WQE we need to post to replenish * consumed RX requests diff -Nru dpdk-24.11.4/drivers/net/mana/tx.c dpdk-24.11.8/drivers/net/mana/tx.c --- dpdk-24.11.4/drivers/net/mana/tx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mana/tx.c 2026-10-14 13:10:05.000000000 +0000 @@ -39,7 +39,7 @@ } /* Drain and free posted WQEs */ - while (txq->desc_ring_tail != txq->desc_ring_head) { + while (txq->desc_ring_len > 0) { struct mana_txq_desc *desc = &txq->desc_ring[txq->desc_ring_tail]; @@ -228,9 +228,11 @@ txq->gdma_sq.tail += desc->wqe_size_in_bu; /* If TX CQE suppression is used, don't read more CQE but move - * on to the next packet + * on to the next packet. On error CQEs, HW generates one CQE + * per WQE regardless of suppression, so always advance. */ - if (desc->suppress_tx_cqe) + if (desc->suppress_tx_cqe && + oob->cqe_hdr.cqe_type == CQE_TX_OKAY) continue; i++; diff -Nru dpdk-24.11.4/drivers/net/memif/rte_eth_memif.c dpdk-24.11.8/drivers/net/memif/rte_eth_memif.c --- dpdk-24.11.4/drivers/net/memif/rte_eth_memif.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/memif/rte_eth_memif.c 2026-10-14 13:10:05.000000000 +0000 @@ -376,6 +376,12 @@ n_slots--; if (d0->flags & MEMIF_DESC_FLAG_NEXT) { + if (unlikely(n_slots == 0)) { + mq->n_err++; + rte_pktmbuf_free_bulk(mbufs + rx_pkts, + MAX_PKT_BURST - rx_pkts); + goto no_free_bufs; + } mbuf_tail = mbuf; mbuf = rte_pktmbuf_alloc(mq->mempool); if (unlikely(mbuf == NULL)) { @@ -414,13 +420,13 @@ goto no_free_bufs; mbuf = mbuf_head; mbuf->port = mq->in_port; + dst_off = 0; next_slot2: s0 = cur_slot & mask; d0 = &ring->desc[s0]; src_len = d0->length; - dst_off = 0; src_off = 0; do { @@ -462,8 +468,14 @@ cur_slot++; n_slots--; - if (d0->flags & MEMIF_DESC_FLAG_NEXT) + if (d0->flags & MEMIF_DESC_FLAG_NEXT) { + if (unlikely(n_slots == 0)) { + mq->n_err++; + rte_pktmbuf_free(mbuf_head); + goto no_free_bufs; + } goto next_slot2; + } mq->n_bytes += rte_pktmbuf_pkt_len(mbuf_head); *bufs++ = mbuf_head; @@ -712,6 +724,7 @@ next_in_chain1: d0 = &ring->desc[slot & mask]; + d0->flags = 0; cp_len = rte_pktmbuf_data_len(mbuf); rte_memcpy((uint8_t *)memif_get_buffer(proc_private, d0), @@ -724,7 +737,7 @@ if (--nb_segs > 0) { if (n_free) { - d0->flags |= MEMIF_DESC_FLAG_NEXT; + d0->flags = MEMIF_DESC_FLAG_NEXT; mbuf = mbuf->next; goto next_in_chain1; } else { @@ -745,6 +758,7 @@ saved_slot = slot; d0 = &ring->desc[slot & mask]; + d0->flags = 0; dst_off = 0; dst_len = (type == MEMIF_RING_C2S) ? pmd->run.pkt_buffer_size : d0->length; @@ -758,12 +772,12 @@ if (n_free) { slot++; n_free--; - d0->flags |= MEMIF_DESC_FLAG_NEXT; + d0->flags = MEMIF_DESC_FLAG_NEXT; d0 = &ring->desc[slot & mask]; + d0->flags = 0; dst_off = 0; dst_len = (type == MEMIF_RING_C2S) ? pmd->run.pkt_buffer_size : d0->length; - d0->flags = 0; } else { slot = saved_slot; goto no_free_slots; @@ -1600,6 +1614,7 @@ stats->q_ibytes[i] = mq->n_bytes; stats->ipackets += mq->n_pkts; stats->ibytes += mq->n_bytes; + stats->ierrors += mq->n_err; } tmp = (pmd->role == MEMIF_ROLE_CLIENT) ? pmd->run.num_c2s_rings : @@ -1630,12 +1645,14 @@ dev->data->rx_queues[i]; mq->n_pkts = 0; mq->n_bytes = 0; + mq->n_err = 0; } for (i = 0; i < pmd->run.num_s2c_rings; i++) { mq = (pmd->role == MEMIF_ROLE_CLIENT) ? dev->data->rx_queues[i] : dev->data->tx_queues[i]; mq->n_pkts = 0; mq->n_bytes = 0; + mq->n_err = 0; } return 0; diff -Nru dpdk-24.11.4/drivers/net/memif/rte_eth_memif.h dpdk-24.11.8/drivers/net/memif/rte_eth_memif.h --- dpdk-24.11.4/drivers/net/memif/rte_eth_memif.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/memif/rte_eth_memif.h 2026-10-14 13:10:05.000000000 +0000 @@ -69,6 +69,7 @@ /* rx/tx info */ uint64_t n_pkts; /**< number of rx/tx packets */ uint64_t n_bytes; /**< number of rx/tx bytes */ + uint64_t n_err; /**< number of rx/tx errors */ struct rte_intr_handle *intr_handle; /**< interrupt handle */ diff -Nru dpdk-24.11.4/drivers/net/mlx4/mlx4_mp.c dpdk-24.11.8/drivers/net/mlx4/mlx4_mp.c --- dpdk-24.11.4/drivers/net/mlx4/mlx4_mp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx4/mlx4_mp.c 2026-10-14 13:10:05.000000000 +0000 @@ -149,6 +149,10 @@ } #endif close(mp_msg->fds[0]); + rte_eth_fp_ops[param->port_id].rx_pkt_burst = dev->rx_pkt_burst; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = dev->tx_pkt_burst; + rte_eth_fp_ops[param->port_id].rxq.data = dev->data->rx_queues; + rte_eth_fp_ops[param->port_id].txq.data = dev->data->tx_queues; rte_mb(); mp_init_msg(dev, &mp_res, param->type); res->result = 0; @@ -158,6 +162,8 @@ INFO("port %u stopping datapath", dev->data->port_id); dev->tx_pkt_burst = rte_eth_pkt_burst_dummy; dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; + rte_eth_fp_ops[param->port_id].rx_pkt_burst = rte_eth_pkt_burst_dummy; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = rte_eth_pkt_burst_dummy; rte_mb(); mp_init_msg(dev, &mp_res, param->type); res->result = 0; diff -Nru dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_action.c dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_action.c --- dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_action.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_action.c 2026-10-14 13:10:05.000000000 +0000 @@ -3417,6 +3417,17 @@ uint8_t *e_src; int i; + /* + * When LTO inlines this into mlx5dr_action_handle_tunnel_l3_to_l2(), + * GCC sees the 64-byte mh_data buffer but cannot prove num_of_actions + * is bounded, causing false -Wstringop-overflow warnings. + * + * Valid num_of_actions values are DECAP_L3_NUM_ACTIONS_W_NO_VLAN (6) + * or DECAP_L3_NUM_ACTIONS_W_VLAN (7). This check gives GCC the proof + * it needs that the loop iterations stay within buffer bounds. + */ + __rte_assume(num_of_actions <= DECAP_L3_NUM_ACTIONS_W_VLAN); + /* num_of_actions = remove l3l2 + 4/5 inserts + remove extra 2 bytes * copy from end of src to the start of dst. * move to the end, 2 is the leftover from 14B or 18B diff -Nru dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_cmd.c dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_cmd.c --- dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_cmd.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_cmd.c 2026-10-14 13:10:05.000000000 +0000 @@ -1008,8 +1008,8 @@ struct mlx5dr_cmd_generate_wqe_attr *attr, struct mlx5_cqe64 *ret_cqe) { - uint32_t out[MLX5_ST_SZ_DW(generate_wqe_out)] = {0}; - uint32_t in[MLX5_ST_SZ_DW(generate_wqe_in)] = {0}; + MLX5DR_ASAN_ALIGN uint32_t out[MLX5_ST_SZ_DW(generate_wqe_out)] = {0}; + MLX5DR_ASAN_ALIGN uint32_t in[MLX5_ST_SZ_DW(generate_wqe_in)] = {0}; uint8_t status; void *ptr; int ret; diff -Nru dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_internal.h dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_internal.h --- dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_internal.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_internal.h 2026-10-14 13:10:05.000000000 +0000 @@ -53,6 +53,12 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif +#ifdef RTE_MALLOC_ASAN +#define MLX5DR_ASAN_ALIGN alignas(64) +#else +#define MLX5DR_ASAN_ALIGN +#endif + #ifdef RTE_LIBRTE_MLX5_DEBUG /* Prevent double function name print when debug is set */ #define DR_LOG DRV_LOG diff -Nru dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_rule.c dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_rule.c --- dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_rule.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_rule.c 2026-10-14 13:10:05.000000000 +0000 @@ -28,6 +28,10 @@ if (mt->item_flags & MLX5_FLOW_ITEM_REPRESENTED_PORT) { v = items[mt->vport_item_id].spec; + if (unlikely(!v)) { + DR_LOG(NOTICE, "Fail to get vport item, ignoring"); + return; + } vport = flow_hw_conv_port_id(matcher->tbl->ctx, v->port_id); if (unlikely(!vport)) { DR_LOG(ERR, "Fail to map port ID %d, ignoring", v->port_id); @@ -470,7 +474,7 @@ bool is_jumbo = mlx5dr_matcher_mt_is_jumbo(mt); struct mlx5dr_matcher *matcher = rule->matcher; struct mlx5dr_context *ctx = matcher->tbl->ctx; - struct mlx5dr_send_ste_attr ste_attr = {0}; + MLX5DR_ASAN_ALIGN struct mlx5dr_send_ste_attr ste_attr = {0}; struct mlx5dr_send_ring_dep_wqe *dep_wqe; struct mlx5dr_actions_wqe_setter *setter; struct mlx5dr_actions_apply_data apply; diff -Nru dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_send.c dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_send.c --- dpdk-24.11.4/drivers/net/mlx5/hws/mlx5dr_send.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/hws/mlx5dr_send.c 2026-10-14 13:10:05.000000000 +0000 @@ -250,8 +250,8 @@ { bool has_range = send_wqe_range_data || send_wqe_range_tag; bool has_match = send_wqe_match_data || send_wqe_match_tag; - struct mlx5dr_wqe_gta_data_seg_ste gta_wqe_data0 = {0}; - struct mlx5dr_wqe_gta_data_seg_ste gta_wqe_data1 = {0}; + MLX5DR_ASAN_ALIGN struct mlx5dr_wqe_gta_data_seg_ste gta_wqe_data0 = {0}; + MLX5DR_ASAN_ALIGN struct mlx5dr_wqe_gta_data_seg_ste gta_wqe_data1 = {0}; struct mlx5dr_wqe_gta_ctrl_seg gta_wqe_ctrl = {0}; struct mlx5dr_cmd_generate_wqe_attr attr = {0}; struct mlx5dr_wqe_ctrl_seg wqe_ctrl = {0}; diff -Nru dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_ethdev_os.c dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_ethdev_os.c --- dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_ethdev_os.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_ethdev_os.c 2026-10-14 13:10:05.000000000 +0000 @@ -532,6 +532,7 @@ return -rte_errno; } } else if (ret < 0) { + memset(&dev->data->dev_link, 0, sizeof(dev->data->dev_link)); return ret; } } while (wait_to_complete || retry-- > 0); @@ -856,6 +857,26 @@ sizeof(struct mlx5dv_devx_async_cmd_hdr)]; } out; uint8_t *buf = out.buf + sizeof(out.cmd_resp); + uint32_t events = rte_intr_active_events_flags(); + + if (events & (RTE_INTR_EVENT_HUP | RTE_INTR_EVENT_RDHUP | RTE_INTR_EVENT_ERR)) { + /* + * Disconnect or Error event that cannot be cleared by reading. + * Unregister callback to prevent interrupt busy-looping. + */ + DRV_LOG(WARNING, "disconnect or error event for mlx5 devx interrupt on fd %d" + " (events=0x%x)", + rte_intr_fd_get(sh->intr_handle_devx), events); + + if (rte_intr_callback_unregister_pending(sh->intr_handle_devx, + mlx5_dev_interrupt_handler_devx, + (void *)sh, NULL) < 0) { + DRV_LOG(WARNING, + "unable to unregister mlx5 devx interrupt callback on fd %d", + rte_intr_fd_get(sh->intr_handle_devx)); + } + return; + } while (!mlx5_glue->devx_get_async_cmd_comp(sh->devx_comp, &out.cmd_resp, diff -Nru dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_mp_os.c dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_mp_os.c --- dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_mp_os.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_mp_os.c 2026-10-14 13:10:05.000000000 +0000 @@ -189,6 +189,10 @@ } } close(mp_msg->fds[0]); + rte_eth_fp_ops[param->port_id].rx_pkt_burst = dev->rx_pkt_burst; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = dev->tx_pkt_burst; + rte_eth_fp_ops[param->port_id].rxq.data = dev->data->rx_queues; + rte_eth_fp_ops[param->port_id].txq.data = dev->data->tx_queues; rte_mb(); mp_init_msg(&priv->mp_id, &mp_res, param->type); res->result = 0; @@ -198,6 +202,8 @@ DRV_LOG(INFO, "port %u stopping datapath", dev->data->port_id); dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; dev->tx_pkt_burst = rte_eth_pkt_burst_dummy; + rte_eth_fp_ops[param->port_id].rx_pkt_burst = rte_eth_pkt_burst_dummy; + rte_eth_fp_ops[param->port_id].tx_pkt_burst = rte_eth_pkt_burst_dummy; rte_mb(); mp_init_msg(&priv->mp_id, &mp_res, param->type); res->result = 0; diff -Nru dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_os.c dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_os.c --- dpdk-24.11.4/drivers/net/mlx5/linux/mlx5_os.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/linux/mlx5_os.c 2026-10-14 13:10:05.000000000 +0000 @@ -1033,6 +1033,166 @@ "available.", dev->data->port_id); } +static bool +is_standard_eswitch(const struct mlx5_dev_spawn_data *spawn) +{ + bool is_bond = spawn->pf_bond >= 0; + + return !is_bond && spawn->nb_uplinks <= 1 && spawn->nb_hpfs <= 1; +} + +static bool +is_hpf(const struct mlx5_dev_spawn_data *spawn) +{ + return spawn->info.port_name == -1 && + spawn->info.name_type == MLX5_PHYS_PORT_NAME_TYPE_PFHPF; +} + +static int +build_port_name(struct rte_device *dpdk_dev, + struct mlx5_dev_spawn_data *spawn, + char *name, + size_t name_sz) +{ + bool is_bond = spawn->pf_bond >= 0; + int written = 0; + int ret; + + ret = snprintf(name, name_sz, "%s", dpdk_dev->name); + if (ret < 0) + return ret; + written += ret; + if (written >= (int)name_sz) + return written; + + /* + * Whenever bond device is detected, include IB device name. + * This is kept to keep port naming backward compatible. + */ + if (is_bond) { + ret = snprintf(name + written, name_sz - written, "_%s", spawn->phys_dev_name); + if (ret < 0) + return ret; + written += ret; + if (written >= (int)name_sz) + return written; + } + + if (spawn->info.name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { + /* Add port to name if and only if there is more than one uplink. */ + if (spawn->nb_uplinks <= 1) + goto end; + + ret = snprintf(name + written, name_sz - written, "_p%u", spawn->info.port_name); + if (ret < 0) + return ret; + written += ret; + if (written >= (int)name_sz) + return written; + } else if (spawn->info.representor) { + /* + * If port is a representor, then switchdev has been enabled. + * In that case add controller, PF and VF/SF indexes to port name + * if at least one of these conditions are met: + * 1. Device is a bond (VF-LAG). + * 2. There are multiple uplinks (MPESW). + * 3. There are multiple host PFs (BlueField socket direct). + * + * If none of these conditions apply, then it is assumed that + * this device manages a single non-shared E-Switch with single controller, + * where there is only one uplink/PF and one host PF (on BlueField). + */ + if (!is_standard_eswitch(spawn)) + ret = snprintf(name + written, name_sz - written, + "_representor_c%dpf%d%s%u", + spawn->info.ctrl_num, + spawn->info.pf_num, + spawn->info.name_type == + MLX5_PHYS_PORT_NAME_TYPE_PFSF ? "sf" : "vf", + spawn->info.port_name); + else + ret = snprintf(name + written, name_sz - written, "_representor_%s%u", + spawn->info.name_type == + MLX5_PHYS_PORT_NAME_TYPE_PFSF ? "sf" : "vf", + spawn->info.port_name); + if (ret < 0) + return ret; + written += ret; + if (written >= (int)name_sz) + return written; + } + +end: + return written; +} + +static bool +representor_match_uplink(const struct mlx5_dev_spawn_data *spawn, + uint16_t port_name, + uint16_t eth_da_pf_num) +{ + if (spawn->info.name_type != MLX5_PHYS_PORT_NAME_TYPE_UPLINK) + return false; + /* One of the uplinks will be a transfer proxy. Must be probed always. */ + if (spawn->info.master) + return true; + + return port_name == eth_da_pf_num; +} + +static bool +representor_match_port(const struct mlx5_dev_spawn_data *spawn, + const struct rte_eth_devargs *eth_da) +{ + for (uint16_t p = 0; p < eth_da->nb_ports; ++p) { + uint16_t pf_num = eth_da->ports[p]; + + /* PF representor in devargs is interpreted as probing uplink port. */ + if (eth_da->type == RTE_ETH_REPRESENTOR_PF) { + if (representor_match_uplink(spawn, spawn->info.port_name, pf_num)) + return true; + + continue; + } + + /* Allow probing related uplink when VF/SF representor is requested. */ + if ((eth_da->type == RTE_ETH_REPRESENTOR_VF || + eth_da->type == RTE_ETH_REPRESENTOR_SF) && + representor_match_uplink(spawn, spawn->info.pf_num, pf_num)) + return true; + + /* Uplink ports should not be matched against representor_ports. */ + if (spawn->info.name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK) + continue; + + for (uint16_t f = 0; f < eth_da->nb_representor_ports; ++f) { + uint16_t port_num = eth_da->representor_ports[f]; + bool pf_num_match; + bool rep_num_match; + + /* + * In standard E-Switch case, allow probing VFs even if wrong PF index + * was provided. + */ + if (is_standard_eswitch(spawn)) + pf_num_match = true; + else + pf_num_match = spawn->info.pf_num == pf_num; + + /* Host PF is indicated through VF/SF representor index == -1. */ + if (is_hpf(spawn)) + rep_num_match = port_num == UINT16_MAX; + else + rep_num_match = port_num == spawn->info.port_name; + + if (pf_num_match && rep_num_match) + return true; + } + } + + return false; +} + /** * Check if representor spawn info match devargs. * @@ -1049,50 +1209,29 @@ struct rte_eth_devargs *eth_da) { struct mlx5_switch_info *switch_info = &spawn->info; - unsigned int p, f; - uint16_t id; - uint16_t repr_id = mlx5_representor_id_encode(switch_info, - eth_da->type); + unsigned int c; + bool ignore_ctrl_num = eth_da->nb_mh_controllers == 0 || + switch_info->name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK; - /* - * Assuming Multiport E-Switch device was detected, - * if spawned port is an uplink, check if the port - * was requested through representor devarg. - */ - if (mlx5_is_probed_port_on_mpesw_device(spawn) && - switch_info->name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { - for (p = 0; p < eth_da->nb_ports; ++p) - if (switch_info->port_name == eth_da->ports[p]) - return true; - rte_errno = EBUSY; - return false; - } switch (eth_da->type) { case RTE_ETH_REPRESENTOR_PF: - /* - * PF representors provided in devargs translate to uplink ports, but - * if and only if the device is a part of MPESW device. - */ - if (!mlx5_is_probed_port_on_mpesw_device(spawn)) { + if (switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { rte_errno = EBUSY; return false; } break; case RTE_ETH_REPRESENTOR_SF: - if (!(spawn->info.port_name == -1 && - switch_info->name_type == - MLX5_PHYS_PORT_NAME_TYPE_PFHPF) && - switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_PFSF) { + if (!is_hpf(spawn) && + switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_PFSF && + switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { rte_errno = EBUSY; return false; } break; case RTE_ETH_REPRESENTOR_VF: - /* Allows HPF representor index -1 as exception. */ - if (!(spawn->info.port_name == -1 && - switch_info->name_type == - MLX5_PHYS_PORT_NAME_TYPE_PFHPF) && - switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_PFVF) { + if (!is_hpf(spawn) && + switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_PFVF && + switch_info->name_type != MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { rte_errno = EBUSY; return false; } @@ -1105,21 +1244,17 @@ DRV_LOG(ERR, "unsupported representor type"); return false; } - /* Check representor ID: */ - for (p = 0; p < eth_da->nb_ports; ++p) { - if (!mlx5_is_probed_port_on_mpesw_device(spawn) && spawn->pf_bond < 0) { - /* For non-LAG mode, allow and ignore pf. */ - switch_info->pf_num = eth_da->ports[p]; - repr_id = mlx5_representor_id_encode(switch_info, - eth_da->type); - } - for (f = 0; f < eth_da->nb_representor_ports; ++f) { - id = MLX5_REPRESENTOR_ID - (eth_da->ports[p], eth_da->type, - eth_da->representor_ports[f]); - if (repr_id == id) + if (!ignore_ctrl_num) { + for (c = 0; c < eth_da->nb_mh_controllers; ++c) { + uint16_t ctrl_num = eth_da->mh_controllers[c]; + + if (spawn->info.ctrl_num == ctrl_num && + representor_match_port(spawn, eth_da)) return true; } + } else { + if (representor_match_port(spawn, eth_da)) + return true; } rte_errno = EBUSY; return false; @@ -1171,44 +1306,12 @@ !mlx5_representor_match(spawn, eth_da)) return NULL; /* Build device name. */ - if (spawn->pf_bond >= 0) { - /* Bonding device. */ - if (!switch_info->representor) { - err = snprintf(name, sizeof(name), "%s_%s", - dpdk_dev->name, spawn->phys_dev_name); - } else { - err = snprintf(name, sizeof(name), "%s_%s_representor_c%dpf%d%s%u", - dpdk_dev->name, spawn->phys_dev_name, - switch_info->ctrl_num, - switch_info->pf_num, - switch_info->name_type == - MLX5_PHYS_PORT_NAME_TYPE_PFSF ? "sf" : "vf", - switch_info->port_name); - } - } else if (mlx5_is_probed_port_on_mpesw_device(spawn)) { - /* MPESW device. */ - if (switch_info->name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK) { - err = snprintf(name, sizeof(name), "%s_p%d", - dpdk_dev->name, spawn->mpesw_port); - } else { - err = snprintf(name, sizeof(name), "%s_representor_c%dpf%d%s%u", - dpdk_dev->name, - switch_info->ctrl_num, - switch_info->pf_num, - switch_info->name_type == - MLX5_PHYS_PORT_NAME_TYPE_PFSF ? "sf" : "vf", - switch_info->port_name); - } - } else { - /* Single device. */ - if (!switch_info->representor) - strlcpy(name, dpdk_dev->name, sizeof(name)); - else - err = snprintf(name, sizeof(name), "%s_representor_%s%u", - dpdk_dev->name, - switch_info->name_type == - MLX5_PHYS_PORT_NAME_TYPE_PFSF ? "sf" : "vf", - switch_info->port_name); + err = build_port_name(dpdk_dev, spawn, name, sizeof(name)); + if (err < 0) { + DRV_LOG(ERR, "Failed to build port name for IB device %s/%u", + spawn->phys_dev_name, spawn->phys_port); + rte_errno = EINVAL; + return NULL; } if (err >= (int)sizeof(name)) DRV_LOG(WARNING, "device name overflow %s", name); @@ -1335,7 +1438,6 @@ priv->sh = sh; priv->dev_port = spawn->phys_port; priv->pci_dev = spawn->pci_dev; - priv->mtu = RTE_ETHER_MTU; /* Some internal functions rely on Netlink sockets, open them now. */ priv->nl_socket_rdma = nl_rdma; priv->nl_socket_route = mlx5_nl_init(NETLINK_ROUTE, 0); @@ -1548,9 +1650,13 @@ err = ENOMEM; goto error; } + priv->port_info.type = spawn->info.name_type; + priv->port_info.ctrl_num = spawn->info.ctrl_num; + priv->port_info.pf_num = spawn->info.pf_num; + priv->port_info.port_num = spawn->info.port_name; if (priv->representor) { eth_dev->data->dev_flags |= RTE_ETH_DEV_REPRESENTOR; - eth_dev->data->representor_id = priv->representor_id; + eth_dev->data->representor_id = eth_dev->data->port_id; MLX5_ETH_FOREACH_DEV(port_id, dpdk_dev) { struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private; @@ -1607,14 +1713,13 @@ } #endif /* Get actual MTU if possible. */ - err = mlx5_get_mtu(eth_dev, &priv->mtu); + err = mlx5_get_mtu(eth_dev, ð_dev->data->mtu); if (err) { err = rte_errno; goto error; } - eth_dev->data->mtu = priv->mtu; DRV_LOG(DEBUG, "port %u MTU is %u", eth_dev->data->port_id, - priv->mtu); + eth_dev->data->mtu); /* Initialize burst functions to prevent crashes before link-up. */ eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy; @@ -1832,6 +1937,11 @@ close(priv->nl_socket_route); if (priv->vmwa_context) mlx5_vlan_vmwa_exit(priv->vmwa_context); + for (i = 0; i < MLX5_FLOW_TYPE_MAXI; i++) { + if (!priv->flows[i]) + continue; + mlx5_ipool_destroy(priv->flows[i]); + } if (eth_dev && priv->drop_queue.hrxq) mlx5_drop_action_destroy(eth_dev); if (priv->mtr_profile_tbl) @@ -1911,8 +2021,8 @@ /** * Match PCI information for possible slaves of bonding device. * - * @param[in] ibdev_name - * Name of Infiniband device. + * @param[in] ibdev + * Pointer to IB device. * @param[in] pci_dev * Pointer to primary PCI address structure to match. * @param[in] nl_rdma @@ -1927,7 +2037,7 @@ * positive index of slave PF in bonding. */ static int -mlx5_device_bond_pci_match(const char *ibdev_name, +mlx5_device_bond_pci_match(const struct ibv_device *ibdev, const struct rte_pci_addr *pci_dev, int nl_rdma, uint16_t owner, struct mlx5_bond_info *bond_info) @@ -1948,9 +2058,9 @@ memset(bond_info, 0, sizeof(*bond_info)); if (nl_rdma < 0) return -1; - if (!strstr(ibdev_name, "bond")) + if (!mlx5_os_is_device_bond(ibdev)) return -1; - np = mlx5_nl_portnum(nl_rdma, ibdev_name); + np = mlx5_nl_portnum(nl_rdma, ibdev->name); if (!np) return -1; if (mlx5_get_device_guid(pci_dev, cur_guid, sizeof(cur_guid)) < 0) @@ -1962,7 +2072,7 @@ */ for (i = 1; i <= np; ++i) { /* Check whether Infiniband port is populated. */ - ifindex = mlx5_nl_ifindex(nl_rdma, ibdev_name, i); + ifindex = mlx5_nl_ifindex(nl_rdma, ibdev->name, i); if (!ifindex) continue; if (!if_indextoname(ifindex, ifname)) @@ -2270,6 +2380,47 @@ return -1; } +static void +calc_nb_uplinks_hpfs(struct ibv_device **ibv_match, + unsigned int nd, + struct mlx5_dev_spawn_data *list, + unsigned int ns) +{ + for (unsigned int i = 0; i != nd; i++) { + uint32_t nb_uplinks = 0; + uint32_t nb_hpfs = 0; + uint32_t j; + + for (unsigned int j = 0; j != ns; j++) { + if (strcmp(ibv_match[i]->name, list[j].phys_dev_name) != 0) + continue; + + if (list[j].info.name_type == MLX5_PHYS_PORT_NAME_TYPE_UPLINK) + nb_uplinks++; + else if (list[j].info.name_type == MLX5_PHYS_PORT_NAME_TYPE_PFHPF) + nb_hpfs++; + } + + if (nb_uplinks > 0 || nb_hpfs > 0) { + for (j = 0; j != ns; j++) { + if (strcmp(ibv_match[i]->name, list[j].phys_dev_name) != 0) + continue; + + list[j].nb_uplinks = nb_uplinks; + list[j].nb_hpfs = nb_hpfs; + } + + DRV_LOG(DEBUG, "IB device %s has %u uplinks, %u host PFs", + ibv_match[i]->name, + nb_uplinks, + nb_hpfs); + } else { + DRV_LOG(DEBUG, "IB device %s unable to recognize uplinks/host PFs", + ibv_match[i]->name); + } + } +} + /** * Register a PCI device within bonding. * @@ -2351,7 +2502,7 @@ struct rte_pci_addr pci_addr; DRV_LOG(DEBUG, "Checking device \"%s\"", ibv_list[ret]->name); - bd = mlx5_device_bond_pci_match(ibv_list[ret]->name, &owner_pci, + bd = mlx5_device_bond_pci_match(ibv_list[ret], &owner_pci, nl_rdma, owner_id, &bond_info); if (bd >= 0) { /* @@ -2555,17 +2706,14 @@ case MLX5_PHYS_PORT_NAME_TYPE_PFHPF: case MLX5_PHYS_PORT_NAME_TYPE_PFVF: case MLX5_PHYS_PORT_NAME_TYPE_PFSF: - /* Only spawn representors related to the probed PF. */ - if (list[ns].info.pf_num == owner_id) { - /* - * Ports of this type have PF index encoded in name, - * which translate to the related uplink port index. - */ - list[ns].mpesw_port = list[ns].info.pf_num; - /* MPESW owner is also saved but not used now. */ - list[ns].info.mpesw_owner = mpesw; - ns++; - } + /* + * Ports of this type have PF index encoded in name, + * which translate to the related uplink port index. + */ + list[ns].mpesw_port = list[ns].info.pf_num; + /* MPESW owner is also saved but not used now. */ + list[ns].info.mpesw_owner = mpesw; + ns++; break; default: break; @@ -2699,6 +2847,8 @@ } } MLX5_ASSERT(ns); + /* Calculate number of uplinks and host PFs for each matched IB device. */ + calc_nb_uplinks_hpfs(ibv_match, nd, list, ns); /* * Sort list to probe devices in natural order for users convenience * (i.e. master first, then representors from lowest to highest ID). @@ -2706,16 +2856,12 @@ qsort(list, ns, sizeof(*list), mlx5_dev_spawn_data_cmp); if (eth_da.type != RTE_ETH_REPRESENTOR_NONE) { /* Set devargs default values. */ - if (eth_da.nb_mh_controllers == 0) { - eth_da.nb_mh_controllers = 1; - eth_da.mh_controllers[0] = 0; - } if (eth_da.nb_ports == 0 && ns > 0) { if (list[0].pf_bond >= 0 && list[0].info.representor) DRV_LOG(WARNING, "Representor on Bonding device should use pf#vf# syntax: %s", pci_dev->device.devargs->args); eth_da.nb_ports = 1; - eth_da.ports[0] = list[0].info.pf_num; + eth_da.ports[0] = list[0].info.port_name; } if (eth_da.nb_representor_ports == 0) { eth_da.nb_representor_ports = 1; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5.c dpdk-24.11.8/drivers/net/mlx5/mlx5.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5.c 2026-10-14 13:10:05.000000000 +0000 @@ -453,6 +453,7 @@ err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_FLOW_HIT, 1); if (err) { mlx5_free(sh->aso_age_mng); + sh->aso_age_mng = NULL; return -1; } rte_rwlock_init(&sh->aso_age_mng->resize_rwl); @@ -817,6 +818,7 @@ err = mlx5_aso_queue_init(sh, ASO_OPC_MOD_CONNECTION_TRACKING, MLX5_ASO_CT_SQ_NUM); if (err) { mlx5_free(sh->ct_mng); + sh->ct_mng = NULL; /* rte_errno should be extracted from the failure. */ rte_errno = EINVAL; return -rte_errno; @@ -977,6 +979,7 @@ mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev) { struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_hca_flex_attr *attr = &priv->sh->cdev->config.hca_attr.flex; struct mlx5_ecpri_parser_profile *prf = &priv->sh->ecpri_parser; struct mlx5_devx_graph_node_attr node = { .modify_field_select = 0, @@ -990,6 +993,7 @@ return -ENOTSUP; } node.header_length_mode = MLX5_GRAPH_NODE_LEN_FIXED; + node.header_length_field_offset_mode = !attr->header_length_field_mode_wa; /* 8 bytes now: 4B common header + 4B message body header. */ node.header_length_base_value = 0x8; /* After MAC layer: Ether / VLAN. */ @@ -1032,6 +1036,11 @@ return (rte_errno == 0) ? -ENODEV : -rte_errno; } +/* IPv6 SRH header is defined in RFC 8754 */ +#define MLX5_SRH_HEADER_LENGTH_FIELD_OFFSET 8 +#define MLX5_SRH_HEADER_LENGTH_FIELD_SIZE 8 +#define MLX5_SRH_HEADER_LENGTH_SHIFT 3 + /* * Destroy the flex parser node, including the parser itself, input / output * arcs and DW samples. Resources could be reused then. @@ -1062,6 +1071,7 @@ int mlx5_alloc_srh_flex_parser(struct rte_eth_dev *dev) { + static rte_spinlock_t srh_init_sl = RTE_SPINLOCK_INITIALIZER; struct mlx5_devx_graph_node_attr node = { .modify_field_select = 0, }; @@ -1079,29 +1089,29 @@ DRV_LOG(ERR, "Dynamic flex parser is not supported on HWS"); return -ENOTSUP; } - if (rte_atomic_fetch_add_explicit(&priv->sh->srh_flex_parser.refcnt, 1, - rte_memory_order_relaxed) + 1 > 1) - return 0; + rte_spinlock_lock(&srh_init_sl); + if (rte_atomic_load_explicit(&priv->sh->srh_flex_parser.refcnt, + rte_memory_order_relaxed) > 0) + goto end; priv->sh->srh_flex_parser.flex.devx_fp = mlx5_malloc(MLX5_MEM_ZERO, sizeof(struct mlx5_flex_parser_devx), 0, SOCKET_ID_ANY); - if (!priv->sh->srh_flex_parser.flex.devx_fp) - return -ENOMEM; + if (!priv->sh->srh_flex_parser.flex.devx_fp) { + rte_errno = ENOMEM; + goto error; + } node.header_length_mode = MLX5_GRAPH_NODE_LEN_FIELD; + node.header_length_field_offset_mode = !attr->header_length_field_mode_wa; /* Srv6 first two DW are not counted in. */ node.header_length_base_value = 0x8; /* The unit is uint64_t. */ - node.header_length_field_shift = 0x3; + node.header_length_field_shift = MLX5_SRH_HEADER_LENGTH_SHIFT; + node.header_length_field_offset_mode = !attr->header_length_field_mode_wa; /* Header length is the 2nd byte. */ - if (attr->header_length_field_mode_wa) { - /* Legacy firmware before ConnectX-8, we should provide offset WA. */ - node.header_length_field_offset = 8; - if (attr->header_length_mask_width < 8) - node.header_length_field_offset += 8 - attr->header_length_mask_width; - } else { - /* The new firmware, we can specify the correct offset directly. */ - node.header_length_field_offset = 12; - } - node.header_length_field_mask = 0xF; + node.header_length_field_offset = MLX5_SRH_HEADER_LENGTH_FIELD_OFFSET; + if (attr->header_length_mask_width < MLX5_SRH_HEADER_LENGTH_FIELD_SIZE) + node.header_length_field_offset += + MLX5_SRH_HEADER_LENGTH_FIELD_SIZE - attr->header_length_mask_width; + node.header_length_field_mask = mlx5_flex_hdr_len_mask(MLX5_SRH_HEADER_LENGTH_SHIFT, attr); /* One byte next header protocol. */ node.next_header_field_size = 0x8; node.in[0].arc_parse_graph_node = MLX5_GRAPH_ARC_NODE_IP; @@ -1155,12 +1165,22 @@ (i + 1) * sizeof(uint32_t) * CHAR_BIT; } priv->sh->srh_flex_parser.flex.map[0].shift = 0; + DRV_LOG(NOTICE, + "SRH flex parser node object is created successfully. " + "Header extension length field size: %d bits\n", + attr->header_length_mask_width > MLX5_SRH_HEADER_LENGTH_FIELD_SIZE ? + MLX5_SRH_HEADER_LENGTH_FIELD_SIZE : attr->header_length_mask_width); +end: + rte_atomic_fetch_add_explicit(&priv->sh->srh_flex_parser.refcnt, 1, + rte_memory_order_relaxed); + rte_spinlock_unlock(&srh_init_sl); return 0; error: if (fp) mlx5_devx_cmd_destroy(fp); if (priv->sh->srh_flex_parser.flex.devx_fp) mlx5_free(priv->sh->srh_flex_parser.flex.devx_fp); + rte_spinlock_unlock(&srh_init_sl); return (rte_errno == 0) ? -ENODEV : -rte_errno; } @@ -1177,7 +1197,7 @@ struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_internal_flex_parser_profile *fp = &priv->sh->srh_flex_parser; - if (rte_atomic_fetch_sub_explicit(&fp->refcnt, 1, rte_memory_order_relaxed) - 1) + if (rte_atomic_fetch_sub_explicit(&fp->refcnt, 1, rte_memory_order_relaxed) > 1) return; mlx5_devx_cmd_destroy(fp->flex.devx_fp->devx_obj); mlx5_free(fp->flex.devx_fp); @@ -1662,6 +1682,12 @@ reg->nat64_regs[0] = REG_C_6; reg->nat64_regs[1] = reg->hw_avl_tags[j - 2]; reg->nat64_regs[2] = reg->hw_avl_tags[j - 1]; + } else { + if (j >= MLX5_FLOW_NAT64_REGS_MAX) { + reg->nat64_regs[0] = reg->hw_avl_tags[j - 3]; + reg->nat64_regs[1] = reg->hw_avl_tags[j - 2]; + reg->nat64_regs[2] = reg->hw_avl_tags[j - 1]; + } } } @@ -1859,6 +1885,8 @@ strerror(rte_errno)); goto error; } + /* Used on Tx send scheduling (tx_pp=1 or wait-on-time). */ + sh->txpp.skew = sh->config.tx_skew; sh->refcnt = 1; sh->max_port = spawn->max_port; strncpy(sh->ibdev_name, mlx5_os_get_ctx_device_name(sh->cdev->ctx), diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5.h dpdk-24.11.8/drivers/net/mlx5/mlx5.h --- dpdk-24.11.4/drivers/net/mlx5/mlx5.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5.h 2026-10-14 13:10:05.000000000 +0000 @@ -215,6 +215,8 @@ struct mlx5_dev_spawn_data { uint32_t ifindex; /**< Network interface index. */ uint32_t max_port; /**< Device maximal port index. */ + uint32_t nb_uplinks; /**< Number of uplinks associated with IB device. */ + uint32_t nb_hpfs; /**< Number of host PFs associated with IB device. */ uint32_t phys_port; /**< Device physical port index. */ int pf_bond; /**< bonding device PF index. < 0 - no bonding */ int mpesw_port; /**< MPESW uplink index. Valid if mpesw_owner_port >= 0. */ @@ -1453,7 +1455,8 @@ }; /* - * Sample an IPv6 address and the first dword of SRv6 header. + * Sample IPv6 address in the first segment list + * and the first dword of SRv6 header. * Then it is 16 + 4 = 20 bytes which is 5 dwords. */ #define MLX5_SRV6_SAMPLE_NUM 5 @@ -1949,6 +1952,24 @@ struct mlx5_indexed_pool *quota_ipool; /* Manage quota objects */ }; +/* Stores info parsed from phys_port_name related to given DPDK port. */ +struct mlx5_representor_info { + enum mlx5_nl_phys_port_name_type type; + /* PCI controller index. 0 if no controller was reported in phys_port_name. */ + int32_t ctrl_num; + /* PF index. */ + int32_t pf_num; + /* + * Representor number: + * + * - For VF/SF - VF/SF index. + * - For PFHPF - -1. + * - For uplink - physical port index. + * - For others - VF representor is assumed, so VF index. + */ + int32_t port_num; +}; + struct mlx5_priv { struct rte_eth_dev_data *dev_data; /* Pointer to device data. */ struct mlx5_dev_ctx_shared *sh; /* Shared device context. */ @@ -1960,7 +1981,6 @@ uint16_t vlan_filter[MLX5_MAX_VLAN_IDS]; /* VLAN filters table. */ unsigned int vlan_filter_n; /* Number of configured VLAN filters. */ /* Device properties. */ - uint16_t mtu; /* Configured MTU. */ uint16_t min_mtu; /* Minimum MTU allowed on the NIC. */ uint16_t max_mtu; /* Maximum MTU allowed on the NIC. */ unsigned int isolated:1; /* Whether isolated mode is enabled. */ @@ -1980,6 +2000,7 @@ uint32_t vport_meta_tag; /* Used for vport index match ove VF LAG. */ uint32_t vport_meta_mask; /* Used for vport index field match mask. */ uint16_t representor_id; /* UINT16_MAX if not a representor. */ + struct mlx5_representor_info port_info; int32_t pf_bond; /* >=0, representor owner PF index in bonding. */ int32_t mpesw_owner; /* >=0, representor owner PF index in MPESW. */ int32_t mpesw_port; /* Related port index of MPESW device. < 0 - no MPESW. */ @@ -2001,6 +2022,7 @@ rte_spinlock_t hw_ctrl_lock; LIST_HEAD(hw_ctrl_flow, mlx5_ctrl_flow_entry) hw_ctrl_flows; LIST_HEAD(hw_ext_ctrl_flow, mlx5_ctrl_flow_entry) hw_ext_ctrl_flows; + struct mlx5_flow_hw_lacp_miss *hw_lacp_miss; /* HWS LACP miss flow tables */ struct mlx5_flow_hw_ctrl_fdb *hw_ctrl_fdb; struct rte_flow_pattern_template *hw_tx_repr_tagging_pt; struct rte_flow_actions_template *hw_tx_repr_tagging_at; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_ethdev.c dpdk-24.11.8/drivers/net/mlx5/mlx5_ethdev.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -346,6 +346,23 @@ } /** + * Get switch port ID for given DPDK port. + * + * @param dev + * Pointer to Ethernet device structure. + * @return + * Switch port ID reported through rte_eth_dev_info_get(). + */ +static uint16_t +mlx5_dev_switch_info_port_id_get(struct rte_eth_dev *dev) +{ + if (rte_eth_dev_is_repr(dev)) + return dev->data->port_id; + + return UINT16_MAX; +} + +/** * DPDK callback to get information about the device. * * @param dev @@ -401,7 +418,7 @@ info->dev_capa |= RTE_ETH_DEV_CAPA_RXQ_SHARE; info->switch_info.name = dev->data->name; info->switch_info.domain_id = priv->domain_id; - info->switch_info.port_id = priv->representor_id; + info->switch_info.port_id = mlx5_dev_switch_info_port_id_get(dev); info->switch_info.rx_domain = 0; /* No sub Rx domains. */ if (priv->representor) { uint16_t port_id; @@ -472,14 +489,162 @@ return MLX5_REPRESENTOR_ID(pf, type, repr); } +static unsigned int +mlx5_representor_info_count_one(struct mlx5_priv *priv) +{ + switch (priv->port_info.type) { + case MLX5_PHYS_PORT_NAME_TYPE_PFHPF: + return 2; + case MLX5_PHYS_PORT_NAME_TYPE_UPLINK: + /* Only representor uplinks should be reported */ + if (!priv->representor) + return 0; + return 1; + case MLX5_PHYS_PORT_NAME_TYPE_NOTSET: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_LEGACY: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_PFVF: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_PFSF: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN: + /* FALLTHROUGH */ + default: + return 1; + } +} + +static unsigned int +mlx5_representor_info_count(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint16_t port_id; + unsigned int count = 0; + + MLX5_ETH_FOREACH_DEV(port_id, dev->device) { + struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private; + + if (!opriv || + opriv->sh != priv->sh || + opriv->domain_id != priv->domain_id) + continue; + + count += mlx5_representor_info_count_one(opriv); + } + + return count; +} + +static void +mlx5_representor_info_fill_one(struct mlx5_priv *priv, + struct rte_eth_representor_info *info) +{ + struct rte_eth_representor_range *range; + unsigned int count; + + count = mlx5_representor_info_count_one(priv); + if (count == 0) + return; + + if (info->nb_ranges + count > info->nb_ranges_alloc) { + DRV_LOG(ERR, "port %u representor info already full", priv->dev_data->port_id); + return; + } + + range = &info->ranges[info->nb_ranges]; + + switch (priv->port_info.type) { + case MLX5_PHYS_PORT_NAME_TYPE_UPLINK: + range->type = RTE_ETH_REPRESENTOR_PF; + range->controller = priv->port_info.ctrl_num; + range->pf = priv->port_info.port_num; + range->id_base = priv->dev_data->port_id; + range->id_end = range->id_base; + snprintf(range->name, sizeof(range->name), "pf%d", range->pf); + break; + case MLX5_PHYS_PORT_NAME_TYPE_PFSF: + /* Secondly, fill in SF variant. */ + range->type = RTE_ETH_REPRESENTOR_SF; + range->controller = priv->port_info.ctrl_num; + range->pf = priv->port_info.pf_num; + range->sf = priv->port_info.port_num; + range->id_base = priv->dev_data->port_id; + range->id_end = range->id_base; + snprintf(range->name, sizeof(range->name), "pf%dsf", range->pf); + break; + case MLX5_PHYS_PORT_NAME_TYPE_PFHPF: + /* + * Host PF can be probed either through VF(0xffff) or SF(0xffff). + * Firstly fill in VF variant. + */ + range->type = RTE_ETH_REPRESENTOR_VF; + range->controller = priv->port_info.ctrl_num; + range->pf = priv->port_info.pf_num; + range->vf = UINT16_MAX; + range->id_base = priv->dev_data->port_id; + range->id_end = range->id_base; + snprintf(range->name, sizeof(range->name), "pf%dvf", range->pf); + + /* Move the SF variant. */ + range++; + + /* Fill in SF variant. */ + range->type = RTE_ETH_REPRESENTOR_SF; + range->controller = priv->port_info.ctrl_num; + range->pf = priv->port_info.pf_num; + range->sf = UINT16_MAX; + range->id_base = priv->dev_data->port_id; + range->id_end = range->id_base; + snprintf(range->name, sizeof(range->name), "pf%dsf", range->pf); + break; + case MLX5_PHYS_PORT_NAME_TYPE_PFVF: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_NOTSET: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_LEGACY: + /* FALLTHROUGH */ + case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN: + range->type = RTE_ETH_REPRESENTOR_VF; + range->controller = priv->port_info.ctrl_num; + range->pf = priv->port_info.pf_num; + range->vf = priv->port_info.port_num; + range->id_base = priv->dev_data->port_id; + range->id_end = range->id_base; + snprintf(range->name, sizeof(range->name), "pf%dvf", range->pf); + break; + } + + info->nb_ranges += count; +} + +static unsigned int +mlx5_representor_info_fill(struct rte_eth_dev *dev, + struct rte_eth_representor_info *info) +{ + struct mlx5_priv *priv = dev->data->dev_private; + uint16_t port_id; + + info->controller = priv->port_info.ctrl_num; + info->pf = RTE_DEV_TO_PCI(dev->device)->addr.function; + + MLX5_ETH_FOREACH_DEV(port_id, dev->device) { + struct mlx5_priv *opriv = rte_eth_devices[port_id].data->dev_private; + + if (!opriv || + opriv->sh != priv->sh || + opriv->domain_id != priv->domain_id) + continue; + + mlx5_representor_info_fill_one(opriv, info); + } + + return info->nb_ranges; +} + /** * DPDK callback to get information about representor. * - * Representor ID bits definition: - * vf/sf: 12 - * type: 2 - * pf: 2 - * * @param dev * Pointer to Ethernet device structure. * @param[out] info @@ -492,105 +657,11 @@ mlx5_representor_info_get(struct rte_eth_dev *dev, struct rte_eth_representor_info *info) { - struct mlx5_priv *priv = dev->data->dev_private; - int n_type = 5; /* Representor types: PF, VF, HPF@VF, SF and HPF@SF. */ - int n_pf = 2; /* Number of PFs. */ - int i = 0, pf; - int n_entries; - if (info == NULL) - goto out; + return mlx5_representor_info_count(dev); + + return mlx5_representor_info_fill(dev, info); - n_entries = n_type * n_pf; - if ((uint32_t)n_entries > info->nb_ranges_alloc) - n_entries = info->nb_ranges_alloc; - - info->controller = 0; - info->pf = 0; - if (mlx5_is_port_on_mpesw_device(priv)) { - info->pf = priv->mpesw_port; - /* PF range, both ports will show the same information. */ - info->ranges[i].type = RTE_ETH_REPRESENTOR_PF; - info->ranges[i].controller = 0; - info->ranges[i].pf = priv->mpesw_owner + 1; - info->ranges[i].vf = 0; - /* - * The representor indexes should be the values set of "priv->mpesw_port". - * In the real case now, only 1 PF/UPLINK representor is supported. - * The port index will always be the value of "owner + 1". - */ - info->ranges[i].id_base = - MLX5_REPRESENTOR_ID(priv->mpesw_owner, info->ranges[i].type, - info->ranges[i].pf); - info->ranges[i].id_end = - MLX5_REPRESENTOR_ID(priv->mpesw_owner, info->ranges[i].type, - info->ranges[i].pf); - snprintf(info->ranges[i].name, sizeof(info->ranges[i].name), - "pf%d", info->ranges[i].pf); - i++; - } else if (priv->pf_bond >= 0) - info->pf = priv->pf_bond; - for (pf = 0; pf < n_pf; ++pf) { - /* VF range. */ - info->ranges[i].type = RTE_ETH_REPRESENTOR_VF; - info->ranges[i].controller = 0; - info->ranges[i].pf = pf; - info->ranges[i].vf = 0; - info->ranges[i].id_base = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, 0); - info->ranges[i].id_end = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - snprintf(info->ranges[i].name, - sizeof(info->ranges[i].name), "pf%dvf", pf); - i++; - if (i == n_entries) - break; - /* HPF range of VF type. */ - info->ranges[i].type = RTE_ETH_REPRESENTOR_VF; - info->ranges[i].controller = 0; - info->ranges[i].pf = pf; - info->ranges[i].vf = UINT16_MAX; - info->ranges[i].id_base = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - info->ranges[i].id_end = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - snprintf(info->ranges[i].name, - sizeof(info->ranges[i].name), "pf%dvf", pf); - i++; - if (i == n_entries) - break; - /* SF range. */ - info->ranges[i].type = RTE_ETH_REPRESENTOR_SF; - info->ranges[i].controller = 0; - info->ranges[i].pf = pf; - info->ranges[i].vf = 0; - info->ranges[i].id_base = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, 0); - info->ranges[i].id_end = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - snprintf(info->ranges[i].name, - sizeof(info->ranges[i].name), "pf%dsf", pf); - i++; - if (i == n_entries) - break; - /* HPF range of SF type. */ - info->ranges[i].type = RTE_ETH_REPRESENTOR_SF; - info->ranges[i].controller = 0; - info->ranges[i].pf = pf; - info->ranges[i].vf = UINT16_MAX; - info->ranges[i].id_base = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - info->ranges[i].id_end = - MLX5_REPRESENTOR_ID(pf, info->ranges[i].type, -1); - snprintf(info->ranges[i].name, - sizeof(info->ranges[i].name), "pf%dsf", pf); - i++; - if (i == n_entries) - break; - } - info->nb_ranges = i; -out: - return n_type * n_pf; } /** @@ -674,7 +745,6 @@ int mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu) { - struct mlx5_priv *priv = dev->data->dev_private; uint16_t kern_mtu = 0; int ret; @@ -683,7 +753,6 @@ return ret; if (kern_mtu == mtu) { - priv->mtu = mtu; DRV_LOG(DEBUG, "port %u adapter MTU was already set to %u", dev->data->port_id, mtu); return 0; @@ -697,7 +766,6 @@ if (ret) return ret; if (kern_mtu == mtu) { - priv->mtu = mtu; DRV_LOG(DEBUG, "port %u adapter MTU set to %u", dev->data->port_id, mtu); return 0; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow.c dpdk-24.11.8/drivers/net/mlx5/mlx5_flow.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -1887,6 +1887,7 @@ data->flow_meta_port_mask = priv->sh->dv_meta_mask; } } + data->mark = !!priv->mark_enabled; data->mark_flag = mark_flag; } } @@ -9889,6 +9890,13 @@ mlx5_flow_async_pool_query_handle(struct mlx5_dev_ctx_shared *sh, uint64_t async_id, int status) { + /* + * Handle async counter pool query completion. + * query_gen is flipped each round: freed counters go into [query_gen], + * while this callback moves [query_gen ^ 1] to the global free list. + * pool->csl must be held when operating on pool->counters[] to serialize + * with concurrent free-path insertions. + */ struct mlx5_flow_counter_pool *pool = (struct mlx5_flow_counter_pool *)(uintptr_t)async_id; struct mlx5_counter_stats_raw *raw_to_free; @@ -9900,6 +9908,21 @@ if (unlikely(status)) { raw_to_free = pool->raw_hw; + /* + * The query failed, so the freed counters accumulated + * in the old-gen list would otherwise be stranded. + * Move them back to the global free list. This is safe + * for both transient and persistent failures: the + * counters are still valid and can be reused. + */ + if (!TAILQ_EMPTY(&pool->counters[query_gen])) { + rte_spinlock_lock(&pool->csl); + rte_spinlock_lock(&cmng->csl[cnt_type]); + TAILQ_CONCAT(&cmng->counters[cnt_type], + &pool->counters[query_gen], next); + rte_spinlock_unlock(&cmng->csl[cnt_type]); + rte_spinlock_unlock(&pool->csl); + } } else { raw_to_free = pool->raw; if (pool->is_aged) @@ -9909,11 +9932,20 @@ rte_spinlock_unlock(&pool->sl); /* Be sure the new raw counters data is updated in memory. */ rte_io_wmb(); + /* + * A counter free thread may have read a stale query_gen + * before the generation was flipped and could still be + * inserting into this same old-gen list. Hold pool->csl to + * serialize TAILQ_CONCAT with that TAILQ_INSERT_TAIL and + * avoid corrupting the list. + */ if (!TAILQ_EMPTY(&pool->counters[query_gen])) { + rte_spinlock_lock(&pool->csl); rte_spinlock_lock(&cmng->csl[cnt_type]); TAILQ_CONCAT(&cmng->counters[cnt_type], &pool->counters[query_gen], next); rte_spinlock_unlock(&cmng->csl[cnt_type]); + rte_spinlock_unlock(&pool->csl); } } LIST_INSERT_HEAD(&sh->sws_cmng.free_stat_raws, raw_to_free, next); @@ -11899,6 +11931,12 @@ "flex item available on BlueField ports only"); return NULL; } + if (!priv->sh->cdev->config.hca_attr.parse_graph_flex_node) { + rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "flex item not supported on current FW"); + return NULL; + } if (!fops->item_create) { DRV_LOG(ERR, "port %u %s.", dev->data->port_id, err_msg); rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow.h dpdk-24.11.8/drivers/net/mlx5/mlx5_flow.h --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow.h 2026-10-14 13:10:05.000000000 +0000 @@ -2969,6 +2969,13 @@ [MLX5_FLOW_HW_CTRL_RX_EXPANDED_RSS_MAX]; }; +/* Contains all templates and table required for redirecting LACP traffic with HWS. */ +struct mlx5_flow_hw_lacp_miss { + struct rte_flow_pattern_template *lacp_rx_items_tmpl; + struct rte_flow_actions_template *lacp_rx_actions_tmpl; + struct rte_flow_template_table *hw_lacp_rx_tbl; +}; + /* Contains all templates required for control flow rules in FDB with HWS. */ struct mlx5_flow_hw_ctrl_fdb { struct rte_flow_pattern_template *esw_mgr_items_tmpl; @@ -2983,9 +2990,6 @@ struct rte_flow_pattern_template *tx_meta_items_tmpl; struct rte_flow_actions_template *tx_meta_actions_tmpl; struct rte_flow_template_table *hw_tx_meta_cpy_tbl; - struct rte_flow_pattern_template *lacp_rx_items_tmpl; - struct rte_flow_actions_template *lacp_rx_actions_tmpl; - struct rte_flow_template_table *hw_lacp_rx_tbl; }; #define MLX5_CTRL_PROMISCUOUS (RTE_BIT32(0)) @@ -3652,6 +3656,8 @@ return 0; } +uint8_t mlx5_flex_hdr_len_mask(uint8_t shift, const struct mlx5_hca_flex_attr *attr); + static inline bool mlx5_dv_modify_ipv6_traffic_class_supported(struct mlx5_priv *priv) { @@ -3660,6 +3666,37 @@ void mlx5_indirect_list_handles_release(struct rte_eth_dev *dev); + +/** + * Returns true if Rx control rule for LACP traffic is needed. + * + * mlx5 PMD needs to create a rule matching LACP traffic and forwarding it back to kernel if: + * + * - Underlying device is a bond interface. + * - User did not request to handle LACP traffic in user space. + * + * Creation of this rule is also controlled by the E-Switch mode: + * + * - It must be created in legacy mode. + * - It must be created only on proxy port in switchdev mode. + * + * @param[in] priv + * Pointer to Ethernet device structure. + * + * @return + * True if LACP rules must be created. + * False otherwise. + */ +static inline bool +mlx5_flow_lacp_miss_needed(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + return !priv->sh->config.lacp_by_user && + priv->pf_bond >= 0 && + (!priv->sh->esw_mode || (priv->sh->esw_mode && priv->master)); +} + #ifdef HAVE_MLX5_HWS_SUPPORT #define MLX5_REPR_STC_MEMORY_LOG 11 diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_aso.c dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_aso.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_aso.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_aso.c 2026-10-14 13:10:05.000000000 +0000 @@ -1851,37 +1851,37 @@ sh->cnt_svc->aso_mng.sq_num = 0; } -static uint16_t +static uint32_t +aso_hw_id(uint32_t base, uint32_t offset) +{ + return (base + offset) / 4; +} + +static uint32_t mlx5_aso_cnt_sq_enqueue_burst(struct mlx5_hws_cnt_pool *cpool, struct mlx5_dev_ctx_shared *sh, struct mlx5_aso_sq *sq, uint32_t n, - uint32_t offset, uint32_t dcs_id_base) + uint32_t stats_mem_idx, uint32_t aso_id) { volatile struct mlx5_aso_wqe *wqe; uint16_t size = 1 << sq->log_desc_n; uint16_t mask = size - 1; uint16_t max; - uint32_t upper_offset = offset; uint64_t addr; - uint32_t ctrl_gen_id = 0; uint8_t opcmod = sh->cdev->config.hca_attr.flow_access_aso_opc_mod; rte_be32_t lkey = rte_cpu_to_be_32(cpool->raw_mng->mr.lkey); uint16_t aso_n = (uint16_t)(RTE_ALIGN_CEIL(n, 4) / 4); - uint32_t ccntid; + uint32_t bursted_cnts = 0; max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), aso_n); if (unlikely(!max)) return 0; - upper_offset += (max * 4); /* Because only one burst at one time, we can use the same elt. */ sq->elts[0].burst_size = max; - ctrl_gen_id = dcs_id_base; - ctrl_gen_id /= 4; do { - ccntid = upper_offset - max * 4; wqe = &sq->sq_obj.aso_wqes[sq->head & mask]; rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]); - wqe->general_cseg.misc = rte_cpu_to_be_32(ctrl_gen_id); + wqe->general_cseg.misc = rte_cpu_to_be_32(aso_id); wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR << MLX5_COMP_MODE_OFFSET); wqe->general_cseg.opcode = rte_cpu_to_be_32 @@ -1891,22 +1891,24 @@ (sq->pi << WQE_CSEG_WQE_INDEX_OFFSET)); addr = (uint64_t)RTE_PTR_ADD(cpool->raw_mng->raw, - ccntid * sizeof(struct flow_counter_stats)); + stats_mem_idx * sizeof(struct flow_counter_stats)); wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32)); wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u); wqe->aso_cseg.lkey = lkey; sq->pi += 2; /* Each WQE contains 2 WQEBB's. */ sq->head++; sq->next++; - ctrl_gen_id++; + aso_id++; max--; + stats_mem_idx += 4; } while (max); wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS << MLX5_COMP_MODE_OFFSET); mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe, sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR], !sh->tx_uar.dbnc); - return sq->elts[0].burst_size; + bursted_cnts = RTE_MIN((uint32_t)(sq->elts[0].burst_size * 4), n); + return bursted_cnts; } static uint16_t @@ -1949,7 +1951,7 @@ return i; } -static uint16_t +static uint64_t mlx5_aso_cnt_query_one_dcs(struct mlx5_dev_ctx_shared *sh, struct mlx5_hws_cnt_pool *cpool, uint8_t dcs_idx, uint32_t num) @@ -1958,7 +1960,7 @@ uint64_t cnt_num = cpool->dcs_mng.dcs[dcs_idx].batch_sz; uint64_t left; uint32_t iidx = cpool->dcs_mng.dcs[dcs_idx].iidx; - uint32_t offset; + uint32_t bursted, dcs_offset = 0; uint16_t mask; uint16_t sq_idx; uint64_t burst_sz = (uint64_t)(1 << MLX5_ASO_CNT_QUEUE_LOG_DESC) * 4 * @@ -1978,12 +1980,12 @@ continue; } n = RTE_MIN(left, qburst_sz); - offset = cnt_num - left; - offset += iidx; - mlx5_aso_cnt_sq_enqueue_burst(cpool, sh, - &sh->cnt_svc->aso_mng.sqs[sq_idx], n, - offset, dcs_id); - left -= n; + bursted = mlx5_aso_cnt_sq_enqueue_burst(cpool, sh, + &sh->cnt_svc->aso_mng.sqs[sq_idx], n, + iidx, aso_hw_id(dcs_id, dcs_offset)); + left -= bursted; + dcs_offset += bursted; + iidx += bursted; } do { for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_dv.c dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_dv.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_dv.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_dv.c 2026-10-14 13:10:05.000000000 +0000 @@ -7119,6 +7119,7 @@ struct mlx5_flow_counter_pool *pool = NULL; struct mlx5_flow_counter *cnt; enum mlx5_counter_type cnt_type; + uint32_t query_gen; if (!counter) return; @@ -7143,16 +7144,17 @@ cnt->pool = pool; /* * Put the counter back to list to be updated in none fallback mode. - * Currently, we are using two list alternately, while one is in query, + * Currently, we are using two lists alternately, while one is in query, * add the freed counter to the other list based on the pool query_gen * value. After query finishes, add counter the list to the global - * container counter list. The list changes while query starts. In - * this case, lock will not be needed as query callback and release - * function both operate with the different list. + * container counter list. Cache query_gen into a local variable before + * TAILQ_INSERT_TAIL, since the macro evaluates its head argument + * multiple times and pool->query_gen is a volatile bit-field. */ if (!priv->sh->sws_cmng.counter_fallback) { rte_spinlock_lock(&pool->csl); - TAILQ_INSERT_TAIL(&pool->counters[pool->query_gen], cnt, next); + query_gen = pool->query_gen; + TAILQ_INSERT_TAIL(&pool->counters[query_gen], cnt, next); rte_spinlock_unlock(&pool->csl); } else { cnt->dcs_when_free = cnt->dcs_when_active; @@ -7276,10 +7278,16 @@ struct mlx5_aso_mtr_pools_mng *pools_mng = &priv->sh->mtrmng->pools_mng; struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx); + void *meter_action_g; + void *meter_action_y; MLX5_ASSERT(aso_mtr); rte_spinlock_lock(&pools_mng->mtrsl); + meter_action_g = aso_mtr->fm.meter_action_g; + meter_action_y = aso_mtr->fm.meter_action_y; memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info)); + aso_mtr->fm.meter_action_g = meter_action_g; + aso_mtr->fm.meter_action_y = meter_action_y; aso_mtr->state = ASO_METER_FREE; LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next); rte_spinlock_unlock(&pools_mng->mtrsl); diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_flex.c dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_flex.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_flex.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_flex.c 2026-10-14 13:10:05.000000000 +0000 @@ -458,7 +458,7 @@ * 6 b00000011 0x03 * 7 b00000001 0x01 */ -static uint8_t +uint8_t mlx5_flex_hdr_len_mask(uint8_t shift, const struct mlx5_hca_flex_attr *attr) { @@ -482,6 +482,7 @@ return rte_flow_error_set (error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL, "not byte aligned header length field"); + node->header_length_field_offset_mode = !attr->header_length_field_mode_wa; switch (field->field_mode) { case FIELD_MODE_DUMMY: return rte_flow_error_set @@ -572,7 +573,6 @@ node->header_length_field_mask = mask; node->header_length_field_shift = shift; node->header_length_field_offset = offset; - node->header_length_field_offset_mode = !attr->header_length_field_mode_wa; break; } case FIELD_MODE_BITMASK: diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_hw.c dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_hw.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_flow_hw.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_flow_hw.c 2026-10-14 13:10:05.000000000 +0000 @@ -1839,64 +1839,67 @@ #endif } -static __rte_always_inline struct mlx5_aso_mtr * +static __rte_always_inline int flow_hw_meter_mark_alloc(struct rte_eth_dev *dev, uint32_t queue, const struct rte_flow_action *action, struct mlx5_hw_q_job *job, bool push, + struct mlx5_aso_mtr **aso_mtr, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; const struct rte_flow_action_meter_mark *meter_mark = action->conf; - struct mlx5_aso_mtr *aso_mtr; struct mlx5_flow_meter_info *fm; uint32_t mtr_id = 0; uintptr_t handle = (uintptr_t)MLX5_INDIRECT_ACTION_TYPE_METER_MARK << MLX5_INDIRECT_ACTION_TYPE_OFFSET; - if (priv->shared_host) { - rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, - "Meter mark actions can only be created on the host port"); - return NULL; - } + if (priv->shared_host) + return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Meter mark actions can only be created on the host port"); + MLX5_ASSERT(aso_mtr); if (meter_mark->profile == NULL) - return NULL; - aso_mtr = mlx5_ipool_malloc(pool->idx_pool, &mtr_id); - if (!aso_mtr) { - rte_flow_error_set(error, ENOMEM, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, - "failed to allocate aso meter entry"); + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "No Meter mark profile"); + + *aso_mtr = mlx5_ipool_malloc(pool->idx_pool, &mtr_id); + if (!*aso_mtr) { if (mtr_id) mlx5_ipool_free(pool->idx_pool, mtr_id); - return NULL; + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "failed to allocate aso meter entry"); } /* Fill the flow meter parameters. */ - aso_mtr->type = ASO_METER_INDIRECT; - fm = &aso_mtr->fm; + (*aso_mtr)->type = ASO_METER_INDIRECT; + fm = &(*aso_mtr)->fm; fm->meter_id = mtr_id; fm->profile = (struct mlx5_flow_meter_profile *)(meter_mark->profile); fm->is_enable = meter_mark->state; fm->color_aware = meter_mark->color_mode; - aso_mtr->pool = pool; - aso_mtr->state = (queue == MLX5_HW_INV_QUEUE) ? + (*aso_mtr)->pool = pool; + (*aso_mtr)->state = (queue == MLX5_HW_INV_QUEUE) ? ASO_METER_WAIT : ASO_METER_WAIT_ASYNC; - aso_mtr->offset = mtr_id - 1; - aso_mtr->init_color = fm->color_aware ? RTE_COLORS : RTE_COLOR_GREEN; + (*aso_mtr)->offset = mtr_id - 1; + (*aso_mtr)->init_color = fm->color_aware ? RTE_COLORS : RTE_COLOR_GREEN; job->action = (void *)(handle | mtr_id); /* Update ASO flow meter by wqe. */ - if (mlx5_aso_meter_update_by_wqe(priv, queue, aso_mtr, + if (mlx5_aso_meter_update_by_wqe(priv, queue, *aso_mtr, &priv->mtr_bulk, job, push)) { mlx5_ipool_free(pool->idx_pool, mtr_id); - return NULL; + return rte_flow_error_set(error, EBUSY, + RTE_FLOW_ERROR_TYPE_UNSPECIFIED, + NULL, + "Failed to enqueue ASO meter update"); } /* Wait for ASO object completion. */ if (queue == MLX5_HW_INV_QUEUE && - mlx5_aso_mtr_wait(priv, aso_mtr, true)) { + mlx5_aso_mtr_wait(priv, *aso_mtr, true)) { mlx5_ipool_free(pool->idx_pool, mtr_id); - return NULL; + return -EIO; } - return aso_mtr; + return 0; } static __rte_always_inline int @@ -1910,20 +1913,22 @@ { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_aso_mtr_pool *pool = priv->hws_mpool; - struct mlx5_aso_mtr *aso_mtr; + struct mlx5_aso_mtr *aso_mtr = NULL; struct mlx5_hw_q_job *job = flow_hw_action_job_init(priv, queue, NULL, NULL, NULL, MLX5_HW_Q_JOB_TYPE_CREATE, MLX5_HW_INDIRECT_TYPE_LEGACY, NULL); + int ret; if (!job) return -1; - aso_mtr = flow_hw_meter_mark_alloc(dev, queue, action, job, - true, error); - if (!aso_mtr) { - if (queue == MLX5_HW_INV_QUEUE) - queue = CTRL_QUEUE_ID(priv); - flow_hw_job_put(priv, job, queue); + ret = flow_hw_meter_mark_alloc(dev, queue, action, job, true, &aso_mtr, error); + if (ret) { + if (ret != -EIO) { + if (queue == MLX5_HW_INV_QUEUE) + queue = CTRL_QUEUE_ID(priv); + flow_hw_job_put(priv, job, queue); + } return -1; } @@ -2185,6 +2190,60 @@ return ret; } +/** + * Translate given encap action and mask to raw tunnel header buffer. + * + * @param[in] action + * Pointer to encap action. + * @param[in] mask + * Pointer to encap action's mask. + * @param[out] conf_encap_data + * Buffer where tunnel header will be written. + * @param[out] data_size + * Pointer to tunnel header size. + * @param[out] error + * Pointer to error structure. + * + * @return + * 0 or greater if translation was successful. + * Negative errno value otherwise. + * + * If returned value is 0, then action is not shared in the actions template + * If bigger than 0, then it is shared. + */ +static int +translate_l2_encap_action(const struct rte_flow_action *action, + const struct rte_flow_action *mask, + uint8_t conf_encap_data[MLX5_ENCAP_MAX_LEN], + size_t *data_size, + struct rte_flow_error *error) +{ + struct rte_flow_item *conf_item; + int ret; + + if (action->conf == NULL) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL, + "Missing VXLAN/NVGRE encap action configuration"); + + /* Only these 2 action types receive encap data as flow item pattern. */ + MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP || + action->type == RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP); + if (action->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) + conf_item = MLX5_CONST_ENCAP_ITEM(rte_flow_action_vxlan_encap, action->conf); + else + conf_item = MLX5_CONST_ENCAP_ITEM(rte_flow_action_nvgre_encap, action->conf); + if (conf_item == NULL) + return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL, + "Missing VXLAN/NVGRE tunnel definition in action config"); + + ret = flow_dv_convert_encap_data(conf_item, conf_encap_data, data_size, error); + if (ret < 0) + return ret; + + /* If mask is provided, then action is shared */ + return mask->conf != NULL; +} + static void mlx5_set_reformat_header(struct mlx5dr_action_reformat_header *hdr, uint8_t *encap_data, @@ -2198,8 +2257,6 @@ mlx5_tbl_translate_reformat(struct mlx5_priv *priv, struct mlx5_hw_actions *acts, struct rte_flow_actions_template *at, - const struct rte_flow_item *enc_item, - const struct rte_flow_item *enc_item_m, uint8_t *encap_data, uint8_t *encap_data_m, struct mlx5_tbl_multi_pattern_ctx *mp_ctx, size_t data_size, uint16_t reformat_src, @@ -2208,22 +2265,12 @@ { int mp_reformat_ix = mlx5_multi_pattern_reformat_to_index(refmt_type); struct mlx5dr_action_reformat_header hdr; - uint8_t buf[MLX5_ENCAP_MAX_LEN]; bool shared_rfmt = false; int ret; MLX5_ASSERT(at->reformat_off != UINT16_MAX); - if (enc_item) { - MLX5_ASSERT(!encap_data); - ret = flow_dv_convert_encap_data(enc_item, buf, &data_size, error); - if (ret) - return ret; - encap_data = buf; - if (enc_item_m) - shared_rfmt = true; - } else if (encap_data && encap_data_m) { + if (encap_data && encap_data_m) shared_rfmt = true; - } acts->encap_decap = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*acts->encap_decap) + data_size, 0, SOCKET_ID_ANY); @@ -2477,8 +2524,8 @@ enum mlx5dr_action_type recom_type = MLX5DR_ACTION_TYP_LAST; const struct rte_flow_action_raw_encap *raw_encap_data; const struct rte_flow_action_ipv6_ext_push *ipv6_ext_data; - const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL; uint16_t reformat_src = 0, recom_src = 0; + uint8_t converted_encap_data[MLX5_ENCAP_MAX_LEN] = { 0 }; uint8_t *encap_data = NULL, *encap_data_m = NULL; uint8_t *push_data = NULL, *push_data_m = NULL; size_t data_size = 0, push_size = 0; @@ -2651,23 +2698,17 @@ } break; case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP: - MLX5_ASSERT(!reformat_used); - enc_item = MLX5_CONST_ENCAP_ITEM(rte_flow_action_vxlan_encap, - actions->conf); - if (masks->conf) - enc_item_m = MLX5_CONST_ENCAP_ITEM(rte_flow_action_vxlan_encap, - masks->conf); - reformat_used = true; - reformat_src = src_pos; - refmt_type = MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2; - break; case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP: MLX5_ASSERT(!reformat_used); - enc_item = MLX5_CONST_ENCAP_ITEM(rte_flow_action_nvgre_encap, - actions->conf); - if (masks->conf) - enc_item_m = MLX5_CONST_ENCAP_ITEM(rte_flow_action_nvgre_encap, - masks->conf); + ret = translate_l2_encap_action(actions, masks, converted_encap_data, + &data_size, error); + if (ret < 0) + goto err; + /* If masked action, then use converted encap data for shared action. */ + if (ret > 0) { + encap_data = converted_encap_data; + encap_data_m = converted_encap_data; + } reformat_used = true; reformat_src = src_pos; refmt_type = MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2; @@ -2921,7 +2962,6 @@ } if (reformat_used) { ret = mlx5_tbl_translate_reformat(priv, acts, at, - enc_item, enc_item_m, encap_data, encap_data_m, mp_ctx, data_size, reformat_src, @@ -4359,6 +4399,9 @@ struct mlx5_priv *priv = dev->data->dev_private; struct rte_ring *ring = priv->hw_q[queue].flow_transfer_completed; + if (ring == NULL) + return 0; + size = RTE_MIN(rte_ring_count(ring), n_res); for (i = 0; i < size; i++) { res[i].status = RTE_FLOW_OP_SUCCESS; @@ -4590,8 +4633,9 @@ struct mlx5_hw_q *hw_q = &priv->hw_q[queue]; mlx5_hw_push_queue(hw_q->indir_iq, hw_q->indir_cq); - mlx5_hw_push_queue(hw_q->flow_transfer_pending, - hw_q->flow_transfer_completed); + if (hw_q->flow_transfer_pending != NULL && hw_q->flow_transfer_completed != NULL) + mlx5_hw_push_queue(hw_q->flow_transfer_pending, + hw_q->flow_transfer_completed); if (!priv->shared_host) { if (priv->hws_ctpool) mlx5_aso_push_wqe(priv->sh, @@ -5965,10 +6009,6 @@ return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, "destination tag index is not supported"); - if (action_conf->dst.class_id) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, action, - "destination class id is not supported"); } if (mask_conf->dst.level != UINT8_MAX) return rte_flow_error_set(error, EINVAL, @@ -5991,10 +6031,6 @@ return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, "source tag index is not supported"); - if (action_conf->src.class_id) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, action, - "source class id is not supported"); } if (mask_conf->src.level != UINT8_MAX) return rte_flow_error_set(error, EINVAL, @@ -8122,6 +8158,34 @@ return 0; } +/* + * Build a new item array prefixed with @p new_item. + * + * Callers typically build @p new_item on their stack with .spec / .mask + * pointing at other stack locals, so a shallow copy of @p new_item would + * leave dangling pointers as soon as the caller's frame goes away. + * + * To make the returned array self-contained, deep-copy @p new_item (item + * header + spec/mask/last payloads) into the tail of the same allocation + * via rte_flow_conv(RTE_FLOW_CONV_OP_ITEM, ...). The remaining items[] + * are still shallow-copied: they reference the application-owned spec/ + * mask blobs handed to rte_flow_create() / rte_flow_pattern_template_ + * create(), whose lifetime already covers the returned array's use. + * + * Layout of the single mlx5_malloc() block: + * + * +--------------------------------------+ <- returned pointer + * | rte_flow_item[nb_items + 1] | slot 0: copy of the deep- + * | | copied header below + * | | slots 1..nb_items: shallow + * | | copies of items[] + * +--------------------------------------+ <- new_item_buf + * | rte_flow_item header (deep copy) | written by rte_flow_conv; + * | + spec / mask / last payloads, | header.spec/.mask/.last point + * | contiguous, self-referential | into the payloads right below + * +--------------------------------------+ + * + */ static struct rte_flow_item * flow_hw_prepend_item(const struct rte_flow_item *items, const uint32_t nb_items, @@ -8129,11 +8193,24 @@ struct rte_flow_error *error) { struct rte_flow_item *copied_items; - size_t size; + size_t header_size; + size_t total_size; + void *new_item_buf; + int new_item_size; + int rc; - /* Allocate new array of items. */ - size = sizeof(*copied_items) * (nb_items + 1); - copied_items = mlx5_malloc(MLX5_MEM_ZERO, size, 0, rte_socket_id()); + /* + * Size the deep copy of the prepended item (header + payloads). + * On error, rte_flow_conv() already populates @p error. + */ + new_item_size = rte_flow_conv(RTE_FLOW_CONV_OP_ITEM, NULL, 0, new_item, error); + if (new_item_size < 0) + return NULL; + + header_size = sizeof(*copied_items) * (nb_items + 1); + total_size = header_size + (size_t)new_item_size; + + copied_items = mlx5_malloc(MLX5_MEM_ZERO, total_size, 0, rte_socket_id()); if (!copied_items) { rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -8141,8 +8218,23 @@ "cannot allocate item template"); return NULL; } - /* Put new item at the beginning and copy the rest. */ - copied_items[0] = *new_item; + + /* Deep-copy the prepended item into the tail region. */ + new_item_buf = (char *)copied_items + header_size; + rc = rte_flow_conv(RTE_FLOW_CONV_OP_ITEM, new_item_buf, (size_t)new_item_size, new_item, + error); + if (rc < 0) { + mlx5_free(copied_items); + return NULL; + } + + /* + * Slot 0 is the prepended item header just written by rte_flow_conv, + * with .spec/.mask/.last already pointing inside the same buffer. + * The remaining items[] retain their (caller-owned, longer-lived) + * spec/mask pointers via shallow copy. + */ + copied_items[0] = *(const struct rte_flow_item *)new_item_buf; rte_memcpy(&copied_items[1], items, sizeof(*items) * nb_items); return copied_items; } @@ -8853,32 +8945,40 @@ return -ret; } -/** - * Create flow item template. - * - * @param[in] dev - * Pointer to the rte_eth_dev structure. - * @param[in] attr - * Pointer to the item template attributes. - * @param[in] items - * The template item pattern. - * @param[out] error - * Pointer to error structure. - * - * @return - * Item template pointer on success, NULL otherwise and rte_errno is set. +/* + * Validate the user-supplied items and, in eSwitch mode, prepend the implicit + * scoping item so the rule/template is bound to the current representor port: + * - ingress -> RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT (dev->data->port_id) + * - egress -> MLX5_RTE_FLOW_ITEM_TYPE_TAG on REG_C_0 (tx vport tag), + * skipped when the user already supplied an SQ item. + * + * @param nt_flow + * Selects between the two call paths that share this helper: + * false -> pattern template creation (async API). The prepended item's + * spec is left zeroed so mlx5dr matches any value; the live + * port_id / tx-tag value is substituted later by + * flow_hw_get_rule_items() at rule-create time. + * true -> sync (non-template) flow creation. The prepended item's spec + * is filled immediately with the live values, and the flag is + * forwarded to __flow_hw_pattern_validate() so that validation + * paths gated on nt_flow (e.g. GENEVE_OPT TLV parser creation) + * take the non-template branch. + * + * Return / ownership: + * - NULL on validation or allocation failure (error populated). + * - `items` unchanged when no prepending is required; *copied_items == NULL. + * - A newly-allocated array otherwise; also stored in *copied_items. The + * caller must mlx5_free(*copied_items) on every path (it is safe to call + * with NULL). Do not free the returned pointer directly. */ -static struct rte_flow_pattern_template * -flow_hw_pattern_template_create(struct rte_eth_dev *dev, - const struct rte_flow_pattern_template_attr *attr, - const struct rte_flow_item items[], - struct rte_flow_error *error) +static const struct rte_flow_item * +flow_hw_adjust_pattern(struct rte_eth_dev *dev, const struct rte_flow_pattern_template_attr *attr, + bool nt_flow, const struct rte_flow_item *items, uint64_t *item_flags, + uint64_t *nb_items, struct rte_flow_item **copied_items, + struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; - struct rte_flow_pattern_template *it; - struct rte_flow_item *copied_items = NULL; - const struct rte_flow_item *tmpl_items; - uint64_t orig_item_nb, item_flags = 0; + struct rte_flow_item_ethdev port_spec = {.port_id = dev->data->port_id}; struct rte_flow_item port = { .type = RTE_FLOW_ITEM_TYPE_REPRESENTED_PORT, .mask = &rte_flow_item_ethdev_mask, @@ -8895,41 +8995,96 @@ .type = (enum rte_flow_item_type)MLX5_RTE_FLOW_ITEM_TYPE_TAG, .spec = &tag_v, .mask = &tag_m, - .last = NULL + .last = NULL, }; - int it_items_size; - unsigned int i = 0; int rc; + if (!copied_items || !item_flags || !nb_items) + return NULL; + + if (nt_flow) { + port.spec = &port_spec; + tag_v.data = flow_hw_tx_tag_regc_value(dev); + } + + /* + * item_flags must be zero-initialized: __flow_hw_pattern_validate() + * OR-accumulates bits into it and reads it (MLX5_FLOW_LAYER_TUNNEL) + * on the first iteration. + */ + *item_flags = 0; + /* Validate application items only */ - rc = flow_hw_pattern_validate(dev, attr, items, &item_flags, error); + rc = __flow_hw_pattern_validate(dev, attr, items, item_flags, nt_flow, error); if (rc < 0) return NULL; - orig_item_nb = rc; + *nb_items = rc; + if (priv->sh->config.dv_esw_en && priv->sh->config.repr_matching && - attr->ingress && !attr->egress && !attr->transfer) { - copied_items = flow_hw_prepend_item(items, orig_item_nb, &port, error); - if (!copied_items) + attr->ingress && + !attr->egress && + !attr->transfer) { + *copied_items = flow_hw_prepend_item(items, *nb_items, &port, error); + if (!*copied_items) return NULL; - tmpl_items = copied_items; + return *copied_items; } else if (priv->sh->config.dv_esw_en && - priv->sh->config.repr_matching && - !attr->ingress && attr->egress && !attr->transfer) { - if (item_flags & MLX5_FLOW_ITEM_SQ) { - DRV_LOG(DEBUG, "Port %u omitting implicit REG_C_0 match for egress " - "pattern template", dev->data->port_id); - tmpl_items = items; - goto setup_pattern_template; + priv->sh->config.repr_matching && + !attr->ingress && + attr->egress && + !attr->transfer) { + if (*item_flags & MLX5_FLOW_ITEM_SQ) { + DRV_LOG(DEBUG, + "Port %u: explicit SQ item present, omitting implicit " + "REG_C_0 match for egress pattern", + dev->data->port_id); + return items; } - copied_items = flow_hw_prepend_item(items, orig_item_nb, &tag, error); - if (!copied_items) + *copied_items = flow_hw_prepend_item(items, *nb_items, &tag, error); + if (!*copied_items) return NULL; - tmpl_items = copied_items; - } else { - tmpl_items = items; + return *copied_items; } -setup_pattern_template: + return items; +} + +/** + * Create flow item template. + * + * @param[in] dev + * Pointer to the rte_eth_dev structure. + * @param[in] attr + * Pointer to the item template attributes. + * @param[in] items + * The template item pattern. + * @param[out] error + * Pointer to error structure. + * + * @return + * Item template pointer on success, NULL otherwise and rte_errno is set. + */ +static struct rte_flow_pattern_template * +flow_hw_pattern_template_create(struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + bool external, + struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_pattern_template *it; + struct rte_flow_item *copied_items = NULL; + const struct rte_flow_item *tmpl_items; + int it_items_size; + uint64_t orig_item_nb, item_flags; + unsigned int i = 0; + int rc; + + tmpl_items = flow_hw_adjust_pattern(dev, attr, false, items, &item_flags, &orig_item_nb, + &copied_items, error); + if (!tmpl_items) + return NULL; + it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id()); if (!it) { rte_flow_error_set(error, ENOMEM, @@ -9028,9 +9183,11 @@ } } rte_atomic_fetch_add_explicit(&it->refcnt, 1, rte_memory_order_relaxed); - rc = pattern_template_validate(dev, &it, 1, error); - if (rc) - goto error; + if (external) { + rc = pattern_template_validate(dev, &it, 1, error); + if (rc) + goto error; + } LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next); return it; error: @@ -9049,6 +9206,16 @@ return NULL; } +static struct rte_flow_pattern_template * +flow_hw_external_pattern_template_create + (struct rte_eth_dev *dev, + const struct rte_flow_pattern_template_attr *attr, + const struct rte_flow_item items[], + struct rte_flow_error *error) +{ + return flow_hw_pattern_template_create(dev, attr, items, true, error); +} + /** * Destroy flow item template. * @@ -9602,7 +9769,7 @@ }, }; - return flow_hw_pattern_template_create(dev, &attr, items, error); + return flow_hw_pattern_template_create(dev, &attr, items, false, error); } static __rte_always_inline uint32_t @@ -9895,7 +10062,7 @@ }, }; - return flow_hw_pattern_template_create(dev, &attr, items, error); + return flow_hw_pattern_template_create(dev, &attr, items, false, error); } /** @@ -9949,7 +10116,7 @@ }, }; - return flow_hw_pattern_template_create(dev, &attr, items, error); + return flow_hw_pattern_template_create(dev, &attr, items, false, error); } /** @@ -9986,7 +10153,7 @@ }, }; - return flow_hw_pattern_template_create(dev, &attr, items, error); + return flow_hw_pattern_template_create(dev, &attr, items, false, error); } /* @@ -10022,7 +10189,8 @@ .type = RTE_FLOW_ITEM_TYPE_END, }, }; - return flow_hw_pattern_template_create(dev, &pa_attr, eth_all, error); + return flow_hw_pattern_template_create(dev, &pa_attr, eth_all, + false, error); } /** @@ -10500,15 +10668,6 @@ if (!priv->hw_ctrl_fdb) return; hw_ctrl_fdb = priv->hw_ctrl_fdb; - /* Clean up templates used for LACP default miss table. */ - if (hw_ctrl_fdb->hw_lacp_rx_tbl) - claim_zero(flow_hw_table_destroy(dev, hw_ctrl_fdb->hw_lacp_rx_tbl, NULL)); - if (hw_ctrl_fdb->lacp_rx_actions_tmpl) - claim_zero(flow_hw_actions_template_destroy(dev, hw_ctrl_fdb->lacp_rx_actions_tmpl, - NULL)); - if (hw_ctrl_fdb->lacp_rx_items_tmpl) - claim_zero(flow_hw_pattern_template_destroy(dev, hw_ctrl_fdb->lacp_rx_items_tmpl, - NULL)); /* Clean up templates used for default Tx metadata copy. */ if (hw_ctrl_fdb->hw_tx_meta_cpy_tbl) claim_zero(flow_hw_table_destroy(dev, hw_ctrl_fdb->hw_tx_meta_cpy_tbl, NULL)); @@ -10587,6 +10746,96 @@ return flow_hw_table_create(dev, &cfg, &it, 1, &at, 1, error); } +/* + * Clean up templates and table used for redirecting LACP traffic to kernel. + * + * @param dev + * Pointer to Ethernet device. + */ +static void +flow_hw_cleanup_lacp_miss_tables(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_hw_lacp_miss *hw_lacp_miss; + + if (priv->hw_lacp_miss == NULL) + return; + + hw_lacp_miss = priv->hw_lacp_miss; + + if (hw_lacp_miss->hw_lacp_rx_tbl) + claim_zero(flow_hw_table_destroy(dev, hw_lacp_miss->hw_lacp_rx_tbl, NULL)); + if (hw_lacp_miss->lacp_rx_actions_tmpl) + claim_zero(flow_hw_actions_template_destroy(dev, + hw_lacp_miss->lacp_rx_actions_tmpl, + NULL)); + if (hw_lacp_miss->lacp_rx_items_tmpl) + claim_zero(flow_hw_pattern_template_destroy(dev, + hw_lacp_miss->lacp_rx_items_tmpl, + NULL)); + + mlx5_free(hw_lacp_miss); + priv->hw_lacp_miss = NULL; +} + +/* + * Create templates and table for redirecting LACP traffic to kernel. + * + * LACP traffic redirection is needed whenever LACP bond is managed by the kernel. + * Required rule has a following structure: + * + * - ingress rule on root table + * - match EtherType 0x8809 + * - action DEFAULT_MISS + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * 0 on success. Negative errno otherwise. + */ +static int +flow_hw_create_lacp_miss_tables(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct mlx5_flow_hw_lacp_miss *hw_lacp_miss; + + hw_lacp_miss = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*hw_lacp_miss), 0, SOCKET_ID_ANY); + if (!hw_lacp_miss) { + DRV_LOG(ERR, "port %u Failed to allocate memory for LACP miss tables", + dev->data->port_id); + return -ENOMEM; + } + priv->hw_lacp_miss = hw_lacp_miss; + + hw_lacp_miss->lacp_rx_items_tmpl = flow_hw_create_lacp_rx_pattern_template(dev, NULL); + if (!hw_lacp_miss->lacp_rx_items_tmpl) { + DRV_LOG(ERR, "port %u Failed to create pattern template for LACP Rx traffic", + dev->data->port_id); + goto error; + } + hw_lacp_miss->lacp_rx_actions_tmpl = flow_hw_create_lacp_rx_actions_template(dev, NULL); + if (!hw_lacp_miss->lacp_rx_actions_tmpl) { + DRV_LOG(ERR, "port %u Failed to create actions template for LACP Rx traffic", + dev->data->port_id); + goto error; + } + hw_lacp_miss->hw_lacp_rx_tbl = + flow_hw_create_lacp_rx_table(dev, hw_lacp_miss->lacp_rx_items_tmpl, + hw_lacp_miss->lacp_rx_actions_tmpl, NULL); + if (!hw_lacp_miss->hw_lacp_rx_tbl) { + DRV_LOG(ERR, "port %u Failed to create template table for LACP Rx traffic", + dev->data->port_id); + goto error; + } + + return 0; + +error: + flow_hw_cleanup_lacp_miss_tables(dev); + return -EINVAL; +} + /** * Creates a set of flow tables used to create control flows used * when E-Switch is engaged. @@ -10717,31 +10966,6 @@ goto err; } } - /* Create LACP default miss table. */ - if (!priv->sh->config.lacp_by_user && priv->pf_bond >= 0 && priv->master) { - hw_ctrl_fdb->lacp_rx_items_tmpl = - flow_hw_create_lacp_rx_pattern_template(dev, error); - if (!hw_ctrl_fdb->lacp_rx_items_tmpl) { - DRV_LOG(ERR, "port %u failed to create pattern template" - " for LACP Rx traffic", dev->data->port_id); - goto err; - } - hw_ctrl_fdb->lacp_rx_actions_tmpl = - flow_hw_create_lacp_rx_actions_template(dev, error); - if (!hw_ctrl_fdb->lacp_rx_actions_tmpl) { - DRV_LOG(ERR, "port %u failed to create actions template" - " for LACP Rx traffic", dev->data->port_id); - goto err; - } - hw_ctrl_fdb->hw_lacp_rx_tbl = flow_hw_create_lacp_rx_table - (dev, hw_ctrl_fdb->lacp_rx_items_tmpl, - hw_ctrl_fdb->lacp_rx_actions_tmpl, error); - if (!hw_ctrl_fdb->hw_lacp_rx_tbl) { - DRV_LOG(ERR, "port %u failed to create template table for" - " for LACP Rx traffic", dev->data->port_id); - goto err; - } - } return 0; err: @@ -11233,7 +11457,7 @@ { .type = RTE_FLOW_ITEM_TYPE_END } }; - return flow_hw_pattern_template_create(dev, &attr, items, NULL); + return flow_hw_pattern_template_create(dev, &attr, items, false, NULL); } int @@ -11464,6 +11688,7 @@ flow_hw_rxq_flag_set(dev, false); flow_hw_flush_all_ctrl_flows(dev); + flow_hw_cleanup_lacp_miss_tables(dev); flow_hw_cleanup_ctrl_fdb_tables(dev); flow_hw_cleanup_tx_repr_tagging(dev); flow_hw_action_template_drop_release(dev); @@ -11569,6 +11794,60 @@ } static int +flow_hw_queue_setup_rings(struct rte_eth_dev *dev, + uint16_t queue, + uint32_t queue_size, + bool nt_mode) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + /* HWS queue info container must be already allocated. */ + MLX5_ASSERT(priv->hw_q != NULL); + + /* Notice ring name length is limited. */ + priv->hw_q[queue].indir_cq = mlx5_hwq_ring_create + (dev->data->port_id, queue, queue_size, "indir_act_cq"); + if (!priv->hw_q[queue].indir_cq) { + DRV_LOG(ERR, "port %u failed to allocate indir_act_cq ring for HWS", + dev->data->port_id); + return -ENOMEM; + } + + priv->hw_q[queue].indir_iq = mlx5_hwq_ring_create + (dev->data->port_id, queue, queue_size, "indir_act_iq"); + if (!priv->hw_q[queue].indir_iq) { + DRV_LOG(ERR, "port %u failed to allocate indir_act_iq ring for HWS", + dev->data->port_id); + return -ENOMEM; + } + + /* + * Sync flow API does not require rings used for table resize handling, + * because these rings are only used through async flow APIs. + */ + if (nt_mode) + return 0; + + priv->hw_q[queue].flow_transfer_pending = mlx5_hwq_ring_create + (dev->data->port_id, queue, queue_size, "tx_pending"); + if (!priv->hw_q[queue].flow_transfer_pending) { + DRV_LOG(ERR, "port %u failed to allocate tx_pending ring for HWS", + dev->data->port_id); + return -ENOMEM; + } + + priv->hw_q[queue].flow_transfer_completed = mlx5_hwq_ring_create + (dev->data->port_id, queue, queue_size, "tx_done"); + if (!priv->hw_q[queue].flow_transfer_completed) { + DRV_LOG(ERR, "port %u failed to allocate tx_done ring for HWS", + dev->data->port_id); + return -ENOMEM; + } + + return 0; +} + +static int flow_hw_validate_attributes(const struct rte_flow_port_attr *port_attr, uint16_t nb_queue, const struct rte_flow_queue_attr *queue_attr[], @@ -11735,22 +12014,8 @@ &priv->hw_q[i].job[_queue_attr[i]->size]; for (j = 0; j < _queue_attr[i]->size; j++) priv->hw_q[i].job[j] = &job[j]; - /* Notice ring name length is limited. */ - priv->hw_q[i].indir_cq = mlx5_hwq_ring_create - (dev->data->port_id, i, _queue_attr[i]->size, "indir_act_cq"); - if (!priv->hw_q[i].indir_cq) - goto err; - priv->hw_q[i].indir_iq = mlx5_hwq_ring_create - (dev->data->port_id, i, _queue_attr[i]->size, "indir_act_iq"); - if (!priv->hw_q[i].indir_iq) - goto err; - priv->hw_q[i].flow_transfer_pending = mlx5_hwq_ring_create - (dev->data->port_id, i, _queue_attr[i]->size, "tx_pending"); - if (!priv->hw_q[i].flow_transfer_pending) - goto err; - priv->hw_q[i].flow_transfer_completed = mlx5_hwq_ring_create - (dev->data->port_id, i, _queue_attr[i]->size, "tx_done"); - if (!priv->hw_q[i].flow_transfer_completed) + + if (flow_hw_queue_setup_rings(dev, i, _queue_attr[i]->size, nt_mode) < 0) goto err; } dr_ctx_attr.pd = priv->sh->cdev->pd; @@ -11855,6 +12120,14 @@ if (ret) goto err; } + if (mlx5_flow_lacp_miss_needed(dev)) { + ret = flow_hw_create_lacp_miss_tables(dev); + if (ret) { + rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, + "Unable to create LACP miss flow tables"); + goto err; + } + } /* * DEFAULT_MISS action have different behaviors in different domains. * In FDB, it will steering the packets to the E-switch manager. @@ -12377,12 +12650,13 @@ struct mlx5_hw_q_job *job = NULL; struct mlx5_priv *priv = dev->data->dev_private; const struct rte_flow_action_age *age; - struct mlx5_aso_mtr *aso_mtr; + struct mlx5_aso_mtr *aso_mtr = NULL; cnt_id_t cnt_id; uint32_t age_idx; bool push = flow_hw_action_push(attr); bool aso = false; bool force_job = action->type == RTE_FLOW_ACTION_TYPE_METER_MARK; + int ret; if (!mlx5_hw_ctx_validate(dev, error)) return NULL; @@ -12438,9 +12712,15 @@ break; case RTE_FLOW_ACTION_TYPE_METER_MARK: aso = true; - aso_mtr = flow_hw_meter_mark_alloc(dev, queue, action, job, push, error); - if (!aso_mtr) + ret = flow_hw_meter_mark_alloc(dev, queue, action, job, push, &aso_mtr, error); + if (ret) { + if (ret != -EIO) { + if (queue == MLX5_HW_INV_QUEUE) + queue = CTRL_QUEUE_ID(priv); + flow_hw_job_put(priv, job, queue); + } break; + } handle = (void *)(uintptr_t)job->action; break; case RTE_FLOW_ACTION_TYPE_RSS: @@ -12456,7 +12736,7 @@ NULL, "action type not supported"); break; } - if (job && !force_job) { + if (job && (!force_job || handle)) { job->action = handle; flow_hw_action_finalize(dev, queue, job, push, aso, handle != NULL); @@ -13948,7 +14228,6 @@ struct rte_flow_hw *prfx_flow = NULL; const struct rte_flow_action *qrss = NULL; const struct rte_flow_action *mark = NULL; - uint64_t item_flags = 0; uint64_t action_flags = flow_hw_action_flags_get(actions, &qrss, &mark, &encap_idx, &actions_n, error); struct mlx5_flow_hw_split_resource resource = { @@ -13965,20 +14244,27 @@ .egress = attr->egress, .transfer = attr->transfer, }; - - /* Validate application items only */ - ret = __flow_hw_pattern_validate(dev, &pattern_template_attr, items, - &item_flags, true, error); - if (ret < 0) - return 0; + struct rte_flow_item *copied_items = NULL; + const struct rte_flow_item *prepend_items; + uint64_t orig_item_nb, item_flags; RTE_SET_USED(encap_idx); if (!error) error = &shadow_error; + + prepend_items = flow_hw_adjust_pattern(dev, &pattern_template_attr, true, items, + &item_flags, &orig_item_nb, &copied_items, error); + if (!prepend_items) + return 0; + split = mlx5_flow_nta_split_metadata(dev, attr, actions, qrss, action_flags, actions_n, external, &resource, error); - if (split < 0) - return split; + if (split < 0) { + mlx5_free(copied_items); + return 0; + } else if (!split) { + resource.suffix.items = prepend_items; + } /* Update the metadata copy table - MLX5_FLOW_MREG_CP_TABLE_GROUP */ if (((attr->ingress && attr->group != MLX5_FLOW_MREG_CP_TABLE_GROUP) || @@ -13992,14 +14278,16 @@ if (action_flags & MLX5_FLOW_ACTION_RSS) { const struct rte_flow_action_rss *rss_conf = flow_nta_locate_rss(dev, actions, error); - flow = flow_nta_handle_rss(dev, attr, items, actions, rss_conf, + flow = flow_nta_handle_rss(dev, attr, prepend_items, actions, rss_conf, item_flags, action_flags, external, type, error); if (flow) { flow->nt2hws->rix_mreg_copy = cpy_idx; cpy_idx = 0; - if (!split) + if (!split) { + mlx5_free(copied_items); return (uintptr_t)flow; + } goto prefix_flow; } goto free; @@ -14013,12 +14301,14 @@ if (flow) { flow->nt2hws->rix_mreg_copy = cpy_idx; cpy_idx = 0; - if (!split) + if (!split) { + mlx5_free(copied_items); return (uintptr_t)flow; + } /* Fall Through to prefix flow creation. */ } prefix_flow: - ret = flow_hw_create_flow(dev, type, attr, items, resource.prefix.actions, + ret = flow_hw_create_flow(dev, type, attr, prepend_items, resource.prefix.actions, item_flags, action_flags, external, &prfx_flow, error); if (ret) goto free; @@ -14027,6 +14317,7 @@ flow->nt2hws->chaned_flow = 1; SLIST_INSERT_AFTER(prfx_flow, flow, nt2hws->next); mlx5_flow_nta_split_resource_free(dev, &resource); + mlx5_free(copied_items); return (uintptr_t)prfx_flow; } free: @@ -14038,6 +14329,7 @@ mlx5_flow_nta_del_copy_action(dev, cpy_idx); if (split > 0) mlx5_flow_nta_split_resource_free(dev, &resource); + mlx5_free(copied_items); return 0; } @@ -15023,6 +15315,12 @@ }; MLX5_ASSERT(hw_flow->flags & MLX5_FLOW_HW_FLOW_FLAG_MATCHER_SELECTOR); + /* + * Update resized can be called only through async flow API. + * These rings are allocated if and only if async flow API was configured. + */ + MLX5_ASSERT(priv->hw_q[queue].flow_transfer_completed != NULL); + MLX5_ASSERT(priv->hw_q[queue].flow_transfer_pending != NULL); /** * mlx5dr_matcher_resize_rule_move() accepts original table matcher - * the one that was used BEFORE table resize. @@ -15107,6 +15405,7 @@ return 0; } + const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = { .list_create = flow_hw_list_create, .list_destroy = flow_hw_list_destroy, @@ -15114,7 +15413,7 @@ .info_get = flow_hw_info_get, .configure = flow_hw_configure, .pattern_validate = flow_hw_pattern_validate, - .pattern_template_create = flow_hw_pattern_template_create, + .pattern_template_create = flow_hw_external_pattern_template_create, .pattern_template_destroy = flow_hw_pattern_template_destroy, .actions_validate = flow_hw_actions_validate, .actions_template_create = flow_hw_actions_template_create, @@ -15824,10 +16123,10 @@ .type = MLX5_CTRL_FLOW_TYPE_LACP_RX, }; - if (!priv->dr_ctx || !priv->hw_ctrl_fdb || !priv->hw_ctrl_fdb->hw_lacp_rx_tbl) + if (!priv->dr_ctx || !priv->hw_lacp_miss || !priv->hw_lacp_miss->hw_lacp_rx_tbl) return 0; return flow_hw_create_ctrl_flow(dev, dev, - priv->hw_ctrl_fdb->hw_lacp_rx_tbl, + priv->hw_lacp_miss->hw_lacp_rx_tbl, eth_lacp, 0, miss_action, 0, &flow_info, false); } diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_rx.c dpdk-24.11.8/drivers/net/mlx5/mlx5_rx.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_rx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_rx.c 2026-10-14 13:10:05.000000000 +0000 @@ -189,6 +189,10 @@ RTE_BIT32(rxq->elts_n); qinfo->avail_thresh = rxq_priv ? mlx5_rxq_lwm_to_percentage(rxq_priv) : 0; + if (rxq_ctrl != NULL) { + qinfo->conf.share_group = rxq_ctrl->share_group; + qinfo->conf.share_qid = rxq_ctrl->share_qid; + } } /** @@ -657,7 +661,7 @@ if (!*elt) { for (i--; i >= 0; --i) { elt_idx = (elts_ci + - i) & elts_n; + i) & e_mask; elt = &(*rxq->elts) [elt_idx]; rte_pktmbuf_free_seg @@ -999,8 +1003,7 @@ vlan_strip = cqe->hdr_type_etc & RTE_BE16(MLX5_CQE_VLAN_STRIPPED); else - vlan_strip = mcqe->hdr_type & - RTE_BE16(MLX5_CQE_VLAN_STRIPPED); + vlan_strip = mcqe->hdr_type & MLX5_CQE_VLAN_STRIPPED; if (vlan_strip) { pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED; pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info); @@ -1047,7 +1050,7 @@ int len = 0; /* keep its value across iterations. */ while (pkts_n) { - uint16_t skip_cnt; + uint16_t skip_cnt = 0; unsigned int idx = rq_ci & wqe_mask; volatile struct mlx5_wqe_data_seg *wqe = &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx]; @@ -1493,7 +1496,7 @@ uint16_t strd_cnt; uint16_t strd_idx; uint32_t byte_cnt; - uint16_t skip_cnt; + uint16_t skip_cnt = 0; volatile struct mlx5_mini_cqe8 *mcqe = NULL; enum mlx5_rqx_code rxq_code; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_rx.h dpdk-24.11.8/drivers/net/mlx5/mlx5_rx.h --- dpdk-24.11.4/drivers/net/mlx5/mlx5_rx.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_rx.h 2026-10-14 13:10:05.000000000 +0000 @@ -146,9 +146,9 @@ uint64_t flow_meta_mask; int32_t flow_meta_offset; uint32_t flow_meta_port_mask; - uint32_t rxseg_n; /* Number of split segment descriptions. */ struct mlx5_eth_rxseg rxseg[MLX5_MAX_RXQ_NSEG]; /* Buffer split segment descriptions - sizes, offsets, pools. */ + uint16_t rxseg_n; /* Number of split segment descriptions. */ uint16_t rq_win_cnt; /* Number of packets in the sliding window data. */ uint16_t rq_win_idx_mask; /* Sliding window index wrapping mask. */ uint16_t rq_win_idx; /* Index of the first element in sliding window. */ @@ -173,9 +173,9 @@ unsigned int irq:1; /* Whether IRQ is enabled. */ uint32_t flow_tunnels_n[MLX5_FLOW_TUNNEL]; /* Tunnels counters. */ uint32_t wqn; /* WQ number. */ - uint32_t rxseg_n; /* Number of split segment descriptions. */ struct rte_eth_rxseg_split rxseg[MLX5_MAX_RXQ_NSEG]; /* Saved original buffer split segment configuration. */ + uint16_t rxseg_n; /* Number of split segment descriptions. */ uint16_t dump_file_n; /* Number of dump files. */ }; @@ -583,6 +583,23 @@ } /** + * Check whether Shared RQ is enabled for the device. + * + * @param dev + * Pointer to Ethernet device. + * + * @return + * 0 if disabled, otherwise enabled. + */ +static __rte_always_inline int +mlx5_shared_rq_enabled(struct rte_eth_dev *dev) +{ + struct mlx5_priv *priv = dev->data->dev_private; + + return !LIST_EMPTY(&priv->sh->shared_rxqs); +} + +/** * Check whether Multi-Packet RQ can be enabled for the device. * * @param dev @@ -596,6 +613,8 @@ { struct mlx5_priv *priv = dev->data->dev_private; + if (mlx5_shared_rq_enabled(dev)) + return -ENOTSUP; if (priv->config.mprq.enabled && priv->rxqs_n >= priv->config.mprq.min_rxqs_num) return 1; @@ -652,23 +671,6 @@ } /** - * Check whether Shared RQ is enabled for the device. - * - * @param dev - * Pointer to Ethernet device. - * - * @return - * 0 if disabled, otherwise enabled. - */ -static __rte_always_inline int -mlx5_shared_rq_enabled(struct rte_eth_dev *dev) -{ - struct mlx5_priv *priv = dev->data->dev_private; - - return !LIST_EMPTY(&priv->sh->shared_rxqs); -} - -/** * Check whether given RxQ is external. * * @param dev diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_rxq.c dpdk-24.11.8/drivers/net/mlx5/mlx5_rxq.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_rxq.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_rxq.c 2026-10-14 13:10:05.000000000 +0000 @@ -658,8 +658,6 @@ struct mlx5_rxq_ctrl **rxq_ctrl) { struct mlx5_priv *priv = dev->data->dev_private; - struct mlx5_rxq_priv *rxq; - bool empty; if (*desc > mlx5_dev_get_max_wq_size(priv->sh)) { DRV_LOG(ERR, @@ -698,14 +696,6 @@ if ((*rxq_ctrl)->obj != NULL) /* Some port using shared Rx queue has been started. */ return 0; - /* Release all owner RxQ to reconfigure Shared RxQ. */ - do { - rxq = LIST_FIRST(&(*rxq_ctrl)->owners); - LIST_REMOVE(rxq, owner_entry); - empty = LIST_EMPTY(&(*rxq_ctrl)->owners); - mlx5_rxq_release(ETH_DEV(rxq->priv), rxq->idx); - } while (!empty); - *rxq_ctrl = NULL; } return 0; } @@ -779,10 +769,21 @@ dev->data->port_id, idx); return false; } - if (priv->mtu != rxq_ctrl->mtu) { - DRV_LOG(ERR, "port %u queue index %u failed to join shared group: mtu mismatch", - dev->data->port_id, idx); - return false; + if (dev->data->mtu != rxq_ctrl->mtu) { + /* + * MTU mismatch is only a problem when the queue hasn't been started yet. + * If rxq_ctrl->obj is NULL, the queue hardware objects haven't been created, + * meaning we're in the initial configuration phase where MTU must match. + * If obj != NULL, the queue is already running with its hardware configured, + * and runtime MTU changes are safe as they only update software bookkeeping + * without recreating hardware resources. + */ + if (rxq_ctrl->obj == NULL) { + DRV_LOG(DEBUG, "port %u queue index %u: mtu mismatch with existing shared rxq_ctrl " + "(port mtu=%u rxq_ctrl mtu=%u), reconfiguration needed", + dev->data->port_id, idx, dev->data->mtu, rxq_ctrl->mtu); + return false; + } } if (priv->dev_data->dev_conf.intr_conf.rxq != spriv->dev_data->dev_conf.intr_conf.rxq) { @@ -925,8 +926,57 @@ if (rxq_ctrl != NULL && !mlx5_shared_rxq_match(rxq_ctrl, dev, idx, desc, socket, conf, mp)) { - rte_errno = EINVAL; - return -rte_errno; + struct mlx5_rxq_priv *rxq_tmp; + bool empty; + + /* + * Configuration mismatch detected with existing shared RXQ. + * We need to reconfigure, but only if it's safe to do so. + * + * First check: If hardware objects are allocated, the shared queue has + * been started. Reconfiguration would require destroying and recreating + * hardware resources, which cannot be done while the queue is active. + * Return EBUSY to force caller to stop the queue first. + */ + if (rxq_ctrl->obj != NULL) { + DRV_LOG(ERR, "port %u queue index %u: cannot reconfigure shared RXQ while started", + dev->data->port_id, idx); + rte_errno = EBUSY; + return -rte_errno; + } + + /* + * Second check: Even if hardware objects aren't allocated yet, + * verify that no owner port is actively using this queue. + * refcnt == 1 means the queue exists but is idle (only setup reference). + * refcnt > 1 means the queue is being used by flows or other components. + * This prevents releasing a queue that other ports depend on. + */ + LIST_FOREACH(rxq_tmp, &rxq_ctrl->owners, owner_entry) { + if (rxq_tmp->refcnt > 1) { + DRV_LOG(ERR, "port %u queue index %u: cannot reconfigure shared RXQ " + "while other ports are running", + dev->data->port_id, idx); + rte_errno = EBUSY; + return -rte_errno; + } + } + + /* + * Safe to reconfigure: hardware not started and no active users. + * Release all owner ports from the existing shared rxq_ctrl. + * This will decrement references and eventually free the old rxq_ctrl. + * Setting rxq_ctrl to NULL triggers creation of a new one below with + * the updated configuration. + */ + do { + rxq_tmp = LIST_FIRST(&rxq_ctrl->owners); + LIST_REMOVE(rxq_tmp, owner_entry); + empty = LIST_EMPTY(&rxq_ctrl->owners); + mlx5_rxq_release(ETH_DEV(rxq_tmp->priv), rxq_tmp->idx); + } while (!empty); + + rxq_ctrl = NULL; } } else { res = mlx5_rx_queue_pre_setup(dev, idx, &desc, &rxq_ctrl); @@ -1770,7 +1820,8 @@ LIST_INIT(&tmpl->owners); MLX5_ASSERT(n_seg && n_seg <= MLX5_MAX_RXQ_NSEG); /* - * Save the original MTU to check against for shared rx queues. + * Save the current MTU to check against for shared rx queues. + * Use dev->data->mtu which reflects the actual current MTU. */ tmpl->mtu = dev->data->mtu; /* diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_rxtx_vec.c dpdk-24.11.8/drivers/net/mlx5/mlx5_rxtx_vec.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_rxtx_vec.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_rxtx_vec.c 2026-10-14 13:10:05.000000000 +0000 @@ -606,6 +606,8 @@ if (!RXQ_PORT(ctrl)->config.rx_vec_en || rxq->sges_n != 0) return -ENOTSUP; + if (mlx5_shared_rq_enabled(RXQ_DEV(ctrl))) + return -ENOTSUP; if (rxq->lro) return -ENOTSUP; return 1; diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_trigger.c dpdk-24.11.8/drivers/net/mlx5/mlx5_trigger.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_trigger.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_trigger.c 2026-10-14 13:10:05.000000000 +0000 @@ -89,6 +89,9 @@ DRV_LOG(ERR, "Port %u Tx queue %u cannot " "allocate memory (FCQ).", dev->data->port_id, i); + priv->obj_ops.txq_obj_release(txq_ctrl->obj); + mlx5_free(txq_ctrl->obj); + txq_ctrl->obj = NULL; rte_errno = ENOMEM; goto error; } @@ -1558,9 +1561,8 @@ } else { DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id); } - if (!priv->sh->config.lacp_by_user && priv->pf_bond >= 0 && priv->master) - if (mlx5_flow_hw_lacp_rx_flow(dev)) - goto error; + if (mlx5_flow_lacp_miss_needed(dev) && mlx5_flow_hw_lacp_rx_flow(dev) != 0) + goto error; if (priv->isolated) return 0; ret = mlx5_flow_hw_create_ctrl_rx_tables(dev); @@ -1569,13 +1571,17 @@ dev->data->port_id, -ret); goto error; } - if (dev->data->promiscuous) + if (dev->data->promiscuous) { flags |= MLX5_CTRL_PROMISCUOUS; - if (dev->data->all_multicast) - flags |= MLX5_CTRL_ALL_MULTICAST; - else - flags |= MLX5_CTRL_BROADCAST | MLX5_CTRL_IPV4_MULTICAST | MLX5_CTRL_IPV6_MULTICAST; - flags |= MLX5_CTRL_DMAC; + } else { + if (dev->data->all_multicast) + flags |= MLX5_CTRL_ALL_MULTICAST; + else + flags |= (MLX5_CTRL_BROADCAST | + MLX5_CTRL_IPV4_MULTICAST | + MLX5_CTRL_IPV6_MULTICAST); + flags |= MLX5_CTRL_DMAC; + } if (priv->vlan_filter_n) flags |= MLX5_CTRL_VLAN_FILTER; return mlx5_flow_hw_ctrl_flows(dev, flags); @@ -1675,7 +1681,7 @@ DRV_LOG(INFO, "port %u FDB default rule is disabled", dev->data->port_id); } - if (!priv->sh->config.lacp_by_user && priv->pf_bond >= 0 && priv->master) { + if (mlx5_flow_lacp_miss_needed(dev)) { ret = mlx5_flow_lacp_miss(dev); if (ret) DRV_LOG(INFO, "port %u LACP rule cannot be created - " diff -Nru dpdk-24.11.4/drivers/net/mlx5/mlx5_txpp.c dpdk-24.11.8/drivers/net/mlx5/mlx5_txpp.c --- dpdk-24.11.4/drivers/net/mlx5/mlx5_txpp.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/mlx5_txpp.c 2026-10-14 13:10:05.000000000 +0000 @@ -812,7 +812,6 @@ /* Store the requested pacing parameters. */ sh->txpp.tick = tx_pp >= 0 ? tx_pp : -tx_pp; sh->txpp.test = !!(tx_pp < 0); - sh->txpp.skew = sh->config.tx_skew; sh->txpp.freq = sh->cdev->config.hca_attr.dev_freq_khz; ret = mlx5_txpp_create_event_channel(sh); if (ret) @@ -838,7 +837,6 @@ mlx5_txpp_destroy_event_channel(sh); sh->txpp.tick = 0; sh->txpp.test = 0; - sh->txpp.skew = 0; } return ret; } @@ -860,7 +858,6 @@ mlx5_txpp_destroy_event_channel(sh); sh->txpp.tick = 0; sh->txpp.test = 0; - sh->txpp.skew = 0; } /** diff -Nru dpdk-24.11.4/drivers/net/mlx5/windows/mlx5_os.c dpdk-24.11.8/drivers/net/mlx5/windows/mlx5_os.c --- dpdk-24.11.4/drivers/net/mlx5/windows/mlx5_os.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mlx5/windows/mlx5_os.c 2026-10-14 13:10:05.000000000 +0000 @@ -397,7 +397,6 @@ priv->sh = sh; priv->dev_port = spawn->phys_port; priv->pci_dev = spawn->pci_dev; - priv->mtu = RTE_ETHER_MTU; priv->mp_id.port_id = port_id; strlcpy(priv->mp_id.name, MLX5_MP_NAME, RTE_MP_MAX_NAME_LEN); priv->representor = !!switch_info->representor; @@ -505,14 +504,13 @@ } #endif /* Get actual MTU if possible. */ - err = mlx5_get_mtu(eth_dev, &priv->mtu); + err = mlx5_get_mtu(eth_dev, ð_dev->data->mtu); if (err) { err = rte_errno; goto error; } - eth_dev->data->mtu = priv->mtu; DRV_LOG(DEBUG, "port %u MTU is %u.", eth_dev->data->port_id, - priv->mtu); + eth_dev->data->mtu); /* Initialize burst functions to prevent crashes before link-up. */ eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy; eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy; @@ -690,23 +688,27 @@ /** * Flush device MAC addresses - * Currently it has no support under Windows. - * + * Currently Windows does not support adding and removing MAC addresses, + * This function resets the mac_own bit for all MAC addresses for internal tracking. * @param dev * Pointer to Ethernet device structure. - * */ void mlx5_os_mac_addr_flush(struct rte_eth_dev *dev) { - (void)dev; - DRV_LOG(WARNING, "%s: is not supported", __func__); + struct mlx5_priv *priv = dev->data->dev_private; + int i; + + for (i = MLX5_MAX_MAC_ADDRESSES - 1; i >= 0; --i) { + if (BITFIELD_ISSET(priv->mac_own, i)) + BITFIELD_RESET(priv->mac_own, i); + } } /** * Remove a MAC address from device - * Currently it has no support under Windows. - * + * Currently Windows does not support adding and removing MAC addresses, + * This function resets the mac_own bit for the specified index for internal tracking. * @param dev * Pointer to Ethernet device structure. * @param index @@ -715,14 +717,16 @@ void mlx5_os_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) { - (void)dev; - (void)(index); - DRV_LOG(WARNING, "%s: is not supported", __func__); + struct mlx5_priv *priv = dev->data->dev_private; + + if (index < MLX5_MAX_MAC_ADDRESSES) + BITFIELD_RESET(priv->mac_own, index); } /** * Adds a MAC address to the device - * Currently it has no support under Windows. + * Currently Windows does not support adding and removing MAC addresses, + * This function sets the mac_own bit only if the MAC address already exists. * * @param dev * Pointer to Ethernet device structure. @@ -738,7 +742,7 @@ mlx5_os_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac, uint32_t index) { - (void)index; + struct mlx5_priv *priv = dev->data->dev_private; struct rte_ether_addr lmac; if (mlx5_get_mac(dev, &lmac.addr_bytes)) { @@ -753,6 +757,8 @@ "adding new mac address to device is unsupported"); return -ENOTSUP; } + /* Mark this MAC address as owned by the PMD */ + BITFIELD_SET(priv->mac_own, index); return 0; } diff -Nru dpdk-24.11.4/drivers/net/mvpp2/mrvl_ethdev.c dpdk-24.11.8/drivers/net/mvpp2/mrvl_ethdev.c --- dpdk-24.11.4/drivers/net/mvpp2/mrvl_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/mvpp2/mrvl_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -2668,7 +2668,6 @@ (!rx_done && num < q->priv->bpool_init_size))) { mrvl_fill_bpool(q, q->priv->fill_bpool_buffs); } else if (unlikely(num > q->priv->bpool_max_size)) { - int i; int pkt_to_remove = num - q->priv->bpool_init_size; struct rte_mbuf *mbuf; struct pp2_buff_inf buff; diff -Nru dpdk-24.11.4/drivers/net/netvsc/hn_ethdev.c dpdk-24.11.8/drivers/net/netvsc/hn_ethdev.c --- dpdk-24.11.4/drivers/net/netvsc/hn_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/netvsc/hn_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -41,6 +41,31 @@ #include "hn_nvs.h" #include "ndis.h" +/* Spinlock for netvsc_shared_data */ +static rte_spinlock_t netvsc_shared_data_lock = RTE_SPINLOCK_INITIALIZER; + +static struct netvsc_shared_data { + RTE_ATOMIC(uint32_t) secondary_cnt; +} *netvsc_shared_data; + +static const struct rte_memzone *netvsc_shared_mz; +#define MZ_NETVSC_SHARED_DATA "netvsc_shared_data" + +static struct netvsc_local_data { + bool init_done; + unsigned int primary_cnt; + unsigned int secondary_cnt; +} netvsc_local_data; + +#define NETVSC_MP_NAME "net_netvsc_mp" +#define NETVSC_MP_REQ_TIMEOUT_SEC 5 + +struct netvsc_mp_param { + enum netvsc_mp_req_type type; + int vf_port; + int result; +}; + #define HN_TX_OFFLOAD_CAPS (RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | \ RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \ RTE_ETH_TX_OFFLOAD_UDP_CKSUM | \ @@ -57,8 +82,14 @@ #define NETVSC_ARG_TXBREAK "tx_copybreak" #define NETVSC_ARG_RX_EXTMBUF_ENABLE "rx_extmbuf_enable" -/* The max number of retry when hot adding a VF device */ -#define NETVSC_MAX_HOTADD_RETRY 10 +/* Retry interval for hot-add VF device (microseconds) */ +#define NETVSC_HOTADD_RETRY_INTERVAL 1000000 + +/* Max retries when net/ directory exists but no matching MAC found. + * On multi-NIC PCI devices, a second VF may register later. + * 120 retries = ~2 minutes. + */ +#define NETVSC_MAX_MAC_RETRY 120 struct hn_xstats_name_off { char name[RTE_ETH_XSTATS_NAME_SIZE]; @@ -579,19 +610,39 @@ PMD_DRV_LOG(DEBUG, "%s: retry count %d", __func__, hot_ctx->eal_hot_plug_retry); - if (hot_ctx->eal_hot_plug_retry++ > NETVSC_MAX_HOTADD_RETRY) { - PMD_DRV_LOG(NOTICE, "Failed to parse PCI device retry=%d", - hot_ctx->eal_hot_plug_retry); + hot_ctx->eal_hot_plug_retry++; + + /* Check if PCI device still exists — if it disappeared, give up. + * Otherwise keep retrying indefinitely until the net directory + * appears. This is safe because: + * - MANA driver probe can take >100s after PCI rescan + * - The retry uses rte_eal_alarm callbacks serialized on the + * EAL interrupt thread, preventing races with device close + * - Device close cancels pending alarms and frees the context + * - If the PCI device is removed, the access() check below + * detects the missing sysfs path and stops immediately + */ + snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s", d->name); + if (access(buf, F_OK) != 0) { + PMD_DRV_LOG(NOTICE, + "PCI device %s no longer exists, giving up after %d retries", + d->name, hot_ctx->eal_hot_plug_retry); goto free_hotadd_ctx; } snprintf(buf, sizeof(buf), "/sys/bus/pci/devices/%s/net", d->name); di = opendir(buf); if (!di) { - PMD_DRV_LOG(DEBUG, "%s: can't open directory %s, " - "retrying in 1 second", __func__, buf); - /* The device is still being initialized, retry after 1 second */ - rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx); + if (hot_ctx->eal_hot_plug_retry % 30 == 0) + PMD_DRV_LOG(NOTICE, + "%s: waiting for %s (retry %d, %ds elapsed)", + __func__, buf, hot_ctx->eal_hot_plug_retry, + hot_ctx->eal_hot_plug_retry); + else + PMD_DRV_LOG(DEBUG, "%s: can't open directory %s, " + "retrying in 1 second", __func__, buf); + rte_eal_alarm_set(NETVSC_HOTADD_RETRY_INTERVAL, + netvsc_hotplug_retry, hot_ctx); return; } @@ -611,10 +662,18 @@ ret = ioctl(s, SIOCGIFHWADDR, &req); close(s); if (ret == -1) { - PMD_DRV_LOG(ERR, - "Failed to send SIOCGIFHWADDR for device %s", + /* Interface may be renamed by udev (e.g. eth1 → ens1). + * Retry from the top — the PCI device check above + * ensures we stop if the device disappears. + */ + PMD_DRV_LOG(DEBUG, + "Failed to send SIOCGIFHWADDR for device %s, " + "interface may be renaming, retrying", dir->d_name); - break; + closedir(di); + rte_eal_alarm_set(NETVSC_HOTADD_RETRY_INTERVAL, + netvsc_hotplug_retry, hot_ctx); + return; } if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) continue; @@ -633,24 +692,75 @@ ret = rte_eal_hotplug_add(d->bus->name, d->name, hv->vf_devargs ? hv->vf_devargs : ""); - if (ret) { - PMD_DRV_LOG(ERR, - "Failed to add PCI device %s", + if (ret == -ENODEV) { + /* IB device not ready yet (mana_ib not probed). + * Restart the full retry from the PCI device + * check so we re-verify the device exists and + * get fresh interface names after any renames. + * This retries indefinitely — the PCI sysfs + * check at the top of this function ensures + * we stop if the device disappears. + */ + PMD_DRV_LOG(NOTICE, + "IB device not ready for %s, " + "restarting probe in 1 second", d->name); + closedir(di); + rte_eal_alarm_set(NETVSC_HOTADD_RETRY_INTERVAL, + netvsc_hotplug_retry, + hot_ctx); + return; } + if (ret && ret != -EEXIST) + PMD_DRV_LOG(ERR, + "Failed to add PCI device %s (ret=%d)", + d->name, ret); + + ret = hn_vf_add(dev, hv); + if (ret) + PMD_DRV_LOG(ERR, "Failed to add VF: %d", ret); break; } } + /* If we opened the net directory but didn't find a matching MAC, + * the VF interface may not have appeared yet (e.g. on a multi-NIC + * PCI device, the second VF registers later). Retry. + */ + if (di != NULL) { + closedir(di); + di = NULL; + if (dir == NULL) { + /* readdir returned NULL — loop ended without match */ + hot_ctx->mac_retry++; + if (hot_ctx->mac_retry < NETVSC_MAX_MAC_RETRY) { + PMD_DRV_LOG(DEBUG, + "%s: no matching MAC found in %s, " + "retrying in 1 second (mac_retry %d/%d)", + __func__, buf, + hot_ctx->mac_retry, + NETVSC_MAX_MAC_RETRY); + rte_eal_alarm_set(NETVSC_HOTADD_RETRY_INTERVAL, + netvsc_hotplug_retry, + hot_ctx); + return; + } + PMD_DRV_LOG(NOTICE, + "%s: no matching MAC found after %d retries, giving up", + __func__, hot_ctx->mac_retry); + } + } + free_hotadd_ctx: - if (di) + if (di != NULL) closedir(di); rte_spinlock_lock(&hv->hotadd_lock); LIST_REMOVE(hot_ctx, list); rte_spinlock_unlock(&hv->hotadd_lock); + rte_devargs_reset(d); rte_free(hot_ctx); } @@ -697,7 +807,8 @@ rte_spinlock_lock(&hv->hotadd_lock); LIST_INSERT_HEAD(&hv->hotadd_list, hot_ctx, list); rte_spinlock_unlock(&hv->hotadd_lock); - rte_eal_alarm_set(1000000, netvsc_hotplug_retry, hot_ctx); + rte_eal_alarm_set(NETVSC_HOTADD_RETRY_INTERVAL, + netvsc_hotplug_retry, hot_ctx); return; } @@ -1010,16 +1121,22 @@ NDIS_PACKET_TYPE_BROADCAST | NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_DIRECTED); - if (error) + if (error) { + rte_dev_event_callback_unregister(NULL, + netvsc_hotadd_callback, hv); return error; + } error = hn_vf_start(dev); - if (error) + if (error) { hn_rndis_set_rxfilter(hv, 0); + rte_dev_event_callback_unregister(NULL, + netvsc_hotadd_callback, hv); + return error; + } /* Initialize Link state */ - if (error == 0) - hn_dev_link_update(dev, 0); + hn_dev_link_update(dev, 0); for (i = 0; i < hv->num_queues; i++) { dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; @@ -1066,6 +1183,7 @@ hot_ctx = LIST_FIRST(&hv->hotadd_list); rte_eal_alarm_cancel(netvsc_hotplug_retry, hot_ctx); LIST_REMOVE(hot_ctx, list); + rte_devargs_reset(&hot_ctx->da); rte_free(hot_ctx); } rte_spinlock_unlock(&hv->hotadd_lock); @@ -1175,14 +1293,23 @@ if (ret) return ret; + /* Free chimney bitmap and rxbuf_info before NVS detach */ + hn_chim_uninit(dev); + rte_free(hv->primary->rxbuf_info); + hv->primary->rxbuf_info = NULL; + /* Release channel resources */ hn_detach(hv); /* Close any secondary vmbus channels */ - for (i = 1; i < hv->num_queues; i++) + for (i = 1; i < hv->num_queues; i++) { rte_vmbus_chan_close(hv->channels[i]); + hv->channels[i] = NULL; + } + hv->num_queues = 1; /* Close primary vmbus channel */ + rte_vmbus_chan_close(hv->channels[0]); rte_free(hv->channels[0]); /* Unmap and re-map vmbus device */ @@ -1206,16 +1333,21 @@ return ret; } + hv->primary->chan = hv->channels[0]; rte_vmbus_set_latency(hv->vmbus, hv->channels[0], hv->latency); ret = hn_reinit(dev, mtu); - if (!ret) + if (!ret) { + hn_chim_init(dev); goto out; + } /* In case of error, attempt to restore original MTU */ ret = hn_reinit(dev, orig_mtu); if (ret) PMD_DRV_LOG(ERR, "Restoring original MTU failed for netvsc"); + else + hn_chim_init(dev); ret = hn_vf_mtu_set(dev, orig_mtu); if (ret) @@ -1343,8 +1475,10 @@ hv->primary = hn_rx_queue_alloc(hv, 0, eth_dev->device->numa_node); - if (!hv->primary) - return -ENOMEM; + if (!hv->primary) { + err = -ENOMEM; + goto failed; + } err = hn_attach(hv, RTE_ETHER_MTU); if (err) @@ -1370,8 +1504,10 @@ max_chan = rte_vmbus_max_channels(vmbus); PMD_INIT_LOG(DEBUG, "VMBus max channels %d", max_chan); - if (max_chan <= 0) + if (max_chan <= 0) { + err = max_chan ? max_chan : -ENODEV; goto failed; + } if (hn_rndis_query_rsscaps(hv, &rxr_cnt) != 0) rxr_cnt = 1; @@ -1379,11 +1515,12 @@ hv->max_queues = RTE_MIN(rxr_cnt, (unsigned int)max_chan); /* If VF was reported but not added, do it now */ + rte_rwlock_write_lock(&hv->vf_lock); if (hv->vf_ctx.vf_vsp_reported && !hv->vf_ctx.vf_vsc_switched) { PMD_INIT_LOG(DEBUG, "Adding VF device"); - - err = hn_vf_add(eth_dev, hv); + err = hn_vf_add_unlocked(eth_dev, hv); } + rte_rwlock_write_unlock(&hv->vf_lock); return 0; @@ -1392,6 +1529,8 @@ hn_chim_uninit(eth_dev); hn_detach(hv); + rte_free(hv->primary); + rte_vmbus_chan_close(hv->channels[0]); return err; } @@ -1400,6 +1539,7 @@ { struct hn_data *hv = eth_dev->data->dev_private; int ret, ret_stop; + int i; PMD_INIT_FUNC_TRACE(); @@ -1414,8 +1554,16 @@ hn_detach(hv); hn_chim_uninit(eth_dev); + + /* Close any subchannels before closing the primary channel */ + for (i = 1; i < HN_MAX_CHANNELS; i++) { + if (hv->channels[i] != NULL) { + rte_vmbus_chan_close(hv->channels[i]); + hv->channels[i] = NULL; + } + } + rte_vmbus_chan_close(hv->channels[0]); - rte_free(hv->primary); ret = rte_eth_dev_owner_delete(hv->owner.id); if (ret != 0) return ret; @@ -1423,6 +1571,217 @@ return ret_stop; } +static int +netvsc_mp_primary_handle(const struct rte_mp_msg *mp_msg __rte_unused, + const void *peer __rte_unused) +{ + /* Stub function required for multi-process message handling registration */ + return 0; +} + +static void +mp_init_msg(struct rte_mp_msg *msg, enum netvsc_mp_req_type type, int vf_port) +{ + struct netvsc_mp_param *param; + + strlcpy(msg->name, NETVSC_MP_NAME, sizeof(msg->name)); + msg->len_param = sizeof(*param); + + param = (struct netvsc_mp_param *)msg->param; + param->type = type; + param->vf_port = vf_port; +} + +static int netvsc_secondary_handle_device_remove(int vf_port) +{ + if (!rte_eth_dev_is_valid_port(vf_port)) { + /* VF not probed in this secondary — nothing to release */ + PMD_DRV_LOG(DEBUG, "VF port %u not present in secondary, skipping", + vf_port); + return 0; + } + + PMD_DRV_LOG(DEBUG, "Secondary releasing VF port %d", vf_port); + return rte_eth_dev_release_port(&rte_eth_devices[vf_port]); +} + +static int +netvsc_mp_secondary_handle(const struct rte_mp_msg *mp_msg, const void *peer) +{ + struct rte_mp_msg mp_res = { 0 }; + struct netvsc_mp_param *res = (struct netvsc_mp_param *)mp_res.param; + const struct netvsc_mp_param *param = + (const struct netvsc_mp_param *)mp_msg->param; + int ret = 0; + + mp_init_msg(&mp_res, param->type, param->vf_port); + + switch (param->type) { + case NETVSC_MP_REQ_VF_REMOVE: + res->result = netvsc_secondary_handle_device_remove(param->vf_port); + ret = rte_mp_reply(&mp_res, peer); + break; + + default: + PMD_DRV_LOG(ERR, "Unknown primary MP type %u", param->type); + ret = -EINVAL; + } + + return ret; +} + +static int netvsc_mp_init_primary(void) +{ + int ret; + ret = rte_mp_action_register(NETVSC_MP_NAME, netvsc_mp_primary_handle); + if (ret && rte_errno != ENOTSUP) { + PMD_DRV_LOG(ERR, "Failed to register primary handler %d %d", + ret, rte_errno); + return -1; + } + + return 0; +} + +static void netvsc_mp_uninit_primary(void) +{ + rte_mp_action_unregister(NETVSC_MP_NAME); +} + +static int netvsc_mp_init_secondary(void) +{ + return rte_mp_action_register(NETVSC_MP_NAME, netvsc_mp_secondary_handle); +} + +static void netvsc_mp_uninit_secondary(void) +{ + rte_mp_action_unregister(NETVSC_MP_NAME); +} + +int netvsc_mp_req_vf(struct hn_data *hv, enum netvsc_mp_req_type type, + int vf_port) +{ + struct rte_mp_msg mp_req = { 0 }; + struct rte_mp_msg *mp_res; + struct rte_mp_reply mp_rep = { 0 }; + struct netvsc_mp_param *res; + struct timespec ts = {.tv_sec = NETVSC_MP_REQ_TIMEOUT_SEC, .tv_nsec = 0}; + int i, ret; + + /* if secondary count is 0, return */ + if (rte_atomic_load_explicit(&netvsc_shared_data->secondary_cnt, + rte_memory_order_acquire) == 0) + return 0; + + mp_init_msg(&mp_req, type, vf_port); + + ret = rte_mp_request_sync(&mp_req, &mp_rep, &ts); + if (ret) { + if (rte_errno != ENOTSUP) + PMD_DRV_LOG(ERR, "port %u failed to request VF remove", + hv->port_id); + else + ret = 0; + goto exit; + } + + if (mp_rep.nb_sent != mp_rep.nb_received) { + PMD_DRV_LOG(ERR, "port %u not all secondaries responded type %d", + hv->port_id, type); + ret = -1; + goto exit; + } + for (i = 0; i < mp_rep.nb_received; i++) { + mp_res = &mp_rep.msgs[i]; + res = (struct netvsc_mp_param *)mp_res->param; + if (res->result) { + PMD_DRV_LOG(ERR, "port %u request failed on secondary %d", + hv->port_id, i); + ret = -1; + goto exit; + } + } + +exit: + free(mp_rep.msgs); + return ret; +} + +static int netvsc_init_once(void) +{ + int ret = 0; + const struct rte_memzone *secondary_mz; + + if (netvsc_local_data.init_done) + return 0; + + switch (rte_eal_process_type()) { + case RTE_PROC_PRIMARY: + netvsc_shared_mz = rte_memzone_reserve(MZ_NETVSC_SHARED_DATA, + sizeof(*netvsc_shared_data), SOCKET_ID_ANY, 0); + if (!netvsc_shared_mz) { + PMD_DRV_LOG(ERR, "Cannot allocate netvsc shared data"); + return -rte_errno; + } + netvsc_shared_data = netvsc_shared_mz->addr; + rte_atomic_store_explicit(&netvsc_shared_data->secondary_cnt, + 0, rte_memory_order_release); + + ret = netvsc_mp_init_primary(); + if (ret) { + rte_memzone_free(netvsc_shared_mz); + netvsc_shared_mz = NULL; + netvsc_shared_data = NULL; + break; + } + + PMD_DRV_LOG(DEBUG, "MP INIT PRIMARY"); + netvsc_local_data.init_done = true; + break; + + case RTE_PROC_SECONDARY: + secondary_mz = rte_memzone_lookup(MZ_NETVSC_SHARED_DATA); + if (!secondary_mz) { + PMD_DRV_LOG(ERR, "Cannot attach netvsc shared data"); + return -rte_errno; + } + netvsc_shared_data = secondary_mz->addr; + ret = netvsc_mp_init_secondary(); + if (ret) { + netvsc_shared_data = NULL; + break; + } + + PMD_DRV_LOG(DEBUG, "MP INIT SECONDARY"); + netvsc_local_data.init_done = true; + break; + + default: + /* Impossible */ + ret = -EPROTO; + break; + } + + return ret; +} + +static void netvsc_uninit_once(void) +{ + if (netvsc_local_data.primary_cnt || + netvsc_local_data.secondary_cnt) + return; + + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + netvsc_mp_uninit_primary(); + rte_memzone_free(netvsc_shared_mz); + netvsc_shared_mz = NULL; + netvsc_shared_data = NULL; + } else { + netvsc_mp_uninit_secondary(); + } + netvsc_local_data.init_done = false; +} + static int eth_hn_probe(struct rte_vmbus_driver *drv __rte_unused, struct rte_vmbus_device *dev) { @@ -1431,23 +1790,57 @@ PMD_INIT_FUNC_TRACE(); + rte_spinlock_lock(&netvsc_shared_data_lock); + ret = netvsc_init_once(); + if (!ret) { + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + netvsc_local_data.primary_cnt++; + } else { + rte_atomic_fetch_add_explicit(&netvsc_shared_data->secondary_cnt, + 1, rte_memory_order_release); + netvsc_local_data.secondary_cnt++; + } + } + rte_spinlock_unlock(&netvsc_shared_data_lock); + if (ret) + return ret; + ret = rte_dev_event_monitor_start(); if (ret) { PMD_DRV_LOG(ERR, "Failed to start device event monitoring"); - return ret; + goto init_once_failed; } eth_dev = eth_dev_vmbus_allocate(dev, sizeof(struct hn_data)); - if (!eth_dev) - return -ENOMEM; + if (!eth_dev) { + ret = -ENOMEM; + goto vmbus_alloc_failed; + } ret = eth_hn_dev_init(eth_dev); - if (ret) { - eth_dev_vmbus_release(eth_dev); - rte_dev_event_monitor_stop(); + if (ret) + goto dev_init_failed; + + rte_eth_dev_probing_finish(eth_dev); + return ret; + +dev_init_failed: + eth_dev_vmbus_release(eth_dev); + +vmbus_alloc_failed: + rte_dev_event_monitor_stop(); + +init_once_failed: + rte_spinlock_lock(&netvsc_shared_data_lock); + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + netvsc_local_data.primary_cnt--; } else { - rte_eth_dev_probing_finish(eth_dev); + rte_atomic_fetch_sub_explicit(&netvsc_shared_data->secondary_cnt, + 1, rte_memory_order_release); + netvsc_local_data.secondary_cnt--; } + netvsc_uninit_once(); + rte_spinlock_unlock(&netvsc_shared_data_lock); return ret; } @@ -1460,16 +1853,31 @@ PMD_INIT_FUNC_TRACE(); eth_dev = rte_eth_dev_allocated(dev->device.name); - if (!eth_dev) - return 0; /* port already released */ + if (!eth_dev) { + ret = 0; /* port already released */ + goto uninit; + } ret = eth_hn_dev_uninit(eth_dev); if (ret) - return ret; + goto uninit; eth_dev_vmbus_release(eth_dev); rte_dev_event_monitor_stop(); - return 0; + +uninit: + rte_spinlock_lock(&netvsc_shared_data_lock); + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + netvsc_local_data.primary_cnt--; + } else { + rte_atomic_fetch_sub_explicit(&netvsc_shared_data->secondary_cnt, + 1, rte_memory_order_release); + netvsc_local_data.secondary_cnt--; + } + netvsc_uninit_once(); + rte_spinlock_unlock(&netvsc_shared_data_lock); + + return ret; } /* Network device GUID */ diff -Nru dpdk-24.11.4/drivers/net/netvsc/hn_nvs.h dpdk-24.11.8/drivers/net/netvsc/hn_nvs.h --- dpdk-24.11.4/drivers/net/netvsc/hn_nvs.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/netvsc/hn_nvs.h 2026-10-14 13:10:05.000000000 +0000 @@ -236,3 +236,9 @@ return rte_vmbus_chan_send_sglist(chan, sg, sglen, nvs_msg, nvs_msglen, (uint64_t)sndc, need_sig); } + +enum netvsc_mp_req_type { + NETVSC_MP_REQ_VF_REMOVE = 1, +}; +int netvsc_mp_req_vf(struct hn_data *hv, enum netvsc_mp_req_type type, + int vf_port); diff -Nru dpdk-24.11.4/drivers/net/netvsc/hn_rxtx.c dpdk-24.11.8/drivers/net/netvsc/hn_rxtx.c --- dpdk-24.11.4/drivers/net/netvsc/hn_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/netvsc/hn_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -1540,20 +1540,18 @@ hn_process_events(hv, txq->queue_id, 0); /* Transmit over VF if present and up */ - if (hv->vf_ctx.vf_vsc_switched) { - rte_rwlock_read_lock(&hv->vf_lock); - vf_dev = hn_get_vf_dev(hv); - if (hv->vf_ctx.vf_vsc_switched && vf_dev && - vf_dev->data->dev_started) { - void *sub_q = vf_dev->data->tx_queues[queue_id]; - - nb_tx = (*vf_dev->tx_pkt_burst) - (sub_q, tx_pkts, nb_pkts); - rte_rwlock_read_unlock(&hv->vf_lock); - return nb_tx; - } + rte_rwlock_read_lock(&hv->vf_lock); + vf_dev = hn_get_vf_dev(hv); + if (hv->vf_ctx.vf_vsc_switched && vf_dev && + vf_dev->data->dev_started) { + void *sub_q = vf_dev->data->tx_queues[queue_id]; + + nb_tx = (*vf_dev->tx_pkt_burst) + (sub_q, tx_pkts, nb_pkts); rte_rwlock_read_unlock(&hv->vf_lock); + return nb_tx; } + rte_rwlock_read_unlock(&hv->vf_lock); for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { struct rte_mbuf *m = tx_pkts[nb_tx]; @@ -1684,17 +1682,15 @@ (void **)rx_pkts, nb_pkts, NULL); /* If VF is available, check that as well */ - if (hv->vf_ctx.vf_vsc_switched) { - rte_rwlock_read_lock(&hv->vf_lock); - vf_dev = hn_get_vf_dev(hv); - if (hv->vf_ctx.vf_vsc_switched && vf_dev && - vf_dev->data->dev_started) - nb_rcv += hn_recv_vf(vf_dev->data->port_id, rxq, - rx_pkts + nb_rcv, - nb_pkts - nb_rcv); + rte_rwlock_read_lock(&hv->vf_lock); + vf_dev = hn_get_vf_dev(hv); + if (hv->vf_ctx.vf_vsc_switched && vf_dev && + vf_dev->data->dev_started) + nb_rcv += hn_recv_vf(vf_dev->data->port_id, rxq, + rx_pkts + nb_rcv, + nb_pkts - nb_rcv); + rte_rwlock_read_unlock(&hv->vf_lock); - rte_rwlock_read_unlock(&hv->vf_lock); - } return nb_rcv; } diff -Nru dpdk-24.11.4/drivers/net/netvsc/hn_var.h dpdk-24.11.8/drivers/net/netvsc/hn_var.h --- dpdk-24.11.4/drivers/net/netvsc/hn_var.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/netvsc/hn_var.h 2026-10-14 13:10:05.000000000 +0000 @@ -127,6 +127,7 @@ struct hn_data *hv; struct rte_devargs da; int eal_hot_plug_retry; + int mac_retry; }; struct hn_data { @@ -240,6 +241,7 @@ int hn_vf_info_get(struct hn_data *hv, struct rte_eth_dev_info *info); int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv); +int hn_vf_add_unlocked(struct rte_eth_dev *dev, struct hn_data *hv); int hn_vf_configure_locked(struct rte_eth_dev *dev, const struct rte_eth_conf *dev_conf); const uint32_t *hn_vf_supported_ptypes(struct rte_eth_dev *dev, diff -Nru dpdk-24.11.4/drivers/net/netvsc/hn_vf.c dpdk-24.11.8/drivers/net/netvsc/hn_vf.c --- dpdk-24.11.4/drivers/net/netvsc/hn_vf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/netvsc/hn_vf.c 2026-10-14 13:10:05.000000000 +0000 @@ -59,8 +59,8 @@ int port, ret; if (hv->vf_ctx.vf_attached) { - PMD_DRV_LOG(ERR, "VF already attached"); - return 0; + PMD_DRV_LOG(NOTICE, "VF already attached"); + return -EEXIST; } port = hn_vf_match(dev); @@ -91,10 +91,30 @@ PMD_DRV_LOG(DEBUG, "Attach VF device %u", port); hv->vf_ctx.vf_attached = true; hv->vf_ctx.vf_port = port; + + ret = rte_eth_dev_callback_register(hv->vf_ctx.vf_port, + RTE_ETH_EVENT_INTR_RMV, + hn_eth_rmv_event_callback, + hv); + if (ret) { + /* Rollback state changes on callback registration failure */ + hv->vf_ctx.vf_attached = false; + hv->vf_ctx.vf_port = 0; + + /* Release port ownership */ + if (rte_eth_dev_owner_unset(port, hv->owner.id) < 0) + PMD_DRV_LOG(ERR, "Failed to unset owner for port %d", port); + + PMD_DRV_LOG(ERR, + "Registering callback failed for vf port %d ret %d", + port, ret); + return ret; + } + return 0; } -static void hn_vf_remove(struct hn_data *hv); +static void hn_vf_remove_unlocked(struct hn_data *hv); static void hn_remove_delayed(void *args) { @@ -104,12 +124,12 @@ int ret; bool all_eth_removed; - /* Tell VSP to switch data path to synthetic */ - hn_vf_remove(hv); - PMD_DRV_LOG(NOTICE, "Start to remove port %d", port_id); rte_rwlock_write_lock(&hv->vf_lock); + /* Tell VSP to switch data path to synthetic */ + hn_vf_remove_unlocked(hv); + /* Give back ownership */ ret = rte_eth_dev_owner_unset(port_id, hv->owner.id); if (ret) @@ -139,6 +159,10 @@ PMD_DRV_LOG(ERR, "rte_eth_dev_close failed port_id=%u ret=%d", port_id, ret); + ret = netvsc_mp_req_vf(hv, NETVSC_MP_REQ_VF_REMOVE, port_id); + if (ret) + PMD_DRV_LOG(ERR, "failed to request secondary VF remove"); + /* Remove the rte device when all its eth devices are removed */ all_eth_removed = true; RTE_ETH_FOREACH_DEV_OF(port_id, dev) { @@ -217,36 +241,38 @@ return ret; } -int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv); +int hn_vf_configure(struct rte_eth_dev *dev, + const struct rte_eth_conf *dev_conf); -static void hn_vf_add_retry(void *args) +/* Undo hn_vf_attach() on configure/start failure */ +static void hn_vf_detach(struct hn_data *hv) { - struct rte_eth_dev *dev = args; - struct hn_data *hv = dev->data->dev_private; + uint16_t port = hv->vf_ctx.vf_port; - hn_vf_add(dev, hv); -} + rte_eth_dev_callback_unregister(port, RTE_ETH_EVENT_INTR_RMV, + hn_eth_rmv_event_callback, hv); -int hn_vf_configure(struct rte_eth_dev *dev, - const struct rte_eth_conf *dev_conf); + if (rte_eth_dev_owner_unset(port, hv->owner.id) < 0) + PMD_DRV_LOG(ERR, "Failed to unset owner for port %d", port); -/* Add new VF device to synthetic device */ -int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv) + hv->vf_ctx.vf_attached = false; + hv->vf_ctx.vf_port = 0; +} + +/* Add new VF device to synthetic device, unlocked version */ +int hn_vf_add_unlocked(struct rte_eth_dev *dev, struct hn_data *hv) { - int ret, port; + int ret = 0, port; + bool fresh_attach; if (!hv->vf_ctx.vf_vsp_reported || hv->vf_ctx.vf_vsc_switched) - return 0; - - rte_rwlock_write_lock(&hv->vf_lock); + goto exit; ret = hn_vf_attach(dev, hv); - if (ret) { - PMD_DRV_LOG(NOTICE, - "RNDIS reports VF but device not found, retrying"); - rte_eal_alarm_set(1000000, hn_vf_add_retry, dev); + if (ret && ret != -EEXIST) goto exit; - } + + fresh_attach = (ret == 0); port = hv->vf_ctx.vf_port; @@ -256,7 +282,7 @@ if (dev->data->dev_started) { if (rte_eth_devices[port].data->dev_started) { PMD_DRV_LOG(ERR, "VF already started on hot add"); - goto exit; + goto switch_data_path; } PMD_DRV_LOG(NOTICE, "configuring VF port %d", port); @@ -264,7 +290,7 @@ if (ret) { PMD_DRV_LOG(ERR, "Failed to configure VF port %d", port); - goto exit; + goto detach; } ret = hn_setup_vf_queues(port, dev); @@ -272,13 +298,13 @@ PMD_DRV_LOG(ERR, "Failed to configure VF queues port %d", port); - goto exit; + goto detach; } ret = rte_eth_dev_set_mtu(port, dev->data->mtu); if (ret) { PMD_DRV_LOG(ERR, "Failed to set VF MTU"); - goto exit; + goto detach; } PMD_DRV_LOG(NOTICE, "Starting VF port %d", port); @@ -286,40 +312,59 @@ if (ret) { PMD_DRV_LOG(ERR, "rte_eth_dev_start failed ret=%d", ret); - goto exit; + goto detach; } hv->vf_ctx.vf_state = vf_started; } - ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_VF); - if (ret == 0) - hv->vf_ctx.vf_vsc_switched = true; +switch_data_path: + /* Only switch data path to VF if the device is started. + * Otherwise defer to hn_vf_start() to avoid routing traffic + * to the VF before queues are set up. + */ + if (dev->data->dev_started) { + ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_VF); + if (ret) + PMD_DRV_LOG(ERR, "Failed to switch to VF: %d", ret); + else + hv->vf_ctx.vf_vsc_switched = true; + } exit: - rte_rwlock_write_unlock(&hv->vf_lock); + return ret; + +detach: + if (fresh_attach) + hn_vf_detach(hv); return ret; } -/* Switch data path to VF device */ -static void hn_vf_remove(struct hn_data *hv) +/* Add new VF device to synthetic device, locked version */ +int hn_vf_add(struct rte_eth_dev *dev, struct hn_data *hv) { int ret; - if (!hv->vf_ctx.vf_vsc_switched) { - PMD_DRV_LOG(ERR, "VF path not active"); - return; - } - rte_rwlock_write_lock(&hv->vf_lock); + ret = hn_vf_add_unlocked(dev, hv); + rte_rwlock_write_unlock(&hv->vf_lock); + + return ret; +} + +/* Switch data path to synthetic, unlocked version */ +static void hn_vf_remove_unlocked(struct hn_data *hv) +{ + int ret; + if (!hv->vf_ctx.vf_vsc_switched) { PMD_DRV_LOG(ERR, "VF path not active"); } else { /* Stop incoming packets from arriving on VF */ ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC); if (ret == 0) + /* Clear switched flag regardless — VF is being removed */ hv->vf_ctx.vf_vsc_switched = false; } - rte_rwlock_write_unlock(&hv->vf_lock); } /* Handle VF association message from host */ @@ -341,14 +386,17 @@ vf_assoc->allocated ? "add to" : "remove from", dev->data->port_id); - hv->vf_ctx.vf_vsp_reported = vf_assoc->allocated; + rte_rwlock_write_lock(&hv->vf_lock); + hv->vf_ctx.vf_vsp_reported = vf_assoc->allocated; if (dev->state == RTE_ETH_DEV_ATTACHED) { if (vf_assoc->allocated) - hn_vf_add(dev, hv); + hn_vf_add_unlocked(dev, hv); else - hn_vf_remove(hv); + hn_vf_remove_unlocked(hv); } + + rte_rwlock_write_unlock(&hv->vf_lock); } static void @@ -429,29 +477,12 @@ vf_conf.intr_conf.rmv = 1; if (hv->vf_ctx.vf_attached) { - ret = rte_eth_dev_callback_register(hv->vf_ctx.vf_port, - RTE_ETH_EVENT_INTR_RMV, - hn_eth_rmv_event_callback, - hv); - if (ret) { - PMD_DRV_LOG(ERR, - "Registering callback failed for vf port %d ret %d", - hv->vf_ctx.vf_port, ret); - return ret; - } - ret = rte_eth_dev_configure(hv->vf_ctx.vf_port, dev->data->nb_rx_queues, dev->data->nb_tx_queues, &vf_conf); if (ret) { PMD_DRV_LOG(ERR, "VF configuration failed: %d", ret); - - rte_eth_dev_callback_unregister(hv->vf_ctx.vf_port, - RTE_ETH_EVENT_INTR_RMV, - hn_eth_rmv_event_callback, - hv); - return ret; } @@ -500,11 +531,31 @@ struct rte_eth_dev *vf_dev; int ret = 0; - rte_rwlock_read_lock(&hv->vf_lock); + rte_rwlock_write_lock(&hv->vf_lock); vf_dev = hn_get_vf_dev(hv); - if (vf_dev) + if (vf_dev) { ret = rte_eth_dev_start(vf_dev->data->port_id); - rte_rwlock_read_unlock(&hv->vf_lock); + if (ret == 0) { + /* Re-switch data path to VF if VSP has reported + * VF is present and we haven't switched yet + * (e.g. after a stop/start cycle). + */ + if (hv->vf_ctx.vf_vsp_reported && + !hv->vf_ctx.vf_vsc_switched) { + ret = hn_nvs_set_datapath(hv, + NVS_DATAPATH_VF); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to switch to VF: %d", + ret); + rte_eth_dev_stop(vf_dev->data->port_id); + } else { + hv->vf_ctx.vf_vsc_switched = true; + } + } + } + } + rte_rwlock_write_unlock(&hv->vf_lock); return ret; } @@ -513,16 +564,33 @@ struct hn_data *hv = dev->data->dev_private; struct rte_eth_dev *vf_dev; int ret = 0; + int err; - rte_rwlock_read_lock(&hv->vf_lock); + rte_rwlock_write_lock(&hv->vf_lock); vf_dev = hn_get_vf_dev(hv); if (vf_dev) { - ret = rte_eth_dev_stop(vf_dev->data->port_id); - if (ret != 0) + /* Switch data path back to synthetic before stopping VF, + * so the host stops routing traffic to the VF device. + */ + if (hv->vf_ctx.vf_vsc_switched) { + ret = hn_nvs_set_datapath(hv, NVS_DATAPATH_SYNTHETIC); + if (ret) { + PMD_DRV_LOG(ERR, + "Failed to switch to synthetic: %d", + ret); + } else { + hv->vf_ctx.vf_vsc_switched = false; + } + } + + err = rte_eth_dev_stop(vf_dev->data->port_id); + if (err != 0) PMD_DRV_LOG(ERR, "Failed to stop device on port %u", vf_dev->data->port_id); + if (ret == 0) + ret = err; } - rte_rwlock_read_unlock(&hv->vf_lock); + rte_rwlock_write_unlock(&hv->vf_lock); return ret; } @@ -558,9 +626,7 @@ int ret = 0; struct hn_data *hv = dev->data->dev_private; - rte_eal_alarm_cancel(hn_vf_add_retry, dev); - - rte_rwlock_read_lock(&hv->vf_lock); + rte_rwlock_write_lock(&hv->vf_lock); if (hv->vf_ctx.vf_attached) { rte_eth_dev_callback_unregister(hv->vf_ctx.vf_port, RTE_ETH_EVENT_INTR_RMV, @@ -570,7 +636,7 @@ ret = rte_eth_dev_close(hv->vf_ctx.vf_port); hv->vf_ctx.vf_attached = false; } - rte_rwlock_read_unlock(&hv->vf_lock); + rte_rwlock_write_unlock(&hv->vf_lock); return ret; } diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb.h dpdk-24.11.8/drivers/net/nfb/nfb.h --- dpdk-24.11.4/drivers/net/nfb/nfb.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb.h 2026-10-14 13:10:05.000000000 +0000 @@ -41,7 +41,10 @@ #define RTE_NFB_DRIVER_NAME net_nfb - +/* + * Handles obtained from the libnfb: each process must use own instance. + * Stored inside dev->process_private. + */ struct pmd_internals { uint16_t max_rxmac; uint16_t max_txmac; @@ -50,4 +53,13 @@ struct nfb_device *nfb; }; +/* + * Common data, single instance usable in all processes. + * Inited in the RTE_PROC_PRIMARY, stored in dev->data->dev_private. + */ +struct pmd_priv { + uint16_t max_rx_queues; + uint16_t max_tx_queues; +}; + #endif /* _NFB_H_ */ diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb_ethdev.c dpdk-24.11.8/drivers/net/nfb/nfb_ethdev.c --- dpdk-24.11.4/drivers/net/nfb/nfb_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -18,6 +18,8 @@ #include "nfb_rxmode.h" #include "nfb.h" +static int nfb_eth_dev_uninit(struct rte_eth_dev *dev); + /** * Default MAC addr */ @@ -137,11 +139,12 @@ return 0; err_tx: - for (i = 0; i < nb_tx; i++) - nfb_eth_tx_queue_stop(dev, i); + for (; i > 0; i--) + nfb_eth_tx_queue_stop(dev, i - 1); + i = nb_rx; err_rx: - for (i = 0; i < nb_rx; i++) - nfb_eth_rx_queue_stop(dev, i); + for (; i > 0; i--) + nfb_eth_rx_queue_stop(dev, i - 1); return ret; } @@ -160,8 +163,6 @@ uint16_t nb_rx = dev->data->nb_rx_queues; uint16_t nb_tx = dev->data->nb_tx_queues; - dev->data->dev_started = 0; - for (i = 0; i < nb_tx; i++) nfb_eth_tx_queue_stop(dev, i); @@ -184,7 +185,6 @@ nfb_eth_dev_configure(struct rte_eth_dev *dev __rte_unused) { int ret; - struct pmd_internals *internals = dev->data->dev_private; struct rte_eth_conf *dev_conf = &dev->data->dev_conf; if (dev_conf->rxmode.offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP) { @@ -193,12 +193,16 @@ &nfb_timestamp_rx_dynflag); if (ret != 0) { NFB_LOG(ERR, "Cannot register Rx timestamp field/flag %d", ret); - nfb_close(internals->nfb); - return -rte_errno; + ret = -ENOMEM; + goto err_ts_register; } } return 0; + +err_ts_register: + nfb_eth_dev_uninit(dev); + return ret; } static uint32_t @@ -207,7 +211,7 @@ uint16_t i; uint32_t c; uint32_t ret = (uint32_t)-1; - struct pmd_internals *internals = dev->data->dev_private; + struct pmd_internals *internals = dev->process_private; /* * Go through all RX MAC components in firmware and find @@ -237,11 +241,13 @@ nfb_eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { + struct pmd_priv *priv = dev->data->dev_private; + dev_info->max_mac_addrs = nfb_eth_get_max_mac_address_count(dev); dev_info->max_rx_pktlen = (uint32_t)-1; - dev_info->max_rx_queues = dev->data->nb_rx_queues; - dev_info->max_tx_queues = dev->data->nb_tx_queues; + dev_info->max_rx_queues = priv->max_rx_queues; + dev_info->max_tx_queues = priv->max_tx_queues; dev_info->speed_capa = RTE_ETH_LINK_SPEED_100G; dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_TIMESTAMP; @@ -260,32 +266,28 @@ static int nfb_eth_dev_close(struct rte_eth_dev *dev) { - struct pmd_internals *internals = dev->data->dev_private; uint16_t i; uint16_t nb_rx = dev->data->nb_rx_queues; uint16_t nb_tx = dev->data->nb_tx_queues; - int ret; - - if (rte_eal_process_type() != RTE_PROC_PRIMARY) - return 0; - ret = nfb_eth_dev_stop(dev); - - nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac); - nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac); - - for (i = 0; i < nb_rx; i++) { - nfb_eth_rx_queue_release(dev, i); - dev->data->rx_queues[i] = NULL; - } - dev->data->nb_rx_queues = 0; - for (i = 0; i < nb_tx; i++) { - nfb_eth_tx_queue_release(dev, i); - dev->data->tx_queues[i] = NULL; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + for (i = 0; i < nb_rx; i++) { + if (dev->data->rx_queues[i]) { + nfb_eth_rx_queue_release(dev, i); + dev->data->rx_queues[i] = NULL; + } + } + for (i = 0; i < nb_tx; i++) { + if (dev->data->tx_queues[i]) { + nfb_eth_tx_queue_release(dev, i); + dev->data->tx_queues[i] = NULL; + } + } } - dev->data->nb_tx_queues = 0; - return ret; + nfb_eth_dev_uninit(dev); + + return 0; } /** @@ -308,7 +310,7 @@ struct rte_eth_link link; memset(&link, 0, sizeof(link)); - struct pmd_internals *internals = dev->data->dev_private; + struct pmd_internals *internals = dev->process_private; status.speed = MAC_SPEED_UNKNOWN; @@ -363,7 +365,7 @@ nfb_eth_dev_set_link_up(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; for (i = 0; i < internals->max_rxmac; ++i) @@ -388,7 +390,7 @@ nfb_eth_dev_set_link_down(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; for (i = 0; i < internals->max_rxmac; ++i) @@ -429,9 +431,8 @@ { unsigned int i; uint64_t mac; - struct rte_eth_dev_data *data = dev->data; struct pmd_internals *internals = (struct pmd_internals *) - data->dev_private; + dev->process_private; mac = nfb_eth_mac_addr_conv(mac_addr); /* Until no real multi-port support, configure all RX MACs the same */ @@ -447,9 +448,8 @@ { unsigned int i; uint64_t mac; - struct rte_eth_dev_data *data = dev->data; struct pmd_internals *internals = (struct pmd_internals *) - data->dev_private; + dev->process_private; mac = nfb_eth_mac_addr_conv(mac_addr); for (i = 0; i < internals->max_rxmac; ++i) @@ -462,9 +462,8 @@ nfb_eth_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) { unsigned int i; - struct rte_eth_dev_data *data = dev->data; struct pmd_internals *internals = (struct pmd_internals *) - data->dev_private; + dev->process_private; for (i = 0; i < internals->max_rxmac; ++i) nc_rxmac_set_mac(internals->rxmac[i], index, 0, 0); @@ -510,19 +509,31 @@ static int nfb_eth_dev_init(struct rte_eth_dev *dev) { + int ret; uint32_t mac_count; struct rte_eth_dev_data *data = dev->data; - struct pmd_internals *internals = (struct pmd_internals *) - data->dev_private; + struct pmd_internals *internals; + struct pmd_priv *priv = data->dev_private; struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); struct rte_pci_addr *pci_addr = &pci_dev->addr; struct rte_ether_addr eth_addr_init; + uint16_t max_rx_queues, max_tx_queues; char nfb_dev[PATH_MAX]; NFB_LOG(INFO, "Initializing NFB device (" PCI_PRI_FMT ")", pci_addr->domain, pci_addr->bus, pci_addr->devid, pci_addr->function); + internals = rte_zmalloc_socket("nfb_internals", + sizeof(struct pmd_internals), RTE_CACHE_LINE_SIZE, + dev->device->numa_node); + if (internals == NULL) { + ret = -ENOMEM; + goto err_alloc_internals; + } + + dev->process_private = internals; + snprintf(nfb_dev, sizeof(nfb_dev), "/dev/nfb/by-pci-slot/" PCI_PRI_FMT, pci_addr->domain, pci_addr->bus, pci_addr->devid, @@ -536,13 +547,14 @@ internals->nfb = nfb_open(nfb_dev); if (internals->nfb == NULL) { NFB_LOG(ERR, "nfb_open(): failed to open %s", nfb_dev); - return -EINVAL; + ret = -EINVAL; + goto err_nfb_open; } - data->nb_rx_queues = ndp_get_rx_queue_available_count(internals->nfb); - data->nb_tx_queues = ndp_get_tx_queue_available_count(internals->nfb); + max_rx_queues = ndp_get_rx_queue_available_count(internals->nfb); + max_tx_queues = ndp_get_tx_queue_available_count(internals->nfb); NFB_LOG(INFO, "Available NDP queues RX: %u TX: %u", - data->nb_rx_queues, data->nb_tx_queues); + max_rx_queues, max_tx_queues); nfb_nc_rxmac_init(internals->nfb, internals->rxmac, @@ -561,34 +573,49 @@ /* Get link state */ nfb_eth_link_update(dev, 0); - /* Allocate space for MAC addresses */ - mac_count = nfb_eth_get_max_mac_address_count(dev); - data->mac_addrs = rte_zmalloc(data->name, - sizeof(struct rte_ether_addr) * mac_count, RTE_CACHE_LINE_SIZE); - if (data->mac_addrs == NULL) { - NFB_LOG(ERR, "Could not alloc space for MAC address"); - nfb_close(internals->nfb); - return -EINVAL; - } - - rte_eth_random_addr(eth_addr_init.addr_bytes); - eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0]; - eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1]; - eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2]; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + priv->max_rx_queues = max_rx_queues; + priv->max_tx_queues = max_tx_queues; + + /* Allocate space for MAC addresses */ + mac_count = nfb_eth_get_max_mac_address_count(dev); + data->mac_addrs = rte_zmalloc(data->name, + sizeof(struct rte_ether_addr) * mac_count, RTE_CACHE_LINE_SIZE); + if (data->mac_addrs == NULL) { + NFB_LOG(ERR, "Could not alloc space for MAC address"); + ret = -ENOMEM; + goto err_malloc_mac_addrs; + } - nfb_eth_mac_addr_set(dev, ð_addr_init); - rte_ether_addr_copy(ð_addr_init, &dev->data->mac_addrs[0]); + rte_eth_random_addr(eth_addr_init.addr_bytes); + eth_addr_init.addr_bytes[0] = eth_addr.addr_bytes[0]; + eth_addr_init.addr_bytes[1] = eth_addr.addr_bytes[1]; + eth_addr_init.addr_bytes[2] = eth_addr.addr_bytes[2]; - data->promiscuous = nfb_eth_promiscuous_get(dev); - data->all_multicast = nfb_eth_allmulticast_get(dev); + nfb_eth_mac_addr_set(dev, ð_addr_init); + rte_ether_addr_copy(ð_addr_init, &data->mac_addrs[0]); - dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; + data->promiscuous = nfb_eth_promiscuous_get(dev); + data->all_multicast = nfb_eth_allmulticast_get(dev); + + data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS; + } NFB_LOG(INFO, "NFB device (" PCI_PRI_FMT ") successfully initialized", pci_addr->domain, pci_addr->bus, pci_addr->devid, pci_addr->function); return 0; + +err_malloc_mac_addrs: + nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac); + nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac); + nfb_close(internals->nfb); + +err_nfb_open: + rte_free(internals); +err_alloc_internals: + return ret; } /** @@ -605,8 +632,13 @@ { struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); struct rte_pci_addr *pci_addr = &pci_dev->addr; + struct pmd_internals *internals = dev->process_private; + + nfb_nc_rxmac_deinit(internals->rxmac, internals->max_rxmac); + nfb_nc_txmac_deinit(internals->txmac, internals->max_txmac); + nfb_close(internals->nfb); - nfb_eth_dev_close(dev); + rte_free(internals); NFB_LOG(INFO, "NFB device (" PCI_PRI_FMT ") successfully uninitialized", pci_addr->domain, pci_addr->bus, pci_addr->devid, @@ -642,7 +674,7 @@ struct rte_pci_device *pci_dev) { return rte_eth_dev_pci_generic_probe(pci_dev, - sizeof(struct pmd_internals), nfb_eth_dev_init); + sizeof(struct pmd_priv), nfb_eth_dev_init); } /** diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb_rx.c dpdk-24.11.8/drivers/net/nfb/nfb_rx.c --- dpdk-24.11.4/drivers/net/nfb/nfb_rx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb_rx.c 2026-10-14 13:10:05.000000000 +0000 @@ -60,7 +60,7 @@ const struct rte_eth_rxconf *rx_conf __rte_unused, struct rte_mempool *mb_pool) { - struct pmd_internals *internals = dev->data->dev_private; + struct pmd_internals *internals = dev->process_private; struct ndp_rx_queue *rxq; int ret; diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb_rxmode.c dpdk-24.11.8/drivers/net/nfb/nfb_rxmode.c --- dpdk-24.11.4/drivers/net/nfb/nfb_rxmode.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb_rxmode.c 2026-10-14 13:10:05.000000000 +0000 @@ -11,7 +11,7 @@ nfb_eth_promiscuous_enable(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; for (i = 0; i < internals->max_rxmac; ++i) { @@ -26,7 +26,7 @@ nfb_eth_promiscuous_disable(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; enum nc_rxmac_mac_filter filter = RXMAC_MAC_FILTER_TABLE_BCAST; @@ -44,7 +44,7 @@ nfb_eth_promiscuous_get(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; struct nc_rxmac_status status; status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS; @@ -59,7 +59,7 @@ nfb_eth_allmulticast_enable(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; if (dev->data->promiscuous) @@ -76,7 +76,7 @@ nfb_eth_allmulticast_disable(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; uint16_t i; @@ -95,7 +95,7 @@ nfb_eth_allmulticast_get(struct rte_eth_dev *dev) { struct pmd_internals *internals = (struct pmd_internals *) - dev->data->dev_private; + dev->process_private; struct nc_rxmac_status status; status.mac_filter = RXMAC_MAC_FILTER_PROMISCUOUS; diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb_stats.c dpdk-24.11.8/drivers/net/nfb/nfb_stats.c --- dpdk-24.11.4/drivers/net/nfb/nfb_stats.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb_stats.c 2026-10-14 13:10:05.000000000 +0000 @@ -20,28 +20,31 @@ uint64_t rx_total_bytes = 0; uint64_t tx_total_bytes = 0; - struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **) - dev->data->rx_queues); - struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **) - dev->data->tx_queues); - for (i = 0; i < nb_rx; i++) { + struct ndp_rx_queue *rx_queue = dev->data->rx_queues[i]; + if (rx_queue == NULL) + continue; + if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) { - stats->q_ipackets[i] = rx_queue[i].rx_pkts; - stats->q_ibytes[i] = rx_queue[i].rx_bytes; + stats->q_ipackets[i] = rx_queue->rx_pkts; + stats->q_ibytes[i] = rx_queue->rx_bytes; } - rx_total += rx_queue[i].rx_pkts; - rx_total_bytes += rx_queue[i].rx_bytes; + rx_total += rx_queue->rx_pkts; + rx_total_bytes += rx_queue->rx_bytes; } for (i = 0; i < nb_tx; i++) { + struct ndp_tx_queue *tx_queue = dev->data->tx_queues[i]; + if (tx_queue == NULL) + continue; + if (i < RTE_ETHDEV_QUEUE_STAT_CNTRS) { - stats->q_opackets[i] = tx_queue[i].tx_pkts; - stats->q_obytes[i] = tx_queue[i].tx_bytes; + stats->q_opackets[i] = tx_queue->tx_pkts; + stats->q_obytes[i] = tx_queue->tx_bytes; } - tx_total += tx_queue[i].tx_pkts; - tx_total_bytes += tx_queue[i].tx_bytes; - tx_err_total += tx_queue[i].err_pkts; + tx_total += tx_queue->tx_pkts; + tx_total_bytes += tx_queue->tx_bytes; + tx_err_total += tx_queue->err_pkts; } stats->ipackets = rx_total; @@ -59,20 +62,24 @@ uint16_t nb_rx = dev->data->nb_rx_queues; uint16_t nb_tx = dev->data->nb_tx_queues; - struct ndp_rx_queue *rx_queue = *((struct ndp_rx_queue **) - dev->data->rx_queues); - struct ndp_tx_queue *tx_queue = *((struct ndp_tx_queue **) - dev->data->tx_queues); - for (i = 0; i < nb_rx; i++) { - rx_queue[i].rx_pkts = 0; - rx_queue[i].rx_bytes = 0; - rx_queue[i].err_pkts = 0; + struct ndp_rx_queue *rx_queue = dev->data->rx_queues[i]; + if (rx_queue == NULL) + continue; + + rx_queue->rx_pkts = 0; + rx_queue->rx_bytes = 0; + rx_queue->err_pkts = 0; } + for (i = 0; i < nb_tx; i++) { - tx_queue[i].tx_pkts = 0; - tx_queue[i].tx_bytes = 0; - tx_queue[i].err_pkts = 0; + struct ndp_tx_queue *tx_queue = dev->data->tx_queues[i]; + if (tx_queue == NULL) + continue; + + tx_queue->tx_pkts = 0; + tx_queue->tx_bytes = 0; + tx_queue->err_pkts = 0; } return 0; diff -Nru dpdk-24.11.4/drivers/net/nfb/nfb_tx.c dpdk-24.11.8/drivers/net/nfb/nfb_tx.c --- dpdk-24.11.4/drivers/net/nfb/nfb_tx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfb/nfb_tx.c 2026-10-14 13:10:05.000000000 +0000 @@ -53,7 +53,7 @@ unsigned int socket_id, const struct rte_eth_txconf *tx_conf __rte_unused) { - struct pmd_internals *internals = dev->data->dev_private; + struct pmd_internals *internals = dev->process_private; int ret; struct ndp_tx_queue *txq; diff -Nru dpdk-24.11.4/drivers/net/nfp/flower/nfp_flower_ctrl.c dpdk-24.11.8/drivers/net/nfp/flower/nfp_flower_ctrl.c --- dpdk-24.11.4/drivers/net/nfp/flower/nfp_flower_ctrl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfp/flower/nfp_flower_ctrl.c 2026-10-14 13:10:05.000000000 +0000 @@ -168,7 +168,7 @@ * enabled. But the queue needs to be configured. */ PMD_TX_LOG(ERR, "Ctrl dev TX Bad queue."); - goto xmit_end; + return 0; } txds = &txq->txds[txq->wr_p]; @@ -183,7 +183,7 @@ free_descs = nfp_net_nfd3_free_tx_desc(txq); if (unlikely(free_descs == 0)) { PMD_TX_LOG(ERR, "Ctrl dev no free descs."); - goto xmit_end; + return 0; } lmbuf = &txq->txbufs[txq->wr_p].mbuf; @@ -207,7 +207,6 @@ cnt++; app_fw_flower->ctrl_vnic_tx_count++; -xmit_end: rte_wmb(); nfp_qcp_ptr_add(txq->qcp_q, NFP_QCP_WRITE_PTR, 1); diff -Nru dpdk-24.11.4/drivers/net/nfp/nfpcore/nfp6000_pcie.c dpdk-24.11.8/drivers/net/nfp/nfpcore/nfp6000_pcie.c --- dpdk-24.11.4/drivers/net/nfp/nfpcore/nfp6000_pcie.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/nfp/nfpcore/nfp6000_pcie.c 2026-10-14 13:10:05.000000000 +0000 @@ -55,11 +55,11 @@ */ #define NFP_PCI_MIN_MAP_SIZE 0x080000 /* 512K */ -#define NFP_PCIE_P2C_FIXED_SIZE(bar) (1 << (bar)->bitsize) -#define NFP_PCIE_P2C_BULK_SIZE(bar) (1 << (bar)->bitsize) +#define NFP_PCIE_P2C_FIXED_SIZE(bar) RTE_BIT64((bar)->bitsize) +#define NFP_PCIE_P2C_BULK_SIZE(bar) RTE_BIT64((bar)->bitsize) #define NFP_PCIE_P2C_GENERAL_TARGET_OFFSET(bar, x) ((x) << ((bar)->bitsize - 2)) #define NFP_PCIE_P2C_GENERAL_TOKEN_OFFSET(bar, x) ((x) << ((bar)->bitsize - 4)) -#define NFP_PCIE_P2C_GENERAL_SIZE(bar) (1 << ((bar)->bitsize - 4)) +#define NFP_PCIE_P2C_GENERAL_SIZE(bar) RTE_BIT64(((bar)->bitsize - 4)) #define NFP_PCIE_P2C_EXPBAR_OFFSET(bar_index) ((bar_index) * 4) @@ -443,7 +443,7 @@ (bar_token < 0 || bar_token == token) && bar_action == action && bar->base <= offset && - (bar->base + (1 << bar->bitsize)) >= (offset + size)) + (bar->base + RTE_BIT64(bar->bitsize)) >= (offset + size)) return true; /* No match */ diff -Nru dpdk-24.11.4/drivers/net/ngbe/base/ngbe_phy_yt.c dpdk-24.11.8/drivers/net/ngbe/base/ngbe_phy_yt.c --- dpdk-24.11.4/drivers/net/ngbe/base/ngbe_phy_yt.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ngbe/base/ngbe_phy_yt.c 2026-10-14 13:10:05.000000000 +0000 @@ -264,6 +264,9 @@ value = YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN | YT_BCR_DUPLEX | YT_BCR_SPEED_SELECT1; } else { + /* force mode need to config cdr */ + ngbe_write_phy_reg_sds_ext_yt(hw, 0x3, 0, 0x1434); + ngbe_write_phy_reg_sds_ext_yt(hw, 0xe, 0, 0x163); value = YT_BCR_RESET | YT_BCR_DUPLEX; if (speed & NGBE_LINK_SPEED_1GB_FULL) value |= YT_BCR_SPEED_SELECT1; diff -Nru dpdk-24.11.4/drivers/net/ngbe/ngbe_ethdev.c dpdk-24.11.8/drivers/net/ngbe/ngbe_ethdev.c --- dpdk-24.11.4/drivers/net/ngbe/ngbe_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ngbe/ngbe_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -227,11 +227,6 @@ HW_XSTAT(tx_size_1024_to_max_packets), /* Flow Control */ - HW_XSTAT(tx_xon_packets), - HW_XSTAT(rx_xon_packets), - HW_XSTAT(tx_xoff_packets), - HW_XSTAT(rx_xoff_packets), - HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"), HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"), HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"), diff -Nru dpdk-24.11.4/drivers/net/ngbe/ngbe_rxtx.c dpdk-24.11.8/drivers/net/ngbe/ngbe_rxtx.c --- dpdk-24.11.4/drivers/net/ngbe/ngbe_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/ngbe/ngbe_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -30,6 +30,7 @@ RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_L4_MASK | RTE_MBUF_F_TX_TCP_SEG | + RTE_MBUF_F_TX_UDP_SEG | NGBE_TX_IEEE1588_TMST); #define NGBE_TX_OFFLOAD_NOTSUP_MASK \ @@ -317,7 +318,7 @@ type_tucmd_mlhl |= NGBE_TXD_PTID(tx_offload.ptid); /* check if TCP segmentation required for this packet */ - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { tx_offload_mask.l2_len |= ~0; tx_offload_mask.l3_len |= ~0; tx_offload_mask.l4_len |= ~0; @@ -427,7 +428,7 @@ tmp |= NGBE_TXD_CC; tmp |= NGBE_TXD_EIPCS; } - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { tmp |= NGBE_TXD_CC; /* implies IPv4 cksum */ if (ol_flags & RTE_MBUF_F_TX_IPV4) @@ -447,7 +448,7 @@ if (ol_flags & RTE_MBUF_F_TX_VLAN) cmdtype |= NGBE_TXD_VLE; - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) cmdtype |= NGBE_TXD_TSE; return cmdtype; } @@ -483,6 +484,8 @@ if (oflags & RTE_MBUF_F_TX_TCP_SEG) ptype |= RTE_PTYPE_L4_TCP; + else if (oflags & RTE_MBUF_F_TX_UDP_SEG) + ptype |= RTE_PTYPE_L4_UDP; return ptype; } @@ -764,7 +767,7 @@ olinfo_status = 0; if (tx_ol_req) { - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { /* when TSO is on, paylen in descriptor is the * not the packet len but the tcp payload len */ @@ -1991,7 +1994,7 @@ RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_TSO | - RTE_ETH_TX_OFFLOAD_UDP_TSO | + RTE_ETH_TX_OFFLOAD_UDP_TSO | RTE_ETH_TX_OFFLOAD_MULTI_SEGS; if (hw->is_pf) diff -Nru dpdk-24.11.4/drivers/net/octeontx/base/octeontx_pkovf.c dpdk-24.11.8/drivers/net/octeontx/base/octeontx_pkovf.c --- dpdk-24.11.4/drivers/net/octeontx/base/octeontx_pkovf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/octeontx/base/octeontx_pkovf.c 2026-10-14 13:10:05.000000000 +0000 @@ -196,8 +196,8 @@ while (dq < RTE_DIM(ctl->dq_map)) { dq_base = dq; dq_cnt = 0; - while (ctl->dq_map[dq].chanid == ~chanid && - dq < RTE_DIM(ctl->dq_map)) { + while (dq < RTE_DIM(ctl->dq_map) && + ctl->dq_map[dq].chanid == ~chanid) { dq_cnt++; if (dq_cnt == dq_num) return dq_base; diff -Nru dpdk-24.11.4/drivers/net/octeontx/octeontx_ethdev.c dpdk-24.11.8/drivers/net/octeontx/octeontx_ethdev.c --- dpdk-24.11.4/drivers/net/octeontx/octeontx_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/octeontx/octeontx_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -1552,7 +1552,7 @@ PMD_INIT_FUNC_TRACE(); - sprintf(octtx_name, "%s_%d", name, port); + snprintf(octtx_name, sizeof(octtx_name), "%s_%d", name, port); if (rte_eal_process_type() != RTE_PROC_PRIMARY) { eth_dev = rte_eth_dev_attach_secondary(octtx_name); if (eth_dev == NULL) @@ -1708,7 +1708,7 @@ return -EINVAL; for (i = 0; i < OCTEONTX_VDEV_DEFAULT_MAX_NR_PORT; i++) { - sprintf(octtx_name, "eth_octeontx_%d", i); + snprintf(octtx_name, sizeof(octtx_name), "eth_octeontx_%d", i); eth_dev = rte_eth_dev_allocated(octtx_name); if (eth_dev == NULL) diff -Nru dpdk-24.11.4/drivers/net/pcap/pcap_ethdev.c dpdk-24.11.8/drivers/net/pcap/pcap_ethdev.c --- dpdk-24.11.4/drivers/net/pcap/pcap_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/pcap/pcap_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -456,13 +456,22 @@ } /* - * Callback to handle sending packets through a real NIC. + * Send a burst of packets to a pcap device. + * + * On Linux, pcap_sendpacket() calls send() on a blocking PF_PACKET + * socket with default kernel buffer sizes and no TX ring (PACKET_TX_RING). + * The send() call only blocks when the kernel socket send buffer is full, + * providing limited backpressure. + * + * On error, pcap_sendpacket() returns non-zero and the loop breaks, + * leaving remaining packets unsent. + * + * Bottom line: backpressure is not an error. */ static uint16_t eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts) { unsigned int i; - int ret; struct rte_mbuf *mbuf; struct pmd_process_private *pp; struct pcap_tx_queue *tx_queue = queue; @@ -470,7 +479,6 @@ uint32_t tx_bytes = 0; pcap_t *pcap; unsigned char temp_data[RTE_ETH_PCAP_SNAPLEN]; - size_t len; pp = rte_eth_devices[tx_queue->port_id].process_private; pcap = pp->tx_pcap[tx_queue->queue_id]; @@ -480,24 +488,26 @@ for (i = 0; i < nb_pkts; i++) { mbuf = bufs[i]; - len = rte_pktmbuf_pkt_len(mbuf); + uint32_t len = rte_pktmbuf_pkt_len(mbuf); + const uint8_t *data; if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) && len > sizeof(temp_data))) { PMD_LOG(ERR, - "Dropping multi segment PCAP packet. Size (%zd) > max size (%zd).", + "Dropping multi segment PCAP packet. Size (%u) > max size (%zd).", len, sizeof(temp_data)); + tx_queue->tx_stat.err_pkts++; rte_pktmbuf_free(mbuf); continue; } - /* rte_pktmbuf_read() returns a pointer to the data directly - * in the mbuf (when the mbuf is contiguous) or, otherwise, - * a pointer to temp_data after copying into it. - */ - ret = pcap_sendpacket(pcap, - rte_pktmbuf_read(mbuf, 0, len, temp_data), len); - if (unlikely(ret != 0)) + data = rte_pktmbuf_read(mbuf, 0, len, temp_data); + RTE_ASSERT(data != NULL); + + if (unlikely(pcap_sendpacket(pcap, data, len) != 0)) { + /* Assume failure is backpressure */ + PMD_LOG(ERR, "pcap_sendpacket() failed: %s", pcap_geterr(pcap)); break; + } num_tx++; tx_bytes += len; rte_pktmbuf_free(mbuf); @@ -505,7 +515,6 @@ tx_queue->tx_stat.pkts += num_tx; tx_queue->tx_stat.bytes += tx_bytes; - tx_queue->tx_stat.err_pkts += i - num_tx; return i; } @@ -523,6 +532,16 @@ return -1; } + /* + * Verify interface supports Ethernet link type. + * Loopback on FreeBSD/macOS uses DLT_NULL which expects a 4-byte + * address family header instead of Ethernet, causing kernel warnings. + */ + if (pcap_datalink(*pcap) != DLT_EN10MB) { + PMD_LOG(ERR, "%s: not Ethernet (link type %d)", + iface, pcap_datalink(*pcap)); + } + if (pcap_setnonblock(*pcap, 1, errbuf)) { PMD_LOG(ERR, "Couldn't set non-blocking on %s: %s", iface, errbuf); pcap_close(*pcap); @@ -745,6 +764,7 @@ dev_info->max_rx_queues = dev->data->nb_rx_queues; dev_info->max_tx_queues = dev->data->nb_tx_queues; dev_info->min_rx_bufsize = 0; + dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS; return 0; } diff -Nru dpdk-24.11.4/drivers/net/pcap/pcap_osdep_windows.c dpdk-24.11.8/drivers/net/pcap/pcap_osdep_windows.c --- dpdk-24.11.4/drivers/net/pcap/pcap_osdep_windows.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/pcap/pcap_osdep_windows.c 2026-10-14 13:10:05.000000000 +0000 @@ -53,7 +53,7 @@ ret = GetAdapterIndex(adapter_name, &index); if (ret != NO_ERROR) { - PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu\n", adapter_name, ret); + PMD_LOG(ERR, "GetAdapterIndex(%S) = %lu", adapter_name, ret); return -1; } @@ -75,20 +75,20 @@ sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, NULL, &size); if (sys_ret != ERROR_BUFFER_OVERFLOW) { - PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu\n", + PMD_LOG(ERR, "GetAdapterAddresses() = %lu, expected %lu", sys_ret, ERROR_BUFFER_OVERFLOW); return -1; } info = (IP_ADAPTER_ADDRESSES *)malloc(size); if (info == NULL) { - PMD_LOG(ERR, "Cannot allocate adapter address info\n"); + PMD_LOG(ERR, "Cannot allocate adapter address info"); return -1; } sys_ret = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, info, &size); if (sys_ret != ERROR_SUCCESS) { - PMD_LOG(ERR, "GetAdapterAddresses() = %lu\n", sys_ret); + PMD_LOG(ERR, "GetAdapterAddresses() = %lu", sys_ret); free(info); return -1; } diff -Nru dpdk-24.11.4/drivers/net/r8169/r8169_hw.c dpdk-24.11.8/drivers/net/r8169/r8169_hw.c --- dpdk-24.11.4/drivers/net/r8169/r8169_hw.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/r8169/r8169_hw.c 2026-10-14 13:10:05.000000000 +0000 @@ -797,6 +797,9 @@ break; } + /* Ensure the old mapping is used. */ + RTL_W8(hw, INT_CFG0_8125, RTL_R8(hw, INT_CFG0_8125) & ~BIT_0); + rtl_disable_cfg9346_write(hw); rte_delay_us(10); diff -Nru dpdk-24.11.4/drivers/net/sfc/sfc.h dpdk-24.11.8/drivers/net/sfc/sfc.h --- dpdk-24.11.4/drivers/net/sfc/sfc.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/sfc/sfc.h 2026-10-14 13:10:05.000000000 +0000 @@ -413,7 +413,7 @@ void sfc_port_close(struct sfc_adapter *sa); int sfc_port_start(struct sfc_adapter *sa); void sfc_port_stop(struct sfc_adapter *sa); -void sfc_port_link_mode_to_info(efx_link_mode_t link_mode, +void sfc_port_link_mode_to_info(efx_link_mode_t link_mode, uint32_t phy_cap_req, struct rte_eth_link *link_info); int sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t manual_update); int sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats, diff -Nru dpdk-24.11.4/drivers/net/sfc/sfc_ethdev.c dpdk-24.11.8/drivers/net/sfc/sfc_ethdev.c --- dpdk-24.11.4/drivers/net/sfc/sfc_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/sfc/sfc_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,8 @@ * for Solarflare) and Solarflare Communications, Inc. */ +#include + #include #include #include @@ -14,6 +16,7 @@ #include #include #include +#include #include #include "efx.h" @@ -256,13 +259,14 @@ SFC_ASSERT(link != NULL); if (sa->state != SFC_ETHDEV_STARTED) { - sfc_port_link_mode_to_info(EFX_LINK_UNKNOWN, link); + sfc_port_link_mode_to_info(EFX_LINK_UNKNOWN, 0, link); } else if (wait_to_complete) { efx_link_mode_t link_mode; if (efx_port_poll(sa->nic, &link_mode) != 0) link_mode = EFX_LINK_UNKNOWN; - sfc_port_link_mode_to_info(link_mode, link); + sfc_port_link_mode_to_info(link_mode, sa->port.phy_adv_cap, + link); } else { sfc_ev_mgmt_qpoll(sa); rte_eth_linkstatus_get(dev, link); @@ -2347,6 +2351,10 @@ return 0; } +/* + * When adding support for new speeds/capabilities, make sure to adjust + * validity checks conducted by 'sfc_fec_capa_check' for user input. + */ static unsigned int sfc_fec_get_capa_speed_to_fec(uint32_t supported_caps, struct rte_eth_fec_capa *speed_fec_capa) @@ -2361,18 +2369,20 @@ rs = true; /* - * NOFEC and AUTO FEC modes are always supported. - * FW does not provide information about the supported - * FEC modes per the link speed. - * Supported FEC depends on supported link speeds and - * supported FEC modes by a device. + * NOFEC can always be requested, but if the link technology for the + * intended speed mandates FEC, doing so will not bring the link up. + * + * FW cannot report supported FEC modes per speed/link technology, + * so use best-effort approximation to fill in the capabilities. + * + * Do not indicate 'AUTO'. This bit is reserved for user + * input. It has nothing to do with capability reporting. */ if (supported_caps & (1u << EFX_PHY_CAP_10000FDX)) { if (speed_fec_capa != NULL) { speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_10G; speed_fec_capa[num].capa = - RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | - RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); if (baser) { speed_fec_capa[num].capa |= RTE_ETH_FEC_MODE_CAPA_MASK(BASER); @@ -2384,8 +2394,7 @@ if (speed_fec_capa != NULL) { speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_25G; speed_fec_capa[num].capa = - RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | - RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); if (baser) { speed_fec_capa[num].capa |= RTE_ETH_FEC_MODE_CAPA_MASK(BASER); @@ -2401,8 +2410,7 @@ if (speed_fec_capa != NULL) { speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_40G; speed_fec_capa[num].capa = - RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | - RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); if (baser) { speed_fec_capa[num].capa |= RTE_ETH_FEC_MODE_CAPA_MASK(BASER); @@ -2414,8 +2422,7 @@ if (speed_fec_capa != NULL) { speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_50G; speed_fec_capa[num].capa = - RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | - RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); if (baser) { speed_fec_capa[num].capa |= RTE_ETH_FEC_MODE_CAPA_MASK(BASER); @@ -2431,8 +2438,7 @@ if (speed_fec_capa != NULL) { speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_100G; speed_fec_capa[num].capa = - RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | - RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); if (rs) { speed_fec_capa[num].capa |= RTE_ETH_FEC_MODE_CAPA_MASK(RS); @@ -2559,60 +2565,74 @@ return -rc; } +/* + * When adding checks for new speeds and/or capabilities, keep that consistent + * with capabilities that 'sfc_fec_get_capa_speed_to_fec' reports to the user. + */ static int sfc_fec_capa_check(struct rte_eth_dev *dev, uint32_t fec_capa, uint32_t supported_caps) { - struct rte_eth_fec_capa *speed_fec_capa; - struct rte_eth_link current_link; - bool is_supported = false; - unsigned int num_entries; - bool auto_fec = false; - unsigned int i; - struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev); - - if (sa->state != SFC_ETHDEV_STARTED) - return 0; + unsigned int ncaps = rte_popcount32(fec_capa); + /* Set by 'sfc_phy_cap_from_link_speeds'. */ + uint32_t speeds_cur = sa->port.phy_adv_cap; + uint32_t speeds_baser = 0; + uint32_t speeds_rs = 0; if (fec_capa & RTE_ETH_FEC_MODE_TO_CAPA(RTE_ETH_FEC_AUTO)) { - auto_fec = true; - fec_capa &= ~RTE_ETH_FEC_MODE_TO_CAPA(RTE_ETH_FEC_AUTO); - } - - /* - * If only the AUTO bit is set, the decision on which FEC - * mode to use will be made by HW/FW or driver. - */ - if (auto_fec && fec_capa == 0) - return 0; - - sfc_dev_get_rte_link(dev, 1, ¤t_link); - - num_entries = sfc_fec_get_capa_speed_to_fec(supported_caps, NULL); - if (num_entries == 0) - return ENOTSUP; - - speed_fec_capa = rte_calloc("fec_capa", num_entries, - sizeof(*speed_fec_capa), 0); - num_entries = sfc_fec_get_capa_speed_to_fec(supported_caps, - speed_fec_capa); - - for (i = 0; i < num_entries; i++) { - if (speed_fec_capa[i].speed == current_link.link_speed) { - if ((fec_capa & speed_fec_capa[i].capa) != 0) - is_supported = true; - - break; + if (ncaps == 1) { + /* Let the FW choose a best-effort setting. */ + return 0; + } else { + /* + * Each requested FEC capability must be supported in + * general and at least one speed that supports this + * FEC mode must be currently advertised/configured. + */ } + } else if (ncaps != 1) { + /* + * Fixed FEC mode does not allow for multiple capabilities. + * Empty mask is invalid, as No-FEC has a capability bit. + */ + return EINVAL; + } else if (fec_capa & RTE_ETH_FEC_MODE_TO_CAPA(RTE_ETH_FEC_NOFEC)) { + /* No-FEC is assumed to be always acceptable. */ + return 0; } - rte_free(speed_fec_capa); - - if (is_supported) - return 0; + /* 25G BASE-R is accounted for separately below. */ + speeds_baser |= (1U << EFX_PHY_CAP_50000FDX); + speeds_baser |= (1U << EFX_PHY_CAP_40000FDX); + speeds_baser |= (1U << EFX_PHY_CAP_10000FDX); + + speeds_rs |= (1U << EFX_PHY_CAP_100000FDX); + speeds_rs |= (1U << EFX_PHY_CAP_50000FDX); + speeds_rs |= (1U << EFX_PHY_CAP_25000FDX); + + if (fec_capa & RTE_ETH_FEC_MODE_TO_CAPA(RTE_ETH_FEC_BASER)) { + bool supported = false; + + if ((supported_caps & EFX_PHY_CAP_FEC_BIT(25G_BASER_FEC)) && + (speeds_cur & (1U << EFX_PHY_CAP_25000FDX))) + supported = true; + + if ((supported_caps & EFX_PHY_CAP_FEC_BIT(BASER_FEC)) && + (speeds_cur & speeds_baser)) + supported = true; + + if (!supported) + return ENOTSUP; + } + + if (fec_capa & RTE_ETH_FEC_MODE_TO_CAPA(RTE_ETH_FEC_RS)) { + if ((supported_caps & EFX_PHY_CAP_FEC_BIT(RS_FEC)) == 0 || + (speeds_cur & speeds_rs) == 0) + return ENOTSUP; + } - return ENOTSUP; + return 0; } static int diff -Nru dpdk-24.11.4/drivers/net/sfc/sfc_ev.c dpdk-24.11.8/drivers/net/sfc/sfc_ev.c --- dpdk-24.11.4/drivers/net/sfc/sfc_ev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/sfc/sfc_ev.c 2026-10-14 13:10:05.000000000 +0000 @@ -469,7 +469,12 @@ struct sfc_adapter *sa = evq->sa; struct rte_eth_link new_link; - sfc_port_link_mode_to_info(link_mode, &new_link); + /* + * Reading 'sa->port.phy_adv_cap' without acquiring adaptor lock may + * render autonegotiation status inaccurate, but that's not critical, + * as it's unlikely to happen often and may be a practical trade-off. + */ + sfc_port_link_mode_to_info(link_mode, sa->port.phy_adv_cap, &new_link); if (rte_eth_linkstatus_set(sa->eth_dev, &new_link) == 0) evq->sa->port.lsc_seq++; diff -Nru dpdk-24.11.4/drivers/net/sfc/sfc_port.c dpdk-24.11.8/drivers/net/sfc/sfc_port.c --- dpdk-24.11.4/drivers/net/sfc/sfc_port.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/sfc/sfc_port.c 2026-10-14 13:10:05.000000000 +0000 @@ -130,7 +130,8 @@ if (rc != 0) return rc; - sfc_port_link_mode_to_info(link_mode, ¤t_link); + sfc_port_link_mode_to_info(link_mode, sa->port.phy_adv_cap, + ¤t_link); EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t)); rte_atomic64_set((rte_atomic64_t *)dev_link, @@ -593,7 +594,7 @@ } void -sfc_port_link_mode_to_info(efx_link_mode_t link_mode, +sfc_port_link_mode_to_info(efx_link_mode_t link_mode, uint32_t phy_cap_req, struct rte_eth_link *link_info) { SFC_ASSERT(link_mode < EFX_LINK_NMODES); @@ -659,7 +660,8 @@ break; } - link_info->link_autoneg = RTE_ETH_LINK_AUTONEG; + if ((phy_cap_req & (1U << EFX_PHY_CAP_AN)) != 0) + link_info->link_autoneg = RTE_ETH_LINK_AUTONEG; } int diff -Nru dpdk-24.11.4/drivers/net/sfc/sfc_repr.c dpdk-24.11.8/drivers/net/sfc/sfc_repr.c --- dpdk-24.11.4/drivers/net/sfc/sfc_repr.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/sfc/sfc_repr.c 2026-10-14 13:10:05.000000000 +0000 @@ -532,7 +532,7 @@ struct rte_eth_link link; if (sr->state != SFC_ETHDEV_STARTED) { - sfc_port_link_mode_to_info(EFX_LINK_UNKNOWN, &link); + sfc_port_link_mode_to_info(EFX_LINK_UNKNOWN, 0, &link); } else { memset(&link, 0, sizeof(link)); link.link_status = RTE_ETH_LINK_UP; diff -Nru dpdk-24.11.4/drivers/net/tap/rte_eth_tap.c dpdk-24.11.8/drivers/net/tap/rte_eth_tap.c --- dpdk-24.11.4/drivers/net/tap/rte_eth_tap.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/tap/rte_eth_tap.c 2026-10-14 13:10:05.000000000 +0000 @@ -214,7 +214,7 @@ * and need to find the resulting device. */ TAP_LOG(DEBUG, "Device name is '%s'", ifr.ifr_name); - strlcpy(pmd->name, ifr.ifr_name, RTE_ETH_NAME_MAX_LEN); + strlcpy(pmd->name, ifr.ifr_name, IFNAMSIZ); if (is_keepalive) { /* @@ -845,7 +845,7 @@ return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE); } -static int +static void tap_mp_req_on_rxtx(struct rte_eth_dev *dev) { struct rte_mp_msg msg; @@ -867,13 +867,10 @@ msg.num_fds = dev->data->nb_rx_queues; err = rte_mp_sendmsg(&msg); - if (err < 0) { + if (err < 0 && rte_errno != ENOTSUP) { TAP_LOG(ERR, "Failed to send start req to secondary %d", rte_errno); - return -1; } - - return 0; } static int @@ -1907,7 +1904,7 @@ static int eth_dev_tap_create(struct rte_vdev_device *vdev, const char *tap_name, - char *remote_iface, struct rte_ether_addr *mac_addr, + const char *remote_iface, struct rte_ether_addr *mac_addr, enum rte_tuntap_type type, int persist) { int numa_node = rte_socket_id(); @@ -1931,7 +1928,7 @@ process_private = malloc(sizeof(struct pmd_process_private)); if (process_private == NULL) { TAP_LOG(ERR, "Failed to alloc memory for process private"); - return -1; + goto error_exit_nodev_release; } memset(process_private, 0, sizeof(struct pmd_process_private)); @@ -2063,7 +2060,7 @@ pmd->name, remote_iface); goto error_remote; } - strlcpy(pmd->remote_iface, remote_iface, RTE_ETH_NAME_MAX_LEN); + strlcpy(pmd->remote_iface, remote_iface, IFNAMSIZ); /* Save state of remote device */ tap_ioctl(pmd, SIOCGIFFLAGS, &pmd->remote_initial_flags, 0, REMOTE_ONLY); @@ -2137,9 +2134,12 @@ close(pmd->ka_fd); if (pmd->ioctl_sock != -1) close(pmd->ioctl_sock); + rte_intr_instance_free(pmd->intr_handle); + free(dev->process_private); + +error_exit_nodev_release: /* mac_addrs must not be freed alone because part of dev_private */ dev->data->mac_addrs = NULL; - rte_intr_instance_free(pmd->intr_handle); rte_eth_dev_release_port(dev); error_exit_nodev: @@ -2180,10 +2180,10 @@ value); return -1; } - strlcpy(name, value, RTE_ETH_NAME_MAX_LEN); + strlcpy(name, value, IFNAMSIZ); } else { /* use tap%d which causes kernel to choose next available */ - strlcpy(name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN); + strlcpy(name, DEFAULT_TAP_NAME "%d", IFNAMSIZ); } return 0; } @@ -2201,7 +2201,7 @@ value); return -1; } - strlcpy(name, value, RTE_ETH_NAME_MAX_LEN); + strlcpy(name, value, IFNAMSIZ); } return 0; @@ -2252,13 +2252,13 @@ const char *name, *params; int ret; struct rte_kvargs *kvlist = NULL; - char tun_name[RTE_ETH_NAME_MAX_LEN]; - char remote_iface[RTE_ETH_NAME_MAX_LEN]; + char tun_name[IFNAMSIZ]; + char remote_iface[IFNAMSIZ]; struct rte_eth_dev *eth_dev; name = rte_vdev_device_name(dev); params = rte_vdev_device_args(dev); - memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN); + memset(remote_iface, 0, IFNAMSIZ); if (rte_eal_process_type() == RTE_PROC_SECONDARY && strlen(params) == 0) { @@ -2274,7 +2274,7 @@ } /* use tun%d which causes kernel to choose next available */ - strlcpy(tun_name, DEFAULT_TUN_NAME "%d", RTE_ETH_NAME_MAX_LEN); + strlcpy(tun_name, DEFAULT_TUN_NAME "%d", IFNAMSIZ); if (params && (params[0] != '\0')) { TAP_LOG(DEBUG, "parameters (%s)", params); @@ -2341,6 +2341,7 @@ /* Attach the queues from received file descriptors */ if (reply_param->q_count != reply->num_fds) { TAP_LOG(ERR, "Unexpected number of fds received"); + free(reply); return -1; } @@ -2415,8 +2416,8 @@ int ret; struct rte_kvargs *kvlist = NULL; int speed; - char tap_name[RTE_ETH_NAME_MAX_LEN]; - char remote_iface[RTE_ETH_NAME_MAX_LEN]; + char tap_name[IFNAMSIZ]; + char remote_iface[IFNAMSIZ]; struct rte_ether_addr user_mac = { .addr_bytes = {0} }; struct rte_eth_dev *eth_dev; int tap_devices_count_increased = 0; @@ -2437,38 +2438,45 @@ eth_dev->tx_pkt_burst = pmd_tx_burst; if (!rte_eal_primary_proc_alive(NULL)) { TAP_LOG(ERR, "Primary process is missing"); - return -1; + goto secondary_fail; } eth_dev->process_private = malloc(sizeof(struct pmd_process_private)); if (eth_dev->process_private == NULL) { TAP_LOG(ERR, "Failed to alloc memory for process private"); - return -1; + goto secondary_fail; } memset(eth_dev->process_private, 0, sizeof(struct pmd_process_private)); ret = tap_mp_attach_queues(name, eth_dev); if (ret != 0) - return -1; + goto secondary_fail_pp; if (!tap_devices_count) { ret = rte_mp_action_register(TAP_MP_REQ_START_RXTX, tap_mp_req_start_rxtx); if (ret < 0 && rte_errno != ENOTSUP) { TAP_LOG(ERR, "tap: Failed to register IPC callback: %s", strerror(rte_errno)); - return -1; + goto secondary_fail_pp; } } tap_devices_count++; rte_eth_dev_probing_finish(eth_dev); return 0; + +secondary_fail_pp: + free(eth_dev->process_private); + eth_dev->process_private = NULL; +secondary_fail: + rte_eth_dev_release_port(eth_dev); + return -1; } speed = RTE_ETH_SPEED_NUM_10G; /* use tap%d which causes kernel to choose next available */ - strlcpy(tap_name, DEFAULT_TAP_NAME "%d", RTE_ETH_NAME_MAX_LEN); - memset(remote_iface, 0, RTE_ETH_NAME_MAX_LEN); + strlcpy(tap_name, DEFAULT_TAP_NAME "%d", IFNAMSIZ); + memset(remote_iface, 0, IFNAMSIZ); if (params && (params[0] != '\0')) { TAP_LOG(DEBUG, "parameters (%s)", params); diff -Nru dpdk-24.11.4/drivers/net/tap/rte_eth_tap.h dpdk-24.11.8/drivers/net/tap/rte_eth_tap.h --- dpdk-24.11.4/drivers/net/tap/rte_eth_tap.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/tap/rte_eth_tap.h 2026-10-14 13:10:05.000000000 +0000 @@ -68,8 +68,8 @@ struct pmd_internals { struct rte_eth_dev *dev; /* Ethernet device. */ - char remote_iface[RTE_ETH_NAME_MAX_LEN]; /* Remote netdevice name */ - char name[RTE_ETH_NAME_MAX_LEN]; /* Internal Tap device name */ + char remote_iface[IFNAMSIZ]; /* Remote netdevice name */ + char name[IFNAMSIZ]; /* Internal Tap device name */ int type; /* Type field - TUN|TAP */ int persist; /* 1 if keep link up, else 0 */ struct rte_ether_addr eth_addr; /* Mac address of the device port */ diff -Nru dpdk-24.11.4/drivers/net/tap/tap_flow.c dpdk-24.11.8/drivers/net/tap/tap_flow.c --- dpdk-24.11.4/drivers/net/tap/tap_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/tap/tap_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -1293,7 +1293,7 @@ rte_flow_error_set( error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "cannot allocate memory for rte_flow"); - goto fail; + goto fail_remove; } msg = &remote_flow->msg; /* set the rule if_index for the remote netdevice */ @@ -1307,14 +1307,14 @@ rte_flow_error_set( error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "rte flow rule validation failed"); - goto fail; + goto fail_remove; } err = tap_nl_send(pmd->nlsk_fd, &msg->nh); if (err < 0) { rte_flow_error_set( error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "Failure sending nl request"); - goto fail; + goto fail_remove; } err = tap_nl_recv_ack(pmd->nlsk_fd); if (err < 0) { @@ -1325,15 +1325,22 @@ error, ENOMEM, RTE_FLOW_ERROR_TYPE_HANDLE, NULL, "overlapping rules or Kernel too old for flower support"); - goto fail; + goto fail_remove; } flow->remote_flow = remote_flow; } return flow; + +fail_remove: + /* Delete the local TC rule that was already installed */ + flow->msg.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + flow->msg.nh.nlmsg_type = RTM_DELTFILTER; + if (tap_nl_send(pmd->nlsk_fd, &flow->msg.nh) >= 0) + tap_nl_recv_ack(pmd->nlsk_fd); + LIST_REMOVE(flow, next); fail: rte_free(remote_flow); - if (flow) - tap_flow_free(pmd, flow); + tap_flow_free(pmd, flow); return NULL; } @@ -1618,8 +1625,10 @@ err = tap_nl_recv_ack(pmd->nlsk_fd); if (err < 0) { /* Silently ignore re-entering existing rule */ - if (errno == EEXIST) + if (errno == EEXIST) { + rte_free(remote_flow); goto success; + } TAP_LOG(ERR, "Kernel refused TC filter rule creation (%d): %s", errno, strerror(errno)); diff -Nru dpdk-24.11.4/drivers/net/txgbe/base/txgbe_dcb_hw.c dpdk-24.11.8/drivers/net/txgbe/base/txgbe_dcb_hw.c --- dpdk-24.11.4/drivers/net/txgbe/base/txgbe_dcb_hw.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/txgbe/base/txgbe_dcb_hw.c 2026-10-14 13:10:05.000000000 +0000 @@ -154,7 +154,7 @@ for (i = 0; i < TXGBE_DCB_UP_MAX; i++) reg |= TXGBE_DCBUP2TC_MAP(i, map[i]); - wr32(hw, TXGBE_PBRXUP2TC, reg); + wr32(hw, TXGBE_PBTXUP2TC, reg); /* Configure traffic class credits and priority */ for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { diff -Nru dpdk-24.11.4/drivers/net/txgbe/base/txgbe_hw.c dpdk-24.11.8/drivers/net/txgbe/base/txgbe_hw.c --- dpdk-24.11.4/drivers/net/txgbe/base/txgbe_hw.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/txgbe/base/txgbe_hw.c 2026-10-14 13:10:05.000000000 +0000 @@ -1018,8 +1018,7 @@ for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { if ((hw->fc.current_mode & txgbe_fc_tx_pause) && hw->fc.high_water[i]) { - fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]) | - TXGBE_FCWTRLO_XON; + fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]); fcrth = TXGBE_FCWTRHI_TH(hw->fc.high_water[i]) | TXGBE_FCWTRHI_XOFF; } else { diff -Nru dpdk-24.11.4/drivers/net/txgbe/base/txgbe_regs.h dpdk-24.11.8/drivers/net/txgbe/base/txgbe_regs.h --- dpdk-24.11.4/drivers/net/txgbe/base/txgbe_regs.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/txgbe/base/txgbe_regs.h 2026-10-14 13:10:05.000000000 +0000 @@ -476,10 +476,8 @@ #define TXGBE_PBRXCTL 0x019000 #define TXGBE_PBRXCTL_ST MS(0, 0x1) #define TXGBE_PBRXCTL_ENA MS(31, 0x1) -#define TXGBE_PBRXUP2TC 0x019008 #define TXGBE_PBTXUP2TC 0x01C800 -#define TXGBE_DCBUP2TC_MAP(tc, v) LS(v, 3 * (tc), 0x7) -#define TXGBE_DCBUP2TC_DEC(tc, r) RS(r, 3 * (tc), 0x7) +#define TXGBE_DCBUP2TC_MAP(tc, v) LS(v, 4 * (tc), 0x7) #define TXGBE_PBRXSIZE(tc) (0x019020 + (tc) * 4) #define TXGBE_PBRXSIZE_KB(v) LS(v, 10, 0x3FF) @@ -1614,7 +1612,7 @@ #define TXGBE_ARBRXCTL_DIA MS(6, 0x1) #define TXGBE_RPUP2TC 0x019008 -#define TXGBE_RPUP2TC_UP_SHIFT 3 +#define TXGBE_RPUP2TC_UP_SHIFT 4 #define TXGBE_RPUP2TC_UP_MASK 0x7 /* mac switcher */ diff -Nru dpdk-24.11.4/drivers/net/txgbe/txgbe_ethdev.c dpdk-24.11.8/drivers/net/txgbe/txgbe_ethdev.c --- dpdk-24.11.4/drivers/net/txgbe/txgbe_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/txgbe/txgbe_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -258,11 +258,6 @@ HW_XSTAT(tx_size_1024_to_max_packets), /* Flow Control */ - HW_XSTAT(tx_xon_packets), - HW_XSTAT(rx_xon_packets), - HW_XSTAT(tx_xoff_packets), - HW_XSTAT(rx_xoff_packets), - HW_XSTAT_NAME(tx_xon_packets, "tx_flow_control_xon_packets"), HW_XSTAT_NAME(rx_xon_packets, "rx_flow_control_xon_packets"), HW_XSTAT_NAME(tx_xoff_packets, "tx_flow_control_xoff_packets"), diff -Nru dpdk-24.11.4/drivers/net/txgbe/txgbe_rxtx.c dpdk-24.11.8/drivers/net/txgbe/txgbe_rxtx.c --- dpdk-24.11.4/drivers/net/txgbe/txgbe_rxtx.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/net/txgbe/txgbe_rxtx.c 2026-10-14 13:10:05.000000000 +0000 @@ -58,6 +58,7 @@ RTE_MBUF_F_TX_VLAN | RTE_MBUF_F_TX_L4_MASK | RTE_MBUF_F_TX_TCP_SEG | + RTE_MBUF_F_TX_UDP_SEG | RTE_MBUF_F_TX_TUNNEL_MASK | RTE_MBUF_F_TX_OUTER_IP_CKSUM | RTE_MBUF_F_TX_OUTER_UDP_CKSUM | @@ -365,7 +366,7 @@ type_tucmd_mlhl |= TXGBE_TXD_PTID(tx_offload.ptid); /* check if TCP segmentation required for this packet */ - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { tx_offload_mask.l2_len |= ~0; tx_offload_mask.l3_len |= ~0; tx_offload_mask.l4_len |= ~0; @@ -515,7 +516,7 @@ tmp |= TXGBE_TXD_CC; tmp |= TXGBE_TXD_EIPCS; } - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { tmp |= TXGBE_TXD_CC; /* implies IPv4 cksum */ if (ol_flags & RTE_MBUF_F_TX_IPV4) @@ -535,7 +536,7 @@ if (ol_flags & RTE_MBUF_F_TX_VLAN) cmdtype |= TXGBE_TXD_VLE; - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) cmdtype |= TXGBE_TXD_TSE; if (ol_flags & RTE_MBUF_F_TX_MACSEC) cmdtype |= TXGBE_TXD_LINKSEC; @@ -585,6 +586,8 @@ if (oflags & RTE_MBUF_F_TX_TCP_SEG) ptype |= (tun ? RTE_PTYPE_INNER_L4_TCP : RTE_PTYPE_L4_TCP); + else if (oflags & RTE_MBUF_F_TX_UDP_SEG) + ptype |= (tun ? RTE_PTYPE_INNER_L4_UDP : RTE_PTYPE_L4_UDP); /* Tunnel */ switch (oflags & RTE_MBUF_F_TX_TUNNEL_MASK) { @@ -1058,7 +1061,7 @@ olinfo_status = 0; if (tx_ol_req) { - if (ol_flags & RTE_MBUF_F_TX_TCP_SEG) { + if (ol_flags & (RTE_MBUF_F_TX_TCP_SEG | RTE_MBUF_F_TX_UDP_SEG)) { /* when TSO is on, paylen in descriptor is the * not the packet len but the tcp payload len */ @@ -2373,7 +2376,7 @@ RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_TSO | - RTE_ETH_TX_OFFLOAD_UDP_TSO | + RTE_ETH_TX_OFFLOAD_UDP_TSO | RTE_ETH_TX_OFFLOAD_UDP_TNL_TSO | RTE_ETH_TX_OFFLOAD_IP_TNL_TSO | RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO | @@ -3305,11 +3308,8 @@ queue_mapping = 0; for (i = 0; i < RTE_ETH_DCB_NUM_USER_PRIORITIES; i++) - /* - * mapping is done with 3 bits per priority, - * so shift by i*3 each time - */ - queue_mapping |= ((cfg->dcb_tc[i] & 0x07) << (i * 3)); + queue_mapping |= ((cfg->dcb_tc[i] & TXGBE_RPUP2TC_UP_MASK) << + (i * TXGBE_RPUP2TC_UP_SHIFT)); wr32(hw, TXGBE_RPUP2TC, queue_mapping); @@ -4272,6 +4272,8 @@ txgbe_set_rsc(struct rte_eth_dev *dev) { struct rte_eth_rxmode *rx_conf = &dev->data->dev_conf.rxmode; + struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); + struct rte_intr_handle *intr_handle = pci_dev->intr_handle; struct txgbe_hw *hw = TXGBE_DEV_HW(dev); struct rte_eth_dev_info dev_info = { 0 }; bool rsc_capable = false; @@ -4322,8 +4324,6 @@ rd32(hw, TXGBE_RXCFG(rxq->reg_idx)); uint32_t psrtype = rd32(hw, TXGBE_POOLRSS(rxq->reg_idx)); - uint32_t eitr = - rd32(hw, TXGBE_ITR(rxq->reg_idx)); /* * txgbe PMD doesn't support header-split at the moment. @@ -4342,6 +4342,9 @@ srrctl |= txgbe_get_rscctl_maxdesc(rxq->mb_pool); psrtype |= TXGBE_POOLRSS_L4HDR; + wr32(hw, TXGBE_RXCFG(rxq->reg_idx), srrctl); + wr32(hw, TXGBE_POOLRSS(rxq->reg_idx), psrtype); + /* * RSC: Set ITR interval corresponding to 2K ints/s. * @@ -4355,19 +4358,20 @@ * For a sparse streaming case this setting will yield * at most 500us latency for a single RSC aggregation. */ - eitr &= ~TXGBE_ITR_IVAL_MASK; - eitr |= TXGBE_ITR_IVAL_10G(TXGBE_QUEUE_ITR_INTERVAL_DEFAULT); - eitr |= TXGBE_ITR_WRDSA; + if (rte_intr_dp_is_en(intr_handle)) { + uint32_t eitr = rd32(hw, TXGBE_ITR(rxq->reg_idx)); - wr32(hw, TXGBE_RXCFG(rxq->reg_idx), srrctl); - wr32(hw, TXGBE_POOLRSS(rxq->reg_idx), psrtype); - wr32(hw, TXGBE_ITR(rxq->reg_idx), eitr); + eitr &= ~TXGBE_ITR_IVAL_MASK; + eitr |= TXGBE_ITR_IVAL_10G(TXGBE_QUEUE_ITR_INTERVAL_DEFAULT); + eitr |= TXGBE_ITR_WRDSA; + wr32(hw, TXGBE_ITR(rxq->reg_idx), eitr); - /* - * RSC requires the mapping of the queue to the - * interrupt vector. - */ - txgbe_set_ivar_map(hw, 0, rxq->reg_idx, i); + /* + * RSC requires the mapping of the queue to the + * interrupt vector. + */ + txgbe_set_ivar_map(hw, 0, rxq->reg_idx, i); + } } dev->data->lro = 1; @@ -4667,12 +4671,13 @@ /* Setup the HW Tx Head and TX Tail descriptor pointers */ wr32(hw, TXGBE_TXRP(txq->reg_idx), 0); wr32(hw, TXGBE_TXWP(txq->reg_idx), 0); - } -#ifndef RTE_LIB_SECURITY - for (i = 0; i < 4; i++) - wr32(hw, TXGBE_TDM_DESC_CHK(i), 0xFFFFFFFF); +#ifdef RTE_LIB_SECURITY + if (!txq->using_ipsec) #endif + wr32m(hw, TXGBE_TDM_DESC_CHK(txq->reg_idx / 32), + RTE_BIT32(txq->reg_idx % 32), RTE_BIT32(txq->reg_idx % 32)); + } /* Device configured with multiple TX queues. */ txgbe_dev_mq_tx_configure(dev); diff -Nru dpdk-24.11.4/drivers/vdpa/nfp/nfp_vdpa.c dpdk-24.11.8/drivers/vdpa/nfp/nfp_vdpa.c --- dpdk-24.11.4/drivers/vdpa/nfp/nfp_vdpa.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/drivers/vdpa/nfp/nfp_vdpa.c 2026-10-14 13:10:05.000000000 +0000 @@ -117,8 +117,6 @@ char dev_name[RTE_DEV_NAME_MAX_LEN] = {0}; struct rte_pci_device *pci_dev = device->pci_dev; - rte_pci_unmap_device(pci_dev); - rte_pci_device_name(&pci_dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN); ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name, &device->iommu_group); @@ -1299,7 +1297,7 @@ .drv_class = NFP_CLASS_VDPA, .name = RTE_STR(NFP_VDPA_DRIVER_NAME), .id_table = pci_id_nfp_vdpa_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .drv_flags = RTE_PCI_DRV_INTR_LSC, .probe = nfp_vdpa_pci_probe, .remove = nfp_vdpa_pci_remove, }; diff -Nru dpdk-24.11.4/dts/framework/testbed_model/capability.py dpdk-24.11.8/dts/framework/testbed_model/capability.py --- dpdk-24.11.4/dts/framework/testbed_model/capability.py 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/dts/framework/testbed_model/capability.py 2026-10-14 13:10:05.000000000 +0000 @@ -402,7 +402,9 @@ Returns: :data:`True` if the instance's topology type is more complex than the compared object's. """ - return other < self + if not self.is_comparable_with(other): + return False + return self.topology_type > other.topology_type def __le__(self, other) -> bool: """Compare the :attr:`~TopologyCapability.topology_type`s. @@ -414,7 +416,9 @@ :data:`True` if the instance's topology type is less complex or equal than the compared object's. """ - return not self > other + if not self.is_comparable_with(other): + return False + return self.topology_type <= other.topology_type def __hash__(self): """Each instance is identified by :attr:`topology_type`.""" diff -Nru dpdk-24.11.4/examples/ethtool/ethtool-app/main.c dpdk-24.11.8/examples/ethtool/ethtool-app/main.c --- dpdk-24.11.4/examples/ethtool/ethtool-app/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ethtool/ethtool-app/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -92,7 +92,7 @@ int size_pktpool; struct rte_eth_conf cfg_port; struct rte_eth_dev_info dev_info; - char str_name[16]; + char str_name[RTE_MEMPOOL_NAMESIZE]; uint16_t nb_rxd = PORT_RX_QUEUE_SIZE; uint16_t nb_txd = PORT_TX_QUEUE_SIZE; int ret; @@ -112,7 +112,7 @@ size_pktpool = dev_info.rx_desc_lim.nb_max + dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE; - snprintf(str_name, 16, "pkt_pool%i", idx_port); + snprintf(str_name, sizeof(str_name), "pkt_pool%i", idx_port); ptr_port->pkt_pool = rte_pktmbuf_pool_create( str_name, size_pktpool, PKTPOOL_CACHE, @@ -288,9 +288,7 @@ if (cnt_ports == 0) rte_exit(EXIT_FAILURE, "No available NIC ports!\n"); if (cnt_ports > MAX_PORTS) { - printf("Info: Using only %i of %i ports\n", - cnt_ports, MAX_PORTS - ); + printf("Info: Using only %i of %i ports\n", MAX_PORTS, cnt_ports); cnt_ports = MAX_PORTS; } diff -Nru dpdk-24.11.4/examples/fips_validation/main.c dpdk-24.11.8/examples/fips_validation/main.c --- dpdk-24.11.4/examples/fips_validation/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/fips_validation/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -882,8 +882,8 @@ uint8_t id_sha1[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; - uint8_t *id = NULL; - int id_len = 0; + const uint8_t *id; + size_t id_len; switch (hash) { case RTE_CRYPTO_AUTH_SHA1: @@ -907,12 +907,10 @@ id_len = sizeof(id_sha512); break; default: - id_len = -1; - break; + return -1; } - if (id != NULL) - rte_memcpy(buf, id, id_len); + memcpy(buf, id, id_len); return id_len; } @@ -1614,8 +1612,8 @@ if (b_len) { msg.len = env.digest_len + b_len; msg.val = rte_zmalloc(NULL, msg.len, 0); - rte_memcpy(msg.val, b, b_len); - rte_memcpy(msg.val + b_len, env.digest, env.digest_len); + memcpy(msg.val, b, b_len); + memcpy(msg.val + b_len, env.digest, env.digest_len); rte_free(env.digest); env.digest = msg.val; env.digest_len = msg.len; @@ -2612,7 +2610,7 @@ rte_free(md[i].val); rte_free(vec.pt.val); - + vec.pt.val = NULL; rte_free(val.val); return 0; } @@ -2700,6 +2698,7 @@ rte_free(md.val); rte_free(vec.pt.val); + vec.pt.val = NULL; rte_free(val.val); return 0; } diff -Nru dpdk-24.11.4/examples/ip_fragmentation/main.c dpdk-24.11.8/examples/ip_fragmentation/main.c --- dpdk-24.11.4/examples/ip_fragmentation/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ip_fragmentation/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -134,7 +134,6 @@ }; #define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 16 struct __rte_cache_aligned lcore_queue_conf { uint16_t n_rx_queue; uint16_t tx_queue_id[RTE_MAX_ETHPORTS]; @@ -948,8 +947,6 @@ fflush(stdout); n_tx_queue = nb_lcores; - if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) - n_tx_queue = MAX_TX_QUEUE_PER_PORT; ret = rte_eth_dev_configure(portid, 1, (uint16_t)n_tx_queue, &local_port_conf); if (ret < 0) { diff -Nru dpdk-24.11.4/examples/ip_pipeline/conn.c dpdk-24.11.8/examples/ip_pipeline/conn.c --- dpdk-24.11.4/examples/ip_pipeline/conn.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ip_pipeline/conn.c 2026-10-14 13:10:05.000000000 +0000 @@ -15,6 +15,8 @@ #include #include +#include + #include "conn.h" #define MSG_CMD_TOO_LONG "Command too long." @@ -115,8 +117,8 @@ } /* Fill in */ - strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); - strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); + strlcpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX + 1); + strlcpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX + 1); conn->buf_size = p->buf_size; conn->msg_in_len_max = p->msg_in_len_max; conn->msg_out_len_max = p->msg_out_len_max; diff -Nru dpdk-24.11.4/examples/ip_reassembly/main.c dpdk-24.11.8/examples/ip_reassembly/main.c --- dpdk-24.11.4/examples/ip_reassembly/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ip_reassembly/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -145,7 +145,6 @@ }; #define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 16 #define MAX_RX_QUEUE_PER_PORT 128 struct __rte_cache_aligned lcore_queue_conf { @@ -1091,8 +1090,6 @@ fflush(stdout); n_tx_queue = nb_lcores; - if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) - n_tx_queue = MAX_TX_QUEUE_PER_PORT; if (dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE) local_port_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; diff -Nru dpdk-24.11.4/examples/ipsec-secgw/ipsec_worker.c dpdk-24.11.8/examples/ipsec-secgw/ipsec_worker.c --- dpdk-24.11.4/examples/ipsec-secgw/ipsec_worker.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/ipsec_worker.c 2026-10-14 13:10:05.000000000 +0000 @@ -428,7 +428,7 @@ if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) { if (unlikely(pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) { - RTE_LOG(ERR, IPSEC, + RTE_LOG(DEBUG, IPSEC, "Inbound security offload failed\n"); goto drop_pkt_and_exit; } @@ -446,7 +446,7 @@ if (pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) { if (unlikely(pkt->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED)) { - RTE_LOG(ERR, IPSEC, + RTE_LOG(DEBUG, IPSEC, "Inbound security offload failed\n"); goto drop_pkt_and_exit; } diff -Nru dpdk-24.11.4/examples/ipsec-secgw/ipsec_worker.h dpdk-24.11.8/examples/ipsec-secgw/ipsec_worker.h --- dpdk-24.11.4/examples/ipsec-secgw/ipsec_worker.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/ipsec_worker.h 2026-10-14 13:10:05.000000000 +0000 @@ -421,7 +421,9 @@ } /* Only check SPI match for processed IPSec packets */ - if (i < lim && ((m->ol_flags & RTE_MBUF_F_RX_SEC_OFFLOAD) == 0)) { + if (i < lim && ((m->ol_flags & (RTE_MBUF_F_RX_SEC_OFFLOAD | + RTE_MBUF_F_RX_SEC_OFFLOAD_FAILED))) != + RTE_MBUF_F_RX_SEC_OFFLOAD) { stats->discard++; free_pkts(&m, 1); continue; diff -Nru dpdk-24.11.4/examples/ipsec-secgw/parser.c dpdk-24.11.8/examples/ipsec-secgw/parser.c --- dpdk-24.11.4/examples/ipsec-secgw/parser.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/parser.c 2026-10-14 13:10:05.000000000 +0000 @@ -48,7 +48,7 @@ parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask) { char ip_str[INET_ADDRSTRLEN] = {0}; - char *pch; + const char *pch; pch = strchr(token, '/'); if (pch != NULL) { @@ -78,7 +78,7 @@ parse_ipv6_addr(const char *token, struct rte_ipv6_addr *ipv6, uint32_t *mask) { char ip_str[256] = {0}; - char *pch; + const char *pch; pch = strchr(token, '/'); if (pch != NULL) { diff -Nru dpdk-24.11.4/examples/ipsec-secgw/sa.c dpdk-24.11.8/examples/ipsec-secgw/sa.c --- dpdk-24.11.4/examples/ipsec-secgw/sa.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/sa.c 2026-10-14 13:10:05.000000000 +0000 @@ -325,12 +325,12 @@ if (pt_end == NULL) { if (strlen(pt_start) > 2) return 0; - strncpy(sub_str, pt_start, 2); + memcpy(sub_str, pt_start, 2); } else { if (pt_end - pt_start > 2) return 0; - strncpy(sub_str, pt_start, pt_end - pt_start); + memcpy(sub_str, pt_start, pt_end - pt_start); pt_start = pt_end + 1; } @@ -1660,7 +1660,7 @@ sa_spi_present(struct sa_ctx *sa_ctx, uint32_t spi, int inbound) { uint32_t num; - struct ipsec_sa *sa; + const struct ipsec_sa *sa; struct ipsec_sa tmpl; const struct ipsec_sa *sar; diff -Nru dpdk-24.11.4/examples/ipsec-secgw/sp4.c dpdk-24.11.8/examples/ipsec-secgw/sp4.c --- dpdk-24.11.4/examples/ipsec-secgw/sp4.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/sp4.c 2026-10-14 13:10:05.000000000 +0000 @@ -610,7 +610,7 @@ uint32_t mask[2]) { uint32_t num; - struct acl4_rules *rule; + const struct acl4_rules *rule; const struct acl4_rules *acr; struct acl4_rules tmpl; diff -Nru dpdk-24.11.4/examples/ipsec-secgw/sp6.c dpdk-24.11.8/examples/ipsec-secgw/sp6.c --- dpdk-24.11.4/examples/ipsec-secgw/sp6.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipsec-secgw/sp6.c 2026-10-14 13:10:05.000000000 +0000 @@ -754,7 +754,7 @@ uint32_t mask[2]) { uint32_t num; - struct acl6_rules *rule; + const struct acl6_rules *rule; const struct acl6_rules *acr; struct acl6_rules tmpl; diff -Nru dpdk-24.11.4/examples/ipv4_multicast/main.c dpdk-24.11.8/examples/ipv4_multicast/main.c --- dpdk-24.11.4/examples/ipv4_multicast/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ipv4_multicast/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -97,7 +97,6 @@ }; #define MAX_RX_QUEUE_PER_LCORE 16 -#define MAX_TX_QUEUE_PER_PORT 16 struct __rte_cache_aligned lcore_queue_conf { uint64_t tx_tsc; uint16_t n_rx_queue; @@ -736,8 +735,6 @@ fflush(stdout); n_tx_queue = nb_lcores; - if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) - n_tx_queue = MAX_TX_QUEUE_PER_PORT; ret = rte_eth_dev_configure(portid, 1, (uint16_t)n_tx_queue, &local_port_conf); diff -Nru dpdk-24.11.4/examples/l2fwd-crypto/main.c dpdk-24.11.8/examples/l2fwd-crypto/main.c --- dpdk-24.11.4/examples/l2fwd-crypto/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/l2fwd-crypto/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -1576,19 +1576,19 @@ char string_aead_op[MAX_STR_LEN]; if (options->cipher_xform.cipher.op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) - strcpy(string_cipher_op, "Encrypt"); + strlcpy(string_cipher_op, "Encrypt", sizeof(string_cipher_op)); else - strcpy(string_cipher_op, "Decrypt"); + strlcpy(string_cipher_op, "Decrypt", sizeof(string_cipher_op)); if (options->auth_xform.auth.op == RTE_CRYPTO_AUTH_OP_GENERATE) - strcpy(string_auth_op, "Auth generate"); + strlcpy(string_auth_op, "Auth generate", sizeof(string_auth_op)); else - strcpy(string_auth_op, "Auth verify"); + strlcpy(string_auth_op, "Auth verify", sizeof(string_auth_op)); if (options->aead_xform.aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) - strcpy(string_aead_op, "Authenticated encryption"); + strlcpy(string_aead_op, "Authenticated encryption", sizeof(string_aead_op)); else - strcpy(string_aead_op, "Authenticated decryption"); + strlcpy(string_aead_op, "Authenticated decryption", sizeof(string_aead_op)); printf("Options:-\nn"); diff -Nru dpdk-24.11.4/examples/l2fwd-jobstats/main.c dpdk-24.11.8/examples/l2fwd-jobstats/main.c --- dpdk-24.11.4/examples/l2fwd-jobstats/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/l2fwd-jobstats/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -542,7 +542,9 @@ } while (likely(stats_read_pending == 0)); rte_spinlock_unlock(&qconf->lock); - rte_pause(); + while (rte_atomic_load_explicit(&qconf->stats_read_pending, + rte_memory_order_relaxed) != 0) + rte_pause(); } /* >8 End of minimize impact of stats reading. */ } diff -Nru dpdk-24.11.4/examples/l3fwd/main.c dpdk-24.11.8/examples/l3fwd/main.c --- dpdk-24.11.4/examples/l3fwd/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/l3fwd/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -49,7 +49,6 @@ #include "l3fwd_event.h" #include "l3fwd_route.h" -#define MAX_TX_QUEUE_PER_PORT RTE_MAX_LCORE #define MAX_RX_QUEUE_PER_PORT 128 #define MAX_LCORE_PARAMS 1024 @@ -1359,8 +1358,6 @@ nb_rx_queue = get_port_n_rx_queues(portid); n_tx_queue = nb_lcores; - if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) - n_tx_queue = MAX_TX_QUEUE_PER_PORT; printf("Creating queues: nb_rxq=%d nb_txq=%u... ", nb_rx_queue, (unsigned)n_tx_queue ); diff -Nru dpdk-24.11.4/examples/l3fwd-graph/main.c dpdk-24.11.8/examples/l3fwd-graph/main.c --- dpdk-24.11.4/examples/l3fwd-graph/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/l3fwd-graph/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -49,7 +49,6 @@ #define RX_DESC_DEFAULT 1024 #define TX_DESC_DEFAULT 1024 -#define MAX_TX_QUEUE_PER_PORT RTE_MAX_ETHPORTS #define MAX_RX_QUEUE_PER_PORT 128 #define MAX_RX_QUEUE_PER_LCORE 16 @@ -1076,8 +1075,6 @@ nb_rx_queue = get_port_n_rx_queues(portid); n_tx_queue = nb_lcores; - if (n_tx_queue > MAX_TX_QUEUE_PER_PORT) - n_tx_queue = MAX_TX_QUEUE_PER_PORT; printf("Creating queues: nb_rxq=%d nb_txq=%u... ", nb_rx_queue, n_tx_queue); diff -Nru dpdk-24.11.4/examples/l3fwd-power/main.c dpdk-24.11.8/examples/l3fwd-power/main.c --- dpdk-24.11.4/examples/l3fwd-power/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/l3fwd-power/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -2283,6 +2283,7 @@ RTE_LOG(ERR, L3FWD_POWER, "Failed to get cpu resume latency on lcore-%u, ret=%d.\n", lcore_id, ret); + return ret; } resume_latency_bk[lcore_id] = ret; diff -Nru dpdk-24.11.4/examples/packet_ordering/main.c dpdk-24.11.8/examples/packet_ordering/main.c --- dpdk-24.11.4/examples/packet_ordering/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/packet_ordering/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -737,7 +737,7 @@ printf("Initializing port %u... done\n", port_id); if (configure_eth_port(port_id) != 0) - rte_exit(EXIT_FAILURE, "Cannot initialize port %"PRIu8"\n", + rte_exit(EXIT_FAILURE, "Cannot initialize port %"PRIu16"\n", port_id); } diff -Nru dpdk-24.11.4/examples/pipeline/cli.c dpdk-24.11.8/examples/pipeline/cli.c --- dpdk-24.11.4/examples/pipeline/cli.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/pipeline/cli.c 2026-10-14 13:10:05.000000000 +0000 @@ -172,9 +172,9 @@ line[0] = 0; for (i = 0; i < n_tokens; i++) { if (i) - strcat(line, " "); + strlcat(line, " ", MAX_LINE_SIZE); - strcat(line, tokens[i]); + strlcat(line, tokens[i], MAX_LINE_SIZE); } /* Read the table entry from the input buffer. */ diff -Nru dpdk-24.11.4/examples/pipeline/conn.c dpdk-24.11.8/examples/pipeline/conn.c --- dpdk-24.11.4/examples/pipeline/conn.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/pipeline/conn.c 2026-10-14 13:10:05.000000000 +0000 @@ -15,6 +15,8 @@ #include #include +#include + #include "conn.h" #define MSG_CMD_TOO_LONG "Command too long." @@ -116,8 +118,8 @@ } /* Fill in */ - strncpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX); - strncpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX); + strlcpy(conn->welcome, p->welcome, CONN_WELCOME_LEN_MAX + 1); + strlcpy(conn->prompt, p->prompt, CONN_PROMPT_LEN_MAX + 1); conn->buf_size = p->buf_size; conn->msg_in_len_max = p->msg_in_len_max; conn->msg_out_len_max = p->msg_out_len_max; diff -Nru dpdk-24.11.4/examples/ptpclient/ptpclient.c dpdk-24.11.8/examples/ptpclient/ptpclient.c --- dpdk-24.11.4/examples/ptpclient/ptpclient.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/ptpclient/ptpclient.c 2026-10-14 13:10:05.000000000 +0000 @@ -798,7 +798,7 @@ ptp_enabled_port_nb++; } else { rte_exit(EXIT_FAILURE, - "Cannot init port %"PRIu8 "\n", + "Cannot init port %"PRIu16"\n", portid); } } else diff -Nru dpdk-24.11.4/examples/vm_power_manager/channel_manager.c dpdk-24.11.8/examples/vm_power_manager/channel_manager.c --- dpdk-24.11.4/examples/vm_power_manager/channel_manager.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/vm_power_manager/channel_manager.c 2026-10-14 13:10:05.000000000 +0000 @@ -560,6 +560,7 @@ int ret; struct core_info *ci; struct channel_info *chan_infos[RTE_MAX_LCORE]; + size_t channel_path_size; int i; for (i = 0; i < RTE_MAX_LCORE; i++) @@ -597,8 +598,15 @@ goto error; } chan_infos[i] = chan_info; - strlcpy(chan_info->channel_path, socket_path, - sizeof(chan_info->channel_path)); + channel_path_size = sizeof(chan_info->channel_path); + if (strlcpy(chan_info->channel_path, socket_path, + channel_path_size) >= channel_path_size) { + RTE_LOG(ERR, CHANNEL_MANAGER, "Socket path is too long " + "'%s' >= %zu\n", socket_path, channel_path_size); + rte_free(chan_info); + chan_infos[i] = NULL; + goto error; + } if (setup_host_channel_info(&chan_info, i) < 0) { rte_free(chan_info); @@ -867,8 +875,7 @@ rte_free(new_domain); return -1; } - strncpy(new_domain->name, vm_name, sizeof(new_domain->name)); - new_domain->name[sizeof(new_domain->name) - 1] = '\0'; + strlcpy(new_domain->name, vm_name, sizeof(new_domain->name)); memset(new_domain->channel_mask, 0, RTE_MAX_LCORE); new_domain->num_channels = 0; diff -Nru dpdk-24.11.4/examples/vm_power_manager/channel_monitor.c dpdk-24.11.8/examples/vm_power_manager/channel_monitor.c --- dpdk-24.11.4/examples/vm_power_manager/channel_monitor.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/vm_power_manager/channel_monitor.c 2026-10-14 13:10:05.000000000 +0000 @@ -131,16 +131,6 @@ return 0; } -static char* -get_resource_name_from_chn_path(const char *channel_path) -{ - char *substr = NULL; - - substr = strstr(channel_path, CHANNEL_MGR_FIFO_PATTERN_NAME); - - return substr; -} - static int get_resource_id_from_vmname(const char *vm_name) { @@ -1066,8 +1056,8 @@ root = json_loads(json_data, 0, &error); if (root) { - resource_name = get_resource_name_from_chn_path( - chan_info->channel_path); + resource_name = strstr(chan_info->channel_path, + CHANNEL_MGR_FIFO_PATTERN_NAME); /* * Because our data is now in the json * object, we can overwrite the pkt diff -Nru dpdk-24.11.4/examples/vm_power_manager/main.c dpdk-24.11.8/examples/vm_power_manager/main.c --- dpdk-24.11.4/examples/vm_power_manager/main.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/examples/vm_power_manager/main.c 2026-10-14 13:10:05.000000000 +0000 @@ -382,7 +382,7 @@ if (port_init(portid, mbuf_pool) != 0) rte_exit(EXIT_FAILURE, - "Cannot init port %"PRIu8 "\n", + "Cannot init port %"PRIu16"\n", portid); for (w = 0; w < RTE_POWER_MAX_VFS; w++) { diff -Nru dpdk-24.11.4/lib/bbdev/rte_bbdev.c dpdk-24.11.8/lib/bbdev/rte_bbdev.c --- dpdk-24.11.4/lib/bbdev/rte_bbdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/bbdev/rte_bbdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -344,7 +344,7 @@ if (dev->data->queues != NULL) { VALID_FUNC_OR_RET_ERR(dev->dev_ops->queue_release, dev_id); for (i = 0; i < dev->data->num_queues; i++) { - int ret = dev->dev_ops->queue_release(dev, i); + ret = dev->dev_ops->queue_release(dev, i); if (ret < 0) { rte_bbdev_log(ERR, "Device %u queue %u release failed", diff -Nru dpdk-24.11.4/lib/bpf/bpf_jit_arm64.c dpdk-24.11.8/lib/bpf/bpf_jit_arm64.c --- dpdk-24.11.4/lib/bpf/bpf_jit_arm64.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/bpf/bpf_jit_arm64.c 2026-10-14 13:10:05.000000000 +0000 @@ -28,7 +28,7 @@ #define A64_ZR 31 #define check_imm(n, val) (((val) >= 0) ? !!((val) >> (n)) : !!((~val) >> (n))) -#define mask_imm(n, val) ((val) & ((1 << (n)) - 1)) +#define mask_imm(n, val) ((val) & (RTE_BIT32(n) - 1)) struct ebpf_a64_map { uint32_t off; /* eBPF to arm64 insn offset mapping for jump */ @@ -238,12 +238,12 @@ uint32_t insn, imm; imm = mask_imm(12, imm12); - insn = (!!is64) << 31; - insn |= (!!sub) << 30; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(sub, 30); insn |= 0x11000000; insn |= rd; - insn |= rn << 5; - insn |= imm << 10; + insn |= RTE_SHIFT_VAL32(rn, 5); + insn |= RTE_SHIFT_VAL32(imm, 10); emit_insn(ctx, insn, check_reg(rd) || check_reg(rn) || check_imm(12, imm12)); @@ -279,16 +279,16 @@ { uint32_t insn; - insn = (!!load) << 22; - insn |= (!!pre_index) << 24; + insn = RTE_SHIFT_VAL32(load, 22); + insn |= RTE_SHIFT_VAL32(pre_index, 24); insn |= 0xa8800000; insn |= rt; - insn |= rn << 5; - insn |= rt2 << 10; + insn |= RTE_SHIFT_VAL32(rn, 5); + insn |= RTE_SHIFT_VAL32(rt2, 10); if (push) - insn |= 0x7e << 15; /* 0x7e means -2 with imm7 */ + insn |= RTE_SHIFT_VAL32(0x7e, 15); /* 0x7e means -2 with imm7 */ else - insn |= 0x2 << 15; + insn |= RTE_SHIFT_VAL32(0x2, 15); emit_insn(ctx, insn, check_reg(rn) || check_reg(rt) || check_reg(rt2)); @@ -317,11 +317,11 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= type << 29; - insn |= 0x25 << 23; - insn |= (shift/16) << 21; - insn |= imm16 << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(type, 29); + insn |= RTE_SHIFT_VAL32(0x25, 23); + insn |= RTE_SHIFT_VAL32(shift/16, 21); + insn |= RTE_SHIFT_VAL32(imm16, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_mov_hw(is64, shift)); @@ -334,7 +334,7 @@ uint16_t lower = val & 0xffff; /* Positive number */ - if ((val & 1UL << 31) == 0) { + if ((val & RTE_BIT32(31)) == 0) { mov_imm(ctx, is64, rd, A64_MOVZ, lower, 0); if (upper) mov_imm(ctx, is64, rd, A64_MOVK, upper, 16); @@ -393,21 +393,21 @@ { uint32_t insn; - insn = 0x1c1 << 21; + insn = RTE_SHIFT_VAL32(0x1c1, 21); if (load) - insn |= 1 << 22; + insn |= RTE_BIT32(22); if (sz == BPF_B) - insn |= 0 << 30; + insn |= RTE_SHIFT_VAL32(0, 30); else if (sz == BPF_H) - insn |= 1 << 30; + insn |= RTE_SHIFT_VAL32(1, 30); else if (sz == BPF_W) - insn |= 2 << 30; + insn |= RTE_SHIFT_VAL32(2, 30); else if (sz == EBPF_DW) - insn |= 3 << 30; + insn |= RTE_SHIFT_VAL32(3, 30); - insn |= rm << 16; - insn |= 0x1a << 10; /* LSL and S = 0 */ - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(0x1a, 10); /* LSL and S = 0 */ + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rt; emit_insn(ctx, insn, check_reg(rt) || check_reg(rn) || check_reg(rm) || @@ -436,10 +436,10 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= op << 21; /* shift == 0 */ - insn |= rm << 16; - insn |= rn << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(op, 21); /* shift == 0 */ + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rm)); @@ -468,11 +468,11 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= 0xd8 << 21; - insn |= rm << 16; - insn |= A64_ZR << 10; - insn |= rd << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(0xd8, 21); + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(A64_ZR, 10); + insn |= RTE_SHIFT_VAL32(rd, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rm)); @@ -489,11 +489,11 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= 0xd6 << 21; - insn |= rm << 16; - insn |= op << 10; - insn |= rn << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(0xd6, 21); + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(op, 10); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rm)); @@ -532,14 +532,14 @@ { uint32_t insn; - insn = (!!is64) << 31; + insn = RTE_SHIFT_VAL32(is64, 31); if (insn) - insn |= 1 << 22; /* Set N bit when is64 is set */ - insn |= op << 29; - insn |= 0x26 << 23; - insn |= immr << 16; - insn |= imms << 10; - insn |= rn << 5; + insn |= RTE_BIT32(22); /* Set N bit when is64 is set */ + insn |= RTE_SHIFT_VAL32(op, 29); + insn |= RTE_SHIFT_VAL32(0x26, 23); + insn |= RTE_SHIFT_VAL32(immr, 16); + insn |= RTE_SHIFT_VAL32(imms, 10); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rn) || @@ -578,11 +578,11 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= op << 29; - insn |= 0x50 << 21; - insn |= rm << 16; - insn |= rd << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(op, 29); + insn |= RTE_SHIFT_VAL32(0x50, 21); + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(rd, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rm)); @@ -612,12 +612,12 @@ { uint32_t insn; - insn = (!!is64) << 31; - insn |= 0xd8 << 21; - insn |= rm << 16; - insn |= 0x1 << 15; - insn |= ra << 10; - insn |= rn << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(0xd8, 21); + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(0x1, 15); + insn |= RTE_SHIFT_VAL32(ra, 10); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rd; emit_insn(ctx, insn, check_reg(rd) || check_reg(rn) || check_reg(rm) || @@ -638,7 +638,7 @@ uint32_t insn; insn = 0xd63f0000; - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(rn, 5); emit_insn(ctx, insn, check_reg(rn)); } @@ -669,22 +669,22 @@ uint32_t insn; insn = 0xdac00000; - insn |= rd << 5; + insn |= RTE_SHIFT_VAL32(rd, 5); insn |= rd; switch (imm) { case 16: - insn |= 1 << 10; + insn |= RTE_SHIFT_VAL32(1, 10); emit_insn(ctx, insn, check_reg(rd)); emit_zero_extend(ctx, rd, 16); break; case 32: - insn |= 2 << 10; + insn |= RTE_SHIFT_VAL32(2, 10); emit_insn(ctx, insn, check_reg(rd)); /* Upper 32 bits already cleared */ break; case 64: - insn |= 3 << 10; + insn |= RTE_SHIFT_VAL32(3, 10); emit_insn(ctx, insn, check_reg(rd)); break; default: @@ -933,9 +933,9 @@ uint32_t insn, imm; imm = mask_imm(19, imm19); - insn = (!!is64) << 31; - insn |= 0x35 << 24; - insn |= imm << 5; + insn = RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(0x35, 24); + insn |= RTE_SHIFT_VAL32(imm, 5); insn |= rt; emit_insn(ctx, insn, check_reg(rt) || check_imm(19, imm19)); @@ -947,7 +947,7 @@ uint32_t insn, imm; imm = mask_imm(26, imm26); - insn = 0x5 << 26; + insn = RTE_SHIFT_VAL32(0x5, 26); insn |= imm; emit_insn(ctx, insn, check_imm(26, imm26)); @@ -971,9 +971,9 @@ uint32_t insn; insn = 0xb820001f; - insn |= (!!is64) << 30; - insn |= rs << 16; - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(is64, 30); + insn |= RTE_SHIFT_VAL32(rs, 16); + insn |= RTE_SHIFT_VAL32(rn, 5); emit_insn(ctx, insn, check_reg(rs) || check_reg(rn)); } @@ -984,8 +984,8 @@ uint32_t insn; insn = 0x885f7c00; - insn |= (!!is64) << 30; - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(is64, 30); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rt; emit_insn(ctx, insn, check_reg(rt) || check_reg(rn)); @@ -998,9 +998,9 @@ uint32_t insn; insn = 0x88007c00; - insn |= (!!is64) << 30; - insn |= rs << 16; - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(is64, 30); + insn |= RTE_SHIFT_VAL32(rs, 16); + insn |= RTE_SHIFT_VAL32(rn, 5); insn |= rt; emit_insn(ctx, insn, check_reg(rs) || check_reg(rt) || check_reg(rn)); @@ -1051,9 +1051,9 @@ uint32_t insn; insn = opc; - insn |= (!!is64) << 31; - insn |= rm << 16; - insn |= rn << 5; + insn |= RTE_SHIFT_VAL32(is64, 31); + insn |= RTE_SHIFT_VAL32(rm, 16); + insn |= RTE_SHIFT_VAL32(rn, 5); emit_insn(ctx, insn, check_reg(rn) || check_reg(rm)); } @@ -1076,8 +1076,8 @@ uint32_t insn, imm; imm = mask_imm(19, imm19); - insn = 0x15 << 26; - insn |= imm << 5; + insn = RTE_SHIFT_VAL32(0x15, 26); + insn |= RTE_SHIFT_VAL32(imm, 5); insn |= cond; emit_insn(ctx, insn, check_cond(cond) || check_imm(19, imm19)); @@ -1301,7 +1301,7 @@ break; /* dst = imm64 */ case (BPF_LD | BPF_IMM | EBPF_DW): - u64 = ((uint64_t)ins[1].imm << 32) | (uint32_t)imm; + u64 = RTE_SHIFT_VAL64(ins[1].imm, 32) | (uint32_t)imm; emit_mov_imm(ctx, 1, dst, u64); i++; break; diff -Nru dpdk-24.11.4/lib/bpf/bpf_jit_x86.c dpdk-24.11.8/lib/bpf/bpf_jit_x86.c --- dpdk-24.11.4/lib/bpf/bpf_jit_x86.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/bpf/bpf_jit_x86.c 2026-10-14 13:10:05.000000000 +0000 @@ -93,6 +93,8 @@ /* * callee saved registers list. * keep RBP as the last one. + * RBP is marked as used every time we have external calls + * since we need it to save RSP before stack realignment. */ static const uint32_t save_regs[] = {RBX, R12, R13, R14, R15, RBP}; @@ -685,6 +687,8 @@ const uint8_t ops = 0xFF; const uint8_t mods = 2; + /* Mark RBP as used to trigger stack realignment in prolog. */ + USED(st->reguse, RBP); emit_ld_imm64(st, RAX, trg, trg >> 32); emit_bytes(st, &ops, sizeof(ops)); emit_modregrm(st, MOD_DIRECT, mods, RAX); @@ -1220,6 +1224,16 @@ if (INUSE(st->reguse, RBP) != 0) { emit_mov_reg(st, EBPF_ALU64 | EBPF_MOV | BPF_X, RSP, RBP); emit_alu_imm(st, EBPF_ALU64 | BPF_SUB | BPF_K, RSP, stack_size); + + /* + * Align stack pointer appropriately for function calls. + * We do not have direct access to function stack alignment + * value (like gcc internal macro INCOMING_STACK_BOUNDARY), + * but hopefully `alignof(max_align_t)` will always be greater. + * Original stack pointer will be restored from rbp. + */ + emit_alu_imm(st, EBPF_ALU64 | BPF_AND | BPF_K, RSP, + -(uint32_t)alignof(max_align_t)); } } diff -Nru dpdk-24.11.4/lib/bpf/bpf_load.c dpdk-24.11.8/lib/bpf/bpf_load.c --- dpdk-24.11.4/lib/bpf/bpf_load.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/bpf/bpf_load.c 2026-10-14 13:10:05.000000000 +0000 @@ -86,7 +86,7 @@ int32_t rc; uint32_t i; - if (prm == NULL || prm->ins == NULL || + if (prm == NULL || prm->ins == NULL || prm->nb_ins == 0 || (prm->nb_xsym != 0 && prm->xsym == NULL)) { rte_errno = EINVAL; return NULL; diff -Nru dpdk-24.11.4/lib/bpf/bpf_validate.c dpdk-24.11.8/lib/bpf/bpf_validate.c --- dpdk-24.11.4/lib/bpf/bpf_validate.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/bpf/bpf_validate.c 2026-10-14 13:10:05.000000000 +0000 @@ -64,7 +64,7 @@ uint8_t cur_edge:4; uint8_t edge_type[MAX_EDGES]; uint32_t edge_dest[MAX_EDGES]; - uint32_t prev_node; + struct inst_node *prev_node; struct { struct bpf_eval_state *cur; /* save/restore for jcc targets */ struct bpf_eval_state *start; @@ -239,12 +239,24 @@ static void eval_add(struct bpf_reg_val *rd, const struct bpf_reg_val *rs, uint64_t msk) { + struct bpf_reg_val rs_buf; struct bpf_reg_val rv; + if (RTE_BPF_ARG_PTR_TYPE(rs->v.type) != 0) { + if (RTE_BPF_ARG_PTR_TYPE(rd->v.type) != 0) { + /* treat sum of pointers as sum of two unknown scalars */ + eval_fill_max_bound(&rs_buf, msk); + *rd = rs_buf; + rs = &rs_buf; + } else + /* scalar + pointer is a pointer of the same type */ + rd->v = rs->v; + } + rv.u.min = (rd->u.min + rs->u.min) & msk; rv.u.max = (rd->u.max + rs->u.max) & msk; - rv.s.min = (rd->s.min + rs->s.min) & msk; - rv.s.max = (rd->s.max + rs->s.max) & msk; + rv.s.min = ((uint64_t)rd->s.min + (uint64_t)rs->s.min) & msk; + rv.s.max = ((uint64_t)rd->s.max + (uint64_t)rs->s.max) & msk; /* * if at least one of the operands is not constant, @@ -272,8 +284,8 @@ rv.u.min = (rd->u.min - rs->u.max) & msk; rv.u.max = (rd->u.max - rs->u.min) & msk; - rv.s.min = (rd->s.min - rs->s.max) & msk; - rv.s.max = (rd->s.max - rs->s.min) & msk; + rv.s.min = ((uint64_t)rd->s.min - (uint64_t)rs->s.max) & msk; + rv.s.max = ((uint64_t)rd->s.max - (uint64_t)rs->s.min) & msk; /* * if at least one of the operands is not constant, @@ -284,9 +296,9 @@ eval_umax_bound(&rv, msk); if ((rd->s.min != rd->s.max || rs->s.min != rs->s.max) && - (((rs->s.min < 0 && rv.s.min < rd->s.min) || + (((rs->s.max < 0 && rv.s.min < rd->s.min) || rv.s.min > rd->s.min) || - ((rs->s.max < 0 && rv.s.max < rd->s.max) || + ((rs->s.min < 0 && rv.s.max < rd->s.max) || rv.s.max > rd->s.max))) eval_smax_bound(&rv, msk); @@ -314,7 +326,8 @@ /* check that dreg values are and would remain always positive */ if ((uint64_t)rd->s.min >> (opsz - 1) != 0 || rd->s.max >= - RTE_LEN2MASK(opsz - rs->u.max - 1, int64_t)) + (rs->u.max == opsz - 1 ? 0 : + RTE_LEN2MASK(opsz - rs->u.max - 1, int64_t))) eval_smax_bound(rd, msk); else { rd->s.max <<= rs->u.max; @@ -416,7 +429,7 @@ rd->u.max &= rs->u.max; } else { rd->u.max = eval_uand_max(rd->u.max, rs->u.max, opsz); - rd->u.min &= rs->u.min; + rd->u.min = 0; } /* both operands are constants */ @@ -427,7 +440,7 @@ } else if (rd->s.min >= 0 || rs->s.min >= 0) { rd->s.max = eval_uand_max(rd->s.max & (msk >> 1), rs->s.max & (msk >> 1), opsz); - rd->s.min &= rs->s.min; + rd->s.min = 0; } else eval_smax_bound(rd, msk); } @@ -442,7 +455,7 @@ rd->u.max |= rs->u.max; } else { rd->u.max = eval_uor_max(rd->u.max, rs->u.max, opsz); - rd->u.min |= rs->u.min; + rd->u.min = RTE_MAX(rd->u.min, rs->u.min); } /* both operands are constants */ @@ -451,9 +464,9 @@ rd->s.max |= rs->s.max; /* both operands are non-negative */ - } else if (rd->s.min >= 0 || rs->s.min >= 0) { + } else if (rd->s.min >= 0 && rs->s.min >= 0) { rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz); - rd->s.min |= rs->s.min; + rd->s.min = RTE_MAX(rd->s.min, rs->s.min); } else eval_smax_bound(rd, msk); } @@ -477,7 +490,7 @@ rd->s.max ^= rs->s.max; /* both operands are non-negative */ - } else if (rd->s.min >= 0 || rs->s.min >= 0) { + } else if (rd->s.min >= 0 && rs->s.min >= 0) { rd->s.max = eval_uor_max(rd->s.max, rs->s.max, opsz); rd->s.min = 0; } else @@ -495,25 +508,24 @@ /* check for overflow */ } else if (rd->u.max <= msk >> opsz / 2 && rs->u.max <= msk >> opsz) { rd->u.max *= rs->u.max; - rd->u.min *= rd->u.min; + rd->u.min *= rs->u.min; } else eval_umax_bound(rd, msk); /* both operands are constants */ if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) { - rd->s.min = (rd->s.min * rs->s.min) & msk; - rd->s.max = (rd->s.max * rs->s.max) & msk; + rd->s.min = ((uint64_t)rd->s.min * (uint64_t)rs->s.min) & msk; + rd->s.max = ((uint64_t)rd->s.max * (uint64_t)rs->s.max) & msk; /* check that both operands are positive and no overflow */ } else if (rd->s.min >= 0 && rs->s.min >= 0) { rd->s.max *= rs->s.max; - rd->s.min *= rd->s.min; + rd->s.min *= rs->s.min; } else eval_smax_bound(rd, msk); } static const char * -eval_divmod(uint32_t op, struct bpf_reg_val *rd, struct bpf_reg_val *rs, - size_t opsz, uint64_t msk) +eval_divmod(uint32_t op, struct bpf_reg_val *rd, struct bpf_reg_val *rs, uint64_t msk) { /* both operands are constants */ if (rd->u.min == rd->u.max && rs->u.min == rs->u.max) { @@ -534,34 +546,17 @@ rd->u.min = 0; } - /* if we have 32-bit values - extend them to 64-bit */ - if (opsz == sizeof(uint32_t) * CHAR_BIT) { - rd->s.min = (int32_t)rd->s.min; - rd->s.max = (int32_t)rd->s.max; - rs->s.min = (int32_t)rs->s.min; - rs->s.max = (int32_t)rs->s.max; - } - - /* both operands are constants */ - if (rd->s.min == rd->s.max && rs->s.min == rs->s.max) { - if (rs->s.max == 0) - return "division by 0"; - if (op == BPF_DIV) { - rd->s.min /= rs->s.min; - rd->s.max /= rs->s.max; - } else { - rd->s.min %= rs->s.min; - rd->s.max %= rs->s.max; - } - } else if (op == BPF_MOD) { - rd->s.min = RTE_MAX(rd->s.max, 0); - rd->s.min = RTE_MIN(rd->s.min, 0); + if (rd->u.min >= (uint64_t)INT64_MIN || rd->u.max <= (uint64_t)INT64_MAX) { + /* + * All values have the same sign bit, which means range + * contiguous as unsigned is also contiguous as signed, + * so we can just reuse it without any changes. + */ + rd->s.min = rd->u.min; + rd->s.max = rd->u.max; } else eval_smax_bound(rd, msk); - rd->s.max &= msk; - rd->s.min &= msk; - return NULL; } @@ -570,6 +565,11 @@ { uint64_t ux, uy; int64_t sx, sy; + /* additional limits imposed by signed on unsigned and back */ + struct bpf_reg_val cross_limits = { + .s = { INT64_MIN, INT64_MAX }, + .u = { 0, UINT64_MAX }, + }; /* if we have 32-bit values - extend them to 64-bit */ if (opsz == sizeof(uint32_t) * CHAR_BIT) { @@ -577,11 +577,29 @@ rd->u.max = (int32_t)rd->u.max; } - ux = -(int64_t)rd->u.min & msk; - uy = -(int64_t)rd->u.max & msk; + if (rd->u.min == 0) { + /* special case: ranges that include 0 and, possibly, 1 */ + + /* + * Calculate requirements on the signed range of negation. + * It is only possible when negated range does not cross from + * INT64_MIN to INT64_MAX, which means our original range does + * not reach (uint64_t)-INT64_MAX. + */ + if (rd->u.max < (uint64_t)-INT64_MAX) { + cross_limits.s.min = -rd->u.max; + cross_limits.s.max = -rd->u.min; + } + + if (rd->u.max != 0) + rd->u.max = UINT64_MAX; + } else { + ux = -rd->u.min & msk; + uy = -rd->u.max & msk; - rd->u.max = RTE_MAX(ux, uy); - rd->u.min = RTE_MIN(ux, uy); + rd->u.max = RTE_MAX(ux, uy); + rd->u.min = RTE_MIN(ux, uy); + } /* if we have 32-bit values - extend them to 64-bit */ if (opsz == sizeof(uint32_t) * CHAR_BIT) { @@ -589,11 +607,27 @@ rd->s.max = (int32_t)rd->s.max; } - sx = -rd->s.min & msk; - sy = -rd->s.max & msk; + if (rd->s.min == INT64_MIN) { + /* special case: negation of INT64_MIN is INT64_MIN */ + if (rd->s.max <= 0) { + cross_limits.u.min = -(uint64_t)rd->s.max; + cross_limits.u.max = -(uint64_t)rd->s.min; + } + if (rd->s.max != INT64_MIN) + rd->s.max = INT64_MAX; + } else { + /* since max >= min, neither can be INT64_MIN here */ + sx = -rd->s.min & msk; + sy = -rd->s.max & msk; + + rd->s.max = RTE_MAX(sx, sy); + rd->s.min = RTE_MIN(sx, sy); + } - rd->s.max = RTE_MAX(sx, sy); - rd->s.min = RTE_MIN(sx, sy); + rd->s.min = RTE_MAX(rd->s.min, cross_limits.s.min) & msk; + rd->s.max = RTE_MIN(rd->s.max, cross_limits.s.max) & msk; + rd->u.min = RTE_MAX(rd->u.min, cross_limits.u.min) & msk; + rd->u.max = RTE_MIN(rd->u.max, cross_limits.u.max) & msk; } static const char * @@ -706,7 +740,7 @@ else if (op == BPF_MUL) eval_mul(rd, &rs, opsz, msk); else if (op == BPF_DIV || op == BPF_MOD) - err = eval_divmod(op, rd, &rs, opsz, msk); + err = eval_divmod(op, rd, &rs, msk); else if (op == BPF_NEG) eval_neg(rd, opsz, msk); else if (op == EBPF_MOV) @@ -800,10 +834,11 @@ /* full 64-bit load */ if (mask == UINT64_MAX) eval_smax_bound(rv, mask); - - /* zero-extend load */ - rv->s.min = rv->u.min; - rv->s.max = rv->u.max; + else { + /* zero-extend load */ + rv->s.min = rv->u.min; + rv->s.max = rv->u.max; + } } @@ -1061,8 +1096,10 @@ eval_jgt_jle(struct bpf_reg_val *trd, struct bpf_reg_val *trs, struct bpf_reg_val *frd, struct bpf_reg_val *frs) { - frd->u.max = RTE_MIN(frd->u.max, frs->u.min); + frd->u.max = RTE_MIN(frd->u.max, frs->u.max); + frs->u.min = RTE_MAX(frs->u.min, frd->u.min); trd->u.min = RTE_MAX(trd->u.min, trs->u.min + 1); + trs->u.max = RTE_MIN(trs->u.max, trd->u.max - 1); } static void @@ -1070,15 +1107,19 @@ struct bpf_reg_val *frd, struct bpf_reg_val *frs) { frd->u.min = RTE_MAX(frd->u.min, frs->u.min); + frs->u.max = RTE_MIN(frs->u.max, frd->u.max); trd->u.max = RTE_MIN(trd->u.max, trs->u.max - 1); + trs->u.min = RTE_MAX(trs->u.min, trd->u.min + 1); } static void eval_jsgt_jsle(struct bpf_reg_val *trd, struct bpf_reg_val *trs, struct bpf_reg_val *frd, struct bpf_reg_val *frs) { - frd->s.max = RTE_MIN(frd->s.max, frs->s.min); + frd->s.max = RTE_MIN(frd->s.max, frs->s.max); + frs->s.min = RTE_MAX(frs->s.min, frd->s.min); trd->s.min = RTE_MAX(trd->s.min, trs->s.min + 1); + trs->s.max = RTE_MIN(trs->s.max, trd->s.max - 1); } static void @@ -1086,7 +1127,9 @@ struct bpf_reg_val *frd, struct bpf_reg_val *frs) { frd->s.min = RTE_MAX(frd->s.min, frs->s.min); + frs->s.max = RTE_MIN(frs->s.max, frd->s.max); trd->s.max = RTE_MIN(trd->s.max, trs->s.max - 1); + trs->s.min = RTE_MAX(trs->s.min, trd->s.min + 1); } static const char * @@ -1827,7 +1870,7 @@ { uint32_t ne; - if (nidx > bvf->prm->nb_ins) { + if (nidx >= bvf->prm->nb_ins) { RTE_BPF_LOG_LINE(ERR, "%s: program boundary violation at pc: %u, next pc: %u", __func__, get_node_idx(bvf, node), nidx); @@ -1875,25 +1918,25 @@ bvf->edge_type[type]++; } -static struct inst_node * -get_prev_node(struct bpf_verifier *bvf, struct inst_node *node) -{ - return bvf->in + node->prev_node; -} - /* * Depth-First Search (DFS) through previously constructed * Control Flow Graph (CFG). * Information collected at this path would be used later * to determine is there any loops, and/or unreachable instructions. + * PREREQUISITE: there is at least one node. */ static void dfs(struct bpf_verifier *bvf) { struct inst_node *next, *node; - node = bvf->in; - while (node != NULL) { + RTE_ASSERT(bvf->nb_nodes != 0); + /* + * Since there is at least one node, node with index 0 always exists; + * it is our program entry point. + */ + node = &bvf->in[0]; + do { if (node->colour == WHITE) set_node_colour(bvf, node, GREY); @@ -1910,7 +1953,7 @@ if (next != NULL) { /* proceed with next child */ - next->prev_node = get_node_idx(bvf, node); + next->prev_node = node; node = next; } else { /* @@ -1919,11 +1962,11 @@ */ set_node_colour(bvf, node, BLACK); node->cur_edge = 0; - node = get_prev_node(bvf, node); + node = node->prev_node; } } else node = NULL; - } + } while (node != NULL); } /* @@ -2062,6 +2105,12 @@ if (rc != 0) return rc; + if (bvf->nb_nodes == 0) { + RTE_BPF_LOG_LINE(ERR, "%s(%p) the program is empty", + __func__, bvf); + return -EINVAL; + } + dfs(bvf); RTE_LOG(DEBUG, BPF, "%s(%p) stats:\n" @@ -2138,6 +2187,10 @@ { uint32_t k, n; + if (bvf->nb_jcc_nodes > UINT32_MAX / 4) + /* Calculations that follow may overflow. */ + return -E2BIG; + /* * We need nb_jcc_nodes + 1 for save_cur/restore_cur * remaining ones will be used for state tracking/pruning. @@ -2478,7 +2531,7 @@ next = NULL; stats.nb_prune++; } else { - next->prev_node = get_node_idx(bvf, node); + next->prev_node = node; node = next; } } else { @@ -2489,11 +2542,9 @@ */ node->cur_edge = 0; save_safe_eval_state(bvf, node); - node = get_prev_node(bvf, node); + node = node->prev_node; - /* finished */ - if (node == bvf->in) - node = NULL; + /* first node will not have prev, signalling finish */ } } diff -Nru dpdk-24.11.4/lib/cfgfile/rte_cfgfile.c dpdk-24.11.8/lib/cfgfile/rte_cfgfile.c --- dpdk-24.11.4/lib/cfgfile/rte_cfgfile.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cfgfile/rte_cfgfile.c 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,15 +16,15 @@ struct rte_cfgfile_section { char name[CFG_NAME_LEN]; - int num_entries; - int allocated_entries; + size_t num_entries; + size_t allocated_entries; struct rte_cfgfile_entry *entries; }; struct rte_cfgfile { int flags; - int num_sections; - int allocated_sections; + size_t num_sections; + size_t allocated_sections; struct rte_cfgfile_section *sections; }; @@ -35,13 +36,33 @@ RTE_LOG_LINE_PREFIX(level, CFGFILE, "%s(): ", __func__, __VA_ARGS__) /* >8 End of setting up dynamic logging */ +/* Define a max allocation limit for entry and section types. + * For 64-bit systems, this is based on INT_MAX since API work on int values. + * For 32-bit systems, this is based on SIZE_MAX / sizeof(type) to prevent overflow on allocation. + */ +#define CFG_ALLOC_MAX(type) \ + (sizeof(int) == sizeof(size_t) ? (SIZE_MAX / sizeof(type)) : ((size_t)INT_MAX)) + /** when we resize a file structure, how many extra entries * for new sections do we add in */ #define CFG_ALLOC_SECTION_BATCH 8 + +/* Max number of section entries we can possibly have. + * Used to prevent overflow on allocation. + * Based on INT_MAX since API work on int values. + */ +#define CFG_ALLOC_SECTION_MAX CFG_ALLOC_MAX(struct rte_cfgfile_section) + /** when we resize a section structure, how many extra entries * for new entries do we add in */ #define CFG_ALLOC_ENTRY_BATCH 16 +/* Max number of data entries we can possibly have. + * Used to prevent overflow on allocation. + * Based on INT_MAX since API work on int values. + */ +#define CFG_ALLOC_ENTRY_MAX CFG_ALLOC_MAX(struct rte_cfgfile_entry) + /** * Default cfgfile load parameters. */ @@ -91,9 +112,7 @@ static struct rte_cfgfile_section * _get_section(struct rte_cfgfile *cfg, const char *sectionname) { - int i; - - for (i = 0; i < cfg->num_sections; i++) { + for (size_t i = 0; i < cfg->num_sections; i++) { if (strncmp(cfg->sections[i].name, sectionname, sizeof(cfg->sections[0].name)) == 0) return &cfg->sections[i]; @@ -107,6 +126,9 @@ { /* resize entry structure if we don't have room for more entries */ if (section->num_entries == section->allocated_entries) { + if (section->allocated_entries > CFG_ALLOC_ENTRY_MAX - CFG_ALLOC_ENTRY_BATCH) + return -ENOMEM; + struct rte_cfgfile_entry *n_entries = realloc( section->entries, sizeof(struct rte_cfgfile_entry) * @@ -272,7 +294,6 @@ struct rte_cfgfile * rte_cfgfile_create(int flags) { - int i; struct rte_cfgfile *cfg; /* future proof flags usage */ @@ -295,7 +316,7 @@ cfg->allocated_sections = CFG_ALLOC_SECTION_BATCH; - for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + for (size_t i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { cfg->sections[i].entries = calloc(CFG_ALLOC_ENTRY_BATCH, sizeof(struct rte_cfgfile_entry)); @@ -312,7 +333,7 @@ return cfg; error1: if (cfg->sections != NULL) { - for (i = 0; i < cfg->allocated_sections; i++) { + for (size_t i = 0; i < cfg->allocated_sections; i++) { if (cfg->sections[i].entries != NULL) { free(cfg->sections[i].entries); cfg->sections[i].entries = NULL; @@ -328,8 +349,6 @@ int rte_cfgfile_add_section(struct rte_cfgfile *cfg, const char *sectionname) { - int i; - if (cfg == NULL) return -EINVAL; @@ -338,6 +357,8 @@ /* resize overall struct if we don't have room for more sections */ if (cfg->num_sections == cfg->allocated_sections) { + if (cfg->allocated_sections > CFG_ALLOC_SECTION_MAX - CFG_ALLOC_SECTION_BATCH) + return -ENOMEM; struct rte_cfgfile_section *n_sections = realloc(cfg->sections, @@ -348,7 +369,7 @@ if (n_sections == NULL) return -ENOMEM; - for (i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { + for (size_t i = 0; i < CFG_ALLOC_SECTION_BATCH; i++) { n_sections[i + cfg->allocated_sections].num_entries = 0; n_sections[i + cfg->allocated_sections].allocated_entries = 0; @@ -393,8 +414,6 @@ int rte_cfgfile_set_entry(struct rte_cfgfile *cfg, const char *sectionname, const char *entryname, const char *entryvalue) { - int i; - if ((cfg == NULL) || (sectionname == NULL) || (entryname == NULL)) return -EINVAL; @@ -407,7 +426,7 @@ if (entryvalue == NULL) entryvalue = ""; - for (i = 0; i < curr_section->num_entries; i++) + for (size_t i = 0; i < curr_section->num_entries; i++) if (!strcmp(curr_section->entries[i].name, entryname)) { strlcpy(curr_section->entries[i].value, entryvalue, sizeof(curr_section->entries[i].value)); @@ -420,8 +439,6 @@ int rte_cfgfile_save(struct rte_cfgfile *cfg, const char *filename) { - int i, j; - if ((cfg == NULL) || (filename == NULL)) return -EINVAL; @@ -430,10 +447,10 @@ if (f == NULL) return -EINVAL; - for (i = 0; i < cfg->num_sections; i++) { + for (size_t i = 0; i < cfg->num_sections; i++) { fprintf(f, "[%s]\n", cfg->sections[i].name); - for (j = 0; j < cfg->sections[i].num_entries; j++) { + for (size_t j = 0; j < cfg->sections[i].num_entries; j++) { fprintf(f, "%s=%s\n", cfg->sections[i].entries[j].name, cfg->sections[i].entries[j].value); @@ -444,13 +461,11 @@ int rte_cfgfile_close(struct rte_cfgfile *cfg) { - int i; - if (cfg == NULL) return -1; if (cfg->sections != NULL) { - for (i = 0; i < cfg->allocated_sections; i++) { + for (size_t i = 0; i < cfg->allocated_sections; i++) { if (cfg->sections[i].entries != NULL) { free(cfg->sections[i].entries); cfg->sections[i].entries = NULL; @@ -469,13 +484,13 @@ rte_cfgfile_num_sections(struct rte_cfgfile *cfg, const char *sectionname, size_t length) { - int i; - int num_sections = 0; - for (i = 0; i < cfg->num_sections; i++) { + size_t num_sections = 0; + for (size_t i = 0; i < cfg->num_sections; i++) { if (strncmp(cfg->sections[i].name, sectionname, length) == 0) num_sections++; } - return num_sections; + + return (int)num_sections; } int @@ -484,7 +499,7 @@ { int i; - for (i = 0; i < cfg->num_sections && i < max_sections; i++) + for (i = 0; (size_t)i < cfg->num_sections && i < max_sections; i++) strlcpy(sections[i], cfg->sections[i].name, CFG_NAME_LEN); return i; @@ -503,20 +518,21 @@ const struct rte_cfgfile_section *s = _get_section(cfg, sectionname); if (s == NULL) return -1; - return s->num_entries; + + return (int)s->num_entries; } int rte_cfgfile_section_num_entries_by_index(struct rte_cfgfile *cfg, char *sectionname, int index) { - if (index < 0 || index >= cfg->num_sections) + if (index < 0 || (size_t)index >= cfg->num_sections) return -1; const struct rte_cfgfile_section *sect = &(cfg->sections[index]); strlcpy(sectionname, sect->name, CFG_NAME_LEN); - return sect->num_entries; + return (int)sect->num_entries; } int rte_cfgfile_section_entries(struct rte_cfgfile *cfg, const char *sectionname, @@ -526,7 +542,7 @@ const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname); if (sect == NULL) return -1; - for (i = 0; i < max_entries && i < sect->num_entries; i++) + for (i = 0; i < max_entries && (size_t)i < sect->num_entries; i++) entries[i] = sect->entries[i]; return i; } @@ -539,11 +555,14 @@ int i; const struct rte_cfgfile_section *sect; - if (index < 0 || index >= cfg->num_sections) + if (max_entries < 0) + return -1; + + if (index < 0 || (size_t)index >= cfg->num_sections) return -1; sect = &cfg->sections[index]; strlcpy(sectionname, sect->name, CFG_NAME_LEN); - for (i = 0; i < max_entries && i < sect->num_entries; i++) + for (i = 0; i < max_entries && (size_t)i < sect->num_entries; i++) entries[i] = sect->entries[i]; return i; } @@ -552,11 +571,10 @@ rte_cfgfile_get_entry(struct rte_cfgfile *cfg, const char *sectionname, const char *entryname) { - int i; const struct rte_cfgfile_section *sect = _get_section(cfg, sectionname); if (sect == NULL) return NULL; - for (i = 0; i < sect->num_entries; i++) + for (size_t i = 0; i < sect->num_entries; i++) if (strncmp(sect->entries[i].name, entryname, CFG_NAME_LEN) == 0) return sect->entries[i].value; diff -Nru dpdk-24.11.4/lib/cmdline/cmdline_parse.c dpdk-24.11.8/lib/cmdline/cmdline_parse.c --- dpdk-24.11.4/lib/cmdline/cmdline_parse.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cmdline/cmdline_parse.c 2026-10-14 13:10:05.000000000 +0000 @@ -131,7 +131,7 @@ } else { unsigned rb_sz; - if (token_hdr.offset > resbuf_size) { + if (token_hdr.offset >= resbuf_size) { printf("Parse error(%s:%d): Token offset(%u) " "exceeds maximum size(%u)\n", __FILE__, __LINE__, @@ -514,7 +514,9 @@ } (*state)++; l=strlcpy(dst, tmpbuf, size); - if (l>=0 && token_hdr.ops->get_help) { + if ((unsigned int)l >= size) + return 1; + if (token_hdr.ops->get_help) { token_hdr.ops->get_help(token_p, tmpbuf, sizeof(tmpbuf)); help_str = inst->help_str; diff -Nru dpdk-24.11.4/lib/cmdline/cmdline_parse_num.c dpdk-24.11.8/lib/cmdline/cmdline_parse_num.c --- dpdk-24.11.4/lib/cmdline/cmdline_parse_num.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cmdline/cmdline_parse_num.c 2026-10-14 13:10:05.000000000 +0000 @@ -319,7 +319,7 @@ struct cmdline_token_num_data nd; int ret; - if (!tk) + if (!tk || !dstbuf || size == 0) return -1; memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd)); diff -Nru dpdk-24.11.4/lib/cmdline/cmdline_parse_string.c dpdk-24.11.8/lib/cmdline/cmdline_parse_string.c --- dpdk-24.11.4/lib/cmdline/cmdline_parse_string.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cmdline/cmdline_parse_string.c 2026-10-14 13:10:05.000000000 +0000 @@ -166,6 +166,9 @@ if (!tk || !dstbuf || idx < 0) return -1; + if (size == 0) + return -1; + tk2 = (struct cmdline_token_string *)tk; sd = &tk2->string_data; diff -Nru dpdk-24.11.4/lib/cmdline/cmdline_rdline.c dpdk-24.11.8/lib/cmdline/cmdline_rdline.c --- dpdk-24.11.4/lib/cmdline/cmdline_rdline.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cmdline/cmdline_rdline.c 2026-10-14 13:10:05.000000000 +0000 @@ -418,8 +418,9 @@ /* choice */ rdline_puts(rdl, "\r\n"); while (ret) { + tmp_size = strnlen(tmp_buf, sizeof(tmp_buf)); rdl->write_char(rdl, ' '); - for (i=0 ; tmp_buf[i] ; i++) + for (i = 0; i < tmp_size; i++) rdl->write_char(rdl, tmp_buf[i]); rdline_puts(rdl, "\r\n"); ret = rdl->complete(rdl, rdl->left_buf, diff -Nru dpdk-24.11.4/lib/cryptodev/rte_cryptodev.c dpdk-24.11.8/lib/cryptodev/rte_cryptodev.c --- dpdk-24.11.4/lib/cryptodev/rte_cryptodev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/cryptodev/rte_cryptodev.c 2026-10-14 13:10:05.000000000 +0000 @@ -713,6 +713,7 @@ if (dev->deq_cbs == NULL) { CDEV_LOG_ERR("Failed to allocate memory for deq callbacks"); rte_free(dev->enq_cbs); + dev->enq_cbs = NULL; return -ENOMEM; } @@ -1069,6 +1070,27 @@ return RTE_CRYPTO_MAX_DEVS; } +static uint8_t +rte_cryptodev_find_device_by_name(const char *name) +{ + char mz_name[RTE_MEMZONE_NAMESIZE]; + const struct rte_memzone *mz; + struct rte_cryptodev_data *data; + uint8_t dev_id; + + for (dev_id = 0; dev_id < RTE_CRYPTO_MAX_DEVS; dev_id++) { + snprintf(mz_name, sizeof(mz_name), "rte_cryptodev_data_%u", dev_id); + mz = rte_memzone_lookup(mz_name); + if (mz == NULL) + continue; + + data = mz->addr; + if (strncmp(data->name, name, RTE_CRYPTODEV_NAME_MAX_LEN) == 0) + return dev_id; + } + return RTE_CRYPTO_MAX_DEVS; +} + struct rte_cryptodev * rte_cryptodev_pmd_allocate(const char *name, int socket_id) { @@ -1081,10 +1103,18 @@ return NULL; } - dev_id = rte_cryptodev_find_free_device_index(); - if (dev_id == RTE_CRYPTO_MAX_DEVS) { - CDEV_LOG_ERR("Reached maximum number of crypto devices"); - return NULL; + if (rte_eal_process_type() == RTE_PROC_SECONDARY) { + dev_id = rte_cryptodev_find_device_by_name(name); + if (dev_id == RTE_CRYPTO_MAX_DEVS) { + CDEV_LOG_ERR("Device %s does not exist in primary process", name); + return NULL; + } + } else { + dev_id = rte_cryptodev_find_free_device_index(); + if (dev_id == RTE_CRYPTO_MAX_DEVS) { + CDEV_LOG_ERR("Reached maximum number of crypto devices"); + return NULL; + } } cryptodev = rte_cryptodev_pmd_get_dev(dev_id); diff -Nru dpdk-24.11.4/lib/dmadev/rte_dmadev.c dpdk-24.11.8/lib/dmadev/rte_dmadev.c --- dpdk-24.11.4/lib/dmadev/rte_dmadev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/dmadev/rte_dmadev.c 2026-10-14 13:10:05.000000000 +0000 @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -949,6 +950,25 @@ return 0; } +/* Parse an unsigned integer telemetry parameter, returning the value or + * -EINVAL. 'max' must be <= INT_MAX. + */ +static int +dmadev_parse_uint(const char *str, char **end, unsigned long max) +{ + unsigned long val; + + if (str == NULL || !isdigit((unsigned char)*str)) + return -EINVAL; + + errno = 0; + val = strtoul(str, end, 0); + if (errno != 0 || val > max) + return -EINVAL; + + return (int)val; +} + #define ADD_CAPA(td, dc, c) rte_tel_data_add_dict_int(td, dma_capability_name(c), !!(dc & c)) static int @@ -961,10 +981,9 @@ uint64_t dev_capa; char *end_param; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + dev_id = dmadev_parse_uint(params, &end_param, INT16_MAX); + if (dev_id < 0) return -EINVAL; - - dev_id = strtoul(params, &end_param, 0); if (*end_param != '\0') RTE_DMA_LOG(WARNING, "Extra parameters passed to dmadev telemetry command, ignoring"); @@ -1017,13 +1036,11 @@ struct rte_dma_stats dma_stats; int dev_id, ret, vchan_id; char *end_param; - const char *vchan_param; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + dev_id = dmadev_parse_uint(params, &end_param, INT16_MAX); + if (dev_id < 0) return -EINVAL; - dev_id = strtoul(params, &end_param, 0); - /* Function info_get validates dev_id so we don't need to. */ ret = rte_dma_info_get(dev_id, &dma_info); if (ret < 0) @@ -1035,11 +1052,11 @@ if (dma_info.nb_vchans == 1 && *end_param == '\0') vchan_id = 0; else { - vchan_param = strtok(end_param, ","); - if (!vchan_param || strlen(vchan_param) == 0 || !isdigit(*vchan_param)) + if (*end_param != ',') + return -EINVAL; + vchan_id = dmadev_parse_uint(end_param + 1, &end_param, UINT16_MAX); + if (vchan_id < 0) return -EINVAL; - - vchan_id = strtoul(vchan_param, &end_param, 0); } if (*end_param != '\0') RTE_DMA_LOG(WARNING, "Extra parameters passed to dmadev telemetry command, ignoring"); @@ -1066,10 +1083,9 @@ int dev_id, ret; FILE *f; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + dev_id = dmadev_parse_uint(params, &end_param, INT16_MAX); + if (dev_id < 0) return -EINVAL; - - dev_id = strtoul(params, &end_param, 0); if (*end_param != '\0') RTE_DMA_LOG(WARNING, "Extra parameters passed to dmadev telemetry command, ignoring"); diff -Nru dpdk-24.11.4/lib/dmadev/rte_dmadev.h dpdk-24.11.8/lib/dmadev/rte_dmadev.h --- dpdk-24.11.4/lib/dmadev/rte_dmadev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/dmadev/rte_dmadev.h 2026-10-14 13:10:05.000000000 +0000 @@ -1015,26 +1015,41 @@ } /** - * Return the number of operations that have been successfully completed. - * Once an operation has been reported as completed, the results of that - * operation will be visible to all cores on the system. + * Return the number of operations that have completed successfully, + * starting from the current ring position. + * + * This function reports a contiguous run of successfully completed operations. + * It stops at the first operation that either failed or has not yet completed. + * Once an operation is reported as successfully completed, + * the results of that operation are visible to all cores on the system. * * @param dev_id * The identifier of the device. * @param vchan - * The identifier of virtual DMA channel. + * The identifier of the virtual DMA channel. * @param nb_cpls - * The maximum number of completed operations that can be processed. + * The maximum number of completed operations to report. * @param[out] last_idx - * The last completed operation's ring_idx. + * The ring_idx of the last successfully completed operation reported by this call. + * The function stops at the first failed or incomplete operation, + * and reports at most nb_cpls operations, + * so this may not be the last successful operation + * the device has actually completed. * If not required, NULL can be passed in. * @param[out] has_error - * Indicates if there are transfer error. + * When set to true, a failed operation was encountered + * among the completed operations on the device (within the nb_cpls limit), + * causing the function to stop early. + * The returned count covers only the successful completions + * preceding that first failure. + * When false, all operations reported by this call succeeded; + * the function stopped either because nb_cpls operations have been reported, + * or because no more completed operations are available on the device. * If not required, NULL can be passed in. * * @return - * The number of operations that successfully completed. This return value - * must be less than or equal to the value of nb_cpls. + * The number of operations that successfully completed. + * This return value is less than or equal to the value of nb_cpls. */ static inline uint16_t rte_dma_completed(int16_t dev_id, uint16_t vchan, const uint16_t nb_cpls, @@ -1074,30 +1089,37 @@ } /** - * Return the number of operations that have been completed, and the operations - * result may succeed or fail. - * Once an operation has been reported as completed successfully, the results of that - * operation will be visible to all cores on the system. + * Return the number of operations that have completed (successfully or with error), + * starting from the current ring position. + * + * This function reports all completed operations up to nb_cpls, + * regardless of whether each individual operation succeeded or failed. + * Once an operation has been reported as completed successfully, + * the results of that operation are visible to all cores on the system. * * @param dev_id * The identifier of the device. * @param vchan - * The identifier of virtual DMA channel. + * The identifier of the virtual DMA channel. * @param nb_cpls - * Indicates the size of status array. + * The size of the status array, + * i.e. the maximum number of completed operations to report. * @param[out] last_idx - * The last completed operation's ring_idx. + * The ring_idx of the last completed operation reported by this call, + * whether successful or failed. + * The function reports up to nb_cpls completed operations + * without stopping on errors, so this may not be the last operation + * the device has actually completed. * If not required, NULL can be passed in. * @param[out] status - * This is a pointer to an array of length 'nb_cpls' that holds the completion - * status code of each operation. + * Pointer to an array of length 'nb_cpls' + * that receives the completion status code of each reported operation. * @see enum rte_dma_status_code * * @return - * The number of operations that completed. This return value must be less - * than or equal to the value of nb_cpls. - * If this number is greater than zero (assuming n), then n values in the - * status array are also set. + * The number of operations that completed. + * This return value is less than or equal to the value of nb_cpls. + * If this number is n (n > 0), the first n entries in the status array are valid. */ static inline uint16_t rte_dma_completed_status(int16_t dev_id, uint16_t vchan, diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_dev.c dpdk-24.11.8/lib/eal/common/eal_common_dev.c --- dpdk-24.11.4/lib/eal/common/eal_common_dev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_dev.c 2026-10-14 13:10:05.000000000 +0000 @@ -237,6 +237,13 @@ struct rte_device *dev; int ret; + + if (strlen(devargs) >= EAL_DEV_MP_DEV_ARGS_MAX_LEN) { + EAL_LOG(ERR, "devargs truncated (len %zu, max %d)", + strlen(devargs), EAL_DEV_MP_DEV_ARGS_MAX_LEN); + return -E2BIG; + } + memset(&req, 0, sizeof(req)); req.t = EAL_DEV_REQ_TYPE_ATTACH; strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_memory.c dpdk-24.11.8/lib/eal/common/eal_common_memory.c --- dpdk-24.11.4/lib/eal/common/eal_common_memory.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_memory.c 2026-10-14 13:10:05.000000000 +0000 @@ -30,11 +30,10 @@ #include "malloc_heap.h" /* - * Try to mmap *size bytes in /dev/zero. If it is successful, return the - * pointer to the mmap'd area and keep *size unmodified. Else, retry - * with a smaller zone: decrease *size by hugepage_sz until it reaches - * 0. In this case, return NULL. Note: this function returns an address - * which is a multiple of hugepage size. + * Try to mmap *size bytes. If it is successful, return the pointer to the + * mmap'd area and keep *size unmodified. Else, retry with a smaller zone: + * decrease *size by page_sz until it reaches 0. In this case, return NULL. + * Note: this function returns an address which is a multiple of page size. */ #define MEMSEG_LIST_FMT "memseg-%" PRIu64 "k-%i-%i" diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_options.c dpdk-24.11.8/lib/eal/common/eal_common_options.c --- dpdk-24.11.4/lib/eal/common/eal_common_options.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_options.c 2026-10-14 13:10:05.000000000 +0000 @@ -188,21 +188,21 @@ handle_eal_info_request(const char *cmd, const char *params __rte_unused, struct rte_tel_data *d) { - char **args; + char **out_args; int used = 0; int i = 0; if (strcmp(cmd, EAL_PARAM_REQ) == 0) - args = eal_args; + out_args = eal_args; else - args = eal_app_args; + out_args = eal_app_args; rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); - if (args == NULL || args[0] == NULL) + if (out_args == NULL || out_args[0] == NULL) return 0; - for ( ; args[i] != NULL; i++) - used = rte_tel_data_add_array_string(d, args[i]); + for ( ; out_args[i] != NULL; i++) + used = rte_tel_data_add_array_string(d, out_args[i]); return used; } @@ -267,21 +267,21 @@ #endif static int -eal_option_device_add(enum rte_devtype type, const char *optarg) +eal_option_device_add(enum rte_devtype type, const char *arg) { struct device_option *devopt; - size_t optlen; + size_t arglen; int ret; - optlen = strlen(optarg) + 1; - devopt = calloc(1, sizeof(*devopt) + optlen); + arglen = strlen(arg) + 1; + devopt = calloc(1, sizeof(*devopt) + arglen); if (devopt == NULL) { EAL_LOG(ERR, "Unable to allocate device option"); return -ENOMEM; } devopt->type = type; - ret = strlcpy(devopt->arg, optarg, optlen); + ret = strlcpy(devopt->arg, arg, arglen); if (ret < 0) { EAL_LOG(ERR, "Unable to copy device option"); free(devopt); diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_proc.c dpdk-24.11.8/lib/eal/common/eal_common_proc.c --- dpdk-24.11.4/lib/eal/common/eal_common_proc.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_proc.c 2026-10-14 13:10:05.000000000 +0000 @@ -73,6 +73,7 @@ struct pending_request { TAILQ_ENTRY(pending_request) next; + unsigned long id; enum { REQUEST_TYPE_SYNC, REQUEST_TYPE_ASYNC @@ -91,6 +92,8 @@ }; }; +static unsigned long next_request_id; + TAILQ_HEAD(pending_request_list, pending_request); static struct { @@ -110,15 +113,15 @@ static void async_reply_handle(void *arg); -/* for use with process_msg */ +/* for use with alarm callback and process_msg */ static struct pending_request * -async_reply_handle_thread_unsafe(void *arg); +async_reply_handle_thread_unsafe(struct pending_request *req); static void trigger_async_action(struct pending_request *req); static struct pending_request * -find_pending_request(const char *dst, const char *act_name) +find_request_by_name(const char *dst, const char *act_name) { struct pending_request *r; @@ -131,6 +134,19 @@ return r; } +static struct pending_request * +find_async_request_by_id(unsigned long id) +{ + struct pending_request *r; + + TAILQ_FOREACH(r, &pending_requests.requests, next) { + if (r->id == id && r->type == REQUEST_TYPE_ASYNC) + return r; + } + + return NULL; +} + static void create_socket_path(const char *name, char *buf, int len) { @@ -346,7 +362,7 @@ struct pending_request *req = NULL; pthread_mutex_lock(&pending_requests.lock); - pending_req = find_pending_request(s->sun_path, msg->name); + pending_req = find_request_by_name(s->sun_path, msg->name); if (pending_req) { memcpy(pending_req->reply, msg, sizeof(*msg)); /* -1 indicates that we've been asked to ignore */ @@ -356,8 +372,7 @@ if (pending_req->type == REQUEST_TYPE_SYNC) pthread_cond_signal(&pending_req->sync.cond); else if (pending_req->type == REQUEST_TYPE_ASYNC) - req = async_reply_handle_thread_unsafe( - pending_req); + req = async_reply_handle_thread_unsafe(pending_req); } else { EAL_LOG(ERR, "Drop mp reply: %s", msg->name); cleanup_msg_fds(msg); @@ -511,9 +526,8 @@ } static struct pending_request * -async_reply_handle_thread_unsafe(void *arg) +async_reply_handle_thread_unsafe(struct pending_request *req) { - struct pending_request *req = (struct pending_request *)arg; enum async_action action; struct timespec ts_now; @@ -526,18 +540,6 @@ TAILQ_REMOVE(&pending_requests.requests, req, next); - if (rte_eal_alarm_cancel(async_reply_handle, req) < 0) { - /* if we failed to cancel the alarm because it's already in - * progress, don't proceed because otherwise we will end up - * handling the same message twice. - */ - if (rte_errno == EINPROGRESS) { - EAL_LOG(DEBUG, "Request handling is already in progress"); - goto no_trigger; - } - EAL_LOG(ERR, "Failed to cancel alarm"); - } - if (action == ACTION_TRIGGER) return req; no_trigger: @@ -549,9 +551,16 @@ async_reply_handle(void *arg) { struct pending_request *req; + /* alarm arg carries the request ID packed into a void * via uintptr_t */ + unsigned long id = (uintptr_t)arg; + + /* ensure request ID matches pointer size */ + RTE_BUILD_BUG_ON(sizeof(next_request_id) != sizeof(uintptr_t)); pthread_mutex_lock(&pending_requests.lock); - req = async_reply_handle_thread_unsafe(arg); + req = find_async_request_by_id(id); + if (req != NULL) + req = async_reply_handle_thread_unsafe(req); pthread_mutex_unlock(&pending_requests.lock); if (req != NULL) @@ -860,33 +869,35 @@ { struct rte_mp_msg *reply_msg; struct pending_request *pending_req, *exist; + unsigned long id; int ret = -1; + /* queue already locked by caller */ + + exist = find_request_by_name(dst, req->name); + if (exist) { + EAL_LOG(ERR, "A pending request %s:%s", dst, req->name); + rte_errno = EEXIST; + return -1; + } + pending_req = calloc(1, sizeof(*pending_req)); reply_msg = calloc(1, sizeof(*reply_msg)); if (pending_req == NULL || reply_msg == NULL) { - EAL_LOG(ERR, "Could not allocate space for sync request"); + EAL_LOG(ERR, "Could not allocate space for async request"); rte_errno = ENOMEM; ret = -1; goto fail; } + id = ++next_request_id; pending_req->type = REQUEST_TYPE_ASYNC; + pending_req->id = id; strlcpy(pending_req->dst, dst, sizeof(pending_req->dst)); pending_req->request = req; pending_req->reply = reply_msg; pending_req->async.param = param; - /* queue already locked by caller */ - - exist = find_pending_request(dst, req->name); - if (exist) { - EAL_LOG(ERR, "A pending request %s:%s", dst, req->name); - rte_errno = EEXIST; - ret = -1; - goto fail; - } - ret = send_msg(dst, req, MP_REQ); if (ret < 0) { EAL_LOG(ERR, "Fail to send request %s:%s", @@ -901,7 +912,7 @@ /* if alarm set fails, we simply ignore the reply */ if (rte_eal_alarm_set(ts->tv_sec * 1000000 + ts->tv_nsec / 1000, - async_reply_handle, pending_req) < 0) { + async_reply_handle, (void *)(uintptr_t)id) < 0) { EAL_LOG(ERR, "Fail to set alarm for request %s:%s", dst, req->name); ret = -1; @@ -934,7 +945,7 @@ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); pthread_cond_init(&pending_req.sync.cond, &attr); - exist = find_pending_request(dst, req->name); + exist = find_request_by_name(dst, req->name); if (exist) { EAL_LOG(ERR, "A pending request %s:%s", dst, req->name); rte_errno = EEXIST; @@ -1153,6 +1164,7 @@ * it, and put it on the queue if we don't send any requests. */ dummy->type = REQUEST_TYPE_ASYNC; + dummy->id = ++next_request_id; dummy->request = copy; dummy->reply = NULL; dummy->async.param = param; @@ -1162,11 +1174,21 @@ if (rte_eal_process_type() == RTE_PROC_SECONDARY) { ret = mp_request_async(eal_mp_socket_path(), copy, param, ts); - /* if we didn't send anything, put dummy request on the queue */ + /* if we didn't send anything, put dummy request on the queue + * and set a minimum-delay alarm so the callback fires immediately. + */ if (ret == 0 && reply->nb_sent == 0) { - TAILQ_INSERT_TAIL(&pending_requests.requests, dummy, - next); + TAILQ_INSERT_TAIL(&pending_requests.requests, dummy, next); dummy_used = true; + if (rte_eal_alarm_set(1, async_reply_handle, + (void *)(uintptr_t)dummy->id) < 0) { + EAL_LOG(ERR, "Fail to set alarm for dummy request"); + /* roll back the changes */ + TAILQ_REMOVE(&pending_requests.requests, dummy, next); + dummy_used = false; + ret = -1; + goto unlock_fail; + } } pthread_mutex_unlock(&pending_requests.lock); @@ -1174,6 +1196,8 @@ /* if we couldn't send anything, clean up */ if (ret != 0) goto fail; + if (!dummy_used) + free(dummy); return 0; } @@ -1206,10 +1230,44 @@ if (mp_request_async(path, copy, param, ts)) ret = -1; } - /* if we didn't send anything, put dummy request on the queue */ + + /* + * On partial failure, roll back all queued requests. We hold the lock + * so no one else touches the queue. All requests in this batch share + * the same param pointer. Stale alarms will fire and harmlessly find + * nothing via ID-based lookup. + */ + if (ret != 0 && reply->nb_sent > 0) { + struct pending_request *r, *tmp; + + RTE_TAILQ_FOREACH_SAFE(r, &pending_requests.requests, next, tmp) { + if (r->type == REQUEST_TYPE_ASYNC && r->async.param == param) { + TAILQ_REMOVE(&pending_requests.requests, r, next); + free(r->reply); + /* r->request == copy, freed below after the loop */ + free(r); + } + } + /* requests on the queue were removed so keep things consistent */ + reply->nb_sent = 0; + } + + /* if we didn't send anything, put dummy request on the queue + * and set a minimum-delay alarm so the callback fires immediately. + */ if (ret == 0 && reply->nb_sent == 0) { TAILQ_INSERT_HEAD(&pending_requests.requests, dummy, next); dummy_used = true; + + if (rte_eal_alarm_set(1, async_reply_handle, + (void *)(uintptr_t)dummy->id) < 0) { + EAL_LOG(ERR, "Fail to set alarm for dummy request"); + /* roll back the changes */ + TAILQ_REMOVE(&pending_requests.requests, dummy, next); + dummy_used = false; + ret = -1; + goto closedir_fail; + } } /* finally, unlock the queue */ @@ -1224,6 +1282,11 @@ /* if dummy was unused, free it */ if (!dummy_used) free(dummy); + /* if nothing was sent, nobody owns copy/param */ + if (ret != 0) { + free(param); + free(copy); + } return ret; closedir_fail: diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_tailqs.c dpdk-24.11.8/lib/eal/common/eal_common_tailqs.c --- dpdk-24.11.4/lib/eal/common/eal_common_tailqs.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_tailqs.c 2026-10-14 13:10:05.000000000 +0000 @@ -70,7 +70,7 @@ mcfg = rte_eal_get_configuration()->mem_config; head = &mcfg->tailq_head[rte_tailqs_count]; - strlcpy(head->name, name, sizeof(head->name) - 1); + strlcpy(head->name, name, sizeof(head->name)); TAILQ_INIT(&head->tailq_head); rte_tailqs_count++; } diff -Nru dpdk-24.11.4/lib/eal/common/eal_common_trace.c dpdk-24.11.8/lib/eal/common/eal_common_trace.c --- dpdk-24.11.4/lib/eal/common/eal_common_trace.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/eal_common_trace.c 2026-10-14 13:10:05.000000000 +0000 @@ -258,32 +258,31 @@ static void trace_lcore_mem_dump(FILE *f) { - struct trace *trace = trace_obj_get(); + struct trace *t = trace_obj_get(); struct __rte_trace_header *header; uint32_t count; - rte_spinlock_lock(&trace->lock); - if (trace->nb_trace_mem_list == 0) + rte_spinlock_lock(&t->lock); + if (t->nb_trace_mem_list == 0) goto out; - fprintf(f, "nb_trace_mem_list = %d\n", trace->nb_trace_mem_list); + fprintf(f, "nb_trace_mem_list = %d\n", t->nb_trace_mem_list); fprintf(f, "\nTrace mem info\n--------------\n"); - for (count = 0; count < trace->nb_trace_mem_list; count++) { - header = trace->lcore_meta[count].mem; + for (count = 0; count < t->nb_trace_mem_list; count++) { + header = t->lcore_meta[count].mem; fprintf(f, "\tid %d, mem=%p, area=%s, lcore_id=%d, name=%s\n", count, header, - trace_area_to_string(trace->lcore_meta[count].area), + trace_area_to_string(t->lcore_meta[count].area), header->stream_header.lcore_id, header->stream_header.thread_name); } out: - rte_spinlock_unlock(&trace->lock); + rte_spinlock_unlock(&t->lock); } void rte_trace_dump(FILE *f) { - struct trace_point_head *tp_list = trace_list_head_get(); - struct trace *trace = trace_obj_get(); + struct trace *t = trace_obj_get(); struct trace_point *tp; fprintf(f, "\nGlobal info\n-----------\n"); @@ -291,13 +290,13 @@ rte_trace_is_enabled() ? "enabled" : "disabled"); fprintf(f, "mode = %s\n", trace_mode_to_string(rte_trace_mode_get())); - fprintf(f, "dir = %s\n", trace->dir); - fprintf(f, "buffer len = %d\n", trace->buff_len); - fprintf(f, "number of trace points = %d\n", trace->nb_trace_points); + fprintf(f, "dir = %s\n", t->dir); + fprintf(f, "buffer len = %d\n", t->buff_len); + fprintf(f, "number of trace points = %d\n", t->nb_trace_points); trace_lcore_mem_dump(f); fprintf(f, "\nTrace point info\n----------------\n"); - STAILQ_FOREACH(tp, tp_list, next) + STAILQ_FOREACH(tp, trace_list_head_get(), next) trace_point_dump(f, tp); } @@ -317,7 +316,7 @@ void __rte_trace_mem_per_thread_alloc(void) { - struct trace *trace = trace_obj_get(); + struct trace *t = trace_obj_get(); struct __rte_trace_header *header; uint32_t count; @@ -327,30 +326,30 @@ if (RTE_PER_LCORE(trace_mem)) return; - rte_spinlock_lock(&trace->lock); + rte_spinlock_lock(&t->lock); - count = trace->nb_trace_mem_list; + count = t->nb_trace_mem_list; /* Allocate room for storing the thread trace mem meta */ - trace->lcore_meta = realloc(trace->lcore_meta, - sizeof(trace->lcore_meta[0]) * (count + 1)); + t->lcore_meta = realloc(t->lcore_meta, + sizeof(t->lcore_meta[0]) * (count + 1)); /* Provide dummy space for fast path to consume */ - if (trace->lcore_meta == NULL) { + if (t->lcore_meta == NULL) { trace_crit("trace mem meta memory realloc failed"); header = NULL; goto fail; } /* First attempt from huge page */ - header = eal_malloc_no_trace(NULL, trace_mem_sz(trace->buff_len), 8); + header = eal_malloc_no_trace(NULL, trace_mem_sz(t->buff_len), 8); if (header) { - trace->lcore_meta[count].area = TRACE_AREA_HUGEPAGE; + t->lcore_meta[count].area = TRACE_AREA_HUGEPAGE; goto found; } /* Second attempt from heap */ - header = malloc(trace_mem_sz(trace->buff_len)); + header = malloc(trace_mem_sz(t->buff_len)); if (header == NULL) { trace_crit("trace mem malloc attempt failed"); header = NULL; @@ -359,14 +358,14 @@ } /* Second attempt from heap is success */ - trace->lcore_meta[count].area = TRACE_AREA_HEAP; + t->lcore_meta[count].area = TRACE_AREA_HEAP; /* Initialize the trace header */ found: header->offset = 0; - header->len = trace->buff_len; + header->len = t->buff_len; header->stream_header.magic = TRACE_CTF_MAGIC; - rte_uuid_copy(header->stream_header.uuid, trace->uuid); + rte_uuid_copy(header->stream_header.uuid, t->uuid); header->stream_header.lcore_id = rte_lcore_id(); /* Store the thread name */ @@ -375,11 +374,11 @@ thread_get_name(rte_thread_self(), name, __RTE_TRACE_EMIT_STRING_LEN_MAX); - trace->lcore_meta[count].mem = header; - trace->nb_trace_mem_list++; + t->lcore_meta[count].mem = header; + t->nb_trace_mem_list++; fail: RTE_PER_LCORE(trace_mem) = header; - rte_spinlock_unlock(&trace->lock); + rte_spinlock_unlock(&t->lock); } static void @@ -394,7 +393,7 @@ void trace_mem_per_thread_free(void) { - struct trace *trace = trace_obj_get(); + struct trace *t = trace_obj_get(); struct __rte_trace_header *header; uint32_t count; @@ -402,37 +401,36 @@ if (header == NULL) return; - rte_spinlock_lock(&trace->lock); - for (count = 0; count < trace->nb_trace_mem_list; count++) { - if (trace->lcore_meta[count].mem == header) + rte_spinlock_lock(&t->lock); + for (count = 0; count < t->nb_trace_mem_list; count++) { + if (t->lcore_meta[count].mem == header) break; } - if (count != trace->nb_trace_mem_list) { - struct thread_mem_meta *meta = &trace->lcore_meta[count]; + if (count != t->nb_trace_mem_list) { + struct thread_mem_meta *meta = &t->lcore_meta[count]; trace_mem_per_thread_free_unlocked(meta); - if (count != trace->nb_trace_mem_list - 1) { + if (count != t->nb_trace_mem_list - 1) { memmove(meta, meta + 1, sizeof(*meta) * - (trace->nb_trace_mem_list - count - 1)); + (t->nb_trace_mem_list - count - 1)); } - trace->nb_trace_mem_list--; + t->nb_trace_mem_list--; } - rte_spinlock_unlock(&trace->lock); + rte_spinlock_unlock(&t->lock); } void trace_mem_free(void) { - struct trace *trace = trace_obj_get(); + struct trace *t = trace_obj_get(); uint32_t count; - rte_spinlock_lock(&trace->lock); - for (count = 0; count < trace->nb_trace_mem_list; count++) { - trace_mem_per_thread_free_unlocked(&trace->lcore_meta[count]); - } - trace->nb_trace_mem_list = 0; - rte_spinlock_unlock(&trace->lock); + rte_spinlock_lock(&t->lock); + for (count = 0; count < t->nb_trace_mem_list; count++) + trace_mem_per_thread_free_unlocked(&t->lcore_meta[count]); + t->nb_trace_mem_list = 0; + rte_spinlock_unlock(&t->lock); } void diff -Nru dpdk-24.11.4/lib/eal/common/malloc_heap.c dpdk-24.11.8/lib/eal/common/malloc_heap.c --- dpdk-24.11.4/lib/eal/common/malloc_heap.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/common/malloc_heap.c 2026-10-14 13:10:05.000000000 +0000 @@ -1043,9 +1043,9 @@ /* if we unmapped some memory, we need to do additional work for ASan */ if (unmapped) { void *asan_end = RTE_PTR_ADD(asan_ptr, asan_data_len); - void *aligned_end = RTE_PTR_ADD(aligned_start, aligned_len); void *aligned_trailer = RTE_PTR_SUB(aligned_start, MALLOC_ELEM_TRAILER_LEN); + aligned_end = RTE_PTR_ADD(aligned_start, aligned_len); /* * There was a memory area that was unmapped. This memory area diff -Nru dpdk-24.11.4/lib/eal/freebsd/eal_interrupts.c dpdk-24.11.8/lib/eal/freebsd/eal_interrupts.c --- dpdk-24.11.4/lib/eal/freebsd/eal_interrupts.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/freebsd/eal_interrupts.c 2026-10-14 13:10:05.000000000 +0000 @@ -748,3 +748,9 @@ { return rte_thread_equal(intr_thread, rte_thread_self()); } + +uint32_t +rte_intr_active_events_flags(void) +{ + return 0; +} diff -Nru dpdk-24.11.4/lib/eal/freebsd/eal_memory.c dpdk-24.11.8/lib/eal/freebsd/eal_memory.c --- dpdk-24.11.4/lib/eal/freebsd/eal_memory.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/freebsd/eal_memory.c 2026-10-14 13:10:05.000000000 +0000 @@ -196,7 +196,10 @@ } seg->addr = addr; - seg->iova = physaddr; + if (rte_eal_iova_mode() == RTE_IOVA_VA) + seg->iova = (uintptr_t)addr; + else + seg->iova = physaddr; seg->hugepage_sz = page_sz; seg->len = page_sz; seg->nchannel = mcfg->nchannel; diff -Nru dpdk-24.11.4/lib/eal/include/generic/rte_spinlock.h dpdk-24.11.8/lib/eal/include/generic/rte_spinlock.h --- dpdk-24.11.4/lib/eal/include/generic/rte_spinlock.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/generic/rte_spinlock.h 2026-10-14 13:10:05.000000000 +0000 @@ -7,12 +7,16 @@ /** * @file + * DPDK spinlocks * - * RTE Spinlocks - * - * This file defines an API for read-write locks, which are implemented - * in an architecture-specific way. This kind of lock simply waits in - * a loop repeatedly checking until the lock becomes available. + * This is an API for spinlocks. + * This kind of lock simply waits in a loop + * repeatedly checking until the lock becomes available. + * + * Some functions may have an architecture-specific implementation + * if RTE_FORCE_INTRINSICS is disabled. + * The hardware transactional memory (lock elision) functions have _tm suffix + * and are implemented in architecture-specific files. * * All locks must be initialised before use, and only initialised once. */ @@ -197,8 +201,8 @@ */ typedef struct { rte_spinlock_t sl; /**< the actual spinlock */ - volatile int user; /**< core id using lock, -1 for unused */ - volatile int count; /**< count of time this lock has been called */ + RTE_ATOMIC(int) owner; /**< thread id owning lock, -1 for unused */ + int count; /**< count of time this lock has been called */ } rte_spinlock_recursive_t; /** @@ -215,7 +219,7 @@ static inline void rte_spinlock_recursive_init(rte_spinlock_recursive_t *slr) { rte_spinlock_init(&slr->sl); - slr->user = -1; + rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed); slr->count = 0; } @@ -230,9 +234,9 @@ { int id = rte_gettid(); - if (slr->user != id) { + if (rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) != id) { rte_spinlock_lock(&slr->sl); - slr->user = id; + rte_atomic_store_explicit(&slr->owner, id, rte_memory_order_relaxed); } slr->count++; } @@ -246,10 +250,9 @@ __rte_no_thread_safety_analysis { if (--(slr->count) == 0) { - slr->user = -1; + rte_atomic_store_explicit(&slr->owner, -1, rte_memory_order_relaxed); rte_spinlock_unlock(&slr->sl); } - } /** @@ -266,10 +269,10 @@ { int id = rte_gettid(); - if (slr->user != id) { + if (rte_atomic_load_explicit(&slr->owner, rte_memory_order_relaxed) != id) { if (rte_spinlock_trylock(&slr->sl) == 0) return 0; - slr->user = id; + rte_atomic_store_explicit(&slr->owner, id, rte_memory_order_relaxed); } slr->count++; return 1; diff -Nru dpdk-24.11.4/lib/eal/include/rte_bitops.h dpdk-24.11.8/lib/eal/include/rte_bitops.h --- dpdk-24.11.4/lib/eal/include/rte_bitops.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_bitops.h 2026-10-14 13:10:05.000000000 +0000 @@ -51,7 +51,7 @@ * @param nr * The shift number in range of 0 to (32 - width of val). */ -#define RTE_SHIFT_VAL32(val, nr) (UINT32_C(val) << (nr)) +#define RTE_SHIFT_VAL32(val, nr) ((uint32_t)(val) << (nr)) /** * Get the uint64_t shifted value. @@ -61,7 +61,7 @@ * @param nr * The shift number in range of 0 to (64 - width of val). */ -#define RTE_SHIFT_VAL64(val, nr) (UINT64_C(val) << (nr)) +#define RTE_SHIFT_VAL64(val, nr) ((uint64_t)(val) << (nr)) /** * Generate a contiguous 32-bit mask @@ -1213,7 +1213,7 @@ /** * Macro to return 1 if n is a power of 2, 0 otherwise */ -#define RTE_IS_POWER_OF_2(n) ((n) && !(((n) - 1) & (n))) +#define RTE_IS_POWER_OF_2(n) ((n) != 0 && (((n) - 1) & (n)) == 0) /** * Returns true if n is a power of 2 diff -Nru dpdk-24.11.4/lib/eal/include/rte_common.h dpdk-24.11.8/lib/eal/include/rte_common.h --- dpdk-24.11.4/lib/eal/include/rte_common.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_common.h 2026-10-14 13:10:05.000000000 +0000 @@ -639,8 +639,12 @@ * * Use as spacing between data accessed by different lcores, * to prevent cache thrashing on hardware with speculative prefetching. + * + * Note: Although __COUNTER__ would be better for uniqueness, + * it is not yet (March 2026) part of the C standard, + * so compilation would fail when building in pedantic mode. */ -#define RTE_CACHE_GUARD _RTE_CACHE_GUARD_HELPER1(__COUNTER__) +#define RTE_CACHE_GUARD _RTE_CACHE_GUARD_HELPER1(__LINE__) /*********** PA/IOVA type definitions ********/ diff -Nru dpdk-24.11.4/lib/eal/include/rte_epoll.h dpdk-24.11.8/lib/eal/include/rte_epoll.h --- dpdk-24.11.4/lib/eal/include/rte_epoll.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_epoll.h 2026-10-14 13:10:05.000000000 +0000 @@ -104,7 +104,8 @@ * Note: The caller must take care the object deletion after CTL_DEL. * @return * - On success, zero. - * - On failure, a negative value. + * - On failure, a negative errno value, e.g. -EEXIST if the fd is already + * registered on the epoll instance (a fd shared between vectors). */ int rte_epoll_ctl(int epfd, int op, int fd, diff -Nru dpdk-24.11.4/lib/eal/include/rte_interrupts.h dpdk-24.11.8/lib/eal/include/rte_interrupts.h --- dpdk-24.11.4/lib/eal/include/rte_interrupts.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_interrupts.h 2026-10-14 13:10:05.000000000 +0000 @@ -39,6 +39,12 @@ #define RTE_INTR_VEC_ZERO_OFFSET 0 #define RTE_INTR_VEC_RXTX_OFFSET 1 +/** Interrupt event flags returned by rte_intr_active_events_flags() */ +#define RTE_INTR_EVENT_IN RTE_BIT32(0) /**< Data available to read */ +#define RTE_INTR_EVENT_ERR RTE_BIT32(1) /**< Error condition on fd */ +#define RTE_INTR_EVENT_HUP RTE_BIT32(2) /**< Hang up / disconnect */ +#define RTE_INTR_EVENT_RDHUP RTE_BIT32(3) /**< Read hang up / disconnect */ + /** * The interrupt source type, e.g. UIO, VFIO, ALARM etc. */ @@ -197,6 +203,21 @@ int rte_thread_is_intr(void); /** + * @internal + * Return the event flags for the interrupt currently being processed. + * + * Must be called from an interrupt callback running on the EAL + * interrupt thread. The returned value is a bitmask of + * RTE_INTR_EVENT_* flags. + * + * @return + * Active event flags, or 0 if not in interrupt context or + * on platforms that do not support this feature. + */ +__rte_internal +uint32_t rte_intr_active_events_flags(void); + +/** * It allocates memory for interrupt instance. API takes flag as an argument * which define from where memory should be allocated i.e. using DPDK memory * management library APIs or normal heap allocation. diff -Nru dpdk-24.11.4/lib/eal/include/rte_lcore_var.h dpdk-24.11.8/lib/eal/include/rte_lcore_var.h --- dpdk-24.11.4/lib/eal/include/rte_lcore_var.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_lcore_var.h 2026-10-14 13:10:05.000000000 +0000 @@ -200,7 +200,7 @@ __rte_experimental void * rte_lcore_var_alloc(size_t size, size_t align) - __rte_alloc_size(1) __rte_alloc_align(2); + __rte_alloc_align(2); #ifdef __cplusplus } diff -Nru dpdk-24.11.4/lib/eal/include/rte_thread.h dpdk-24.11.8/lib/eal/include/rte_thread.h --- dpdk-24.11.4/lib/eal/include/rte_thread.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/include/rte_thread.h 2026-10-14 13:10:05.000000000 +0000 @@ -3,6 +3,7 @@ * Copyright (C) 2022 Microsoft Corporation */ +#include #include #include @@ -463,6 +464,20 @@ */ void *rte_thread_value_get(rte_thread_key key); +/** + * Initialize a pthread mutex for use in shared memory accessible by + * multiple DPDK processes. + * + * Sets PTHREAD_PROCESS_SHARED so the mutex can synchronize threads + * across DPDK primary and secondary processes when the mutex resides + * in shared memory (e.g. hugepage memory). + * + * @param mutex + * The mutex to initialize. + */ +__rte_internal +void rte_thread_mutex_init_shared(pthread_mutex_t *mutex); + #ifdef __cplusplus } #endif diff -Nru dpdk-24.11.4/lib/eal/linux/eal_interrupts.c dpdk-24.11.8/lib/eal/linux/eal_interrupts.c --- dpdk-24.11.4/lib/eal/linux/eal_interrupts.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/linux/eal_interrupts.c 2026-10-14 13:10:05.000000000 +0000 @@ -36,6 +36,8 @@ static RTE_DEFINE_PER_LCORE(int, _epfd) = -1; /**< epoll fd per thread */ +static uint32_t active_events; /**< events for active interrupt */ + /** * union for pipe fds. */ @@ -894,6 +896,44 @@ return rc; } +static uint32_t +epoll_to_intr_events(uint32_t epoll_events) +{ + uint32_t ev = 0; + + if (epoll_events & EPOLLIN) + ev |= RTE_INTR_EVENT_IN; + if (epoll_events & EPOLLERR) + ev |= RTE_INTR_EVENT_ERR; + if (epoll_events & EPOLLHUP) + ev |= RTE_INTR_EVENT_HUP; + if (epoll_events & EPOLLRDHUP) + ev |= RTE_INTR_EVENT_RDHUP; + return ev; +} + +static void +eal_intr_source_remove_and_free(struct rte_intr_source *src) +{ + struct rte_intr_callback *cb, *next; + + /* Remove the interrupt source */ + rte_spinlock_lock(&intr_lock); + TAILQ_REMOVE(&intr_sources, src, next); + rte_spinlock_unlock(&intr_lock); + + /* Free callbacks */ + for (cb = TAILQ_FIRST(&src->callbacks); cb; cb = next) { + next = TAILQ_NEXT(cb, next); + TAILQ_REMOVE(&src->callbacks, cb, next); + free(cb); + } + + /* Free the interrupt source */ + rte_intr_instance_free(src->intr_handle); + free(src); +} + static int eal_intr_process_interrupts(struct epoll_event *events, int nfds) { @@ -963,49 +1003,47 @@ } if (bytes_read > 0) { - /** + /* + * Check for epoll error or disconnect events for + * interrupts that are read directly in eal. + */ + if (events[n].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) { + EAL_LOG(ERR, "Disconnect condition on fd %d " + "(events=0x%x), removing from epoll", + events[n].data.fd, events[n].events); + eal_intr_source_remove_and_free(src); + return -1; + } + + /* * read out to clear the ready-to-be-read flag * for epoll_wait. */ bytes_read = read(events[n].data.fd, &buf, bytes_read); - if (bytes_read < 0) { + if (bytes_read > 0) { + call = true; + } else if (bytes_read < 0) { if (errno == EINTR || errno == EWOULDBLOCK) continue; - EAL_LOG(ERR, "Error reading from file " - "descriptor %d: %s", + EAL_LOG(ERR, "Error reading from file descriptor %d: %s", events[n].data.fd, strerror(errno)); - /* - * The device is unplugged or buggy, remove - * it as an interrupt source and return to - * force the wait list to be rebuilt. - */ - rte_spinlock_lock(&intr_lock); - TAILQ_REMOVE(&intr_sources, src, next); - rte_spinlock_unlock(&intr_lock); - - for (cb = TAILQ_FIRST(&src->callbacks); cb; - cb = next) { - next = TAILQ_NEXT(cb, next); - TAILQ_REMOVE(&src->callbacks, cb, next); - free(cb); - } - rte_intr_instance_free(src->intr_handle); - free(src); + } else { + EAL_LOG(ERR, "Read nothing from file descriptor %d", + events[n].data.fd); + } + if (bytes_read <= 0) { + eal_intr_source_remove_and_free(src); return -1; - } else if (bytes_read == 0) - EAL_LOG(ERR, "Read nothing from file " - "descriptor %d", events[n].data.fd); - else - call = true; + } } /* grab a lock, again to call callbacks and update status. */ rte_spinlock_lock(&intr_lock); if (call) { - + active_events = epoll_to_intr_events(events[n].events); /* Finally, call all callbacks. */ TAILQ_FOREACH(cb, &src->callbacks, next) { @@ -1019,6 +1057,7 @@ /*get the lock back. */ rte_spinlock_lock(&intr_lock); } + active_events = 0; } /* we done with that interrupt source, release it. */ src->active = 0; @@ -1394,7 +1433,7 @@ if (!event) { EAL_LOG(ERR, "rte_epoll_event can't be NULL"); - return -1; + return -EINVAL; } /* using per thread epoll fd */ @@ -1411,13 +1450,21 @@ ev.events = event->epdata.event; if (epoll_ctl(epfd, op, fd, &ev) < 0) { + int err = errno; + + /* the fd is already in the set (e.g. shared across vectors): + * keep the event valid and report -EEXIST, not a hard error. + */ + if (op == EPOLL_CTL_ADD && err == EEXIST) + return -EEXIST; + EAL_LOG(ERR, "Error op %d fd %d epoll_ctl, %s", - op, fd, strerror(errno)); + op, fd, strerror(err)); if (op == EPOLL_CTL_ADD) /* rollback status when CTL_ADD fail */ rte_atomic_store_explicit(&event->status, RTE_EPOLL_INVALID, rte_memory_order_relaxed); - return -1; + return -err; } if (op == EPOLL_CTL_DEL && rte_atomic_load_explicit(&event->status, @@ -1468,8 +1515,6 @@ EAL_LOG(DEBUG, "efd %d associated with vec %d added on epfd %d", rev->fd, vec, epfd); - else - rc = -EPERM; break; case RTE_INTR_EVENT_DEL: epfd_op = EPOLL_CTL_DEL; @@ -1481,8 +1526,6 @@ } rc = rte_epoll_ctl(rev->epfd, epfd_op, rev->fd, rev); - if (rc) - rc = -EPERM; break; default: EAL_LOG(ERR, "event op type mismatch"); @@ -1603,3 +1646,12 @@ { return rte_thread_equal(intr_thread, rte_thread_self()); } + +uint32_t +rte_intr_active_events_flags(void) +{ + if (rte_thread_is_intr()) + return active_events; + + return 0; +} diff -Nru dpdk-24.11.4/lib/eal/linux/eal_memalloc.c dpdk-24.11.8/lib/eal/linux/eal_memalloc.c --- dpdk-24.11.4/lib/eal/linux/eal_memalloc.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/linux/eal_memalloc.c 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -27,10 +28,12 @@ #include #include /* for hugetlb-related mmap flags */ +#include #include #include #include #include +#include #include "eal_filesystem.h" #include "eal_internal_cfg.h" @@ -638,10 +641,11 @@ /* we need to trigger a write to the page to enforce page fault and * ensure that page is accessible to us, but we can't overwrite value - * that is already there, so read the old value, and write itback. - * kernel populates the page with zeroes initially. + * that is already there. + * Use an atomic OR with zero to touch the page without changing its contents. */ - *(volatile int *)addr = *(volatile int *)addr; + (void)rte_atomic_fetch_or_explicit((__rte_atomic uint64_t *)addr, 0, + rte_memory_order_relaxed); iova = rte_mem_virt2iova(addr); if (iova == RTE_BAD_PHYS_ADDR) { @@ -1436,8 +1440,10 @@ { struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config; struct rte_memseg_list *primary_msl, *local_msl; - char name[PATH_MAX]; + char name[RTE_FBARRAY_NAME_LEN]; int msl_idx, ret; + uint64_t tsc; + pid_t pid; if (msl->external) return 0; @@ -1446,9 +1452,23 @@ primary_msl = &mcfg->memsegs[msl_idx]; local_msl = &local_memsegs[msl_idx]; - /* create distinct fbarrays for each secondary */ - snprintf(name, RTE_FBARRAY_NAME_LEN, "%s_%i", - primary_msl->memseg_arr.name, getpid()); + /* + * Create distinct fbarrays for each secondary using TSC for uniqueness, + * since PID is not unique across containers (different PID namespaces). + * The worst case name length is: + * Base name: "memseg-1048576k-99-99" ~21 chars + * Suffix "__<16hex>" +24 + * Total = ~45 < RTE_FBARRAY_NAME_LEN 64 + */ + tsc = rte_get_tsc_cycles(); + pid = getpid(); + ret = snprintf(name, sizeof(name), "%s_%d_%"PRIx64, + primary_msl->memseg_arr.name, pid, tsc); + if (ret >= (int)sizeof(name)) { + EAL_LOG(ERR, "fbarray name \"%s_%d_%"PRIx64"\" is too long", + primary_msl->memseg_arr.name, pid, tsc); + return -1; + } ret = rte_fbarray_init(&local_msl->memseg_arr, name, primary_msl->memseg_arr.len, diff -Nru dpdk-24.11.4/lib/eal/unix/rte_thread.c dpdk-24.11.8/lib/eal/unix/rte_thread.c --- dpdk-24.11.4/lib/eal/unix/rte_thread.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/unix/rte_thread.c 2026-10-14 13:10:05.000000000 +0000 @@ -405,3 +405,14 @@ return pthread_getaffinity_np((pthread_t)thread_id.opaque_id, sizeof(*cpuset), cpuset); } + +void +rte_thread_mutex_init_shared(pthread_mutex_t *mutex) +{ + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(mutex, &attr); + pthread_mutexattr_destroy(&attr); +} diff -Nru dpdk-24.11.4/lib/eal/version.map dpdk-24.11.8/lib/eal/version.map --- dpdk-24.11.4/lib/eal/version.map 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/version.map 2026-10-14 13:10:05.000000000 +0000 @@ -408,6 +408,7 @@ rte_eal_get_baseaddr; rte_eal_parse_coremask; rte_firmware_read; + rte_intr_active_events_flags; rte_intr_allow_others; rte_intr_cap_multiple; rte_intr_dev_fd_get; @@ -447,5 +448,6 @@ rte_mem_page_size; rte_mem_unmap; rte_thread_create_internal_control; + rte_thread_mutex_init_shared; rte_thread_set_prefixed_name; }; diff -Nru dpdk-24.11.4/lib/eal/windows/eal_interrupts.c dpdk-24.11.8/lib/eal/windows/eal_interrupts.c --- dpdk-24.11.4/lib/eal/windows/eal_interrupts.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/eal_interrupts.c 2026-10-14 13:10:05.000000000 +0000 @@ -114,6 +114,12 @@ return rte_thread_equal(intr_thread, rte_thread_self()); } +uint32_t +rte_intr_active_events_flags(void) +{ + return 0; +} + int rte_intr_rx_ctl(__rte_unused struct rte_intr_handle *intr_handle, __rte_unused int epfd, __rte_unused int op, diff -Nru dpdk-24.11.4/lib/eal/windows/eal_lcore.c dpdk-24.11.8/lib/eal/windows/eal_lcore.c --- dpdk-24.11.4/lib/eal/windows/eal_lcore.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/eal_lcore.c 2026-10-14 13:10:05.000000000 +0000 @@ -17,13 +17,27 @@ /** Number of logical processors (cores) in a processor group (32 or 64). */ #define EAL_PROCESSOR_GROUP_SIZE (sizeof(KAFFINITY) * CHAR_BIT) +/* + * NUMA_NODE_RELATIONSHIP layout differs: + * - MSVC + modern SDK: GroupCount + GroupMasks[] + * - MinGW-w64: only GroupMask (MinGW headers lag behind Windows SDK ABI changes) + */ +#ifdef RTE_TOOLCHAIN_GCC +#define EAL_NUMA_GROUP_COUNT(numa) (RTE_SET_USED(numa), 1) +#define EAL_NUMA_GROUP_MASKS(numa) (&((numa).GroupMask)) +#else +#define EAL_NUMA_GROUP_COUNT(numa) ((numa).GroupCount) +#define EAL_NUMA_GROUP_MASKS(numa) ((numa).GroupMasks) +#endif + struct lcore_map { - uint8_t socket_id; - uint8_t core_id; + unsigned int socket_id; + unsigned int core_id; }; struct socket_map { uint16_t node_id; + unsigned int lcore_count; }; struct cpu_map { @@ -112,11 +126,15 @@ eal_create_lcore_map(const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *info) { const unsigned int node_id = info->NumaNode.NodeNumber; - const GROUP_AFFINITY *cores = &info->NumaNode.GroupMask; + const GROUP_AFFINITY *group_masks = EAL_NUMA_GROUP_MASKS(info->NumaNode); struct lcore_map *lcore; unsigned int socket_id; + unsigned int group_count; + unsigned int group_no; unsigned int i; + group_count = EAL_NUMA_GROUP_COUNT(info->NumaNode); + /* * NUMA node may be reported multiple times if it includes * cores from different processor groups, e. g. 80 cores @@ -132,20 +150,33 @@ return true; cpu_map.sockets[socket_id].node_id = node_id; + cpu_map.sockets[socket_id].lcore_count = 0; cpu_map.socket_count++; } - for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) { - if ((cores->Mask & ((KAFFINITY)1 << i)) == 0) - continue; + /* Old Windows versions report NUMA nodes with GroupCount == 0 */ + if (group_count == 0) { + group_count = 1; + group_masks = &info->NumaNode.GroupMask; + } - if (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) - return true; + for (group_no = 0; group_no < group_count; group_no++) { + const GROUP_AFFINITY *cores = &group_masks[group_no]; + for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) { + if ((cores->Mask & ((KAFFINITY)1 << i)) == 0) + continue; + + if (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) + return true; - lcore = &cpu_map.lcores[cpu_map.lcore_count]; - lcore->socket_id = socket_id; - lcore->core_id = cores->Group * EAL_PROCESSOR_GROUP_SIZE + i; - cpu_map.lcore_count++; + lcore = &cpu_map.lcores[cpu_map.lcore_count]; + lcore->socket_id = socket_id; + + /* core_id within the socket */ + lcore->core_id = cpu_map.sockets[socket_id].lcore_count; + cpu_map.sockets[socket_id].lcore_count++; + cpu_map.lcore_count++; + } } return false; } @@ -160,8 +191,9 @@ infos = NULL; infos_size = 0; + /* RelationAll is needed to get full multi-group NUMA affinity */ if (!GetLogicalProcessorInformationEx( - RelationNumaNode, NULL, &infos_size)) { + RelationAll, NULL, &infos_size)) { DWORD error = GetLastError(); if (error != ERROR_INSUFFICIENT_BUFFER) { log_early("Cannot get NUMA node info size, error %lu\n", @@ -181,7 +213,7 @@ } if (!GetLogicalProcessorInformationEx( - RelationNumaNode, infos, &infos_size)) { + RelationAll, infos, &infos_size)) { log_early("Cannot get NUMA node information, error %lu\n", GetLastError()); rte_errno = EINVAL; @@ -191,9 +223,11 @@ info = infos; while ((uint8_t *)info - (uint8_t *)infos < infos_size) { - if (eal_create_lcore_map(info)) { - full = true; - break; + if (info->Relationship == RelationNumaNode) { + if (eal_create_lcore_map(info)) { + full = true; + break; + } } info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)( diff -Nru dpdk-24.11.4/lib/eal/windows/getline.c dpdk-24.11.8/lib/eal/windows/getline.c --- dpdk-24.11.4/lib/eal/windows/getline.c 1970-01-01 00:00:00.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/getline.c 2026-10-14 13:10:05.000000000 +0000 @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + */ + +#include + +#include "getline.h" + +ssize_t +getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) +{ + char *ptr, *eptr; + + if (*buf == NULL || *bufsiz == 0) { + *bufsiz = BUFSIZ; + *buf = malloc(*bufsiz); + if (buf == NULL) + return -1; + } + + for (ptr = *buf, eptr = *buf + *bufsiz;;) { + int c = fgetc(fp); + if (c == -1) { + if (feof(fp)) { + ssize_t diff = (ssize_t)(ptr - *buf); + if (diff != 0) { + *ptr = '\0'; + return diff; + } + } + return -1; + } + *ptr++ = c; + if (c == delimiter) { + *ptr = '\0'; + return ptr - *buf; + } + if (ptr + 2 >= eptr) { + char *nbuf; + size_t nbufsiz = *bufsiz * 2; + ssize_t d = ptr - *buf; + nbuf = realloc(*buf, nbufsiz); + if (nbuf == NULL) + return -1; + *buf = nbuf; + *bufsiz = nbufsiz; + eptr = nbuf + nbufsiz; + ptr = nbuf + d; + } + } +} + +ssize_t +getline(char **buf, size_t *bufsiz, FILE *fp) +{ + return getdelim(buf, bufsiz, '\n', fp); +} diff -Nru dpdk-24.11.4/lib/eal/windows/include/getline.h dpdk-24.11.8/lib/eal/windows/include/getline.h --- dpdk-24.11.4/lib/eal/windows/include/getline.h 1970-01-01 00:00:00.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/include/getline.h 2026-10-14 13:10:05.000000000 +0000 @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + */ + +/** + * @file + * getline compat. + * + * This module provides getline() and getdelim(). + */ + +#pragma once + +#include + +#ifndef ssize_t +#define ssize_t ptrdiff_t +#endif + +ssize_t +getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp); + +ssize_t +getline(char **buf, size_t *bufsiz, FILE *fp); diff -Nru dpdk-24.11.4/lib/eal/windows/include/rte_os_shim.h dpdk-24.11.8/lib/eal/windows/include/rte_os_shim.h --- dpdk-24.11.4/lib/eal/windows/include/rte_os_shim.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/include/rte_os_shim.h 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,7 @@ #include #include +#include /** * @file diff -Nru dpdk-24.11.4/lib/eal/windows/meson.build dpdk-24.11.8/lib/eal/windows/meson.build --- dpdk-24.11.4/lib/eal/windows/meson.build 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/meson.build 2026-10-14 13:10:05.000000000 +0000 @@ -17,6 +17,7 @@ 'eal_mp.c', 'eal_thread.c', 'eal_timer.c', + 'getline.c', 'getopt.c', 'rte_thread.c', ) diff -Nru dpdk-24.11.4/lib/eal/windows/rte_thread.c dpdk-24.11.8/lib/eal/windows/rte_thread.c --- dpdk-24.11.4/lib/eal/windows/rte_thread.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/windows/rte_thread.c 2026-10-14 13:10:05.000000000 +0000 @@ -606,3 +606,12 @@ } return ret; } + +/* Note: Windows does not have PTHREAD_PROCESS_SHARED + * and DPDK on Windows only supports single process model. + */ +void +rte_thread_mutex_init_shared(pthread_mutex_t *mutex) +{ + pthread_mutex_init(mutex, NULL); +} diff -Nru dpdk-24.11.4/lib/eal/x86/rte_cycles.c dpdk-24.11.8/lib/eal/x86/rte_cycles.c --- dpdk-24.11.4/lib/eal/x86/rte_cycles.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eal/x86/rte_cycles.c 2026-10-14 13:10:05.000000000 +0000 @@ -145,7 +145,7 @@ /* EBX : TSC/Crystal ratio, ECX : Crystal Hz */ if (b && c) - return c * (b / a); + return (uint64_t)c * b / a; } #ifdef RTE_TOOLCHAIN_MSVC diff -Nru dpdk-24.11.4/lib/ethdev/ethdev_driver.c dpdk-24.11.8/lib/ethdev/ethdev_driver.c --- dpdk-24.11.4/lib/ethdev/ethdev_driver.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ethdev/ethdev_driver.c 2026-10-14 13:10:05.000000000 +0000 @@ -118,7 +118,7 @@ eth_dev->data->port_id = port_id; eth_dev->data->backer_port_id = RTE_MAX_ETHPORTS; eth_dev->data->mtu = RTE_ETHER_MTU; - pthread_mutex_init(ð_dev->data->flow_ops_mutex, NULL); + rte_thread_mutex_init_shared(ð_dev->data->flow_ops_mutex); RTE_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); eth_dev_shared_data->allocated_ports++; @@ -287,7 +287,7 @@ int rte_eth_dev_create(struct rte_device *device, const char *name, size_t priv_data_size, - ethdev_bus_specific_init ethdev_bus_specific_init, + ethdev_bus_specific_init bus_specific_init, void *bus_init_params, ethdev_init_t ethdev_init, void *init_params) { @@ -335,8 +335,8 @@ ethdev->device = device; - if (ethdev_bus_specific_init) { - retval = ethdev_bus_specific_init(ethdev, bus_init_params); + if (bus_specific_init) { + retval = bus_specific_init(ethdev, bus_init_params); if (retval) { RTE_ETHDEV_LOG_LINE(ERR, "ethdev bus specific initialisation failed"); diff -Nru dpdk-24.11.4/lib/ethdev/rte_ethdev.c dpdk-24.11.8/lib/ethdev/rte_ethdev.c --- dpdk-24.11.4/lib/ethdev/rte_ethdev.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ethdev/rte_ethdev.c 2026-10-14 13:10:05.000000000 +0000 @@ -2419,7 +2419,6 @@ if (local_conf.offloads & RTE_ETH_RX_OFFLOAD_TCP_LRO) { uint32_t overhead_len; uint32_t max_rx_pktlen; - int ret; overhead_len = eth_dev_get_overhead_len(dev_info.max_rx_pktlen, dev_info.max_mtu); diff -Nru dpdk-24.11.4/lib/ethdev/rte_ethdev_telemetry.c dpdk-24.11.8/lib/ethdev/rte_ethdev_telemetry.c --- dpdk-24.11.4/lib/ethdev/rte_ethdev_telemetry.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ethdev/rte_ethdev_telemetry.c 2026-10-14 13:10:05.000000000 +0000 @@ -10,6 +10,7 @@ #include "rte_ethdev.h" #include "ethdev_driver.h" +#include "ethdev_private.h" #include "sff_telemetry.h" #include "rte_tm.h" @@ -31,7 +32,7 @@ uint64_t pi; if (params == NULL || strlen(params) == 0 || - !isdigit(*params) || port_id == NULL) + !isdigit((unsigned char)*params) || port_id == NULL) return -EINVAL; pi = strtoul(params, end_param, 0); @@ -477,6 +478,7 @@ const char *qid_param; uint16_t nb_queues; char *end_param; + char *saveptr = NULL; uint64_t qid; int ret; @@ -489,8 +491,8 @@ if (nb_queues == 1 && *end_param == '\0') qid = 0; else { - qid_param = strtok(end_param, ","); - if (!qid_param || strlen(qid_param) == 0 || !isdigit(*qid_param)) + qid_param = strtok_r(end_param, ",", &saveptr); + if (!qid_param || strlen(qid_param) == 0 || !isdigit((unsigned char)*qid_param)) return -EINVAL; qid = strtoul(qid_param, &end_param, 0); @@ -1221,10 +1223,11 @@ eth_dev_parse_tm_params(char *params, uint32_t *result) { const char *splited_param; + char *saveptr = NULL; uint64_t ret; - splited_param = strtok(params, ","); - if (!splited_param || strlen(splited_param) == 0 || !isdigit(*splited_param)) + splited_param = strtok_r(params, ",", &saveptr); + if (!splited_param || strlen(splited_param) == 0 || !isdigit((unsigned char)*splited_param)) return -EINVAL; ret = strtoul(splited_param, ¶ms, 0); diff -Nru dpdk-24.11.4/lib/ethdev/rte_flow.c dpdk-24.11.8/lib/ethdev/rte_flow.c --- dpdk-24.11.4/lib/ethdev/rte_flow.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ethdev/rte_flow.c 2026-10-14 13:10:05.000000000 +0000 @@ -33,7 +33,7 @@ struct rte_flow_desc_data { const char *name; size_t size; - size_t (*desc_fn)(void *dst, const void *src); + size_t (*desc_fn)(void *dst, const void *src, size_t size); }; /** @@ -65,16 +65,17 @@ if (buf != NULL) rte_memcpy(buf, data, (size > sz ? sz : size)); if (rte_type && desc[type].desc_fn) - sz += desc[type].desc_fn(size > 0 ? buf : NULL, data); + sz += desc[type].desc_fn(size > 0 ? buf : NULL, data, + size > sz ? size - sz : 0); return sz; } static size_t -rte_flow_item_flex_conv(void *buf, const void *data) +rte_flow_item_flex_conv(void *buf, const void *data, size_t size) { struct rte_flow_item_flex *dst = buf; const struct rte_flow_item_flex *src = data; - if (buf) { + if (buf && size >= src->length) { dst->pattern = rte_memcpy ((void *)((uintptr_t)(dst + 1)), src->pattern, src->length); @@ -660,13 +661,17 @@ }), size > sizeof(*dst.raw) ? sizeof(*dst.raw) : size); off = sizeof(*dst.raw); - if (type == RTE_FLOW_CONV_ITEM_SPEC || - (type == RTE_FLOW_CONV_ITEM_MASK && - ((spec.raw->length & mask.raw->length) >= - (last.raw->length & mask.raw->length)))) + if (type == RTE_FLOW_CONV_ITEM_SPEC && spec.raw) tmp = spec.raw->length & mask.raw->length; - else + else if (type == RTE_FLOW_CONV_ITEM_MASK && spec.raw && last.raw && + ((spec.raw->length & mask.raw->length) >= + (last.raw->length & mask.raw->length))) + tmp = spec.raw->length & mask.raw->length; + else if (last.raw) tmp = last.raw->length & mask.raw->length; + else + tmp = 0; + if (tmp) { off = RTE_ALIGN_CEIL(off, sizeof(*dst.raw->pattern)); if (size >= off + tmp) { @@ -684,8 +689,8 @@ spec.geneve_opt = item->spec; src.geneve_opt = data; dst.geneve_opt = buf; - tmp = spec.geneve_opt->option_len << 2; - if (size > 0 && src.geneve_opt->data) { + tmp = spec.geneve_opt ? (spec.geneve_opt->option_len << 2) : 0; + if (size >= off + tmp && tmp > 0 && src.geneve_opt->data) { deep_src = (void *)((uintptr_t)(dst.geneve_opt + 1)); dst.geneve_opt->data = rte_memcpy(deep_src, src.geneve_opt->data, diff -Nru dpdk-24.11.4/lib/eventdev/rte_event_eth_rx_adapter.c dpdk-24.11.8/lib/eventdev/rte_event_eth_rx_adapter.c --- dpdk-24.11.4/lib/eventdev/rte_event_eth_rx_adapter.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eventdev/rte_event_eth_rx_adapter.c 2026-10-14 13:10:05.000000000 +0000 @@ -269,8 +269,8 @@ event_eth_rx_timestamp_dynfield_offset, rte_mbuf_timestamp_t *); } -static inline int -rxa_validate_id(uint8_t id) +static inline bool +rxa_validate_id(unsigned long id) { return id < RTE_EVENT_ETH_RX_ADAPTER_MAX_INSTANCE; } @@ -293,21 +293,21 @@ #define RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_ERR_RET(id, retval) do { \ if (!rxa_validate_id(id)) { \ - RTE_EDEV_LOG_ERR("Invalid eth Rx adapter id = %d", id); \ + RTE_EDEV_LOG_ERR("Invalid eth Rx adapter id = %lu", (unsigned long)id); \ return retval; \ } \ } while (0) #define RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_GOTO_ERR_RET(id, retval) do { \ if (!rxa_validate_id(id)) { \ - RTE_EDEV_LOG_ERR("Invalid eth Rx adapter id = %d", id); \ + RTE_EDEV_LOG_ERR("Invalid eth Rx adapter id = %lu", (unsigned long)id); \ ret = retval; \ goto error; \ } \ } while (0) #define RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, retval) do { \ - if ((token) == NULL || strlen(token) == 0 || !isdigit(*token)) { \ + if ((token) == NULL || strlen(token) == 0 || !isdigit((unsigned char)*token)) { \ RTE_EDEV_LOG_ERR("Invalid eth Rx adapter token"); \ ret = retval; \ goto error; \ @@ -315,8 +315,8 @@ } while (0) #define RTE_EVENT_ETH_RX_ADAPTER_PORTID_VALID_OR_GOTO_ERR_RET(port_id, retval) do { \ - if (!rte_eth_dev_is_valid_port(port_id)) { \ - RTE_EDEV_LOG_ERR("Invalid port_id=%u", port_id); \ + if (port_id >= RTE_MAX_ETHPORTS || !rte_eth_dev_is_valid_port(port_id)) { \ + RTE_EDEV_LOG_ERR("Invalid port_id=%lu", (unsigned long)port_id); \ ret = retval; \ goto error; \ } \ @@ -1190,7 +1190,6 @@ static inline bool rxa_intr_ring_dequeue(struct event_eth_rx_adapter *rx_adapter) { - uint32_t n; uint32_t nb_rx = 0; int rxq_empty; struct eth_event_enqueue_buffer *buf; @@ -1259,9 +1258,9 @@ if (rxa_shared_intr(dev_info, queue)) { uint16_t i; uint16_t nb_queues; + uint32_t n = 0; nb_queues = dev_info->dev->data->nb_rx_queues; - n = 0; for (i = dev_info->next_q_idx; i < nb_queues; i++) { uint8_t enq_buffer_full; @@ -1288,7 +1287,7 @@ RTE_MAX_RXTX_INTR_VEC_ID - 1 : 0; } else { - n = rxa_eth_rx(rx_adapter, port, queue, nb_rx, + uint32_t n = rxa_eth_rx(rx_adapter, port, queue, nb_rx, rx_adapter->max_nb_rx, &rxq_empty, buf, stats); rx_adapter->qd_valid = !rxq_empty; @@ -3584,14 +3583,14 @@ const char *params, struct rte_tel_data *d) { - uint8_t rx_adapter_id; + unsigned long rx_adapter_id; struct rte_event_eth_rx_adapter_stats rx_adptr_stats; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; /* Get Rx adapter ID from parameter string */ - rx_adapter_id = atoi(params); + rx_adapter_id = strtoul(params, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_ERR_RET(rx_adapter_id, -EINVAL); /* Get Rx adapter stats */ @@ -3625,13 +3624,13 @@ const char *params, struct rte_tel_data *d __rte_unused) { - uint8_t rx_adapter_id; + unsigned long rx_adapter_id; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; /* Get Rx adapter ID from parameter string */ - rx_adapter_id = atoi(params); + rx_adapter_id = strtoul(params, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_ERR_RET(rx_adapter_id, -EINVAL); /* Reset Rx adapter stats */ @@ -3648,43 +3647,42 @@ const char *params, struct rte_tel_data *d) { - uint8_t rx_adapter_id; - uint16_t rx_queue_id; - int eth_dev_id, ret = -1; - char *token, *l_params; + unsigned long rx_adapter_id, rx_queue_id, eth_dev_id; + int ret = -1; + char *token, *l_params, *saveptr = NULL; struct rte_event_eth_rx_adapter_queue_conf queue_conf; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; /* Get Rx adapter ID from parameter string */ l_params = strdup(params); if (l_params == NULL) return -ENOMEM; - token = strtok(l_params, ","); + token = strtok_r(l_params, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); rx_adapter_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_GOTO_ERR_RET(rx_adapter_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get device ID from parameter string */ eth_dev_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_PORTID_VALID_OR_GOTO_ERR_RET(eth_dev_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get Rx queue ID from parameter string */ rx_queue_id = strtoul(token, NULL, 10); if (rx_queue_id >= rte_eth_devices[eth_dev_id].data->nb_rx_queues) { - RTE_EDEV_LOG_ERR("Invalid rx queue_id %u", rx_queue_id); + RTE_EDEV_LOG_ERR("Invalid rx queue_id %lu", rx_queue_id); ret = -EINVAL; goto error; } - token = strtok(NULL, "\0"); + token = strtok_r(NULL, "\0", &saveptr); if (token != NULL) RTE_EDEV_LOG_ERR("Extra parameters passed to eventdev" " telemetry command, ignoring"); @@ -3720,43 +3718,42 @@ const char *params, struct rte_tel_data *d) { - uint8_t rx_adapter_id; - uint16_t rx_queue_id; - int eth_dev_id, ret = -1; - char *token, *l_params; + unsigned long rx_adapter_id, rx_queue_id, eth_dev_id; + int ret = -1; + char *token, *l_params, *saveptr = NULL; struct rte_event_eth_rx_adapter_queue_stats q_stats; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; /* Get Rx adapter ID from parameter string */ l_params = strdup(params); if (l_params == NULL) return -ENOMEM; - token = strtok(l_params, ","); + token = strtok_r(l_params, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); rx_adapter_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_GOTO_ERR_RET(rx_adapter_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get device ID from parameter string */ eth_dev_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_PORTID_VALID_OR_GOTO_ERR_RET(eth_dev_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get Rx queue ID from parameter string */ rx_queue_id = strtoul(token, NULL, 10); if (rx_queue_id >= rte_eth_devices[eth_dev_id].data->nb_rx_queues) { - RTE_EDEV_LOG_ERR("Invalid rx queue_id %u", rx_queue_id); + RTE_EDEV_LOG_ERR("Invalid rx queue_id %lu", rx_queue_id); ret = -EINVAL; goto error; } - token = strtok(NULL, "\0"); + token = strtok_r(NULL, "\0", &saveptr); if (token != NULL) RTE_EDEV_LOG_ERR("Extra parameters passed to eventdev" " telemetry command, ignoring"); @@ -3791,42 +3788,41 @@ const char *params, struct rte_tel_data *d __rte_unused) { - uint8_t rx_adapter_id; - uint16_t rx_queue_id; - int eth_dev_id, ret = -1; - char *token, *l_params; + unsigned long rx_adapter_id, rx_queue_id, eth_dev_id; + int ret = -1; + char *token, *l_params, *saveptr = NULL; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; /* Get Rx adapter ID from parameter string */ l_params = strdup(params); if (l_params == NULL) return -ENOMEM; - token = strtok(l_params, ","); + token = strtok_r(l_params, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); rx_adapter_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_ID_VALID_OR_GOTO_ERR_RET(rx_adapter_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get device ID from parameter string */ eth_dev_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_PORTID_VALID_OR_GOTO_ERR_RET(eth_dev_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get Rx queue ID from parameter string */ rx_queue_id = strtoul(token, NULL, 10); if (rx_queue_id >= rte_eth_devices[eth_dev_id].data->nb_rx_queues) { - RTE_EDEV_LOG_ERR("Invalid rx queue_id %u", rx_queue_id); + RTE_EDEV_LOG_ERR("Invalid rx queue_id %lu", rx_queue_id); ret = -EINVAL; goto error; } - token = strtok(NULL, "\0"); + token = strtok_r(NULL, "\0", &saveptr); if (token != NULL) RTE_EDEV_LOG_ERR("Extra parameters passed to eventdev" " telemetry command, ignoring"); @@ -3853,35 +3849,35 @@ struct rte_tel_data *d) { uint8_t instance_id; - uint16_t rx_queue_id; - int eth_dev_id, ret = -1; - char *token, *l_params; + unsigned long rx_queue_id, eth_dev_id; + int ret = -1; + char *token, *l_params, *saveptr = NULL; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; l_params = strdup(params); if (l_params == NULL) return -ENOMEM; - token = strtok(l_params, ","); + token = strtok_r(l_params, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get device ID from parameter string */ eth_dev_id = strtoul(token, NULL, 10); RTE_EVENT_ETH_RX_ADAPTER_PORTID_VALID_OR_GOTO_ERR_RET(eth_dev_id, -EINVAL); - token = strtok(NULL, ","); + token = strtok_r(NULL, ",", &saveptr); RTE_EVENT_ETH_RX_ADAPTER_TOKEN_VALID_OR_GOTO_ERR_RET(token, -1); /* Get Rx queue ID from parameter string */ rx_queue_id = strtoul(token, NULL, 10); if (rx_queue_id >= rte_eth_devices[eth_dev_id].data->nb_rx_queues) { - RTE_EDEV_LOG_ERR("Invalid rx queue_id %u", rx_queue_id); + RTE_EDEV_LOG_ERR("Invalid rx queue_id %lu", rx_queue_id); ret = -EINVAL; goto error; } - token = strtok(NULL, "\0"); + token = strtok_r(NULL, "\0", &saveptr); if (token != NULL) RTE_EDEV_LOG_ERR("Extra parameters passed to eventdev" " telemetry command, ignoring"); @@ -3893,7 +3889,7 @@ rx_queue_id, &instance_id)) { RTE_EDEV_LOG_ERR("Failed to get RX adapter instance ID " - " for rx_queue_id = %d", rx_queue_id); + " for rx_queue_id = %lu", rx_queue_id); return -1; } diff -Nru dpdk-24.11.4/lib/eventdev/rte_event_eth_tx_adapter.c dpdk-24.11.8/lib/eventdev/rte_event_eth_tx_adapter.c --- dpdk-24.11.4/lib/eventdev/rte_event_eth_tx_adapter.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eventdev/rte_event_eth_tx_adapter.c 2026-10-14 13:10:05.000000000 +0000 @@ -63,11 +63,11 @@ #define TXA_CHECK_OR_ERR_RET(id) \ do {\ - int ret; \ + int _ret; \ RTE_EVENT_ETH_TX_ADAPTER_ID_VALID_OR_ERR_RET((id), -EINVAL); \ - ret = txa_init(); \ - if (ret != 0) \ - return ret; \ + _ret = txa_init(); \ + if (_ret != 0) \ + return _ret; \ if (!txa_adapter_exist((id))) \ return -EINVAL; \ } while (0) diff -Nru dpdk-24.11.4/lib/eventdev/rte_event_timer_adapter.c dpdk-24.11.8/lib/eventdev/rte_event_timer_adapter.c --- dpdk-24.11.4/lib/eventdev/rte_event_timer_adapter.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/eventdev/rte_event_timer_adapter.c 2026-10-14 13:10:05.000000000 +0000 @@ -1390,16 +1390,15 @@ { struct rte_event_timer_adapter_info adapter_info; struct rte_event_timer_adapter *adapter; - uint16_t adapter_id; + unsigned long adapter_id; int ret; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; - adapter_id = atoi(params); - + adapter_id = strtoul(params, NULL, 10); if (adapters == NULL || adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) { - EVTIM_LOG_ERR("Invalid timer adapter id %u", adapter_id); + EVTIM_LOG_ERR("Invalid timer adapter id %lu", adapter_id); return -EINVAL; } @@ -1407,7 +1406,7 @@ ret = rte_event_timer_adapter_get_info(adapter, &adapter_info); if (ret < 0) { - EVTIM_LOG_ERR("Failed to get info for timer adapter id %u", adapter_id); + EVTIM_LOG_ERR("Failed to get info for timer adapter id %lu", adapter_id); return ret; } @@ -1436,16 +1435,15 @@ { struct rte_event_timer_adapter_stats stats; struct rte_event_timer_adapter *adapter; - uint16_t adapter_id; + unsigned long adapter_id; int ret; - if (params == NULL || strlen(params) == 0 || !isdigit(*params)) + if (params == NULL || strlen(params) == 0 || !isdigit((unsigned char)*params)) return -1; - adapter_id = atoi(params); - + adapter_id = strtoul(params, NULL, 10); if (adapters == NULL || adapter_id >= RTE_EVENT_TIMER_ADAPTER_NUM_MAX) { - EVTIM_LOG_ERR("Invalid timer adapter id %u", adapter_id); + EVTIM_LOG_ERR("Invalid timer adapter id %lu", adapter_id); return -EINVAL; } @@ -1453,7 +1451,7 @@ ret = rte_event_timer_adapter_stats_get(adapter, &stats); if (ret < 0) { - EVTIM_LOG_ERR("Failed to get stats for timer adapter id %u", adapter_id); + EVTIM_LOG_ERR("Failed to get stats for timer adapter id %lu", adapter_id); return ret; } diff -Nru dpdk-24.11.4/lib/fib/dir24_8.c dpdk-24.11.8/lib/fib/dir24_8.c --- dpdk-24.11.4/lib/fib/dir24_8.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/fib/dir24_8.c 2026-10-14 13:10:05.000000000 +0000 @@ -495,13 +495,14 @@ if (parent != NULL) { rte_rib_get_nh(parent, &par_nh); if (par_nh == next_hop) - return 0; + goto successfully_added; } ret = modify_fib(dp, rib, ip, depth, next_hop); if (ret != 0) { rte_rib_remove(rib, ip, depth); return ret; } +successfully_added: if ((depth > 24) && (tmp == NULL)) dp->rsvd_tbl8s++; return 0; diff -Nru dpdk-24.11.4/lib/fib/trie.c dpdk-24.11.8/lib/fib/trie.c --- dpdk-24.11.4/lib/fib/trie.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/fib/trie.c 2026-10-14 13:10:05.000000000 +0000 @@ -12,6 +12,7 @@ #include #include +#include #include "trie.h" #ifdef CC_TRIE_AVX512_SUPPORT @@ -506,19 +507,47 @@ return 0; } +/* + * Count number of TBL8s that can be freed after deleting a prefix or allocated + * after adding a prefix. + */ +static uint8_t +count_empty_levels(const struct rte_rib6_node *node) +{ + struct rte_rib6_node *parent; + uint8_t depth, parent_depth = 24; + + /* more specifics present */ + if (rte_rib6_node_has_children(node)) + return 0; + + rte_rib6_get_depth(node, &depth); + depth = RTE_MAX(depth, 24); + + /* we know parent depth lt a target node depth + * also, there exists tbl8 path up to RTE_ALIGN_CEIL(parent depth, 8) + */ + parent = rte_rib6_get_parent(node); + if (parent != NULL) { + rte_rib6_get_depth(parent, &parent_depth); + parent_depth = RTE_MAX(parent_depth, 24); + } + + return (RTE_ALIGN_CEIL(depth, 8) - RTE_ALIGN_CEIL(parent_depth, 8)) >> 3; +} + int trie_modify(struct rte_fib6 *fib, const struct rte_ipv6_addr *ip, uint8_t depth, uint64_t next_hop, int op) { struct rte_trie_tbl *dp; struct rte_rib6 *rib; - struct rte_rib6_node *tmp = NULL; struct rte_rib6_node *node; struct rte_rib6_node *parent; - struct rte_ipv6_addr ip_masked, tmp_ip; + struct rte_ipv6_addr ip_masked; int ret = 0; uint64_t par_nh, node_nh; - uint8_t tmp_depth, depth_diff = 0, parent_depth = 24; + uint8_t new_levels; if ((fib == NULL) || (ip == NULL) || (depth > RTE_IPV6_MAX_DEPTH)) return -EINVAL; @@ -531,37 +560,6 @@ ip_masked = *ip; rte_ipv6_addr_mask(&ip_masked, depth); - if (depth > 24) { - tmp = rte_rib6_get_nxt(rib, &ip_masked, - RTE_ALIGN_FLOOR(depth, 8), NULL, - RTE_RIB6_GET_NXT_ALL); - if (tmp && op == RTE_FIB6_DEL) { - /* in case of delete operation, skip the prefix we are going to delete */ - rte_rib6_get_ip(tmp, &tmp_ip); - rte_rib6_get_depth(tmp, &tmp_depth); - if (rte_ipv6_addr_eq(&ip_masked, &tmp_ip) && depth == tmp_depth) - tmp = rte_rib6_get_nxt(rib, &ip_masked, - RTE_ALIGN_FLOOR(depth, 8), tmp, RTE_RIB6_GET_NXT_ALL); - } - - if (tmp == NULL) { - tmp = rte_rib6_lookup(rib, ip); - /** - * in case of delete operation, lookup returns the prefix - * we are going to delete. Find the parent. - */ - if (tmp && op == RTE_FIB6_DEL) - tmp = rte_rib6_lookup_parent(tmp); - - if (tmp != NULL) { - rte_rib6_get_depth(tmp, &tmp_depth); - parent_depth = RTE_MAX(tmp_depth, 24); - } - depth_diff = RTE_ALIGN_CEIL(depth, 8) - - RTE_ALIGN_CEIL(parent_depth, 8); - depth_diff = depth_diff >> 3; - } - } node = rte_rib6_lookup_exact(rib, &ip_masked, depth); switch (op) { case RTE_FIB6_ADD: @@ -572,29 +570,34 @@ ret = modify_dp(dp, rib, &ip_masked, depth, next_hop); if (ret == 0) rte_rib6_set_nh(node, next_hop); - return 0; - } - if ((depth > 24) && (dp->rsvd_tbl8s + depth_diff > dp->number_tbl8s)) - return -ENOSPC; + return ret; + } node = rte_rib6_insert(rib, &ip_masked, depth); if (node == NULL) return -rte_errno; + + new_levels = count_empty_levels(node); + if (dp->rsvd_tbl8s + new_levels > dp->number_tbl8s) { + rte_rib6_remove(rib, &ip_masked, depth); + return -ENOSPC; + } + rte_rib6_set_nh(node, next_hop); parent = rte_rib6_lookup_parent(node); if (parent != NULL) { rte_rib6_get_nh(parent, &par_nh); if (par_nh == next_hop) - return 0; + goto successfully_added; } ret = modify_dp(dp, rib, &ip_masked, depth, next_hop); if (ret != 0) { rte_rib6_remove(rib, &ip_masked, depth); return ret; } - - dp->rsvd_tbl8s += depth_diff; +successfully_added: + dp->rsvd_tbl8s += new_levels; return 0; case RTE_FIB6_DEL: if (node == NULL) @@ -612,9 +615,10 @@ if (ret != 0) return ret; - rte_rib6_remove(rib, ip, depth); - dp->rsvd_tbl8s -= depth_diff; + dp->rsvd_tbl8s -= count_empty_levels(node); + rte_rib6_remove(rib, &ip_masked, depth); + return 0; default: break; diff -Nru dpdk-24.11.4/lib/gso/gso_common.c dpdk-24.11.8/lib/gso/gso_common.c --- dpdk-24.11.4/lib/gso/gso_common.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/gso/gso_common.c 2026-10-14 13:10:05.000000000 +0000 @@ -50,8 +50,20 @@ struct rte_mbuf *hdr_segment, *pyld_segment, *prev_segment; uint16_t pkt_in_data_pos, segment_bytes_remaining; uint16_t pyld_len, nb_segs; + uint16_t direct_buf_size, direct_tailroom; bool more_in_pkt, more_out_segs; + /* + * The header must be fully contained in pkt's first segment and must fit + * in a freshly allocated direct_pool mbuf. + */ + direct_buf_size = rte_pktmbuf_data_room_size(direct_pool); + if (unlikely(direct_buf_size <= (uint16_t)RTE_PKTMBUF_HEADROOM)) + return -EINVAL; + direct_tailroom = direct_buf_size - RTE_PKTMBUF_HEADROOM; + if (unlikely(pkt_hdr_offset > pkt->data_len || pkt_hdr_offset > direct_tailroom)) + return -EINVAL; + pkt_in = pkt; nb_segs = 0; more_in_pkt = 1; diff -Nru dpdk-24.11.4/lib/gso/gso_tcp4.c dpdk-24.11.8/lib/gso/gso_tcp4.c --- dpdk-24.11.4/lib/gso/gso_tcp4.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/gso/gso_tcp4.c 2026-10-14 13:10:05.000000000 +0000 @@ -53,11 +53,10 @@ return 0; } - /* Don't process the packet without data */ + /* Don't process the packet without data or hdr larger than seg size */ hdr_offset = pkt->l2_len + pkt->l3_len + pkt->l4_len; - if (unlikely(hdr_offset >= pkt->pkt_len)) { + if (unlikely(hdr_offset >= pkt->pkt_len || hdr_offset >= gso_size)) return 0; - } pyld_unit_size = gso_size - hdr_offset; diff -Nru dpdk-24.11.4/lib/gso/gso_tunnel_tcp4.c dpdk-24.11.8/lib/gso/gso_tunnel_tcp4.c --- dpdk-24.11.4/lib/gso/gso_tunnel_tcp4.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/gso/gso_tunnel_tcp4.c 2026-10-14 13:10:05.000000000 +0000 @@ -77,10 +77,10 @@ } hdr_offset += pkt->l3_len + pkt->l4_len; - /* Don't process the packet without data */ - if (hdr_offset >= pkt->pkt_len) { + /* Don't process the packet without data or hdr larger than seg size */ + if (hdr_offset >= pkt->pkt_len || hdr_offset >= gso_size) return 0; - } + pyld_unit_size = gso_size - hdr_offset; /* Segment the payload */ diff -Nru dpdk-24.11.4/lib/gso/gso_tunnel_udp4.c dpdk-24.11.8/lib/gso/gso_tunnel_udp4.c --- dpdk-24.11.4/lib/gso/gso_tunnel_udp4.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/gso/gso_tunnel_udp4.c 2026-10-14 13:10:05.000000000 +0000 @@ -78,8 +78,8 @@ return 0; hdr_offset += pkt->l3_len; - /* Don't process the packet without data */ - if ((hdr_offset + pkt->l4_len) >= pkt->pkt_len) + /* Don't process the packet without data or hdrs larger than seg size */ + if ((hdr_offset + pkt->l4_len) >= pkt->pkt_len || hdr_offset >= gso_size) return 0; /* pyld_unit_size must be a multiple of 8 because frag_off diff -Nru dpdk-24.11.4/lib/gso/gso_udp4.c dpdk-24.11.8/lib/gso/gso_udp4.c --- dpdk-24.11.4/lib/gso/gso_udp4.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/gso/gso_udp4.c 2026-10-14 13:10:05.000000000 +0000 @@ -62,10 +62,9 @@ */ hdr_offset = pkt->l2_len + pkt->l3_len; - /* Don't process the packet without data. */ - if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) { + /* Don't process the packet without data or header larger than seg size. */ + if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len || hdr_offset >= gso_size)) return 0; - } /* pyld_unit_size must be a multiple of 8 because frag_off * uses 8 bytes as unit. diff -Nru dpdk-24.11.4/lib/hash/rte_cuckoo_hash.c dpdk-24.11.8/lib/hash/rte_cuckoo_hash.c --- dpdk-24.11.4/lib/hash/rte_cuckoo_hash.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/hash/rte_cuckoo_hash.c 2026-10-14 13:10:05.000000000 +0000 @@ -74,6 +74,7 @@ struct __rte_hash_rcu_dq_entry { uint32_t key_idx; uint32_t ext_bkt_idx; + void *old_data; }; struct rte_hash * @@ -681,7 +682,7 @@ } memset(h->buckets, 0, h->num_buckets * sizeof(struct rte_hash_bucket)); - memset(h->key_store, 0, h->key_entry_size * (h->entries + 1)); + memset(h->key_store, 0, (size_t)h->key_entry_size * (h->entries + 1)); *h->tbl_chng_cnt = 0; /* reset the free ring */ @@ -737,6 +738,28 @@ sizeof(uint32_t)); } +/* + * When RCU is configured with a free function, auto-free the overwritten + * data pointer via RCU. + */ +static inline void +__rte_hash_rcu_auto_free_old_data(const struct rte_hash *h, void *d) +{ + struct __rte_hash_rcu_dq_entry rcu_dq_entry = { + .key_idx = EMPTY_SLOT, /* sentinel value for __hash_rcu_qsbr_free_resource */ + .old_data = d, + }; + + if (d == NULL || h->hash_rcu_cfg == NULL || h->hash_rcu_cfg->free_key_data_func == NULL) + return; + + if (h->dq == NULL || rte_rcu_qsbr_dq_enqueue(h->dq, &rcu_dq_entry) != 0) { + /* SYNC mode or enqueue failed in DQ mode */ + rte_rcu_qsbr_synchronize(h->hash_rcu_cfg->v, RTE_QSBR_THRID_INVALID); + h->hash_rcu_cfg->free_key_data_func(h->hash_rcu_cfg->key_data_ptr, d); + } +} + /* Search a key from bucket and update its data. * Writer holds the lock before calling this. */ @@ -746,11 +769,12 @@ { int i; struct rte_hash_key *k, *keys = h->key_store; + void *old_data; for (i = 0; i < RTE_HASH_BUCKET_ENTRIES; i++) { if (bkt->sig_current[i] == sig) { k = (struct rte_hash_key *) ((char *)keys + - bkt->key_idx[i] * h->key_entry_size); + bkt->key_idx[i] * (size_t)h->key_entry_size); if (rte_hash_cmp_eq(key, k->key, h) == 0) { /* The store to application data at *data * should not leak after the store to pdata @@ -758,9 +782,12 @@ * variable. Release the application data * to the readers. */ - rte_atomic_store_explicit(&k->pdata, + old_data = rte_atomic_exchange_explicit(&k->pdata, data, rte_memory_order_release); + + __rte_hash_rcu_auto_free_old_data(h, old_data); + /* * Return index where key is stored, * subtracting the first dummy index @@ -1116,7 +1143,7 @@ return -ENOSPC; } - new_k = RTE_PTR_ADD(keys, slot_id * h->key_entry_size); + new_k = RTE_PTR_ADD(keys, slot_id * (size_t)h->key_entry_size); /* The store to application data (by the application) at *data should * not leak after the store of pdata in the key store. i.e. pdata is * the guard variable. Release the application data to the readers. @@ -1301,7 +1328,7 @@ if (bkt->sig_current[i] == sig && bkt->key_idx[i] != EMPTY_SLOT) { k = (struct rte_hash_key *) ((char *)keys + - bkt->key_idx[i] * h->key_entry_size); + bkt->key_idx[i] * (size_t)h->key_entry_size); if (rte_hash_cmp_eq(key, k->key, h) == 0) { if (data != NULL) @@ -1339,7 +1366,7 @@ rte_memory_order_acquire); if (key_idx != EMPTY_SLOT) { k = (struct rte_hash_key *) ((char *)keys + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); if (rte_hash_cmp_eq(key, k->key, h) == 0) { if (data != NULL) { @@ -1534,10 +1561,19 @@ *((struct __rte_hash_rcu_dq_entry *)e); RTE_SET_USED(n); + + if (rcu_dq_entry.key_idx == EMPTY_SLOT) { + /* Overwrite case: free old data only, do not recycle slot */ + RTE_ASSERT(h->hash_rcu_cfg->free_key_data_func != NULL); + h->hash_rcu_cfg->free_key_data_func(h->hash_rcu_cfg->key_data_ptr, + rcu_dq_entry.old_data); + return; + } + keys = h->key_store; k = (struct rte_hash_key *) ((char *)keys + - rcu_dq_entry.key_idx * h->key_entry_size); + rcu_dq_entry.key_idx * (size_t)h->key_entry_size); key_data = k->pdata; if (h->hash_rcu_cfg->free_key_data_func) h->hash_rcu_cfg->free_key_data_func(h->hash_rcu_cfg->key_data_ptr, @@ -1721,7 +1757,7 @@ rte_memory_order_acquire); if (bkt->sig_current[i] == sig && key_idx != EMPTY_SLOT) { k = (struct rte_hash_key *) ((char *)keys + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); if (rte_hash_cmp_eq(key, k->key, h) == 0) { bkt->sig_current[i] = NULL_SIGNATURE; /* Free the key store index if @@ -1834,18 +1870,15 @@ /* Key index where key is stored, adding the first dummy index */ rcu_dq_entry.key_idx = ret + 1; rcu_dq_entry.ext_bkt_idx = index; - if (h->dq == NULL) { + if (h->dq == NULL || rte_rcu_qsbr_dq_enqueue(h->dq, &rcu_dq_entry) != 0) { /* Wait for quiescent state change if using - * RTE_HASH_QSBR_MODE_SYNC + * RTE_HASH_QSBR_MODE_SYNC or if RCU enqueue failed. */ rte_rcu_qsbr_synchronize(h->hash_rcu_cfg->v, RTE_QSBR_THRID_INVALID); __hash_rcu_qsbr_free_resource((void *)((uintptr_t)h), &rcu_dq_entry, 1); - } else if (h->dq) - /* Push into QSBR FIFO if using RTE_HASH_QSBR_MODE_DQ */ - if (rte_rcu_qsbr_dq_enqueue(h->dq, &rcu_dq_entry) != 0) - HASH_LOG(ERR, "Failed to push QSBR FIFO"); + } } __hash_rw_writer_unlock(h); return ret; @@ -1873,8 +1906,7 @@ RETURN_IF_TRUE(((h == NULL) || (key == NULL)), -EINVAL); struct rte_hash_key *k, *keys = h->key_store; - k = (struct rte_hash_key *) ((char *) keys + (position + 1) * - h->key_entry_size); + k = (struct rte_hash_key *) ((char *) keys + (position + 1) * (size_t)h->key_entry_size); *key = k->key; if (position != @@ -1967,7 +1999,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); rte_prefetch0(key_slot); continue; } @@ -1981,7 +2013,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); rte_prefetch0(key_slot); } } @@ -2006,7 +2038,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); /* * If key index is 0, do not compare key, @@ -2034,7 +2066,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); /* * If key index is 0, do not compare key, @@ -2153,7 +2185,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); rte_prefetch0(key_slot); continue; } @@ -2167,7 +2199,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); rte_prefetch0(key_slot); } } @@ -2193,7 +2225,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); /* * If key index is 0, do not compare key, @@ -2225,7 +2257,7 @@ const struct rte_hash_key *key_slot = (const struct rte_hash_key *)( (const char *)h->key_store + - key_idx * h->key_entry_size); + key_idx * (size_t)h->key_entry_size); /* * If key index is 0, do not compare key, @@ -2576,7 +2608,7 @@ __hash_rw_reader_lock(h); next_key = (struct rte_hash_key *) ((char *)h->key_store + - position * h->key_entry_size); + position * (size_t)h->key_entry_size); /* Return key and data */ *key = next_key->key; *data = next_key->pdata; @@ -2607,7 +2639,7 @@ } __hash_rw_reader_lock(h); next_key = (struct rte_hash_key *) ((char *)h->key_store + - position * h->key_entry_size); + position * (size_t)h->key_entry_size); /* Return key and data */ *key = next_key->key; *data = next_key->pdata; diff -Nru dpdk-24.11.4/lib/hash/rte_hash.h dpdk-24.11.8/lib/hash/rte_hash.h --- dpdk-24.11.4/lib/hash/rte_hash.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/hash/rte_hash.h 2026-10-14 13:10:05.000000000 +0000 @@ -224,7 +224,9 @@ * Thread safety can be enabled by setting flag during * table creation. * If the key exists already in the table, this API updates its value - * with 'data' passed in this API. It is the responsibility of + * with 'data' passed in this API. If RCU is configured with a + * free_key_data_func callback, the old data is automatically + * deferred-freed via RCU. Otherwise, it is the responsibility of * the application to manage any memory associated with the old value. * The readers might still be using the old value even after this API * has returned. @@ -251,7 +253,9 @@ * Thread safety can be enabled by setting flag during * table creation. * If the key exists already in the table, this API updates its value - * with 'data' passed in this API. It is the responsibility of + * with 'data' passed in this API. If RCU is configured with a + * free_key_data_func callback, the old data is automatically + * deferred-freed via RCU. Otherwise, it is the responsibility of * the application to manage any memory associated with the old value. * The readers might still be using the old value even after this API * has returned. diff -Nru dpdk-24.11.4/lib/hash/rte_hash_crc.h dpdk-24.11.8/lib/hash/rte_hash_crc.h --- dpdk-24.11.4/lib/hash/rte_hash_crc.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/hash/rte_hash_crc.h 2026-10-14 13:10:05.000000000 +0000 @@ -127,6 +127,16 @@ unsigned i; uintptr_t pd = (uintptr_t) data; + /* align input to 8 byte boundary if needed */ + if (pd & 0x7) { + unsigned int unaligned_bytes = RTE_MIN(8 - (pd & 0x7), data_len); + for (i = 0; i < unaligned_bytes; i++) { + init_val = rte_hash_crc_1byte(*(const uint8_t *)pd, init_val); + pd++; + data_len--; + } + } + for (i = 0; i < data_len / 8; i++) { init_val = rte_hash_crc_8byte(*(const uint64_t *)pd, init_val); pd += 8; diff -Nru dpdk-24.11.4/lib/hash/rte_thash_x86_gfni.h dpdk-24.11.8/lib/hash/rte_thash_x86_gfni.h --- dpdk-24.11.4/lib/hash/rte_thash_x86_gfni.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/hash/rte_thash_x86_gfni.h 2026-10-14 13:10:05.000000000 +0000 @@ -89,9 +89,9 @@ const __m512i shift_8 = _mm512_set1_epi8(8); __m512i xor_acc = _mm512_setzero_si512(); __m512i perm_bytes = _mm512_setzero_si512(); - __m512i vals, matrixes, tuple_bytes_2; + __m512i vals, matrixes, tuple_bytes_2 = _mm512_setzero_si512(); __m512i tuple_bytes = _mm512_setzero_si512(); - __mmask64 load_mask, permute_mask_2; + __mmask64 load_mask, permute_mask_2 = 0; __mmask64 permute_mask = 0; int chunk_len = 0, i = 0; uint8_t mtrx_msk; diff -Nru dpdk-24.11.4/lib/ip_frag/ip_frag_common.h dpdk-24.11.8/lib/ip_frag/ip_frag_common.h --- dpdk-24.11.4/lib/ip_frag/ip_frag_common.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/ip_frag_common.h 2026-10-14 13:10:05.000000000 +0000 @@ -8,6 +8,7 @@ #include #include +#include #if defined(RTE_ARCH_ARM64) #include diff -Nru dpdk-24.11.4/lib/ip_frag/ip_frag_internal.c dpdk-24.11.8/lib/ip_frag/ip_frag_internal.c --- dpdk-24.11.4/lib/ip_frag/ip_frag_internal.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/ip_frag_internal.c 2026-10-14 13:10:05.000000000 +0000 @@ -9,8 +9,6 @@ #include "ip_frag_common.h" -#define PRIME_VALUE 0xeaad8405 - #define IP_FRAG_TBL_POS(tbl, sig) \ ((tbl)->pkt + ((sig) & (tbl)->entry_mask)) @@ -38,7 +36,7 @@ static inline void -ipv4_frag_hash(const struct ip_frag_key *key, uint32_t *v1, uint32_t *v2) +ipv4_frag_hash(const struct ip_frag_key *key, uint32_t *v1, uint32_t *v2, uint32_t seed) { uint32_t v; const uint32_t *p; @@ -46,12 +44,12 @@ p = (const uint32_t *)&key->src_dst; #if defined(RTE_ARCH_X86) || defined(RTE_ARCH_ARM64) - v = rte_hash_crc_4byte(p[0], PRIME_VALUE); + v = rte_hash_crc_4byte(p[0], seed); v = rte_hash_crc_4byte(p[1], v); v = rte_hash_crc_4byte(key->id, v); #else - v = rte_jhash_3words(p[0], p[1], key->id, PRIME_VALUE); + v = rte_jhash_3words(p[0], p[1], key->id, seed); #endif /* RTE_ARCH_X86 */ *v1 = v; @@ -59,7 +57,7 @@ } static inline void -ipv6_frag_hash(const struct ip_frag_key *key, uint32_t *v1, uint32_t *v2) +ipv6_frag_hash(const struct ip_frag_key *key, uint32_t *v1, uint32_t *v2, uint32_t seed) { uint32_t v; const uint32_t *p; @@ -67,7 +65,7 @@ p = (const uint32_t *) &key->src_dst; #if defined(RTE_ARCH_X86) || defined(RTE_ARCH_ARM64) - v = rte_hash_crc_4byte(p[0], PRIME_VALUE); + v = rte_hash_crc_4byte(p[0], seed); v = rte_hash_crc_4byte(p[1], v); v = rte_hash_crc_4byte(p[2], v); v = rte_hash_crc_4byte(p[3], v); @@ -78,7 +76,7 @@ v = rte_hash_crc_4byte(key->id, v); #else - v = rte_jhash_3words(p[0], p[1], p[2], PRIME_VALUE); + v = rte_jhash_3words(p[0], p[1], p[2], seed); v = rte_jhash_3words(p[3], p[4], p[5], v); v = rte_jhash_3words(p[6], p[7], key->id, v); #endif /* RTE_ARCH_X86 */ @@ -301,9 +299,9 @@ /* different hashing methods for IPv4 and IPv6 */ if (key->key_len == IPV4_KEYLEN) - ipv4_frag_hash(key, &sig1, &sig2); + ipv4_frag_hash(key, &sig1, &sig2, tbl->seed); else - ipv6_frag_hash(key, &sig1, &sig2); + ipv6_frag_hash(key, &sig1, &sig2, tbl->seed); p1 = IP_FRAG_TBL_POS(tbl, sig1); p2 = IP_FRAG_TBL_POS(tbl, sig2); diff -Nru dpdk-24.11.4/lib/ip_frag/ip_reassembly.h dpdk-24.11.8/lib/ip_frag/ip_reassembly.h --- dpdk-24.11.4/lib/ip_frag/ip_reassembly.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/ip_reassembly.h 2026-10-14 13:10:05.000000000 +0000 @@ -79,6 +79,7 @@ uint32_t bucket_entries; /* hash associativity. */ uint32_t nb_entries; /* total size of the table. */ uint32_t nb_buckets; /* num of associativity lines. */ + uint32_t seed; /* hash function init value */ struct ip_frag_pkt *last; /* last used entry. */ struct ip_pkt_list lru; /* LRU list for table entries. */ struct ip_frag_tbl_stat stat; /* statistics counters. */ diff -Nru dpdk-24.11.4/lib/ip_frag/rte_ip_frag_common.c dpdk-24.11.8/lib/ip_frag/rte_ip_frag_common.c --- dpdk-24.11.4/lib/ip_frag/rte_ip_frag_common.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/rte_ip_frag_common.c 2026-10-14 13:10:05.000000000 +0000 @@ -76,6 +76,7 @@ tbl->nb_buckets = bucket_num; tbl->bucket_entries = bucket_entries; tbl->entry_mask = (tbl->nb_entries - 1) & ~(tbl->bucket_entries - 1); + tbl->seed = rte_rand(); TAILQ_INIT(&(tbl->lru)); return tbl; @@ -129,18 +130,18 @@ struct rte_ip_frag_death_row *dr, uint64_t tms) { uint64_t max_cycles; - struct ip_frag_pkt *fp; + struct ip_frag_pkt *fp, *tmp; max_cycles = tbl->max_cycles; - TAILQ_FOREACH(fp, &tbl->lru, lru) - if (max_cycles + fp->start < tms) { - /* check that death row has enough space */ - if (RTE_IP_FRAG_DEATH_ROW_MBUF_LEN - dr->cnt >= - fp->last_idx) - ip_frag_tbl_del(tbl, dr, fp); - else - return; - } else + RTE_TAILQ_FOREACH_SAFE(fp, &tbl->lru, lru, tmp) { + if (max_cycles + fp->start >= tms) + return; + + /* check that death row has enough space */ + if (RTE_IP_FRAG_DEATH_ROW_MBUF_LEN - dr->cnt < fp->last_idx) return; + + ip_frag_tbl_del(tbl, dr, fp); + } } diff -Nru dpdk-24.11.4/lib/ip_frag/rte_ipv4_reassembly.c dpdk-24.11.8/lib/ip_frag/rte_ipv4_reassembly.c --- dpdk-24.11.4/lib/ip_frag/rte_ipv4_reassembly.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/rte_ipv4_reassembly.c 2026-10-14 13:10:05.000000000 +0000 @@ -109,9 +109,15 @@ ip_ofs = (uint16_t)(flag_offset & RTE_IPV4_HDR_OFFSET_MASK); ip_flag = (uint16_t)(flag_offset & RTE_IPV4_HDR_MF_FLAG); + /* + * RFC 791 requires using: source, destination, identifier field and protocol + */ + /* use first 8 bytes only */ memcpy(&key.src_dst[0], &ip_hdr->src_addr, 8); - key.id = ip_hdr->packet_id; + + /* packet_id is 16 bits and proto id is 8 bits */ + key.id = ((uint32_t) ip_hdr->next_proto_id << 16) | ip_hdr->packet_id; key.key_len = IPV4_KEYLEN; ip_ofs *= RTE_IPV4_HDR_OFFSET_UNITS; @@ -128,8 +134,13 @@ tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries, tbl->use_entries); - /* check that fragment length is greater then zero. */ - if (ip_len <= 0) { + /* + * Drop fragments with no payload, and any fragment whose end would + * make the reassembled datagram exceed the maximum IPv4 size. The + * total_length field is 16 bits, so otherwise it is silently + * truncated while the mbuf still holds the full length. + */ + if (ip_len <= 0 || ip_ofs + ip_len + mb->l3_len > UINT16_MAX) { IP_FRAG_MBUF2DR(dr, mb); return NULL; } diff -Nru dpdk-24.11.4/lib/ip_frag/rte_ipv6_reassembly.c dpdk-24.11.8/lib/ip_frag/rte_ipv6_reassembly.c --- dpdk-24.11.4/lib/ip_frag/rte_ipv6_reassembly.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ip_frag/rte_ipv6_reassembly.c 2026-10-14 13:10:05.000000000 +0000 @@ -172,8 +172,35 @@ tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries, tbl->use_entries); - /* check that fragment length is greater then zero. */ - if (ip_len <= 0) { + /* + * Drop fragments with no payload, and any fragment whose end would + * make the reassembled payload exceed 65535 bytes. The payload_len + * field is 16 bits, so otherwise it is silently truncated while the + * mbuf still holds the full length. + */ + if (ip_len <= 0 || ip_ofs + ip_len > UINT16_MAX) { + IP_FRAG_MBUF2DR(dr, mb); + return NULL; + } + + /* + * Only a fragment header directly following the IPv6 header is supported. + * Per-fragment (unfragmentable) extension headers placed + * before the fragment header are not handled: ipv6_frag_reassemble() + * patches the IPv6 header's next-header field and removes the fragment + * header assuming it sits immediately after the IPv6 header, so such a + * fragment would be reassembled into a corrupt datagram. Drop it. + * + * Extension headers after the fragment header (destination options, + * AH, ESP, upper-layer) are part of the fragmentable payload and are + * reassembled as opaque bytes, so they are not affected. The test uses + * the fragment header's position rather than l3_len so that callers + * which include later headers in l3_len are not rejected. + */ + if ((uintptr_t)frag_hdr != (uintptr_t)(ip_hdr + 1)) { + IP_FRAG_LOG(DEBUG, + "%s:%d: drop fragment with header before frag header, offset %zu\n", + __func__, __LINE__, (uintptr_t)frag_hdr - (uintptr_t)ip_hdr); IP_FRAG_MBUF2DR(dr, mb); return NULL; } diff -Nru dpdk-24.11.4/lib/mbuf/rte_mbuf.c dpdk-24.11.8/lib/mbuf/rte_mbuf.c --- dpdk-24.11.4/lib/mbuf/rte_mbuf.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/mbuf/rte_mbuf.c 2026-10-14 13:10:05.000000000 +0000 @@ -599,7 +599,7 @@ __rte_mbuf_sanity_check(m, 1); /* check for request to copy at offset past end of mbuf */ - if (unlikely(off >= m->pkt_len)) + if (unlikely(off > m->pkt_len)) return NULL; mc = rte_pktmbuf_alloc(mp); @@ -612,8 +612,12 @@ __rte_pktmbuf_copy_hdr(mc, m); - /* copied mbuf is not indirect or external */ - mc->ol_flags = m->ol_flags & ~(RTE_MBUF_F_INDIRECT|RTE_MBUF_F_EXTERNAL); + /* + * copy flags except indirect and external, + * while preserving flags of newly allocated mbuf + * (specifically RTE_MBUF_F_EXTERNAL if using pinned external buffer) + */ + mc->ol_flags |= m->ol_flags & ~(RTE_MBUF_F_INDIRECT | RTE_MBUF_F_EXTERNAL); prev = &mc->next; m_last = mc; @@ -713,7 +717,7 @@ const struct rte_mbuf *seg = m; uint32_t buf_off = 0, copy_len; - if (off + len > rte_pktmbuf_pkt_len(m)) + if ((uint64_t)off + len > rte_pktmbuf_pkt_len(m)) return NULL; while (off >= rte_pktmbuf_data_len(seg)) { diff -Nru dpdk-24.11.4/lib/mbuf/rte_mbuf.h dpdk-24.11.8/lib/mbuf/rte_mbuf.h --- dpdk-24.11.4/lib/mbuf/rte_mbuf.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/mbuf/rte_mbuf.h 2026-10-14 13:10:05.000000000 +0000 @@ -1738,7 +1738,7 @@ static inline const void *rte_pktmbuf_read(const struct rte_mbuf *m, uint32_t off, uint32_t len, void *buf) { - if (likely(off + len <= rte_pktmbuf_data_len(m))) + if (likely((uint64_t)off + len <= rte_pktmbuf_data_len(m))) return rte_pktmbuf_mtod_offset(m, char *, off); else return __rte_pktmbuf_read(m, off, len, buf); diff -Nru dpdk-24.11.4/lib/mldev/rte_mldev.h dpdk-24.11.8/lib/mldev/rte_mldev.h --- dpdk-24.11.4/lib/mldev/rte_mldev.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/mldev/rte_mldev.h 2026-10-14 13:10:05.000000000 +0000 @@ -497,7 +497,7 @@ * * The rte_ml_enqueue_burst() function returns the number of inferences it * actually enqueued for processing. A return value equal to *nb_ops* means that - * all packets have been enqueued. + * all inferences have been enqueued. * * @param dev_id * The identifier of the device. @@ -540,7 +540,7 @@ * @param dev_id * The identifier of the device. * @param qp_id - * The index of the queue pair from which to retrieve processed packets. + * The index of the queue pair from which to retrieve processed inferences. * The value must be in the range [0, nb_queue_pairs - 1] previously supplied to * rte_ml_dev_configure(). * @param ops @@ -840,7 +840,7 @@ * Identifier of the model to be started. * * @return - * - 0: Success, Model loaded. + * - 0: Success, Model started. * - < 0: Failure, Error code of the model start driver function. */ __rte_experimental @@ -859,7 +859,7 @@ * Identifier of the model to be stopped. * * @return - * - 0: Success, Model unloaded. + * - 0: Success, Model stopped. * - < 0: Failure, Error code of the model stop driver function. */ __rte_experimental diff -Nru dpdk-24.11.4/lib/net/net_crc_avx512.c dpdk-24.11.8/lib/net/net_crc_avx512.c --- dpdk-24.11.4/lib/net/net_crc_avx512.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/net/net_crc_avx512.c 2026-10-14 13:10:05.000000000 +0000 @@ -180,7 +180,6 @@ __m512i temp, k; __m512i qw0 = _mm512_set1_epi64(0), qw1, qw2, qw3; __m512i fold0, fold1, fold2, fold3; - __mmask16 mask; uint32_t n = 0; int reduction = 0; @@ -260,8 +259,7 @@ res = _mm_xor_si128(res, d); } else { res = _mm_cvtsi32_si128(crc); - mask = byte_len_to_mask_table[data_len]; - d = _mm_maskz_loadu_epi8(mask, data); + d = _mm_maskz_loadu_epi8(byte_len_to_mask_table[data_len], data); res = _mm_xor_si128(res, d); if (data_len > 3) { diff -Nru dpdk-24.11.4/lib/pcapng/rte_pcapng.c dpdk-24.11.8/lib/pcapng/rte_pcapng.c --- dpdk-24.11.4/lib/pcapng/rte_pcapng.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pcapng/rte_pcapng.c 2026-10-14 13:10:05.000000000 +0000 @@ -33,9 +33,6 @@ /* conversion from DPDK speed to PCAPNG */ #define PCAPNG_MBPS_SPEED 1000000ull -/* upper bound for section, stats and interface blocks (in uint32_t) */ -#define PCAPNG_BLKSIZ (2048 / sizeof(uint32_t)) - /* Format of the capture file handle */ struct rte_pcapng { int outfd; /* output file */ @@ -144,8 +141,9 @@ { struct pcapng_section_header *hdr; struct pcapng_option *opt; - uint32_t buf[PCAPNG_BLKSIZ]; + uint32_t *buf; uint32_t len; + ssize_t ret; len = sizeof(*hdr); if (hw) @@ -161,8 +159,9 @@ len += pcapng_optlen(0); len += sizeof(uint32_t); - if (len > sizeof(buf)) - return -1; + buf = malloc(len); + if (buf == NULL) + return -ENOMEM; hdr = (struct pcapng_section_header *)buf; *hdr = (struct pcapng_section_header) { @@ -195,7 +194,9 @@ /* clone block_length after option */ memcpy(opt, &hdr->block_length, sizeof(uint32_t)); - return write(self->outfd, buf, len); + ret = write(self->outfd, buf, len); + free(buf); + return ret < 0 ? -errno : 0; } /* Write an interface block for a DPDK port */ @@ -212,10 +213,11 @@ struct pcapng_option *opt; const uint8_t tsresol = 9; /* nanosecond resolution */ uint32_t len; - uint32_t buf[PCAPNG_BLKSIZ]; + uint32_t *buf; char ifname_buf[IF_NAMESIZE]; char ifhw[256]; uint64_t speed = 0; + int ret; if (rte_eth_dev_info_get(port, &dev_info) < 0) return -1; @@ -266,8 +268,9 @@ len += pcapng_optlen(0); len += sizeof(uint32_t); - if (len > sizeof(buf)) - return -1; + buf = malloc(len); + if (buf == NULL) + return -1; /* ENOMEM */ hdr = (struct pcapng_interface_block *)buf; *hdr = (struct pcapng_interface_block) { @@ -294,16 +297,15 @@ opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE, ifhw, strlen(ifhw)); if (filter) { - size_t len; + const size_t filter_len = strlen(filter) + 1; - len = strlen(filter) + 1; opt->code = PCAPNG_IFB_FILTER; - opt->length = len; + opt->length = filter_len; /* Encoding is that the first octet indicates string vs BPF */ opt->data[0] = 0; memcpy(opt->data + 1, filter, strlen(filter)); - opt = (struct pcapng_option *)((uint8_t *)opt + pcapng_optlen(len)); + opt = (struct pcapng_option *)((uint8_t *)opt + pcapng_optlen(filter_len)); } opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); @@ -311,10 +313,14 @@ /* clone block_length after optionsa */ memcpy(opt, &hdr->block_length, sizeof(uint32_t)); - /* remember the file index */ - self->port_index[port] = self->ports++; + ret = write(self->outfd, buf, len); + free(buf); - return write(self->outfd, buf, len); + /* remember the file index only after successful write */ + if (ret > 0) + self->port_index[port] = self->ports++; + + return ret; } /* @@ -330,7 +336,8 @@ uint64_t start_time = self->offset_ns; uint64_t sample_time; uint32_t optlen, len; - uint32_t buf[PCAPNG_BLKSIZ]; + uint32_t *buf; + ssize_t ret; RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); @@ -350,8 +357,9 @@ optlen += pcapng_optlen(0); len = sizeof(*hdr) + optlen + sizeof(uint32_t); - if (len > sizeof(buf)) - return -1; + buf = malloc(len); + if (buf == NULL) + return -ENOMEM; hdr = (struct pcapng_statistics *)buf; opt = (struct pcapng_option *)(hdr + 1); @@ -382,7 +390,9 @@ /* clone block_length after option */ memcpy(opt, &len, sizeof(uint32_t)); - return write(self->outfd, buf, len); + ret = write(self->outfd, buf, len); + free(buf); + return ret; } uint32_t @@ -534,11 +544,26 @@ if (comment) optlen += pcapng_optlen(strlen(comment)); - /* reserve trailing options and block length */ - opt = (struct pcapng_option *) - rte_pktmbuf_append(mc, optlen + sizeof(uint32_t)); - if (unlikely(opt == NULL)) - goto fail; + /* + * Try to put options at the end of this mbuf. + * If not extend the mbuf by adding another segment. + */ + opt = (struct pcapng_option *)rte_pktmbuf_append(mc, optlen + sizeof(uint32_t)); + if (unlikely(opt == NULL)) { + struct rte_mbuf *ml = rte_pktmbuf_alloc(mp); + + if (unlikely(ml == NULL)) + goto fail; /* mbuf pool is empty */ + + if (unlikely(rte_pktmbuf_chain(mc, ml) != 0)) { + rte_pktmbuf_free(ml); + goto fail; /* too many segments in the mbuf */ + } + + opt = (struct pcapng_option *)rte_pktmbuf_append(mc, optlen + sizeof(uint32_t)); + if (unlikely(opt == NULL)) + goto fail; /* additional segment and still no space */ + } switch (direction) { case RTE_PCAPNG_DIRECTION_IN: @@ -685,6 +710,7 @@ rte_pcapng_t *self; struct timespec ts; uint64_t cycles; + int ret; self = malloc(sizeof(*self)); if (!self) { @@ -704,8 +730,11 @@ for (i = 0; i < RTE_MAX_ETHPORTS; i++) self->port_index[i] = UINT32_MAX; - if (pcapng_section_block(self, osname, hardware, appname, comment) < 0) + ret = pcapng_section_block(self, osname, hardware, appname, comment); + if (ret < 0) { + rte_errno = -ret; goto fail; + } return self; fail: diff -Nru dpdk-24.11.4/lib/pcapng/rte_pcapng.h dpdk-24.11.8/lib/pcapng/rte_pcapng.h --- dpdk-24.11.4/lib/pcapng/rte_pcapng.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pcapng/rte_pcapng.h 2026-10-14 13:10:05.000000000 +0000 @@ -82,6 +82,9 @@ * Interfaces must be added to the output file after opening * and before any packet record. All ports used in packet capture * must be added. + * + * @return + * number of bytes written to file, -1 on failure */ int rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, @@ -121,7 +124,7 @@ * * @return * - The pointer to the new mbuf formatted for pcapng_write - * - NULL if allocation fails. + * - NULL on error such as invalid port or out of memory. */ struct rte_mbuf * rte_pcapng_copy(uint16_t port_id, uint32_t queue, @@ -185,7 +188,10 @@ * @param comment * Optional comment to add to statistics. * @return - * number of bytes written to file, -1 on failure to write file + * On success number of bytes written to file, + * -1 on failure to write file (and errno is set) + * - (-EINVAL) if bad parameter. + * - (-ENOMEM) if unable to allocate resources. */ ssize_t rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port, diff -Nru dpdk-24.11.4/lib/pdcp/pdcp_process.c dpdk-24.11.8/lib/pdcp/pdcp_process.c --- dpdk-24.11.4/lib/pdcp/pdcp_process.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pdcp/pdcp_process.c 2026-10-14 13:10:05.000000000 +0000 @@ -351,6 +351,8 @@ op->auth.data.length = (pkt_len - RTE_PDCP_MAC_I_LEN) << auth_shift; op->auth.digest.data = rte_pktmbuf_mtod_offset(mb, uint8_t *, (pkt_len - RTE_PDCP_MAC_I_LEN)); + op->auth.digest.phys_addr = rte_pktmbuf_iova_offset(mb, + (pkt_len - RTE_PDCP_MAC_I_LEN)); } __rte_crypto_sym_op_attach_sym_session(op, en_priv->crypto_sess); diff -Nru dpdk-24.11.4/lib/pipeline/rte_swx_ctl.c dpdk-24.11.8/lib/pipeline/rte_swx_ctl.c --- dpdk-24.11.4/lib/pipeline/rte_swx_ctl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pipeline/rte_swx_ctl.c 2026-10-14 13:10:05.000000000 +0000 @@ -209,7 +209,7 @@ uint32_t key_size = 0, key_offset = 0, action_data_size = 0, i; if (table->info.n_match_fields) { - uint32_t n_match_fields_em = 0, i; + uint32_t n_match_fields_em = 0; /* Find first (smallest offset) and last (biggest offset) match fields. */ first = &table->mf[0]; @@ -854,22 +854,21 @@ for (i = 0; i < ctl->info.n_selectors; i++) { struct selector *s = &ctl->selectors[i]; - uint32_t i; /* selector_fields. */ free(s->selector_fields); /* groups. */ if (s->groups) - for (i = 0; i < s->info.n_groups_max; i++) - selector_group_members_free(s, i); + for (uint32_t j = 0; j < s->info.n_groups_max; j++) + selector_group_members_free(s, j); free(s->groups); /* pending_groups. */ if (s->pending_groups) - for (i = 0; i < s->info.n_groups_max; i++) - selector_pending_group_members_free(s, i); + for (uint32_t j = 0; j < s->info.n_groups_max; j++) + selector_pending_group_members_free(s, j); free(s->pending_groups); diff -Nru dpdk-24.11.4/lib/pipeline/rte_swx_pipeline.c dpdk-24.11.8/lib/pipeline/rte_swx_pipeline.c --- dpdk-24.11.4/lib/pipeline/rte_swx_pipeline.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pipeline/rte_swx_pipeline.c 2026-10-14 13:10:05.000000000 +0000 @@ -1501,10 +1501,10 @@ header_build(struct rte_swx_pipeline *p) { struct header *h; - uint32_t n_bytes = 0, i; + uint32_t total_bytes = 0, i; TAILQ_FOREACH(h, &p->headers, node) { - n_bytes += h->st->n_bits / 8; + total_bytes += h->st->n_bits / 8; } for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) { @@ -1519,10 +1519,10 @@ sizeof(struct header_out_runtime)); CHECK(t->headers_out, ENOMEM); - t->header_storage = calloc(1, n_bytes); + t->header_storage = calloc(1, total_bytes); CHECK(t->header_storage, ENOMEM); - t->header_out_storage = calloc(1, n_bytes); + t->header_out_storage = calloc(1, total_bytes); CHECK(t->header_out_storage, ENOMEM); TAILQ_FOREACH(h, &p->headers, node) { @@ -2509,7 +2509,7 @@ return 0; } - CHECK(0, EINVAL); + return -EINVAL; } static inline void @@ -3034,7 +3034,7 @@ return 0; } - CHECK(0, EINVAL); + return -EINVAL; } static inline void @@ -3442,7 +3442,7 @@ return 0; } - CHECK(0, EINVAL); + return -EINVAL; } static inline void @@ -13959,7 +13959,6 @@ for (i = 0; i < p->n_instructions; i++) { struct instruction_data *data = &p->instruction_data[i]; - struct instruction_group *g; uint32_t j; /* Continue when the current instruction is not a jump destination. */ @@ -14672,11 +14671,11 @@ /* Action instructions. */ TAILQ_FOREACH(a, &p->actions, node) { - char name[RTE_SWX_NAME_SIZE * 2]; + char action_name[RTE_SWX_NAME_SIZE * 2]; - snprintf(name, sizeof(name), "action_%s_run", a->name); + snprintf(action_name, sizeof(action_name), "action_%s_run", a->name); - p->action_funcs[a->id] = dlsym(lib, name); + p->action_funcs[a->id] = dlsym(lib, action_name); if (!p->action_funcs[a->id]) { status = -EINVAL; goto free; @@ -14691,14 +14690,14 @@ } TAILQ_FOREACH(g, igl, node) { - char name[RTE_SWX_NAME_SIZE * 2]; + char pipeline_name[RTE_SWX_NAME_SIZE * 2]; if (g->first_instr_id == g->last_instr_id) continue; - snprintf(name, sizeof(name), "pipeline_func_%u", g->group_id); + snprintf(pipeline_name, sizeof(pipeline_name), "pipeline_func_%u", g->group_id); - g->func = dlsym(lib, name); + g->func = dlsym(lib, pipeline_name); if (!g->func) { status = -EINVAL; goto free; diff -Nru dpdk-24.11.4/lib/pipeline/rte_swx_pipeline_internal.h dpdk-24.11.8/lib/pipeline/rte_swx_pipeline_internal.h --- dpdk-24.11.4/lib/pipeline/rte_swx_pipeline_internal.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/pipeline/rte_swx_pipeline_internal.h 2026-10-14 13:10:05.000000000 +0000 @@ -1772,14 +1772,14 @@ if ((t->n_headers_out == 2) && (h1->ptr + h1->n_bytes == t->ptr) && (h0->ptr == h0->ptr0)) { - uint32_t offset; + uint32_t ofs; TRACE("Emit handler: header encapsulation.\n"); - offset = h0->n_bytes + h1->n_bytes; - memcpy(t->ptr - offset, h0->ptr, h0->n_bytes); - t->pkt.offset -= offset; - t->pkt.length += offset; + ofs = h0->n_bytes + h1->n_bytes; + memcpy(t->ptr - ofs, h0->ptr, h0->n_bytes); + t->pkt.offset -= ofs; + t->pkt.length += ofs; return; } diff -Nru dpdk-24.11.4/lib/power/power_uncore_ops.h dpdk-24.11.8/lib/power/power_uncore_ops.h --- dpdk-24.11.4/lib/power/power_uncore_ops.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/power/power_uncore_ops.h 2026-10-14 13:10:05.000000000 +0000 @@ -75,33 +75,11 @@ typedef uint32_t (*rte_power_get_uncore_freq_t)(unsigned int pkg, unsigned int die); /** - * Set minimum and maximum uncore frequency for specified die on a package - * to specified index value. + * Set uncore frequency for specified die on a package to specified index value. * It should be protected outside of this function for threadsafe. * * This function should NOT be called in the fast path. * - * @param pkg - * Package number. - * Each physical CPU in a system is referred to as a package. - * @param die - * Die number. - * Each package can have several dies connected together via the uncore mesh. - * @param index - * The index of available frequencies. - * - * @return - * - 1 on success with frequency changed. - * - 0 on success without frequency changed. - * - Negative on error. - */ -typedef int (*rte_power_set_uncore_freq_t)(unsigned int pkg, unsigned int die, uint32_t index); - -/** - * Return the list length of available frequencies in the index array. - * - * This function should NOT be called in the fast path. - * * @param pkg * Package number. * Each physical CPU in a system is referred to as a package. diff -Nru dpdk-24.11.4/lib/power/rte_power_pmd_mgmt.c dpdk-24.11.8/lib/power/rte_power_pmd_mgmt.c --- dpdk-24.11.4/lib/power/rte_power_pmd_mgmt.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/power/rte_power_pmd_mgmt.c 2026-10-14 13:10:05.000000000 +0000 @@ -336,7 +336,7 @@ struct queue_list_entry *queue_conf = arg; struct pmd_core_cfg *lcore_conf; const bool empty = nb_rx == 0; - uint32_t pause_duration = rte_power_pmd_mgmt_get_pause_duration(); + const uint32_t duration = rte_power_pmd_mgmt_get_pause_duration(); lcore_conf = RTE_LCORE_VAR(lcore_cfgs); @@ -356,11 +356,11 @@ if (global_data.intrinsics_support.power_pause) { const uint64_t cur = rte_rdtsc(); const uint64_t wait_tsc = - cur + global_data.tsc_per_us * pause_duration; + cur + global_data.tsc_per_us * duration; rte_power_pause(wait_tsc); } else { uint64_t i; - for (i = 0; i < global_data.pause_per_us * pause_duration; i++) + for (i = 0; i < global_data.pause_per_us * duration; i++) rte_pause(); } } @@ -509,7 +509,8 @@ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); - if (queue_id >= RTE_MAX_QUEUES_PER_PORT || lcore_id >= RTE_MAX_LCORE) { + if (queue_id >= RTE_MAX_QUEUES_PER_PORT || + !rte_lcore_is_enabled(lcore_id)) { ret = -EINVAL; goto end; } @@ -624,7 +625,7 @@ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); - if (lcore_id >= RTE_MAX_LCORE || queue_id >= RTE_MAX_QUEUES_PER_PORT) + if (!rte_lcore_is_enabled(lcore_id) || queue_id >= RTE_MAX_QUEUES_PER_PORT) return -EINVAL; /* check if the queue is stopped */ @@ -721,8 +722,8 @@ int rte_power_pmd_mgmt_set_scaling_freq_min(unsigned int lcore, unsigned int min) { - if (lcore >= RTE_MAX_LCORE) { - POWER_LOG(ERR, "Invalid lcore ID: %u", lcore); + if (!rte_lcore_is_enabled(lcore)) { + POWER_LOG(ERR, "lcore id %u is not enabled", lcore); return -EINVAL; } @@ -738,8 +739,8 @@ int rte_power_pmd_mgmt_set_scaling_freq_max(unsigned int lcore, unsigned int max) { - if (lcore >= RTE_MAX_LCORE) { - POWER_LOG(ERR, "Invalid lcore ID: %u", lcore); + if (!rte_lcore_is_enabled(lcore)) { + POWER_LOG(ERR, "lcore id %u is not enabled", lcore); return -EINVAL; } @@ -759,8 +760,8 @@ int rte_power_pmd_mgmt_get_scaling_freq_min(unsigned int lcore) { - if (lcore >= RTE_MAX_LCORE) { - POWER_LOG(ERR, "Invalid lcore ID: %u", lcore); + if (!rte_lcore_is_enabled(lcore)) { + POWER_LOG(ERR, "lcore id %u is not enabled", lcore); return -EINVAL; } @@ -773,8 +774,8 @@ int rte_power_pmd_mgmt_get_scaling_freq_max(unsigned int lcore) { - if (lcore >= RTE_MAX_LCORE) { - POWER_LOG(ERR, "Invalid lcore ID: %u", lcore); + if (!rte_lcore_is_enabled(lcore)) { + POWER_LOG(ERR, "lcore id %u is not enabled", lcore); return -EINVAL; } diff -Nru dpdk-24.11.4/lib/power/rte_power_uncore.c dpdk-24.11.8/lib/power/rte_power_uncore.c --- dpdk-24.11.4/lib/power/rte_power_uncore.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/power/rte_power_uncore.c 2026-10-14 13:10:05.000000000 +0000 @@ -64,7 +64,7 @@ */ env = RTE_UNCORE_PM_ENV_INTEL_UNCORE; - if (env <= RTE_DIM(uncore_env_str)) { + if (env < RTE_DIM(uncore_env_str)) { RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next) if (strncmp(ops->name, uncore_env_str[env], RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) { diff -Nru dpdk-24.11.4/lib/rcu/rte_rcu_qsbr.h dpdk-24.11.8/lib/rcu/rte_rcu_qsbr.h --- dpdk-24.11.4/lib/rcu/rte_rcu_qsbr.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/rcu/rte_rcu_qsbr.h 2026-10-14 13:10:05.000000000 +0000 @@ -563,7 +563,7 @@ if (c != __RTE_QSBR_CNT_THR_OFFLINE && acked_token > c) acked_token = c; - bmap &= ~(1UL << j); + bmap &= ~RTE_BIT64(j); } } diff -Nru dpdk-24.11.4/lib/rib/rib6_internal.h dpdk-24.11.8/lib/rib/rib6_internal.h --- dpdk-24.11.4/lib/rib/rib6_internal.h 1970-01-01 00:00:00.000000000 +0000 +++ dpdk-24.11.8/lib/rib/rib6_internal.h 2026-10-14 13:10:05.000000000 +0000 @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2026 Maxime Leroy, Free Mobile + */ + +#ifndef RIB6_INTERNAL_H +#define RIB6_INTERNAL_H + +#include + +#include + +struct rte_rib6_node; + +__rte_internal +bool +rte_rib6_node_has_children(const struct rte_rib6_node *node); + +__rte_internal +struct rte_rib6_node * +rte_rib6_get_parent(const struct rte_rib6_node *node); + +#endif /* RIB6_INTERNAL_H */ diff -Nru dpdk-24.11.4/lib/rib/rte_rib6.c dpdk-24.11.8/lib/rib/rte_rib6.c --- dpdk-24.11.4/lib/rib/rte_rib6.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/rib/rte_rib6.c 2026-10-14 13:10:05.000000000 +0000 @@ -18,6 +18,7 @@ #include #include "rib_log.h" +#include "rib6_internal.h" #define RTE_RIB_VALID_NODE 1 /* Maximum length of a RIB6 name. */ @@ -415,6 +416,18 @@ return 0; } +bool +rte_rib6_node_has_children(const struct rte_rib6_node *node) +{ + return node->left != NULL || node->right != NULL; +} + +struct rte_rib6_node * +rte_rib6_get_parent(const struct rte_rib6_node *node) +{ + return node->parent; +} + void * rte_rib6_get_ext(struct rte_rib6_node *node) { diff -Nru dpdk-24.11.4/lib/rib/version.map dpdk-24.11.8/lib/rib/version.map --- dpdk-24.11.4/lib/rib/version.map 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/rib/version.map 2026-10-14 13:10:05.000000000 +0000 @@ -32,3 +32,10 @@ local: *; }; + +INTERNAL { + global: + + rte_rib6_node_has_children; + rte_rib6_get_parent; +}; diff -Nru dpdk-24.11.4/lib/ring/rte_ring_peek_zc.h dpdk-24.11.8/lib/ring/rte_ring_peek_zc.h --- dpdk-24.11.4/lib/ring/rte_ring_peek_zc.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/ring/rte_ring_peek_zc.h 2026-10-14 13:10:05.000000000 +0000 @@ -235,7 +235,7 @@ * If non-NULL, returns the amount of space in the ring after the * reservation operation has finished. * @return - * The number of objects that can be enqueued, either 0 or n + * The actual number of objects that can be enqueued. */ static __rte_always_inline unsigned int rte_ring_enqueue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize, @@ -265,7 +265,7 @@ * If non-NULL, returns the amount of space in the ring after the * reservation operation has finished. * @return - * The number of objects that can be enqueued, either 0 or n. + * The actual number of objects that can be enqueued. */ static __rte_always_inline unsigned int rte_ring_enqueue_zc_burst_start(struct rte_ring *r, unsigned int n, @@ -442,7 +442,7 @@ * If non-NULL, returns the number of remaining ring entries after the * dequeue has finished. * @return - * The number of objects that can be dequeued, either 0 or n. + * The actual number of objects that can be dequeued. */ static __rte_always_inline unsigned int rte_ring_dequeue_zc_burst_elem_start(struct rte_ring *r, unsigned int esize, @@ -471,7 +471,7 @@ * If non-NULL, returns the number of remaining ring entries after the * dequeue has finished. * @return - * The number of objects that can be dequeued, either 0 or n. + * The actual number of objects that can be dequeued. */ static __rte_always_inline unsigned int rte_ring_dequeue_zc_burst_start(struct rte_ring *r, unsigned int n, diff -Nru dpdk-24.11.4/lib/sched/rte_red.h dpdk-24.11.8/lib/sched/rte_red.h --- dpdk-24.11.4/lib/sched/rte_red.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/sched/rte_red.h 2026-10-14 13:10:05.000000000 +0000 @@ -172,8 +172,15 @@ f = (n >> 6) & 0xf; n >>= 10; - if (n < RTE_RED_SCALING) + if (n < RTE_RED_SCALING) { + /* When n == 0, no rounding or shifting needed. + * For n > 0, add 2^(n-1) for rounding before right shift. + * This avoids UB from (1 << -1) when n == 0. + */ + if (n == 0) + return (uint16_t) rte_red_pow2_frac_inv[f]; return (uint16_t) ((rte_red_pow2_frac_inv[f] + (1 << (n - 1))) >> n); + } return 0; } diff -Nru dpdk-24.11.4/lib/security/rte_security.c dpdk-24.11.8/lib/security/rte_security.c --- dpdk-24.11.4/lib/security/rte_security.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/security/rte_security.c 2026-10-14 13:10:05.000000000 +0000 @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -454,6 +456,25 @@ return 0; } +/* Parse an unsigned integer parameter, returning the value or -EINVAL. + * 'max' must be <= INT_MAX. + */ +static int +telemetry_parse_uint(const char *str, char **end, unsigned long max) +{ + unsigned long val; + + if (str == NULL || !isdigit((unsigned char)*str)) + return -EINVAL; + + errno = 0; + val = strtoul(str, end, 0); + if (errno != 0 || val > max) + return -EINVAL; + + return (int)val; +} + static int security_handle_cryptodev_sec_caps(const char *cmd __rte_unused, const char *params, struct rte_tel_data *d) @@ -465,13 +486,10 @@ int dev_id; int rc; - if (!params || strlen(params) == 0 || !isdigit(*params)) + dev_id = telemetry_parse_uint(params, &end_param, RTE_CRYPTO_MAX_DEVS - 1); + if (dev_id < 0 || *end_param != '\0') return -EINVAL; - dev_id = strtoul(params, &end_param, 0); - if (*end_param != '\0') - CDEV_LOG_ERR("Extra parameters passed to command, ignoring"); - rc = security_capabilities_from_dev_id(dev_id, (void *)&capabilities); if (rc < 0) return rc; @@ -493,24 +511,19 @@ { const struct rte_security_capability *capabilities; struct rte_tel_data *crypto_caps; - const char *capa_param; int dev_id, capa_id; int crypto_caps_n; char *end_param; int rc; - if (!params || strlen(params) == 0 || !isdigit(*params)) + dev_id = telemetry_parse_uint(params, &end_param, RTE_CRYPTO_MAX_DEVS - 1); + if (dev_id < 0 || *end_param != ',') return -EINVAL; - dev_id = strtoul(params, &end_param, 0); - capa_param = strtok(end_param, ","); - if (!capa_param || strlen(capa_param) == 0 || !isdigit(*capa_param)) + capa_id = telemetry_parse_uint(end_param + 1, &end_param, INT_MAX); + if (capa_id < 0 || *end_param != '\0') return -EINVAL; - capa_id = strtoul(capa_param, &end_param, 0); - if (*end_param != '\0') - CDEV_LOG_ERR("Extra parameters passed to command, ignoring"); - rc = security_capabilities_from_dev_id(dev_id, (void *)&capabilities); if (rc < 0) return rc; diff -Nru dpdk-24.11.4/lib/table/rte_lru.h dpdk-24.11.8/lib/table/rte_lru.h --- dpdk-24.11.4/lib/table/rte_lru.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_lru.h 2026-10-14 13:10:05.000000000 +0000 @@ -41,33 +41,33 @@ #define lru_update(bucket, mru_val) \ do { \ - uint64_t x, pos, x0, x1, x2, mask; \ + uint64_t _x, _pos, _x0, _x1, _x2, _mask; \ \ - x = bucket->lru_list; \ + _x = bucket->lru_list; \ \ - pos = 4; \ - if ((x >> 48) == ((uint64_t) mru_val)) \ - pos = 3; \ + _pos = 4; \ + if ((_x >> 48) == ((uint64_t) mru_val)) \ + _pos = 3; \ \ - if (((x >> 32) & 0xFFFFLLU) == ((uint64_t) mru_val)) \ - pos = 2; \ + if (((_x >> 32) & 0xFFFFLLU) == ((uint64_t) mru_val)) \ + _pos = 2; \ \ - if (((x >> 16) & 0xFFFFLLU) == ((uint64_t) mru_val)) \ - pos = 1; \ + if (((_x >> 16) & 0xFFFFLLU) == ((uint64_t) mru_val)) \ + _pos = 1; \ \ - if ((x & 0xFFFFLLU) == ((uint64_t) mru_val)) \ - pos = 0; \ + if ((_x & 0xFFFFLLU) == ((uint64_t) mru_val)) \ + _pos = 0; \ \ \ - pos <<= 4; \ - mask = (~0LLU) << pos; \ - x0 = x & (~mask); \ - x1 = (x >> 16) & mask; \ - x2 = (x << (48 - pos)) & (0xFFFFLLU << 48); \ - x = x0 | x1 | x2; \ + _pos <<= 4; \ + _mask = (~0LLU) << _pos; \ + _x0 = _x & (~_mask); \ + _x1 = (_x >> 16) & _mask; \ + _x2 = (_x << (48 - _pos)) & (0xFFFFLLU << 48); \ + _x = _x0 | _x1 | _x2; \ \ - if (pos != 64) \ - bucket->lru_list = x; \ + if (_pos != 64) \ + bucket->lru_list = _x; \ } while (0) #elif (RTE_TABLE_HASH_LRU_STRATEGY == 2) || (RTE_TABLE_HASH_LRU_STRATEGY == 3) diff -Nru dpdk-24.11.4/lib/table/rte_lru_arm64.h dpdk-24.11.8/lib/table/rte_lru_arm64.h --- dpdk-24.11.4/lib/table/rte_lru_arm64.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_lru_arm64.h 2026-10-14 13:10:05.000000000 +0000 @@ -40,16 +40,16 @@ #define lru_update(bucket, mru_val) \ do { \ - const uint64_t orvals[] = {0xFFFFLLU, 0xFFFFLLU << 16, \ + const uint64_t _orvals[] = {0xFFFFLLU, 0xFFFFLLU << 16, \ 0xFFFFLLU << 32, 0xFFFFLLU << 48, 0LLU}; \ - const uint64_t decs[] = {0x1000100010001LLU, 0}; \ - uint64x1_t lru = vdup_n_u64(bucket->lru_list); \ - uint64x1_t vdec = vdup_n_u64(decs[mru_val>>2]); \ + const uint64_t _decs[] = {0x1000100010001LLU, 0}; \ + uint64x1_t _lru = vdup_n_u64(bucket->lru_list); \ + uint64x1_t _vdec = vdup_n_u64(_decs[mru_val>>2]); \ bucket->lru_list = vget_lane_u64(vreinterpret_u64_u16( \ - vsub_u16(vreinterpret_u16_u64(lru), \ - vreinterpret_u16_u64(vdec))), \ + vsub_u16(vreinterpret_u16_u64(_lru), \ + vreinterpret_u16_u64(_vdec))), \ 0); \ - bucket->lru_list |= orvals[mru_val]; \ + bucket->lru_list |= _orvals[mru_val]; \ } while (0) #endif diff -Nru dpdk-24.11.4/lib/table/rte_lru_x86.h dpdk-24.11.8/lib/table/rte_lru_x86.h --- dpdk-24.11.4/lib/table/rte_lru_x86.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_lru_x86.h 2026-10-14 13:10:05.000000000 +0000 @@ -50,9 +50,9 @@ /* Find the minimum value (first zero word, if it's in there) */\ __m128i d = _mm_minpos_epu16(c); \ /* Second word is the index to found word (first word is the value) */\ - unsigned int pos = _mm_extract_epi16(d, 1); \ + unsigned int _pos = _mm_extract_epi16(d, 1); \ /* move the recently used location to top of list */ \ - __m128i k = _mm_shuffle_epi8(b, *((__m128i *) &masks[2 * pos]));\ + __m128i k = _mm_shuffle_epi8(b, *((__m128i *) &masks[2 * _pos]));\ /* Finally, update the original list with the reordered data */ \ bucket->lru_list = _mm_extract_epi64(k, 0); \ /* Phwew! */ \ diff -Nru dpdk-24.11.4/lib/table/rte_swx_table_em.c dpdk-24.11.8/lib/table/rte_swx_table_em.c --- dpdk-24.11.4/lib/table/rte_swx_table_em.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_swx_table_em.c 2026-10-14 13:10:05.000000000 +0000 @@ -620,8 +620,6 @@ return t; TAILQ_FOREACH(entry, entries, node) { - int status; - status = table_add(t, entry); if (status) { table_free(t); diff -Nru dpdk-24.11.4/lib/table/rte_swx_table_learner.c dpdk-24.11.8/lib/table/rte_swx_table_learner.c --- dpdk-24.11.4/lib/table/rte_swx_table_learner.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_swx_table_learner.c 2026-10-14 13:10:05.000000000 +0000 @@ -404,13 +404,13 @@ for (i = 0; i < TABLE_KEYS_PER_BUCKET; i++) { uint64_t time = b->time[i]; uint32_t sig = b->sig[i]; - uint8_t *key = table_bucket_key_get(t, b, i); + uint8_t *k = table_bucket_key_get(t, b, i); time <<= 32; if ((time > input_time) && (sig == m->input_sig) && - t->params.keycmp_func(key, m->input_key, t->params.key_size)) { + t->params.keycmp_func(k, m->input_key, t->params.key_size)) { uint64_t *data = table_bucket_data_get(t, b, i); /* Hit. */ diff -Nru dpdk-24.11.4/lib/table/rte_table_hash_key16.c dpdk-24.11.8/lib/table/rte_table_hash_key16.c --- dpdk-24.11.4/lib/table/rte_table_hash_key16.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_table_hash_key16.c 2026-10-14 13:10:05.000000000 +0000 @@ -1132,12 +1132,10 @@ uint64_t buckets_mask_next = 0; for ( ; buckets_mask; ) { - uint64_t pkt_mask; uint32_t pkt_index; pkt_index = rte_ctz64(buckets_mask); - pkt_mask = 1LLU << pkt_index; - buckets_mask &= ~pkt_mask; + buckets_mask &= ~(1LLU << pkt_index); lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries, buckets_mask_next, f); diff -Nru dpdk-24.11.4/lib/table/rte_table_hash_key32.c dpdk-24.11.8/lib/table/rte_table_hash_key32.c --- dpdk-24.11.4/lib/table/rte_table_hash_key32.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_table_hash_key32.c 2026-10-14 13:10:05.000000000 +0000 @@ -1166,12 +1166,10 @@ uint64_t buckets_mask_next = 0; for ( ; buckets_mask; ) { - uint64_t pkt_mask; uint32_t pkt_index; pkt_index = rte_ctz64(buckets_mask); - pkt_mask = 1LLU << pkt_index; - buckets_mask &= ~pkt_mask; + buckets_mask &= ~(1LLU << pkt_index); lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries, buckets_mask_next, f); diff -Nru dpdk-24.11.4/lib/table/rte_table_hash_key8.c dpdk-24.11.8/lib/table/rte_table_hash_key8.c --- dpdk-24.11.4/lib/table/rte_table_hash_key8.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/table/rte_table_hash_key8.c 2026-10-14 13:10:05.000000000 +0000 @@ -1100,12 +1100,10 @@ uint64_t buckets_mask_next = 0; for ( ; buckets_mask; ) { - uint64_t pkt_mask; uint32_t pkt_index; pkt_index = rte_ctz64(buckets_mask); - pkt_mask = 1LLU << pkt_index; - buckets_mask &= ~pkt_mask; + buckets_mask &= ~(1LLU << pkt_index); lookup_grinder(pkt_index, buckets, keys, pkts_mask_out, entries, buckets_mask_next, f); diff -Nru dpdk-24.11.4/lib/telemetry/telemetry.c dpdk-24.11.8/lib/telemetry/telemetry.c --- dpdk-24.11.4/lib/telemetry/telemetry.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/telemetry/telemetry.c 2026-10-14 13:10:05.000000000 +0000 @@ -412,8 +412,9 @@ int bytes = read(s, buffer, sizeof(buffer) - 1); while (bytes > 0) { buffer[bytes] = 0; - const char *cmd = strtok(buffer, ","); - const char *param = strtok(NULL, "\0"); + char *saveptr = NULL; + const char *cmd = strtok_r(buffer, ",", &saveptr); + const char *param = strtok_r(NULL, "\0", &saveptr); struct cmd_callback cb = {.fn = unknown_command}; int i; diff -Nru dpdk-24.11.4/lib/telemetry/telemetry_data.c dpdk-24.11.8/lib/telemetry/telemetry_data.c --- dpdk-24.11.4/lib/telemetry/telemetry_data.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/telemetry/telemetry_data.c 2026-10-14 13:10:05.000000000 +0000 @@ -94,10 +94,10 @@ rte_tel_data_add_array_container(struct rte_tel_data *d, struct rte_tel_data *val, int keep) { - if (d->type != TEL_ARRAY_CONTAINER || - (val->type != TEL_ARRAY_UINT + if (d->type != TEL_ARRAY_CONTAINER || (val->type != TEL_ARRAY_UINT && val->type != TEL_ARRAY_INT - && val->type != TEL_ARRAY_STRING)) + && val->type != TEL_ARRAY_STRING + && val->type != TEL_DICT)) return -EINVAL; if (d->data_len >= RTE_TEL_MAX_ARRAY_ENTRIES) return -ENOSPC; diff -Nru dpdk-24.11.4/lib/vhost/fd_man.c dpdk-24.11.8/lib/vhost/fd_man.c --- dpdk-24.11.4/lib/vhost/fd_man.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/fd_man.c 2026-10-14 13:10:05.000000000 +0000 @@ -4,13 +4,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include @@ -94,7 +94,7 @@ return fdset; } - fdset = rte_zmalloc(NULL, sizeof(*fdset), 0); + fdset = calloc(1, sizeof(*fdset)); if (!fdset) { VHOST_FDMAN_LOG(ERR, "failed to alloc fdset %s", name); goto err_unlock; @@ -142,7 +142,7 @@ err_epoll: close(fdset->epfd); err_free: - rte_free(fdset); + free(fdset); err_unlock: pthread_mutex_unlock(&fdsets_mutex); @@ -387,9 +387,52 @@ } } - if (pfdset->destroy) + pthread_mutex_lock(&pfdset->fd_mutex); + bool should_destroy = pfdset->destroy; + pthread_mutex_unlock(&pfdset->fd_mutex); + if (should_destroy) break; } return 0; } + +/** + * Destroy the fdset and stop its event dispatch thread. + */ +void +fdset_destroy(struct fdset *pfdset) +{ + uint32_t val; + int i; + + if (pfdset == NULL) + return; + + /* Signal the event dispatch thread to stop */ + pthread_mutex_lock(&pfdset->fd_mutex); + pfdset->destroy = true; + pthread_mutex_unlock(&pfdset->fd_mutex); + + /* Wait for the event dispatch thread to finish */ + rte_thread_join(pfdset->tid, &val); + + /* Close the epoll file descriptor */ + close(pfdset->epfd); + + /* Destroy the mutex */ + pthread_mutex_destroy(&pfdset->fd_mutex); + + /* Remove from global registry */ + pthread_mutex_lock(&fdsets_mutex); + for (i = 0; i < MAX_FDSETS; i++) { + if (fdsets[i] == pfdset) { + fdsets[i] = NULL; + break; + } + } + pthread_mutex_unlock(&fdsets_mutex); + + /* Free the fdset structure */ + free(pfdset); +} diff -Nru dpdk-24.11.4/lib/vhost/fd_man.h dpdk-24.11.8/lib/vhost/fd_man.h --- dpdk-24.11.4/lib/vhost/fd_man.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/fd_man.h 2026-10-14 13:10:05.000000000 +0000 @@ -21,5 +21,6 @@ void fdset_del(struct fdset *pfdset, int fd); int fdset_try_del(struct fdset *pfdset, int fd); +void fdset_destroy(struct fdset *pfdset); #endif diff -Nru dpdk-24.11.4/lib/vhost/socket.c dpdk-24.11.8/lib/vhost/socket.c --- dpdk-24.11.4/lib/vhost/socket.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/socket.c 2026-10-14 13:10:05.000000000 +0000 @@ -1141,6 +1141,13 @@ count = --vhost_user.vsocket_cnt; vhost_user.vsockets[i] = vhost_user.vsockets[count]; vhost_user.vsockets[count] = NULL; + + /* Check if we need to destroy the vhost fdset */ + if (vhost_user.vsocket_cnt == 0 && vhost_user.fdset != NULL) { + fdset_destroy(vhost_user.fdset); + vhost_user.fdset = NULL; + } + pthread_mutex_unlock(&vhost_user.mutex); return 0; } diff -Nru dpdk-24.11.4/lib/vhost/vdpa.c dpdk-24.11.8/lib/vhost/vdpa.c --- dpdk-24.11.4/lib/vhost/vdpa.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vdpa.c 2026-10-14 13:10:05.000000000 +0000 @@ -189,7 +189,9 @@ return -1; if (vq->desc[desc_id].flags & VRING_DESC_F_INDIRECT) { - dlen = vq->desc[desc_id].len; + uint64_t desc_len = vq->desc[desc_id].len; + + dlen = desc_len; nr_descs = dlen / sizeof(struct vring_desc); if (unlikely(nr_descs > vq->size)) return -1; @@ -203,11 +205,11 @@ if (unlikely(!desc_ring)) return -1; - if (unlikely(dlen < vq->desc[desc_id].len)) { + if (unlikely(dlen < desc_len)) { vhost_user_iotlb_rd_lock(vq); idesc = vhost_alloc_copy_ind_table(dev, vq, vq->desc[desc_id].addr, - vq->desc[desc_id].len); + desc_len); vhost_user_iotlb_rd_unlock(vq); if (unlikely(!idesc)) return -1; diff -Nru dpdk-24.11.4/lib/vhost/vduse.c dpdk-24.11.8/lib/vhost/vduse.c --- dpdk-24.11.4/lib/vhost/vduse.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vduse.c 2026-10-14 13:10:05.000000000 +0000 @@ -85,9 +85,10 @@ size = entry.last - entry.start + 1; mmap_addr = mmap(0, size + entry.offset, entry.perm, MAP_SHARED, fd, 0); - if (!mmap_addr) { + if (mmap_addr == MAP_FAILED) { VHOST_CONFIG_LOG(dev->ifname, ERR, - "Failed to mmap IOTLB entry for 0x%" PRIx64, iova); + "Failed to mmap IOTLB entry for 0x%" PRIx64 ": %s", + iova, strerror(errno)); ret = -1; goto close_fd; } @@ -440,13 +441,35 @@ dev->reconnect_log->status = dev->status; resp.result = VDUSE_REQ_RESULT_OK; break; - case VDUSE_UPDATE_IOTLB: + case VDUSE_UPDATE_IOTLB: { + struct vhost_iotlb_msg imsg; + uint32_t i; + VHOST_CONFIG_LOG(dev->ifname, INFO, "\tIOVA range: %" PRIx64 " - %" PRIx64, (uint64_t)req.iova.start, (uint64_t)req.iova.last); vhost_user_iotlb_cache_remove(dev, req.iova.start, req.iova.last - req.iova.start + 1); + + /* Invalidate vring translations if affected by this range */ + imsg.iova = req.iova.start; + imsg.size = req.iova.last - req.iova.start + 1; + + for (i = 0; i < dev->nr_vring; i++) { + vq = dev->virtqueue[i]; + + if (!vq) + continue; + + if (is_vring_iotlb(dev, vq, &imsg)) { + rte_rwlock_write_lock(&vq->access_lock); + vring_invalidate(dev, vq); + rte_rwlock_write_unlock(&vq->access_lock); + } + } + resp.result = VDUSE_REQ_RESULT_OK; break; + } default: resp.result = VDUSE_REQ_RESULT_FAILED; break; diff -Nru dpdk-24.11.4/lib/vhost/vhost.c dpdk-24.11.8/lib/vhost/vhost.c --- dpdk-24.11.4/lib/vhost/vhost.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vhost.c 2026-10-14 13:10:05.000000000 +0000 @@ -581,6 +581,82 @@ return 0; } +static int +is_vring_iotlb_split(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg) +{ + struct vhost_vring_addr *ra; + uint64_t start, end, len; + + start = imsg->iova; + end = start + imsg->size; + + ra = &vq->ring_addrs; + len = sizeof(struct vring_desc) * vq->size; + if (ra->desc_user_addr < end && (ra->desc_user_addr + len) > start) + return 1; + + len = sizeof(struct vring_avail) + sizeof(uint16_t) * vq->size; + if (ra->avail_user_addr < end && (ra->avail_user_addr + len) > start) + return 1; + + len = sizeof(struct vring_used) + + sizeof(struct vring_used_elem) * vq->size; + if (ra->used_user_addr < end && (ra->used_user_addr + len) > start) + return 1; + + if (ra->flags & (1 << VHOST_VRING_F_LOG)) { + len = sizeof(uint64_t); + if (ra->log_guest_addr < end && + (ra->log_guest_addr + len) > start) + return 1; + } + + return 0; +} + +static int +is_vring_iotlb_packed(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg) +{ + struct vhost_vring_addr *ra; + uint64_t start, end, len; + + start = imsg->iova; + end = start + imsg->size; + + ra = &vq->ring_addrs; + len = sizeof(struct vring_packed_desc) * vq->size; + if (ra->desc_user_addr < end && (ra->desc_user_addr + len) > start) + return 1; + + len = sizeof(struct vring_packed_desc_event); + if (ra->avail_user_addr < end && (ra->avail_user_addr + len) > start) + return 1; + + len = sizeof(struct vring_packed_desc_event); + if (ra->used_user_addr < end && (ra->used_user_addr + len) > start) + return 1; + + if (ra->flags & (1 << VHOST_VRING_F_LOG)) { + len = sizeof(uint64_t); + if (ra->log_guest_addr < end && + (ra->log_guest_addr + len) > start) + return 1; + } + + return 0; +} + +int +is_vring_iotlb(struct virtio_net *dev, + struct vhost_virtqueue *vq, + struct vhost_iotlb_msg *imsg) +{ + if (vq_is_packed(dev)) + return is_vring_iotlb_packed(vq, imsg); + else + return is_vring_iotlb_split(vq, imsg); +} + void vring_invalidate(struct virtio_net *dev __rte_unused, struct vhost_virtqueue *vq) { @@ -1084,6 +1160,9 @@ if (unlikely(idx >= vq->size)) return -1; + if (unlikely(idx >= vq->inflight_split->desc_num)) + return -1; + vq->inflight_split->desc[idx].counter = vq->global_counter++; vq->inflight_split->desc[idx].inflight = 1; return 0; @@ -1130,6 +1209,9 @@ if (unlikely(old_free_head >= vq->size)) return -1; + if (unlikely(old_free_head >= inflight_info->desc_num)) + return -1; + free_head = old_free_head; /* init header descriptor */ @@ -1188,6 +1270,9 @@ if (unlikely(idx >= vq->size)) return -1; + if (unlikely(idx >= vq->inflight_split->desc_num)) + return -1; + rte_atomic_thread_fence(rte_memory_order_seq_cst); vq->inflight_split->desc[idx].inflight = 0; @@ -1231,6 +1316,9 @@ if (unlikely(head >= vq->size)) return -1; + if (unlikely(head >= inflight_info->desc_num)) + return -1; + rte_atomic_thread_fence(rte_memory_order_seq_cst); inflight_info->desc[head].inflight = 0; @@ -1313,10 +1401,16 @@ if (unlikely(head >= vq->size)) return -1; + if (unlikely(head >= inflight_info->desc_num)) + return -1; + last = inflight_info->desc[head].last; if (unlikely(last >= vq->size)) return -1; + if (unlikely(last >= inflight_info->desc_num)) + return -1; + inflight_info->desc[last].next = inflight_info->free_head; inflight_info->free_head = head; inflight_info->used_idx += inflight_info->desc[head].num; diff -Nru dpdk-24.11.4/lib/vhost/vhost.h dpdk-24.11.8/lib/vhost/vhost.h --- dpdk-24.11.4/lib/vhost/vhost.h 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vhost.h 2026-10-14 13:10:05.000000000 +0000 @@ -270,8 +270,9 @@ }; #define VHOST_RECONNECT_VERSION 0x0 -#define VHOST_MAX_VRING 0x100 #define VHOST_MAX_QUEUE_PAIRS 0x80 +/* Max vring count: 2 per queue pair plus 1 control queue */ +#define VHOST_MAX_VRING (VHOST_MAX_QUEUE_PAIRS * 2 + 1) struct __rte_cache_aligned vhost_reconnect_vring { uint16_t last_avail_idx; @@ -510,7 +511,7 @@ int extbuf; int linearbuf; - struct vhost_virtqueue *virtqueue[VHOST_MAX_QUEUE_PAIRS * 2]; + struct vhost_virtqueue *virtqueue[VHOST_MAX_VRING]; rte_rwlock_t iotlb_pending_lock; struct vhost_iotlb_entry *iotlb_pool; @@ -917,6 +918,8 @@ __rte_shared_locks_required(&vq->iotlb_lock); void vring_invalidate(struct virtio_net *dev, struct vhost_virtqueue *vq) __rte_exclusive_locks_required(&vq->access_lock); +int is_vring_iotlb(struct virtio_net *dev, struct vhost_virtqueue *vq, + struct vhost_iotlb_msg *imsg); static __rte_always_inline uint64_t vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, diff -Nru dpdk-24.11.4/lib/vhost/vhost_crypto.c dpdk-24.11.8/lib/vhost/vhost_crypto.c --- dpdk-24.11.4/lib/vhost/vhost_crypto.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vhost_crypto.c 2026-10-14 13:10:05.000000000 +0000 @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2017-2018 Intel Corporation */ -#include + #include #include #include #include @@ -207,8 +207,6 @@ uint64_t last_session_id; - uint64_t cache_session_id; - struct rte_cryptodev_sym_session *cache_session; /** socket id for the device */ int socket_id; @@ -614,6 +612,15 @@ } static void +init_wb_data(struct rte_mempool *mp __rte_unused, void *opaque __rte_unused, + void *obj, unsigned int obj_idx __rte_unused) +{ + struct vhost_crypto_writeback_data *wb_data = obj; + + wb_data->next = NULL; +} + +static void write_back_data(struct vhost_crypto_data_req *vc_req) { struct vhost_crypto_writeback_data *wb_data = vc_req->wb, *wb_last; @@ -623,6 +630,8 @@ memset(wb_data->src, 0, wb_data->len); wb_last = wb_data; wb_data = wb_data->next; + + wb_last->next = NULL; rte_mempool_put(vc_req->wb_pool, wb_last); } } @@ -631,9 +640,10 @@ free_wb_data(struct vhost_crypto_writeback_data *wb_data, struct rte_mempool *mp) { - while (wb_data->next != NULL) + if (wb_data->next != NULL) free_wb_data(wb_data->next, mp); + wb_data->next = NULL; rte_mempool_put(mp, wb_data); } @@ -673,7 +683,7 @@ uint32_t max_n_descs) __rte_shared_locks_required(&vc_req->vq->iotlb_lock) { - struct vhost_crypto_writeback_data *wb_data, *head; + struct vhost_crypto_writeback_data *wb_data, *head = NULL; struct vhost_crypto_desc *desc = *cur_desc; uint64_t dlen; uint8_t *dst; @@ -712,8 +722,7 @@ } wb_data = wb_data->next; - } else - wb_data->next = NULL; + } } else offset -= desc->len; @@ -755,8 +764,7 @@ } wb_data = wb_data->next; - } else - wb_data->next = NULL; + } } if (unlikely(desc - head_desc == (int)max_n_descs)) @@ -930,11 +938,11 @@ (req->para.hash_start_src_offset < VHOST_CRYPTO_MAX_DATA_SIZE) && (req->para.len_to_hash <= VHOST_CRYPTO_MAX_DATA_SIZE) && - (req->para.cipher_start_src_offset + req->para.len_to_cipher <= + ((uint64_t)req->para.cipher_start_src_offset + req->para.len_to_cipher <= req->para.src_data_len) && - (req->para.hash_start_src_offset + req->para.len_to_hash <= + ((uint64_t)req->para.hash_start_src_offset + req->para.len_to_hash <= req->para.src_data_len) && - (req->para.dst_data_len + req->para.hash_result_len <= + ((uint64_t)req->para.dst_data_len + req->para.hash_result_len <= VHOST_CRYPTO_MAX_DATA_SIZE))) return VIRTIO_CRYPTO_OK; return VIRTIO_CRYPTO_BADMSG; @@ -1228,23 +1236,15 @@ case VIRTIO_CRYPTO_CIPHER_DECRYPT: session_id = req.header.session_id; - /* one branch to avoid unnecessary table lookup */ - if (vcrypto->cache_session_id != session_id) { - err = rte_hash_lookup_data(vcrypto->session_map, - &session_id, (void **)&session); - if (unlikely(err < 0)) { - err = VIRTIO_CRYPTO_ERR; - VC_LOG_ERR("Failed to find session %"PRIu64, + err = rte_hash_lookup_data(vcrypto->session_map, + &session_id, (void **)&session); + if (unlikely(err < 0)) { + err = VIRTIO_CRYPTO_ERR; + VC_LOG_ERR("Failed to find session %"PRIu64, session_id); - goto error_exit; - } - - vcrypto->cache_session = session; - vcrypto->cache_session_id = session_id; + goto error_exit; } - session = vcrypto->cache_session; - err = rte_crypto_op_attach_sym_session(op, session); if (unlikely(err < 0)) { err = VIRTIO_CRYPTO_ERR; @@ -1298,18 +1298,23 @@ struct rte_mbuf *m_dst = op->sym->m_dst; struct vhost_crypto_data_req *vc_req = rte_mbuf_to_priv(m_src); struct vhost_virtqueue *vq; - uint16_t used_idx, desc_idx; + uint16_t desc_idx; if (unlikely(!vc_req)) { VC_LOG_ERR("Failed to retrieve vc_req"); return NULL; } vq = vc_req->vq; - used_idx = vc_req->desc_idx; + desc_idx = vc_req->desc_idx; if (old_vq && (vq != old_vq)) return vq; + if (unlikely(desc_idx >= vq->size)) { + VC_LOG_ERR("Invalid descriptor index %u", desc_idx); + return NULL; + } + if (unlikely(op->status != RTE_CRYPTO_OP_STATUS_SUCCESS)) vc_req->inhdr->status = VIRTIO_CRYPTO_ERR; else { @@ -1317,8 +1322,7 @@ write_back_data(vc_req); } - desc_idx = vq->avail->ring[used_idx]; - vq->used->ring[desc_idx].id = vq->avail->ring[desc_idx]; + vq->used->ring[desc_idx].id = desc_idx; vq->used->ring[desc_idx].len = vc_req->len; rte_mempool_put(m_src->pool, (void *)m_src); @@ -1407,7 +1411,6 @@ vcrypto->sess_pool = sess_pool; vcrypto->cid = cryptodev_id; - vcrypto->cache_session_id = UINT64_MAX; vcrypto->last_session_id = 1; vcrypto->dev = dev; vcrypto->option = RTE_VHOST_CRYPTO_ZERO_COPY_DISABLE; @@ -1441,7 +1444,7 @@ vcrypto->wb_pool = rte_mempool_create(name, VHOST_CRYPTO_MBUF_POOL_SIZE, sizeof(struct vhost_crypto_writeback_data), - 128, 0, NULL, NULL, NULL, NULL, + 128, 0, NULL, NULL, init_wb_data, NULL, rte_socket_id(), 0); if (!vcrypto->wb_pool) { VC_LOG_ERR("Failed to creath mempool"); @@ -1532,7 +1535,7 @@ vcrypto->wb_pool = rte_mempool_create(name, VHOST_CRYPTO_MBUF_POOL_SIZE, sizeof(struct vhost_crypto_writeback_data), - 128, 0, NULL, NULL, NULL, NULL, + 128, 0, NULL, NULL, init_wb_data, NULL, rte_socket_id(), 0); if (!vcrypto->wb_pool) { VC_LOG_ERR("Failed to creath mbuf pool"); @@ -1617,16 +1620,20 @@ for (i = 0; i < count; i++) { uint16_t used_idx = (start_idx + i) & (vq->size - 1); uint16_t desc_idx = vq->avail->ring[used_idx]; - struct vring_desc *head = &vq->desc[desc_idx]; + struct vring_desc *head; struct rte_crypto_op *op = ops[i]; + if (unlikely(desc_idx >= vq->size)) + break; + + head = &vq->desc[desc_idx]; op->sym->m_src = mbufs[i * 2]; op->sym->m_dst = mbufs[i * 2 + 1]; op->sym->m_src->data_off = 0; op->sym->m_dst->data_off = 0; if (unlikely(vhost_crypto_process_one_req(vcrypto, vq, - op, head, descs, used_idx) < 0)) + op, head, descs, desc_idx) < 0)) break; } @@ -1647,9 +1654,13 @@ for (i = 0; i < count; i++) { uint16_t used_idx = (start_idx + i) & (vq->size - 1); uint16_t desc_idx = vq->avail->ring[used_idx]; - struct vring_desc *head = &vq->desc[desc_idx]; + struct vring_desc *head; struct rte_crypto_op *op = ops[i]; + if (unlikely(desc_idx >= vq->size)) + break; + + head = &vq->desc[desc_idx]; op->sym->m_src = mbufs[i]; op->sym->m_dst = NULL; op->sym->m_src->data_off = 0; diff -Nru dpdk-24.11.4/lib/vhost/vhost_user.c dpdk-24.11.8/lib/vhost/vhost_user.c --- dpdk-24.11.4/lib/vhost/vhost_user.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/vhost_user.c 2026-10-14 13:10:05.000000000 +0000 @@ -266,7 +266,8 @@ dev->guest_pages = NULL; if (dev->log_addr) { - munmap((void *)(uintptr_t)dev->log_addr, dev->log_size); + munmap((void *)(uintptr_t)dev->log_addr, + dev->log_size + dev->log_base - dev->log_addr); dev->log_addr = 0; } @@ -1295,6 +1296,7 @@ void *mmap_addr; uint64_t mmap_size; uint64_t alignment; + struct stat file_stat; int populate; /* Check for memory_size + mmap_offset overflow */ @@ -1334,6 +1336,19 @@ return -1; } + /* Validate mmap_size does not exceed backing file size */ + if (fstat(region->fd, &file_stat) == -1) { + VHOST_CONFIG_LOG(dev->ifname, ERR, + "failed to get backing file size: %s", strerror(errno)); + return -1; + } + if (mmap_size > (uint64_t)file_stat.st_size) { + VHOST_CONFIG_LOG(dev->ifname, ERR, + "mmap size (0x%" PRIx64 ") exceeds backing file size (0x%" PRIx64 ")", + mmap_size, (uint64_t)file_stat.st_size); + return -1; + } + populate = dev->async_copy ? MAP_POPULATE : 0; mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED | populate, region->fd, 0); @@ -2404,7 +2419,7 @@ * mmap from 0 to workaround a hugepage mmap bug: mmap will * fail when offset is not page size aligned. */ - addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, off); + addr = mmap(0, size + off, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); alignment = get_blk_size(fd); close(fd); if (addr == MAP_FAILED) { @@ -2417,7 +2432,8 @@ * multiple VHOST_USER_SET_LOG_BASE. */ if (dev->log_addr) { - munmap((void *)(uintptr_t)dev->log_addr, dev->log_size); + munmap((void *)(uintptr_t)dev->log_addr, + dev->log_size + dev->log_base - dev->log_addr); } dev->log_addr = (uint64_t)(uintptr_t)addr; dev->log_base = dev->log_addr + off; @@ -2555,81 +2571,6 @@ } static int -is_vring_iotlb_split(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg) -{ - struct vhost_vring_addr *ra; - uint64_t start, end, len; - - start = imsg->iova; - end = start + imsg->size; - - ra = &vq->ring_addrs; - len = sizeof(struct vring_desc) * vq->size; - if (ra->desc_user_addr < end && (ra->desc_user_addr + len) > start) - return 1; - - len = sizeof(struct vring_avail) + sizeof(uint16_t) * vq->size; - if (ra->avail_user_addr < end && (ra->avail_user_addr + len) > start) - return 1; - - len = sizeof(struct vring_used) + - sizeof(struct vring_used_elem) * vq->size; - if (ra->used_user_addr < end && (ra->used_user_addr + len) > start) - return 1; - - if (ra->flags & (1 << VHOST_VRING_F_LOG)) { - len = sizeof(uint64_t); - if (ra->log_guest_addr < end && - (ra->log_guest_addr + len) > start) - return 1; - } - - return 0; -} - -static int -is_vring_iotlb_packed(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg) -{ - struct vhost_vring_addr *ra; - uint64_t start, end, len; - - start = imsg->iova; - end = start + imsg->size; - - ra = &vq->ring_addrs; - len = sizeof(struct vring_packed_desc) * vq->size; - if (ra->desc_user_addr < end && (ra->desc_user_addr + len) > start) - return 1; - - len = sizeof(struct vring_packed_desc_event); - if (ra->avail_user_addr < end && (ra->avail_user_addr + len) > start) - return 1; - - len = sizeof(struct vring_packed_desc_event); - if (ra->used_user_addr < end && (ra->used_user_addr + len) > start) - return 1; - - if (ra->flags & (1 << VHOST_VRING_F_LOG)) { - len = sizeof(uint64_t); - if (ra->log_guest_addr < end && - (ra->log_guest_addr + len) > start) - return 1; - } - - return 0; -} - -static int is_vring_iotlb(struct virtio_net *dev, - struct vhost_virtqueue *vq, - struct vhost_iotlb_msg *imsg) -{ - if (vq_is_packed(dev)) - return is_vring_iotlb_packed(vq, imsg); - else - return is_vring_iotlb_split(vq, imsg); -} - -static int vhost_user_get_config(struct virtio_net **pdev, struct vhu_msg_context *ctx, int main_fd __rte_unused) @@ -3031,6 +2972,7 @@ struct vhu_msg_context *ctx) { uint32_t vring_idx; + uint32_t queue_num; switch (ctx->msg.request.frontend) { case VHOST_USER_SET_VRING_KICK: @@ -3054,7 +2996,12 @@ return 0; } - if (vring_idx >= VHOST_MAX_VRING) { + if (rte_vhost_driver_get_queue_num(dev->ifname, &queue_num) < 0) { + VHOST_CONFIG_LOG(dev->ifname, ERR, "failed to get queue num"); + return -1; + } + + if (vring_idx >= queue_num * 2) { VHOST_CONFIG_LOG(dev->ifname, ERR, "invalid vring index: %u", vring_idx); return -1; } diff -Nru dpdk-24.11.4/lib/vhost/virtio_net.c dpdk-24.11.8/lib/vhost/virtio_net.c --- dpdk-24.11.4/lib/vhost/virtio_net.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/virtio_net.c 2026-10-14 13:10:05.000000000 +0000 @@ -774,7 +774,9 @@ *desc_chain_head = idx; if (vq->desc[idx].flags & VRING_DESC_F_INDIRECT) { - dlen = vq->desc[idx].len; + uint64_t desc_len = vq->desc[idx].len; + + dlen = desc_len; nr_descs = dlen / sizeof(struct vring_desc); if (unlikely(nr_descs > vq->size)) return -1; @@ -786,13 +788,13 @@ if (unlikely(!descs)) return -1; - if (unlikely(dlen < vq->desc[idx].len)) { + if (unlikely(dlen < desc_len)) { /* * The indirect desc table is not contiguous * in process VA space, we have to copy it. */ idesc = vhost_alloc_copy_ind_table(dev, vq, - vq->desc[idx].addr, vq->desc[idx].len); + vq->desc[idx].addr, desc_len); if (unlikely(!idesc)) return -1; @@ -897,29 +899,29 @@ uint16_t i; uint32_t nr_descs; uint16_t vec_id = *vec_idx; - uint64_t dlen; + uint64_t desc_len = desc->len; + uint64_t dlen = desc_len; struct vring_packed_desc *descs, *idescs = NULL; - dlen = desc->len; descs = (struct vring_packed_desc *)(uintptr_t) vhost_iova_to_vva(dev, vq, desc->addr, &dlen, VHOST_ACCESS_RO); if (unlikely(!descs)) return -1; - if (unlikely(dlen < desc->len)) { + if (unlikely(dlen < desc_len)) { /* * The indirect desc table is not contiguous * in process VA space, we have to copy it. */ idescs = vhost_alloc_copy_ind_table(dev, - vq, desc->addr, desc->len); + vq, desc->addr, desc_len); if (unlikely(!idescs)) return -1; descs = idescs; } - nr_descs = desc->len / sizeof(struct vring_packed_desc); + nr_descs = desc_len / sizeof(struct vring_packed_desc); if (unlikely(nr_descs >= vq->size)) { free_ind_table(idescs); return -1; @@ -935,8 +937,10 @@ *len += dlen; if (unlikely(map_one_desc(dev, vq, buf_vec, &vec_id, descs[i].addr, dlen, - perm))) + perm))) { + free_ind_table(idescs); return -1; + } } *vec_idx = vec_id; @@ -1013,21 +1017,24 @@ return 0; } -static __rte_noinline void +static __rte_noinline int copy_vnet_hdr_to_desc(struct virtio_net *dev, struct vhost_virtqueue *vq, - struct buf_vector *buf_vec, - struct virtio_net_hdr_mrg_rxbuf *hdr) + struct buf_vector *buf_vec, uint16_t nr_vec, + struct virtio_net_hdr_mrg_rxbuf *hdr, + uint32_t *vec_idx, uint32_t *buf_offset) __rte_shared_locks_required(&vq->iotlb_lock) { - uint64_t len; + uint64_t len = 0; uint64_t remain = dev->vhost_hlen; - uint64_t src = (uint64_t)(uintptr_t)hdr, dst; - uint64_t iova = buf_vec->buf_iova; + uint64_t src = (uint64_t)(uintptr_t)hdr; + uint32_t idx = 0; while (remain) { + uint64_t iova = buf_vec->buf_iova; + uint64_t dst = buf_vec->buf_addr; + len = RTE_MIN(remain, buf_vec->buf_len); - dst = buf_vec->buf_addr; rte_memcpy((void *)(uintptr_t)dst, (void *)(uintptr_t)src, len); @@ -1038,10 +1045,21 @@ iova, len); remain -= len; - iova += len; src += len; - buf_vec++; + + if (remain) { + if (unlikely(idx + 1 >= nr_vec)) + return -1; + + buf_vec++; + idx++; + } } + + *vec_idx = idx; + *buf_offset = (uint32_t)len; + + return 0; } static __rte_always_inline int @@ -1208,9 +1226,6 @@ uint32_t buf_offset, buf_avail; uint64_t buf_addr, buf_iova, buf_len; uint32_t cpy_len; - uint64_t hdr_addr; - struct rte_mbuf *hdr_mbuf; - struct virtio_net_hdr_mrg_rxbuf tmp_hdr, *hdr = NULL; struct vhost_async *async = vq->async; if (unlikely(m == NULL)) @@ -1223,24 +1238,35 @@ if (unlikely(buf_len < dev->vhost_hlen && nr_vec <= 1)) return -1; - hdr_mbuf = m; - hdr_addr = buf_addr; + VHOST_DATA_LOG(dev->ifname, DEBUG, "RX: num merge buffers %d", num_buffers); + if (unlikely(buf_len < dev->vhost_hlen)) { + struct virtio_net_hdr_mrg_rxbuf tmp_hdr; + memset(&tmp_hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf)); - hdr = &tmp_hdr; - } else - hdr = (struct virtio_net_hdr_mrg_rxbuf *)(uintptr_t)hdr_addr; + virtio_enqueue_offload(m, &tmp_hdr.hdr); + if (rxvq_is_mergeable(dev)) + ASSIGN_UNLESS_EQUAL(tmp_hdr.num_buffers, num_buffers); - VHOST_DATA_LOG(dev->ifname, DEBUG, "RX: num merge buffers %d", num_buffers); + if (copy_vnet_hdr_to_desc(dev, vq, buf_vec, nr_vec, + &tmp_hdr, &vec_idx, &buf_offset) < 0) + return -1; - if (unlikely(buf_len < dev->vhost_hlen)) { - buf_offset = dev->vhost_hlen - buf_len; - vec_idx++; buf_addr = buf_vec[vec_idx].buf_addr; buf_iova = buf_vec[vec_idx].buf_iova; buf_len = buf_vec[vec_idx].buf_len; buf_avail = buf_len - buf_offset; } else { + struct virtio_net_hdr_mrg_rxbuf *hdr; + + hdr = (struct virtio_net_hdr_mrg_rxbuf *)(uintptr_t)buf_addr; + virtio_enqueue_offload(m, &hdr->hdr); + if (rxvq_is_mergeable(dev)) + ASSIGN_UNLESS_EQUAL(hdr->num_buffers, num_buffers); + + PRINT_PACKET(dev, (uintptr_t)buf_addr, dev->vhost_hlen, 0); + vhost_log_cache_write_iova(dev, vq, buf_iova, dev->vhost_hlen); + buf_offset = dev->vhost_hlen; buf_avail = buf_len - dev->vhost_hlen; } @@ -1276,25 +1302,6 @@ mbuf_avail = rte_pktmbuf_data_len(m); } - if (hdr_addr) { - virtio_enqueue_offload(hdr_mbuf, &hdr->hdr); - if (rxvq_is_mergeable(dev)) - ASSIGN_UNLESS_EQUAL(hdr->num_buffers, - num_buffers); - - if (unlikely(hdr == &tmp_hdr)) { - copy_vnet_hdr_to_desc(dev, vq, buf_vec, hdr); - } else { - PRINT_PACKET(dev, (uintptr_t)hdr_addr, - dev->vhost_hlen, 0); - vhost_log_cache_write_iova(dev, vq, - buf_vec[0].buf_iova, - dev->vhost_hlen); - } - - hdr_addr = 0; - } - cpy_len = RTE_MIN(buf_avail, mbuf_avail); if (is_async) { diff -Nru dpdk-24.11.4/lib/vhost/virtio_net_ctrl.c dpdk-24.11.8/lib/vhost/virtio_net_ctrl.c --- dpdk-24.11.4/lib/vhost/virtio_net_ctrl.c 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/lib/vhost/virtio_net_ctrl.c 2026-10-14 13:10:05.000000000 +0000 @@ -20,6 +20,7 @@ struct virtio_net_ctrl *ctrl_req; uint16_t head_idx; uint16_t n_descs; + uint32_t data_len; uint8_t *desc_ack; }; @@ -28,7 +29,7 @@ struct virtio_net_ctrl_elem *ctrl_elem) __rte_shared_locks_required(&cvq->iotlb_lock) { - uint16_t avail_idx, desc_idx, n_descs = 0; + uint16_t avail_idx, desc_idx, n_descs = 0, nr_descs, cnt = 0; uint64_t desc_len, desc_addr, desc_iova, data_len = 0; uint8_t *ctrl_req; struct vring_desc *descs; @@ -59,12 +60,19 @@ goto err; } + nr_descs = desc_len / sizeof(struct vring_desc); desc_idx = 0; } else { descs = cvq->desc; + nr_descs = cvq->size; } while (1) { + if (unlikely(desc_idx >= nr_descs || cnt++ >= nr_descs)) { + VHOST_CONFIG_LOG(dev->ifname, ERR, "Invalid ctrl descriptor chain"); + goto err; + } + desc_len = descs[desc_idx].len; desc_iova = descs[desc_idx].addr; @@ -128,9 +136,12 @@ VHOST_CONFIG_LOG(dev->ifname, ERR, "Failed to alloc ctrl request"); goto err; } + ctrl_elem->data_len = data_len; ctrl_req = (uint8_t *)ctrl_elem->ctrl_req; + uint64_t copied = 0; + if (cvq->desc[desc_idx].flags & VRING_DESC_F_INDIRECT) { desc_len = cvq->desc[desc_idx].len; desc_iova = cvq->desc[desc_idx].addr; @@ -142,12 +153,23 @@ goto free_err; } + nr_descs = desc_len / sizeof(struct vring_desc); desc_idx = 0; } else { descs = cvq->desc; + nr_descs = cvq->size; } - while (!(descs[desc_idx].flags & VRING_DESC_F_WRITE)) { + cnt = 0; + while (1) { + if (unlikely(desc_idx >= nr_descs || cnt++ >= nr_descs)) { + VHOST_CONFIG_LOG(dev->ifname, ERR, "Invalid ctrl descriptor chain"); + goto free_err; + } + + if (descs[desc_idx].flags & VRING_DESC_F_WRITE) + break; + desc_len = descs[desc_idx].len; desc_iova = descs[desc_idx].addr; @@ -157,8 +179,14 @@ goto free_err; } + if (copied + desc_len > data_len) { + VHOST_CONFIG_LOG(dev->ifname, ERR, "Descriptor length overflow detected"); + goto free_err; + } + memcpy(ctrl_req, (void *)(uintptr_t)desc_addr, desc_len); ctrl_req += desc_len; + copied += desc_len; if (!(descs[desc_idx].flags & VRING_DESC_F_NEXT)) break; @@ -187,7 +215,8 @@ } static uint8_t -virtio_net_ctrl_handle_req(struct virtio_net *dev, struct virtio_net_ctrl *ctrl_req) +virtio_net_ctrl_handle_req(struct virtio_net *dev, struct virtio_net_ctrl *ctrl_req, + uint32_t data_len) { uint8_t ret = VIRTIO_NET_ERR; @@ -196,6 +225,12 @@ uint16_t queue_pairs; uint32_t i; + if (data_len < sizeof(*ctrl_req) + sizeof(queue_pairs)) { + VHOST_CONFIG_LOG(dev->ifname, ERR, + "Invalid MQ control request size"); + return VIRTIO_NET_ERR; + } + queue_pairs = *(uint16_t *)(uintptr_t)ctrl_req->command_data; VHOST_CONFIG_LOG(dev->ifname, INFO, "Ctrl req: MQ %u queue pairs", queue_pairs); ret = VIRTIO_NET_OK; @@ -270,7 +305,8 @@ if (ret <= 0) break; - *ctrl_elem.desc_ack = virtio_net_ctrl_handle_req(dev, ctrl_elem.ctrl_req); + *ctrl_elem.desc_ack = virtio_net_ctrl_handle_req(dev, ctrl_elem.ctrl_req, + ctrl_elem.data_len); ret = virtio_net_ctrl_push(dev, &ctrl_elem); if (ret < 0) diff -Nru dpdk-24.11.4/license/exceptions.txt dpdk-24.11.8/license/exceptions.txt --- dpdk-24.11.4/license/exceptions.txt 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/license/exceptions.txt 2026-10-14 13:10:05.000000000 +0000 @@ -17,4 +17,6 @@ 3.ISC AND BSD-2-Clause 10/23/2019 12/18/2019 lib/eal/windows/getopt.c 4. MIT 10/19/2022 10/18/2022 drivers/net/gve/base/* +5.BSD-2-Clause 28/05/2025 30/05/2025 lib/eal/windows/include/getline.h +6.BSD-2-Clause 28/05/2025 30/05/2025 lib/eal/windows/getline.c --------------------------------------------------------------------------------------------------- diff -Nru dpdk-24.11.4/usertools/dpdk-pmdinfo.py dpdk-24.11.8/usertools/dpdk-pmdinfo.py --- dpdk-24.11.4/usertools/dpdk-pmdinfo.py 2025-12-19 12:05:33.000000000 +0000 +++ dpdk-24.11.8/usertools/dpdk-pmdinfo.py 2026-10-14 13:10:05.000000000 +0000 @@ -213,8 +213,9 @@ if b == 0: # end of string s = view[start:i].tobytes().decode("ascii") - if s.startswith(prefix): - yield s[len(prefix):] + idx = s.find(prefix) + if idx >= 0: + yield s[idx + len(prefix) :] # There can be byte sequences where a non-printable byte # follows a printable one. Ignore that. start = None