On 25 Feb 2026, at 11:42, Eli Britstein wrote:

> On 23/02/2026 13:09, Eelco Chaudron wrote:
>> External email: Use caution opening links or attachments
>>
>>
>> This patch introduces a new API to the offload provider framework that
>> allows hardware offload implementations to control UDP tunnel source port
>> selection during tunnel encapsulation.
>>
>> Background and Motivation
>> ==========================
>>
>> UDP-based tunnels (VXLAN, Geneve, etc.) use the UDP source port as an
>> entropy field to enable ECMP load balancing across multiple paths in the
>> network. The source port is typically calculated by hashing packet header
>> fields (5-tuple or inner packet headers) to distribute flows across
>> different paths.
>>
>> However, hardware offload implementations may require different approaches
>> to source port calculation:
>>
>> 1. Hardware NICs may use different hash functions or hash inputs than
>>     the software datapath, which can lead to inconsistent flow distribution
>>     when mixing hardware and software paths.
>>
>> 2. Some hardware may support enhanced entropy mechanisms (e.g., using
>>     additional packet fields or hardware-specific hash engines) that provide
>>     better load distribution than the default software implementation.
>>
>> Design
>> ======
>>
>> This patch adds a new optional callback to the dpif_offload_class:
>>
>>    bool (*netdev_udp_tnl_get_src_port)(const struct dpif_offload *,
>>                                        const struct netdev *ingress_netdev,
>>                                        const struct dp_packet *packet,
>>                                        ovs_be16 *src_port);
>
> I already have a local version of doca offloads supporting vxlan offload.
>
> I applied this patch and ported the actual implementation for doca. Here are 
> my findings:
>
> - There wasn't a need for dpif_offload * argument. I wonder if maybe it's 
> safe to omit it?

I assume this is uniform across the API, so for now I'd like to keep it as is. 
I guess we can always change it if it becomes noticeable or starts impacting 
performance.

> - In the implementation, need to parse the packet in order to set fields in a 
> doca struct. For that there is a call to parse_tcp_flags(packet). the const 
> interfere with that. I worked around it using CONST_CAST. maybe we can omit 
> the const? alternatives?

I'll remove the const in the next patch.

> Other than that, it works.
>
> Also, small nit below.

Thanks for the review, I'll sent out a v2.

//Eelco

>>
>> The callback is invoked during tunnel push operations when hardware offload
>> is enabled and the original ingress port is known. It receives:
>>    - ingress_netdev: The original ingress port where the packet was received
>>    - packet: The inner packet to be encapsulated
>>
>> If the provider implements this callback and returns true, the returned
>> src_port value is used. Otherwise, OVS falls back to the standard hash-based
>> source port calculation.
>>
>> NOTE: This patch needs to be applied on top of the patch series below:
>>       https://patchwork.ozlabs.org/project/openvswitch/list/?series=491639
>>
>> Signed-off-by: Eelco Chaudron <[email protected]>
>> ---
>>   lib/dpif-netdev.c             |  18 ++++-
>>   lib/dpif-offload-dummy.c      | 133 +++++++++++++++++++++++++++++++++-
>>   lib/dpif-offload-provider.h   |  13 ++++
>>   lib/dpif-offload.c            |  19 +++++
>>   lib/dpif-offload.h            |   4 +-
>>   lib/netdev-native-tnl.c       |  11 ++-
>>   lib/netdev-native-tnl.h       |   5 ++
>>   lib/netdev-provider.h         |   9 ++-
>>   lib/netdev.c                  |   4 +-
>>   lib/netdev.h                  |   1 +
>>   tests/dpif-netdev.at          | 101 +++++++++++++++++++++++---
>>   utilities/checkpatch_dict.txt |   1 +
>>   12 files changed, 298 insertions(+), 21 deletions(-)
>>
>> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>> index 64531a02c0..9384edcd96 100644
>> --- a/lib/dpif-netdev.c
>> +++ b/lib/dpif-netdev.c
>> @@ -8374,8 +8374,9 @@ push_tnl_action(const struct dp_netdev_pmd_thread *pmd,
>>                   const struct nlattr *attr,
>>                   struct dp_packet_batch *batch)
>>   {
>> -    struct tx_port *tun_port;
>> +    const struct netdev *ingress_netdev = NULL;
>>       const struct ovs_action_push_tnl *data;
>> +    struct tx_port *tun_port;
>>       int err;
>>
>>       data = nl_attr_get(attr);
>> @@ -8385,7 +8386,20 @@ push_tnl_action(const struct dp_netdev_pmd_thread 
>> *pmd,
>>           err = -EINVAL;
>>           goto error;
>>       }
>> -    err = netdev_push_header(tun_port->port->netdev, batch, data);
>> +
>> +    if (dpif_offload_enabled() && !dp_packet_batch_is_empty(batch)) {
>> +        /* To avoid multiple port lookups per batch, assume that all packets
>> +         * in the batch originate from the same flow and therefore share the
>> +         * same original input port. */
>> +        struct tx_port *in_port = pmd_send_port_cache_lookup(
>> +                                      pmd, 
>> batch->packets[0]->md.orig_in_port);
>> +        if (in_port) {
>> +            ingress_netdev = in_port->port->netdev;
>> +        }
>> +    }
>> +
>> +    err = netdev_push_header(tun_port->port->netdev, ingress_netdev, batch,
>> +                             data);
>>       if (!err) {
>>           return 0;
>>       }
>> diff --git a/lib/dpif-offload-dummy.c b/lib/dpif-offload-dummy.c
>> index 3dd9eff14b..4c199c3aec 100644
>> --- a/lib/dpif-offload-dummy.c
>> +++ b/lib/dpif-offload-dummy.c
>> @@ -24,6 +24,7 @@
>>   #include "dummy.h"
>>   #include "id-fpool.h"
>>   #include "netdev-provider.h"
>> +#include "netdev-native-tnl.h"
> move line up

Thanks, I guess I'll never learn my ABC ;)

[...]

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to