On 1/12/26 4:53 PM, Numan Siddique wrote:
> On Mon, Jan 12, 2026 at 8:28 AM Eelco Chaudron <[email protected]> wrote:
>>
>>
>>
>> On 12 Jan 2026, at 14:26, Eelco Chaudron wrote:
>>
>>> On 20 Dec 2025, at 0:50, [email protected] wrote:
>>>
>>>> From: Numan Siddique <[email protected]>
>>
>> Forgot to mention the subject needs a component:
>>
>> ofproto-dpif: Limit the recirc_id to max of 2^28.
>>
>>>> netdev-offload-tc when offloading a flow to tc, uses the flow's
>>>> recirc_id as flower chain id. recirc_id is of type 'uint32_t'.
>>>> Kernel tc reserves the upper nibble (4 bits) of the tc flower's
>>>> chain index for extended action opcode [1]. If a flow's recirc_id
>>>> value is greater than 268,435,455 (2^28), kernel returns
>>>
>>> (2^28 - 1)
>
> Ack.
>
>
>>>
>>>> EINVAL when ovs-vswitchd tries to offload the flow.
>>>>
>>>> This commit fixes this offload issue by setting the maximum
>>>> value of recirc id to 2^28. 2^28 is a fairly big number and
>>>
>>> value of recirc id to 2^28 - 1. 2^28 - 1 is a fairly big number and
>>>
>>>> we should not have that many active datapath flows at a time.
>>>>
>>>> Reported-at:
>>>> https://mail.openvswitch.org/pipermail/ovs-dev/2025-November/427485.html
>>>> Suggested-by: Ilya Maximets <[email protected]>
>>>> Suggested-by: Eelco Chaudron <[email protected]>
>>>> Signed-off-by: Numan Siddique <[email protected]>
>>>> ---
>>>> ofproto/ofproto-dpif-rid.c | 13 ++++++++++---
>>>> 1 file changed, 10 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c
>>>> index f01468025..09f8a84f1 100644
>>>> --- a/ofproto/ofproto-dpif-rid.c
>>>> +++ b/ofproto/ofproto-dpif-rid.c
>>>> @@ -38,6 +38,13 @@ static uint32_t next_id OVS_GUARDED_BY(mutex) = 1; /*
>>>> Possible next free id. */
>>>>
>>>> #define RECIRC_POOL_STATIC_IDS 1024
>>>>
>>>> +/* Limit the recirc_ic maximum value to 268435455 (which is 2^^28).
>>>
>>> recirc_ic -> recirc_id
>>>
>>> Guess this is not correct, it should be 2^^28 - 1 (same below).
>>>
>>>> + * When kernel tc offload is enabled, we use the recirc_id as
>>>> + * the chain id and kernel limits the chain id maximum value
>>>> + * to 2^^28.
>>>> + */
>>>> +#define RECIRC_ID_MAX_VALUE 268435455
>>>
>>> Would it make sense to use TC_ACT_EXT_VAL_MASK here? Not 100% sure about
>>> this, Ilya?
>
> We could. I thought about it. I was not sure if its ok to include
> "include/uapi/linux/pkt_cls.h" (or appropriate linux header file)
> in ofproto/ofprot-dpif-rid.c. Is that ok ?
Inclusion of platform-specific headers in ofproto is not good.
Should avoid that, if possible.
If we really want to have a compile-time proof that we're not out of range,
then we should define the value in some common header and add a build assert
to the linux-specific code. But I'm not sure this is necessary, as kernel
uAPI is unlikely to change. May mention the TC_ACT_EXT_VAL_MASK in the
comment though, e.g. "kernel limits the chain id maximum value to
TC_ACT_EXT_VAL_MASK (2^28 - 1)".
BTW, I'd suggest to define the value as ((UINT32_C(1) << 28) - 1) instead of
a "magic" number. This way you'll also not need to explain what it equals to
in the comments.
>
>
>
>>>
>>>> +
>>>> static void recirc_id_node_free(struct recirc_id_node *);
>>>>
>>>> /* This should be called by the revalidator once at each round (every
>>>> 500ms or
>>>> @@ -227,8 +234,8 @@ frozen_state_free(struct frozen_state *state)
>>>> }
>>>>
>>>> /* Allocate a unique recirculation id for the given set of flow metadata.
>>>> - * The ID space is 2^^32, so there should never be a situation in which
>>>> all
>>>> - * the IDs are used up. We loop until we find a free one. */
>>>> + * The ID space is limited to 2^^28, so there should never be a situation
>>>
>>> 2^^28 - 1, should we maybe also move to use a single carat for power of?
>>> Other comments in the code use a single caret.
>
> I used double carat because the existing comment used double carat (i.e
> 2^^32).
> I can change it to single. Please let me know.
>
It should be either 2^28 or 2**28. Current code uses ^^ and it is strange. :)
I'd suggest we don't follow this pattern.
Best regards, Ilya Maximets.
> Thanks
> Numan
>
>
>>>
>>>> + * in which all the IDs are used up. We loop until we find a free one. */
>>>> static struct recirc_id_node *
>>>> recirc_alloc_id__(const struct frozen_state *state, uint32_t hash)
>>>> {
>>>> @@ -247,7 +254,7 @@ recirc_alloc_id__(const struct frozen_state *state,
>>>> uint32_t hash)
>>>> RECIRC_POOL_STATIC_IDS IDs on the later rounds, though, as
>>>> some of
>>>> the initial allocations may be for long term uses (like
>>>> bonds). */
>>>> node->id = next_id++;
>>>> - if (OVS_UNLIKELY(!node->id)) {
>>>> + if (OVS_UNLIKELY(!node->id || node->id > RECIRC_ID_MAX_VALUE)) {
>>>> next_id = RECIRC_POOL_STATIC_IDS + 1;
>>>> node->id = next_id++;
>>>> }
>>>> --
>>>> 2.52.0
>>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev