On 7/1/24 13:52, Sunyang Wu wrote:
> Hi, Ilya, Thank you for your valuable advice!
> In lines 7390-7406 of the 'ofproto_dpif xlate.c' file, show below:
> case OFPACT_SET_IP_DSCP:
>       if (is_ip_any(flow)) {
>               WC_MASK_FIELD(wc, nw_proto);
>               wc->masks.nw_tos |= IP_DSCP_MASK;
>               flow->nw_tos &= ~IP_DSCP_MASK;
>               flow->nw_tos |= ofpact_get_SET_IP_DSCP(a)->dscp;
>       }
>       break;
> 
> case OFPACT_SET_IP_ECN:
>       if (is_ip_any(flow)) {
>               WC_MASK_FIELD(wc, nw_proto);
>               wc->masks.nw_tos |= IP_ECN_MASK;
>               flow->nw_tos &= ~IP_ECN_MASK;
>               flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn;
>       }
>       break;
> when parsing and setting the DSCP and ECN actions, different masks are applied
> to the `nw_tos` field respectively, and a mask operation is performed on 
> `nw_tos`.

True.

> Additionally, the same action identifier is used for offloading both DSCP
> and ECN, ensuring that setting DSCP and setting ECN do not interfere with 
> each other.

I'm not sure I understand what you mean here.

Consider the following sequence of events:

1. OFPACT_SET_IP_ECN is executed.
   wc->masks.nw_tos |= IP_ECN_MASK;
   flow->nw_tos |= ofpact_get_SET_IP_ECN(a)->ecn;

2. flow and wc are translated into ovs_key_ipv4 elements in key and mask.
   So, key->ipv4_tos == flow->nw_tos and mask->ipv4_tos == IP_ECN_MASK.

3. We call add_set_flow_action(ipv4_tos, RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP)
   We check if mask->ipv4_tos is all-zero -- it is not.
   We check if it is all-ones -- it is not.
   We check if the action is RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP -- yes!

4. add_flow_action() is called with value flow->nw_tos, which is our
   original ofpact_get_SET_IP_ECN(a)->ecn.  Since ECN bits are higher
   than DSCP, that is equivalent ot setting DSCP to zero.

5. mask->ipv4_tos is set to all zeroes.

6. Offload suceeds.

Original action was to set ECN to some value, what we offloaded is
seting DSCP to zero, which is a completely different action.

Offloading should have failed instead.

> 
> Regarding the `add_set_flow_action__` function, the mask is cleared to zero.
> This clearing operation is intended for subsequent checks to determine if all 
> the
> fields issued are supported. This mask will not be passed to the DPDK side, 
> so it
> will not affect the offloading operation.

It will, because we should have failed offloading, since we can't
offload setting of ECN bits.

> 
> On 6/28/24 23:08, Ilya Maximets wrote:
>> On 6/20/24 09:35, Sunyang Wu via dev wrote:
>>> Add the "set dscp action" parsing function, so that the "set dscp 
>>> action" can be offloaded.
>>>
>>> Signed-off-by: Sunyang Wu <[email protected]>
>>> ---
>>>  lib/netdev-offload-dpdk.c | 19 ++++++++++++++++++-
>>>  1 file changed, 18 insertions(+), 1 deletion(-)
>>>
>>
>> Hi, Sunyang Wu.  Thanks for the patch!
>> See some comments inline.
>>
>> Best regards, Ilya Maximets.
>>
>>> diff --git a/lib/netdev-offload-dpdk.c b/lib/netdev-offload-dpdk.c 
>>> index 623005b1c..524942457 100644
>>> --- a/lib/netdev-offload-dpdk.c
>>> +++ b/lib/netdev-offload-dpdk.c
>>> @@ -791,6 +791,17 @@ dump_flow_action(struct ds *s, struct ds *s_extra,
>>>              ds_put_format(s, "port %"PRIu16" ", ntohs(set_tp->port));
>>>          }
>>>          ds_put_cstr(s, "/ ");
>>> +    } else if (actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP ||
>>> +               actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP) {
>>> +        const struct rte_flow_action_set_dscp *set_dscp = actions->conf;
>>> +        char *dirstr = actions->type == RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP
>>> +                       ? "set_ipv4_dscp " : "set_ipv6_dscp ";
>>> +
>>> +        ds_put_cstr(s, dirstr);
>>> +        if (set_dscp) {
>>> +            ds_put_format(s, "dscp_value %d ", set_dscp->dscp);
>>> +        }
>>> +        ds_put_cstr(s, "/ ");
>>>      } else if (actions->type == RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN) {
>>>          const struct rte_flow_action_of_push_vlan *of_push_vlan =
>>>              actions->conf;
>>> @@ -1835,7 +1846,10 @@ add_set_flow_action__(struct flow_actions *actions,
>>>          if (is_all_zeros(mask, size)) {
>>>              return 0;
>>>          }
>>> -        if (!is_all_ones(mask, size)) {
>>> +        if (!is_all_ones(mask, size) &&
>>> +            /* set dscp need patial mask */
>>> +            attr != RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP &&
>>> +            attr != RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP) {
>>
>> This doesn't seem right.  We need to check that the mask contains all 
>> the DSCP bits and that it doesn't have anything else inside.
>>
>> For example, if we try to set ECN bits, we'll have them in a mask.
>> In this case is_all_zeros() check will fail and then this check will 
>> allow us to proceed as well.  In the end, we'll end up setting DSCP 
>> bits to all zeroes, or worse, to whatever was in the first six bits of 
>> nw_tos.
>>
> 
> Also, this function will clear the whole mask below, but we should only clear 
> DSCP bits in this case.
> 
>>>              VLOG_DBG_RL(&rl, "Partial mask is not supported");
>>>              return -1;
>>>          }
>>> @@ -1912,6 +1926,7 @@ parse_set_actions(struct flow_actions *actions,
>>>              add_set_flow_action(ipv4_src, 
>>> RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC);
>>>              add_set_flow_action(ipv4_dst, 
>>> RTE_FLOW_ACTION_TYPE_SET_IPV4_DST);
>>>              add_set_flow_action(ipv4_ttl, 
>>> RTE_FLOW_ACTION_TYPE_SET_TTL);
>>> +            add_set_flow_action(ipv4_tos, 
>>> + RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP);z
>>>
>>>              if (mask && !is_all_zeros(mask, sizeof *mask)) {
>>>                  VLOG_DBG_RL(&rl, "Unsupported IPv4 set action"); @@ 
>>> -1924,6 +1939,8 @@ parse_set_actions(struct flow_actions *actions,
>>>              add_set_flow_action(ipv6_src, 
>>> RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC);
>>>              add_set_flow_action(ipv6_dst, 
>>> RTE_FLOW_ACTION_TYPE_SET_IPV6_DST);
>>>              add_set_flow_action(ipv6_hlimit, 
>>> RTE_FLOW_ACTION_TYPE_SET_TTL);
>>> +            add_set_flow_action(ipv6_tclass,
>>> +                                RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP);
>>>
>>>              if (mask && !is_all_zeros(mask, sizeof *mask)) {
>>>                  VLOG_DBG_RL(&rl, "Unsupported IPv6 set action");
>>
> 

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

Reply via email to