diff mbox series

[ovs-dev] logical-fields: Reuse registers for ct_*_dst() actions.

Message ID 20241111104327.65539-1-dceara@redhat.com
State Accepted
Headers show
Series [ovs-dev] logical-fields: Reuse registers for ct_*_dst() actions. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes fail github build: failed
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/github-robot-_ovn-kubernetes success github build: passed

Commit Message

Dumitru Ceara Nov. 11, 2024, 10:43 a.m. UTC
The actions that retrieve the original tuple destination IPs and ports
were used in the following way in ovn-northd:

  REG_ORIG_DIP_IPV4 " = ct_nw_dst()
  REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
  REG_ORIG_TP_DPORT " = ct_tp_dst()

Where:
  REG_ORIG_DIP_IPV4 is reg1
  REG_ORIG_DIP_IPV6 is xxreg1
  REG_ORIG_TP_DPORT is reg2[0..15]

While the actions use a different intermediate register:
  ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
  ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
  ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst

We can reduce the set of registers we use in the OVN pipeline by
changing the action definition to use the same registers ovn-northd uses
as final destination for the ct_*_dst() values.  This will generate the
following openflow rules:

  REG_ORIG_DIP_IPV4 " = ct_nw_dst()
    reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
  REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
    xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
  REG_ORIG_TP_DPORT " = ct_tp_dst()
    reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]

As Ilya Maximets points out, overlapping source and destination are
well defined for move actions:
https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf

  This action must behaves properly when src_oxm_id overlaps with
  dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
  to a temporary buffer, then the temporary buffer copied to
  dst_oxm_id, if this is not possible the switch must reject the
  Copy Field action with a Bad Set Type error message.

OpenvSwitch doesn't reject such actions.

Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented packets.")
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
---
 include/ovn/logical-fields.h | 7 ++++---
 tests/ovn.at                 | 8 ++++----
 2 files changed, 8 insertions(+), 7 deletions(-)

Comments

Dumitru Ceara Nov. 25, 2024, 12:49 p.m. UTC | #1
Recheck-request: github-robot

On 11/11/24 11:43 AM, Dumitru Ceara wrote:
> The actions that retrieve the original tuple destination IPs and ports
> were used in the following way in ovn-northd:
> 
>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>   REG_ORIG_TP_DPORT " = ct_tp_dst()
> 
> Where:
>   REG_ORIG_DIP_IPV4 is reg1
>   REG_ORIG_DIP_IPV6 is xxreg1
>   REG_ORIG_TP_DPORT is reg2[0..15]
> 
> While the actions use a different intermediate register:
>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
> 
> We can reduce the set of registers we use in the OVN pipeline by
> changing the action definition to use the same registers ovn-northd uses
> as final destination for the ct_*_dst() values.  This will generate the
> following openflow rules:
> 
>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
> 
> As Ilya Maximets points out, overlapping source and destination are
> well defined for move actions:
> https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
> 
>   This action must behaves properly when src_oxm_id overlaps with
>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
>   to a temporary buffer, then the temporary buffer copied to
>   dst_oxm_id, if this is not possible the switch must reject the
>   Copy Field action with a Bad Set Type error message.
> 
> OpenvSwitch doesn't reject such actions.
> 
> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented packets.")
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
Ales Musil Dec. 10, 2024, 11:35 a.m. UTC | #2
On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com> wrote:

> The actions that retrieve the original tuple destination IPs and ports
> were used in the following way in ovn-northd:
>
>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>
> Where:
>   REG_ORIG_DIP_IPV4 is reg1
>   REG_ORIG_DIP_IPV6 is xxreg1
>   REG_ORIG_TP_DPORT is reg2[0..15]
>
> While the actions use a different intermediate register:
>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
>
> We can reduce the set of registers we use in the OVN pipeline by
> changing the action definition to use the same registers ovn-northd uses
> as final destination for the ct_*_dst() values.  This will generate the
> following openflow rules:
>
>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
>
> As Ilya Maximets points out, overlapping source and destination are
> well defined for move actions:
>
> https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
>
>   This action must behaves properly when src_oxm_id overlaps with
>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
>   to a temporary buffer, then the temporary buffer copied to
>   dst_oxm_id, if this is not possible the switch must reject the
>   Copy Field action with a Bad Set Type error message.
>
> OpenvSwitch doesn't reject such actions.
>
> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented
> packets.")
> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> ---
>  include/ovn/logical-fields.h | 7 ++++---
>  tests/ovn.at                 | 8 ++++----
>  2 files changed, 8 insertions(+), 7 deletions(-)
>
> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
> index d563e044cb..70c6b93c41 100644
> --- a/include/ovn/logical-fields.h
> +++ b/include/ovn/logical-fields.h
> @@ -60,9 +60,10 @@ enum ovn_controller_event {
>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
>
> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
> REG_ORIG_DIP_IPV4 */
> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
> REG_ORIG_DIP_IPV6 */
> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
> REG_ORIG_TP_DPORT
> +                                                        * (bits 0..15). */
>
>  void ovn_init_symtab(struct shash *symtab);
>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 15b78f4c37..03fd2090fc 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -2420,10 +2420,10 @@ mac_cache_use;
>
>  # ct_nw_dst()
>  reg1 = ct_nw_dst();
> -    encodes as
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
> +    encodes as
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
>
>  xreg1[[3..34]] = ct_nw_dst();
> -    encodes as
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
> +    encodes as
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
>
>  reg1[[3..34]] = ct_nw_dst();
>      Cannot select bits 3 to 34 of 32-bit field reg1.
> @@ -2442,7 +2442,7 @@ ct_nw_dst();
>
>  # ct_ip6_dst()
>  xxreg1 = ct_ip6_dst();
> -    encodes as
> set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
> +    encodes as
> set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
>
>  reg1 = ct_ip6_dst();
>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is required.
> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
>
>  # ct_tp_dst()
>  reg1[[0..15]] = ct_tp_dst();
> -    encodes as
> set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
> +    encodes as
> set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
>
>  reg1 = ct_tp_dst();
>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is required.
> --
> 2.46.2
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Looks good to me, thanks.

Acked-by: Ales Musil <amusil@redhat.com>
Dumitru Ceara Dec. 11, 2024, 1:35 p.m. UTC | #3
On 12/10/24 12:35 PM, Ales Musil wrote:
> On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com> wrote:
> 
>> The actions that retrieve the original tuple destination IPs and ports
>> were used in the following way in ovn-northd:
>>
>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>
>> Where:
>>   REG_ORIG_DIP_IPV4 is reg1
>>   REG_ORIG_DIP_IPV6 is xxreg1
>>   REG_ORIG_TP_DPORT is reg2[0..15]
>>
>> While the actions use a different intermediate register:
>>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
>>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
>>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
>>
>> We can reduce the set of registers we use in the OVN pipeline by
>> changing the action definition to use the same registers ovn-northd uses
>> as final destination for the ct_*_dst() values.  This will generate the
>> following openflow rules:
>>
>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
>>
>> As Ilya Maximets points out, overlapping source and destination are
>> well defined for move actions:
>>
>> https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
>>
>>   This action must behaves properly when src_oxm_id overlaps with
>>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
>>   to a temporary buffer, then the temporary buffer copied to
>>   dst_oxm_id, if this is not possible the switch must reject the
>>   Copy Field action with a Bad Set Type error message.
>>
>> OpenvSwitch doesn't reject such actions.
>>
>> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented
>> packets.")
>> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
>> ---
>>  include/ovn/logical-fields.h | 7 ++++---
>>  tests/ovn.at                 | 8 ++++----
>>  2 files changed, 8 insertions(+), 7 deletions(-)
>>
>> diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
>> index d563e044cb..70c6b93c41 100644
>> --- a/include/ovn/logical-fields.h
>> +++ b/include/ovn/logical-fields.h
>> @@ -60,9 +60,10 @@ enum ovn_controller_event {
>>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
>>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
>>
>> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
>> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
>> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
>> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
>> REG_ORIG_DIP_IPV4 */
>> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
>> REG_ORIG_DIP_IPV6 */
>> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
>> REG_ORIG_TP_DPORT
>> +                                                        * (bits 0..15). */
>>
>>  void ovn_init_symtab(struct shash *symtab);
>>
>> diff --git a/tests/ovn.at b/tests/ovn.at
>> index 15b78f4c37..03fd2090fc 100644
>> --- a/tests/ovn.at
>> +++ b/tests/ovn.at
>> @@ -2420,10 +2420,10 @@ mac_cache_use;
>>
>>  # ct_nw_dst()
>>  reg1 = ct_nw_dst();
>> -    encodes as
>> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
>> +    encodes as
>> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
>>
>>  xreg1[[3..34]] = ct_nw_dst();
>> -    encodes as
>> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
>> +    encodes as
>> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
>>
>>  reg1[[3..34]] = ct_nw_dst();
>>      Cannot select bits 3 to 34 of 32-bit field reg1.
>> @@ -2442,7 +2442,7 @@ ct_nw_dst();
>>
>>  # ct_ip6_dst()
>>  xxreg1 = ct_ip6_dst();
>> -    encodes as
>> set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
>> +    encodes as
>> set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
>>
>>  reg1 = ct_ip6_dst();
>>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is required.
>> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
>>
>>  # ct_tp_dst()
>>  reg1[[0..15]] = ct_tp_dst();
>> -    encodes as
>> set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
>> +    encodes as
>> set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
>>
>>  reg1 = ct_tp_dst();
>>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is required.
>> --
>> 2.46.2
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>>
> Looks good to me, thanks.
> 
> Acked-by: Ales Musil <amusil@redhat.com>
> 

Thanks, Ales!  Applied to main and backported to 24.09 and 24.03.

Regards,
Dumitru
Han Zhou July 9, 2025, 6:01 p.m. UTC | #4
On Wed, Dec 11, 2024 at 5:35 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> On 12/10/24 12:35 PM, Ales Musil wrote:
> > On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com>
wrote:
> >
> >> The actions that retrieve the original tuple destination IPs and ports
> >> were used in the following way in ovn-northd:
> >>
> >>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
> >>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
> >>   REG_ORIG_TP_DPORT " = ct_tp_dst()
> >>
> >> Where:
> >>   REG_ORIG_DIP_IPV4 is reg1
> >>   REG_ORIG_DIP_IPV6 is xxreg1
> >>   REG_ORIG_TP_DPORT is reg2[0..15]
> >>
> >> While the actions use a different intermediate register:
> >>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
> >>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
> >>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
> >>
> >> We can reduce the set of registers we use in the OVN pipeline by
> >> changing the action definition to use the same registers ovn-northd
uses
> >> as final destination for the ct_*_dst() values.  This will generate the
> >> following openflow rules:
> >>
> >>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
> >>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
> >>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
> >>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
> >>   REG_ORIG_TP_DPORT " = ct_tp_dst()
> >>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
> >>
> >> As Ilya Maximets points out, overlapping source and destination are
> >> well defined for move actions:
> >>
> >>
https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
> >>
> >>   This action must behaves properly when src_oxm_id overlaps with
> >>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
> >>   to a temporary buffer, then the temporary buffer copied to
> >>   dst_oxm_id, if this is not possible the switch must reject the
> >>   Copy Field action with a Bad Set Type error message.
> >>
> >> OpenvSwitch doesn't reject such actions.
> >>
> >> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented
> >> packets.")
> >> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> >> ---
> >>  include/ovn/logical-fields.h | 7 ++++---
> >>  tests/ovn.at                 | 8 ++++----
> >>  2 files changed, 8 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/include/ovn/logical-fields.h
b/include/ovn/logical-fields.h
> >> index d563e044cb..70c6b93c41 100644
> >> --- a/include/ovn/logical-fields.h
> >> +++ b/include/ovn/logical-fields.h
> >> @@ -60,9 +60,10 @@ enum ovn_controller_event {
> >>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
> >>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
> >>
> >> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
> >> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
> >> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
> >> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
> >> REG_ORIG_DIP_IPV4 */
> >> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
> >> REG_ORIG_DIP_IPV6 */
> >> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
> >> REG_ORIG_TP_DPORT
> >> +                                                        * (bits
0..15). */
> >>
> >>  void ovn_init_symtab(struct shash *symtab);
> >>
> >> diff --git a/tests/ovn.at b/tests/ovn.at
> >> index 15b78f4c37..03fd2090fc 100644
> >> --- a/tests/ovn.at
> >> +++ b/tests/ovn.at
> >> @@ -2420,10 +2420,10 @@ mac_cache_use;
> >>
> >>  # ct_nw_dst()
> >>  reg1 = ct_nw_dst();
> >> -    encodes as
> >>
set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
> >> +    encodes as
> >>
set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
> >>
> >>  xreg1[[3..34]] = ct_nw_dst();
> >> -    encodes as
> >>
set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
> >> +    encodes as
> >>
set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
> >>
> >>  reg1[[3..34]] = ct_nw_dst();
> >>      Cannot select bits 3 to 34 of 32-bit field reg1.
> >> @@ -2442,7 +2442,7 @@ ct_nw_dst();
> >>
> >>  # ct_ip6_dst()
> >>  xxreg1 = ct_ip6_dst();
> >> -    encodes as
> >>
set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
> >> +    encodes as
> >>
set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
> >>
> >>  reg1 = ct_ip6_dst();
> >>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is
required.
> >> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
> >>
> >>  # ct_tp_dst()
> >>  reg1[[0..15]] = ct_tp_dst();
> >> -    encodes as
> >>
set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
> >> +    encodes as
> >>
set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
> >>
> >>  reg1 = ct_tp_dst();
> >>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is
required.
> >> --
> >> 2.46.2
> >>
> >> _______________________________________________
> >> dev mailing list
> >> dev@openvswitch.org
> >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >>
> >>
> > Looks good to me, thanks.
> >
> > Acked-by: Ales Musil <amusil@redhat.com>
> >
>
> Thanks, Ales!  Applied to main and backported to 24.09 and 24.03.
>
> Regards,
> Dumitru
>

Hi Dumitru, Ales, I am trying to figure out the current register usage and
saw this old commit. I am not sure I understand the motivation of this
patch. Is there a problem of using different registers for intermediate
usage? Although this patch tried to use the same register for intermediate
and final destination, a later commit from Ales 91988089c5 ("northd:
Consolidate register usage in logical flows.") already broke it again.
Shall we fix that again?

Thanks,
Han


>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Dumitru Ceara July 9, 2025, 6:37 p.m. UTC | #5
On 7/9/25 8:01 PM, Han Zhou wrote:
> On Wed, Dec 11, 2024 at 5:35 AM Dumitru Ceara <dceara@redhat.com> wrote:
>>
>> On 12/10/24 12:35 PM, Ales Musil wrote:
>>> On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com>
> wrote:
>>>
>>>> The actions that retrieve the original tuple destination IPs and ports
>>>> were used in the following way in ovn-northd:
>>>>
>>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>>>
>>>> Where:
>>>>   REG_ORIG_DIP_IPV4 is reg1
>>>>   REG_ORIG_DIP_IPV6 is xxreg1
>>>>   REG_ORIG_TP_DPORT is reg2[0..15]
>>>>
>>>> While the actions use a different intermediate register:
>>>>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
>>>>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
>>>>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
>>>>
>>>> We can reduce the set of registers we use in the OVN pipeline by
>>>> changing the action definition to use the same registers ovn-northd
> uses
>>>> as final destination for the ct_*_dst() values.  This will generate the
>>>> following openflow rules:
>>>>
>>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>>>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
>>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>>>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
>>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>>>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
>>>>
>>>> As Ilya Maximets points out, overlapping source and destination are
>>>> well defined for move actions:
>>>>
>>>>
> https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
>>>>
>>>>   This action must behaves properly when src_oxm_id overlaps with
>>>>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
>>>>   to a temporary buffer, then the temporary buffer copied to
>>>>   dst_oxm_id, if this is not possible the switch must reject the
>>>>   Copy Field action with a Bad Set Type error message.
>>>>
>>>> OpenvSwitch doesn't reject such actions.
>>>>
>>>> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for fragmented
>>>> packets.")
>>>> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
>>>> ---
>>>>  include/ovn/logical-fields.h | 7 ++++---
>>>>  tests/ovn.at                 | 8 ++++----
>>>>  2 files changed, 8 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/include/ovn/logical-fields.h
> b/include/ovn/logical-fields.h
>>>> index d563e044cb..70c6b93c41 100644
>>>> --- a/include/ovn/logical-fields.h
>>>> +++ b/include/ovn/logical-fields.h
>>>> @@ -60,9 +60,10 @@ enum ovn_controller_event {
>>>>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
>>>>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
>>>>
>>>> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
>>>> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
>>>> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
>>>> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
>>>> REG_ORIG_DIP_IPV4 */
>>>> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
>>>> REG_ORIG_DIP_IPV6 */
>>>> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
>>>> REG_ORIG_TP_DPORT
>>>> +                                                        * (bits
> 0..15). */
>>>>
>>>>  void ovn_init_symtab(struct shash *symtab);
>>>>
>>>> diff --git a/tests/ovn.at b/tests/ovn.at
>>>> index 15b78f4c37..03fd2090fc 100644
>>>> --- a/tests/ovn.at
>>>> +++ b/tests/ovn.at
>>>> @@ -2420,10 +2420,10 @@ mac_cache_use;
>>>>
>>>>  # ct_nw_dst()
>>>>  reg1 = ct_nw_dst();
>>>> -    encodes as
>>>>
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
>>>> +    encodes as
>>>>
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
>>>>
>>>>  xreg1[[3..34]] = ct_nw_dst();
>>>> -    encodes as
>>>>
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
>>>> +    encodes as
>>>>
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
>>>>
>>>>  reg1[[3..34]] = ct_nw_dst();
>>>>      Cannot select bits 3 to 34 of 32-bit field reg1.
>>>> @@ -2442,7 +2442,7 @@ ct_nw_dst();
>>>>
>>>>  # ct_ip6_dst()
>>>>  xxreg1 = ct_ip6_dst();
>>>> -    encodes as
>>>>
> set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
>>>> +    encodes as
>>>>
> set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
>>>>
>>>>  reg1 = ct_ip6_dst();
>>>>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is
> required.
>>>> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
>>>>
>>>>  # ct_tp_dst()
>>>>  reg1[[0..15]] = ct_tp_dst();
>>>> -    encodes as
>>>>
> set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
>>>> +    encodes as
>>>>
> set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
>>>>
>>>>  reg1 = ct_tp_dst();
>>>>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is
> required.
>>>> --
>>>> 2.46.2
>>>>
>>>> _______________________________________________
>>>> dev mailing list
>>>> dev@openvswitch.org
>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>>
>>>>
>>> Looks good to me, thanks.
>>>
>>> Acked-by: Ales Musil <amusil@redhat.com>
>>>
>>
>> Thanks, Ales!  Applied to main and backported to 24.09 and 24.03.
>>
>> Regards,
>> Dumitru
>>
> 

Hi Han,

> Hi Dumitru, Ales, I am trying to figure out the current register usage and
> saw this old commit. I am not sure I understand the motivation of this
> patch. Is there a problem of using different registers for intermediate

There's no problem per se but we were using two registers instead of
one.  The intermediate register was overwritten and then its new value
immediately copied to the final destination register.

The goal of the patch was to free up registers for other things in we
might need to do in the pipeline.

> usage? Although this patch tried to use the same register for intermediate
> and final destination, a later commit from Ales 91988089c5 ("northd:
> Consolidate register usage in logical flows.") already broke it again.
> Shall we fix that again?
> 

I guess we probably should.  Maybe this time we should change the way
the ct_*_dst() actions are encoded?  I'm not sure how to prevent this
from happening again in the future though.

> Thanks,
> Han
> 

Regards,
Dumitru

> 
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Han Zhou July 9, 2025, 9:35 p.m. UTC | #6
On Wed, Jul 9, 2025 at 11:38 AM Dumitru Ceara <dceara@redhat.com> wrote:
>
> On 7/9/25 8:01 PM, Han Zhou wrote:
> > On Wed, Dec 11, 2024 at 5:35 AM Dumitru Ceara <dceara@redhat.com> wrote:
> >>
> >> On 12/10/24 12:35 PM, Ales Musil wrote:
> >>> On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com>
> > wrote:
> >>>
> >>>> The actions that retrieve the original tuple destination IPs and
ports
> >>>> were used in the following way in ovn-northd:
> >>>>
> >>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
> >>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
> >>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
> >>>>
> >>>> Where:
> >>>>   REG_ORIG_DIP_IPV4 is reg1
> >>>>   REG_ORIG_DIP_IPV6 is xxreg1
> >>>>   REG_ORIG_TP_DPORT is reg2[0..15]
> >>>>
> >>>> While the actions use a different intermediate register:
> >>>>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
> >>>>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
> >>>>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
> >>>>
> >>>> We can reduce the set of registers we use in the OVN pipeline by
> >>>> changing the action definition to use the same registers ovn-northd
> > uses
> >>>> as final destination for the ct_*_dst() values.  This will generate
the
> >>>> following openflow rules:
> >>>>
> >>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
> >>>>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
> >>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
> >>>>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
> >>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
> >>>>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
> >>>>
> >>>> As Ilya Maximets points out, overlapping source and destination are
> >>>> well defined for move actions:
> >>>>
> >>>>
> >
https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
> >>>>
> >>>>   This action must behaves properly when src_oxm_id overlaps with
> >>>>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
> >>>>   to a temporary buffer, then the temporary buffer copied to
> >>>>   dst_oxm_id, if this is not possible the switch must reject the
> >>>>   Copy Field action with a Bad Set Type error message.
> >>>>
> >>>> OpenvSwitch doesn't reject such actions.
> >>>>
> >>>> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for
fragmented
> >>>> packets.")
> >>>> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
> >>>> ---
> >>>>  include/ovn/logical-fields.h | 7 ++++---
> >>>>  tests/ovn.at                 | 8 ++++----
> >>>>  2 files changed, 8 insertions(+), 7 deletions(-)
> >>>>
> >>>> diff --git a/include/ovn/logical-fields.h
> > b/include/ovn/logical-fields.h
> >>>> index d563e044cb..70c6b93c41 100644
> >>>> --- a/include/ovn/logical-fields.h
> >>>> +++ b/include/ovn/logical-fields.h
> >>>> @@ -60,9 +60,10 @@ enum ovn_controller_event {
> >>>>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
> >>>>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
> >>>>
> >>>> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
> >>>> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
> >>>> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
> >>>> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
> >>>> REG_ORIG_DIP_IPV4 */
> >>>> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
> >>>> REG_ORIG_DIP_IPV6 */
> >>>> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
> >>>> REG_ORIG_TP_DPORT
> >>>> +                                                        * (bits
> > 0..15). */
> >>>>
> >>>>  void ovn_init_symtab(struct shash *symtab);
> >>>>
> >>>> diff --git a/tests/ovn.at b/tests/ovn.at
> >>>> index 15b78f4c37..03fd2090fc 100644
> >>>> --- a/tests/ovn.at
> >>>> +++ b/tests/ovn.at
> >>>> @@ -2420,10 +2420,10 @@ mac_cache_use;
> >>>>
> >>>>  # ct_nw_dst()
> >>>>  reg1 = ct_nw_dst();
> >>>> -    encodes as
> >>>>
> >
set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
> >>>> +    encodes as
> >>>>
> >
set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
> >>>>
> >>>>  xreg1[[3..34]] = ct_nw_dst();
> >>>> -    encodes as
> >>>>
> >
set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
> >>>> +    encodes as
> >>>>
> >
set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
> >>>>
> >>>>  reg1[[3..34]] = ct_nw_dst();
> >>>>      Cannot select bits 3 to 34 of 32-bit field reg1.
> >>>> @@ -2442,7 +2442,7 @@ ct_nw_dst();
> >>>>
> >>>>  # ct_ip6_dst()
> >>>>  xxreg1 = ct_ip6_dst();
> >>>> -    encodes as
> >>>>
> >
set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
> >>>> +    encodes as
> >>>>
> >
set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
> >>>>
> >>>>  reg1 = ct_ip6_dst();
> >>>>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is
> > required.
> >>>> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
> >>>>
> >>>>  # ct_tp_dst()
> >>>>  reg1[[0..15]] = ct_tp_dst();
> >>>> -    encodes as
> >>>>
> >
set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
> >>>> +    encodes as
> >>>>
> >
set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
> >>>>
> >>>>  reg1 = ct_tp_dst();
> >>>>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is
> > required.
> >>>> --
> >>>> 2.46.2
> >>>>
> >>>> _______________________________________________
> >>>> dev mailing list
> >>>> dev@openvswitch.org
> >>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >>>>
> >>>>
> >>> Looks good to me, thanks.
> >>>
> >>> Acked-by: Ales Musil <amusil@redhat.com>
> >>>
> >>
> >> Thanks, Ales!  Applied to main and backported to 24.09 and 24.03.
> >>
> >> Regards,
> >> Dumitru
> >>
> >
>
> Hi Han,
>
> > Hi Dumitru, Ales, I am trying to figure out the current register usage
and
> > saw this old commit. I am not sure I understand the motivation of this
> > patch. Is there a problem of using different registers for intermediate
>
> There's no problem per se but we were using two registers instead of
> one.  The intermediate register was overwritten and then its new value
> immediately copied to the final destination register.
>
> The goal of the patch was to free up registers for other things in we
> might need to do in the pipeline.
>
> > usage? Although this patch tried to use the same register for
intermediate
> > and final destination, a later commit from Ales 91988089c5 ("northd:
> > Consolidate register usage in logical flows.") already broke it again.
> > Shall we fix that again?
> >
>
> I guess we probably should.  Maybe this time we should change the way
> the ct_*_dst() actions are encoded?  I'm not sure how to prevent this
> from happening again in the future though.
>

I think the right way to encode actions that require intermediate registers
is to save the original content of the register on the stack beforehand and
restore it afterwards. This way the intermediate registers won't really
occupy the register space, and we don't need to worry about conflict
usage/overwriting. Otherwise, it is very hard to maintain and not even easy
to ensure the register is not overwritten accidentally if the same action
is called at different stages.
I will go ahead with this approach if it makes sense. What do you think?

Regards,
Han

> > Thanks,
> > Han
> >
>
> Regards,
> Dumitru
>
> >
> >>
> >> _______________________________________________
> >> dev mailing list
> >> dev@openvswitch.org
> >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
>
Dumitru Ceara July 10, 2025, 8:52 a.m. UTC | #7
On 7/9/25 11:35 PM, Han Zhou wrote:
> On Wed, Jul 9, 2025 at 11:38 AM Dumitru Ceara <dceara@redhat.com> wrote:
>>
>> On 7/9/25 8:01 PM, Han Zhou wrote:
>>> On Wed, Dec 11, 2024 at 5:35 AM Dumitru Ceara <dceara@redhat.com> wrote:
>>>>
>>>> On 12/10/24 12:35 PM, Ales Musil wrote:
>>>>> On Mon, Nov 11, 2024 at 11:43 AM Dumitru Ceara <dceara@redhat.com>
>>> wrote:
>>>>>
>>>>>> The actions that retrieve the original tuple destination IPs and
> ports
>>>>>> were used in the following way in ovn-northd:
>>>>>>
>>>>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>>>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>>>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>>>>>
>>>>>> Where:
>>>>>>   REG_ORIG_DIP_IPV4 is reg1
>>>>>>   REG_ORIG_DIP_IPV6 is xxreg1
>>>>>>   REG_ORIG_TP_DPORT is reg2[0..15]
>>>>>>
>>>>>> While the actions use a different intermediate register:
>>>>>>   ct_nw_dst()  was reg4<-0; reg4<-ct_nw_dst
>>>>>>   ct_ip6_dst() was xxreg0<-0; xxreg0<-ct_ip6_dst
>>>>>>   ct_tp_dst()  was reg8[0..15]<-0; reg8[0..15]<-ct_tp_dst
>>>>>>
>>>>>> We can reduce the set of registers we use in the OVN pipeline by
>>>>>> changing the action definition to use the same registers ovn-northd
>>> uses
>>>>>> as final destination for the ct_*_dst() values.  This will generate
> the
>>>>>> following openflow rules:
>>>>>>
>>>>>>   REG_ORIG_DIP_IPV4 " = ct_nw_dst()
>>>>>>     reg1<-0; reg1<-ct_nw_dst; reg1<-reg1
>>>>>>   REG_ORIG_DIP_IPV6 " = ct_ip6_dst()
>>>>>>     xxreg1<-0; xxreg1<-ct_ip6_dst; xxreg1<-xxreg1
>>>>>>   REG_ORIG_TP_DPORT " = ct_tp_dst()
>>>>>>     reg2[0..15]<-0; reg2[0..15]<-ct_tp_dst; reg2[0..15]<-reg2[0..15]
>>>>>>
>>>>>> As Ilya Maximets points out, overlapping source and destination are
>>>>>> well defined for move actions:
>>>>>>
>>>>>>
>>>
> https://opennetworking.org/wp-content/uploads/2014/10/openflow-switch-v1.5.0.noipr.pdf
>>>>>>
>>>>>>   This action must behaves properly when src_oxm_id overlaps with
>>>>>>   dst_oxm_id, that is, it behaves as if src_oxm_id were copied out
>>>>>>   to a temporary buffer, then the temporary buffer copied to
>>>>>>   dst_oxm_id, if this is not possible the switch must reject the
>>>>>>   Copy Field action with a Bad Set Type error message.
>>>>>>
>>>>>> OpenvSwitch doesn't reject such actions.
>>>>>>
>>>>>> Fixes: 0f806cf08c36 ("Fix load balanced hairpin traffic for
> fragmented
>>>>>> packets.")
>>>>>> Signed-off-by: Dumitru Ceara <dceara@redhat.com>
>>>>>> ---
>>>>>>  include/ovn/logical-fields.h | 7 ++++---
>>>>>>  tests/ovn.at                 | 8 ++++----
>>>>>>  2 files changed, 8 insertions(+), 7 deletions(-)
>>>>>>
>>>>>> diff --git a/include/ovn/logical-fields.h
>>> b/include/ovn/logical-fields.h
>>>>>> index d563e044cb..70c6b93c41 100644
>>>>>> --- a/include/ovn/logical-fields.h
>>>>>> +++ b/include/ovn/logical-fields.h
>>>>>> @@ -60,9 +60,10 @@ enum ovn_controller_event {
>>>>>>  #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
>>>>>>  #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
>>>>>>
>>>>>> -#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
>>>>>> -#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
>>>>>> -#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
>>>>>> +#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /*
>>>>>> REG_ORIG_DIP_IPV4 */
>>>>>> +#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /*
>>>>>> REG_ORIG_DIP_IPV6 */
>>>>>> +#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /*
>>>>>> REG_ORIG_TP_DPORT
>>>>>> +                                                        * (bits
>>> 0..15). */
>>>>>>
>>>>>>  void ovn_init_symtab(struct shash *symtab);
>>>>>>
>>>>>> diff --git a/tests/ovn.at b/tests/ovn.at
>>>>>> index 15b78f4c37..03fd2090fc 100644
>>>>>> --- a/tests/ovn.at
>>>>>> +++ b/tests/ovn.at
>>>>>> @@ -2420,10 +2420,10 @@ mac_cache_use;
>>>>>>
>>>>>>  # ct_nw_dst()
>>>>>>  reg1 = ct_nw_dst();
>>>>>> -    encodes as
>>>>>>
>>>
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
>>>>>> +    encodes as
>>>>>>
>>>
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
>>>>>>
>>>>>>  xreg1[[3..34]] = ct_nw_dst();
>>>>>> -    encodes as
>>>>>>
>>>
> set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
>>>>>> +    encodes as
>>>>>>
>>>
> set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
>>>>>>
>>>>>>  reg1[[3..34]] = ct_nw_dst();
>>>>>>      Cannot select bits 3 to 34 of 32-bit field reg1.
>>>>>> @@ -2442,7 +2442,7 @@ ct_nw_dst();
>>>>>>
>>>>>>  # ct_ip6_dst()
>>>>>>  xxreg1 = ct_ip6_dst();
>>>>>> -    encodes as
>>>>>>
>>>
> set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
>>>>>> +    encodes as
>>>>>>
>>>
> set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
>>>>>>
>>>>>>  reg1 = ct_ip6_dst();
>>>>>>      Cannot use 32-bit field reg1[[0..31]] where 128-bit field is
>>> required.
>>>>>> @@ -2455,7 +2455,7 @@ ct_ip6_dst();
>>>>>>
>>>>>>  # ct_tp_dst()
>>>>>>  reg1[[0..15]] = ct_tp_dst();
>>>>>> -    encodes as
>>>>>>
>>>
> set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
>>>>>> +    encodes as
>>>>>>
>>>
> set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
>>>>>>
>>>>>>  reg1 = ct_tp_dst();
>>>>>>      Cannot use 32-bit field reg1[[0..31]] where 16-bit field is
>>> required.
>>>>>> --
>>>>>> 2.46.2
>>>>>>
>>>>>> _______________________________________________
>>>>>> dev mailing list
>>>>>> dev@openvswitch.org
>>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>>>>
>>>>>>
>>>>> Looks good to me, thanks.
>>>>>
>>>>> Acked-by: Ales Musil <amusil@redhat.com>
>>>>>
>>>>
>>>> Thanks, Ales!  Applied to main and backported to 24.09 and 24.03.
>>>>
>>>> Regards,
>>>> Dumitru
>>>>
>>>
>>
>> Hi Han,
>>
>>> Hi Dumitru, Ales, I am trying to figure out the current register usage
> and
>>> saw this old commit. I am not sure I understand the motivation of this
>>> patch. Is there a problem of using different registers for intermediate
>>
>> There's no problem per se but we were using two registers instead of
>> one.  The intermediate register was overwritten and then its new value
>> immediately copied to the final destination register.
>>
>> The goal of the patch was to free up registers for other things in we
>> might need to do in the pipeline.
>>
>>> usage? Although this patch tried to use the same register for
> intermediate
>>> and final destination, a later commit from Ales 91988089c5 ("northd:
>>> Consolidate register usage in logical flows.") already broke it again.
>>> Shall we fix that again?
>>>
>>
>> I guess we probably should.  Maybe this time we should change the way
>> the ct_*_dst() actions are encoded?  I'm not sure how to prevent this
>> from happening again in the future though.
>>
> 

Hi Han,

> I think the right way to encode actions that require intermediate registers
> is to save the original content of the register on the stack beforehand and
> restore it afterwards. This way the intermediate registers won't really
> occupy the register space, and we don't need to worry about conflict
> usage/overwriting. Otherwise, it is very hard to maintain and not even easy
> to ensure the register is not overwritten accidentally if the same action
> is called at different stages.
> I will go ahead with this approach if it makes sense. What do you think?
> 

Sure, I was thinking of something similar initially too but I'm not sure
how we can easily implement it.  I might be missing something though.

For example:

reg4 = ct_nw_dst();

Is actually parsed as the following sequence of logical actions today:

// ct_nw_dst()
LOAD(reg1, 0)
RESUBMIT(table=81) // This might write reg1.
LOAD(reg4, reg1)

So the problem I saw was that we're losing the information we had in reg1.

To fix it, IIUC, you're suggesting to use the stack, I assume something
like:

// ct_nw_dst()
PUSH(reg1)
LOAD(reg1, 0)
RESUBMIT(table=81) // This might write reg1.
LOAD(reg4, reg1)
POP(reg1)

But the problem is that we're mixing the encoding of two logical actions
(the push/pop are for the ct_nw_dst() call while the load(reg4, ..) is
for the assignment).

I guess, the correct way is to have a proper calling convention for all
function-like actions like ct_nw_dst(), get_fdb(), etc.  And ensure we
always return the value in a predefined way, maybe always push it on the
stack?

Regards,
Dumitru

> Regards,
> Han
> 
>>> Thanks,
>>> Han
>>>
>>
>> Regards,
>> Dumitru
>>
>>>
>>>>
>>>> _______________________________________________
>>>> dev mailing list
>>>> dev@openvswitch.org
>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>
>>
>
diff mbox series

Patch

diff --git a/include/ovn/logical-fields.h b/include/ovn/logical-fields.h
index d563e044cb..70c6b93c41 100644
--- a/include/ovn/logical-fields.h
+++ b/include/ovn/logical-fields.h
@@ -60,9 +60,10 @@  enum ovn_controller_event {
 #define MFF_LOG_LB_AFF_MATCH_LR_IP6_ADDR    MFF_XXREG1
 #define MFF_LOG_LB_AFF_MATCH_PORT           MFF_REG8
 
-#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG4
-#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG0
-#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG8
+#define MFF_LOG_CT_ORIG_NW_DST_ADDR         MFF_REG1   /* REG_ORIG_DIP_IPV4 */
+#define MFF_LOG_CT_ORIG_IP6_DST_ADDR        MFF_XXREG1 /* REG_ORIG_DIP_IPV6 */
+#define MFF_LOG_CT_ORIG_TP_DST_PORT         MFF_REG2   /* REG_ORIG_TP_DPORT
+                                                        * (bits 0..15). */
 
 void ovn_init_symtab(struct shash *symtab);
 
diff --git a/tests/ovn.at b/tests/ovn.at
index 15b78f4c37..03fd2090fc 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -2420,10 +2420,10 @@  mac_cache_use;
 
 # ct_nw_dst()
 reg1 = ct_nw_dst();
-    encodes as set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[64..95]]
+    encodes as set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[64..95]]
 
 xreg1[[3..34]] = ct_nw_dst();
-    encodes as set_field:0->reg4,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG4[[]]->NXM_NX_XXREG0[[3..34]]
+    encodes as set_field:0->reg1,resubmit(,OFTABLE_CT_ORIG_NW_DST_LOAD),move:NXM_NX_REG1[[]]->NXM_NX_XXREG0[[3..34]]
 
 reg1[[3..34]] = ct_nw_dst();
     Cannot select bits 3 to 34 of 32-bit field reg1.
@@ -2442,7 +2442,7 @@  ct_nw_dst();
 
 # ct_ip6_dst()
 xxreg1 = ct_ip6_dst();
-    encodes as set_field:0/0xffffffffffffffff->xxreg0,set_field:0/0xffffffffffffffff0000000000000000->xxreg0,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG0[[]]->NXM_NX_XXREG1[[]]
+    encodes as set_field:0/0xffffffffffffffff->xxreg1,set_field:0/0xffffffffffffffff0000000000000000->xxreg1,resubmit(,OFTABLE_CT_ORIG_IP6_DST_LOAD),move:NXM_NX_XXREG1[[]]->NXM_NX_XXREG1[[]]
 
 reg1 = ct_ip6_dst();
     Cannot use 32-bit field reg1[[0..31]] where 128-bit field is required.
@@ -2455,7 +2455,7 @@  ct_ip6_dst();
 
 # ct_tp_dst()
 reg1[[0..15]] = ct_tp_dst();
-    encodes as set_field:0/0xffff->reg8,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG8[[0..15]]->NXM_NX_XXREG0[[64..79]]
+    encodes as set_field:0/0xffff->reg2,resubmit(,OFTABLE_CT_ORIG_TP_DST_LOAD),move:NXM_NX_REG2[[0..15]]->NXM_NX_XXREG0[[64..79]]
 
 reg1 = ct_tp_dst();
     Cannot use 32-bit field reg1[[0..31]] where 16-bit field is required.