On 9/1/26 7:41 AM, Han Zhou wrote:
> On Tue, Aug 18, 2026 at 2:27 AM Dumitru Ceara <[email protected]> wrote:
>>
>> On 7/22/26 7:49 AM, Han Zhou wrote:
>>> OVS 3.7 (OVS commit 3900653) increased FLOW_N_REGS from 16 to 32, making
>>> registers reg16..reg31 (xxreg4..xxreg7) usable.  However, whether the
>>> running ovs-vswitchd actually supports them depends on its version, so
>>> OVN must detect this at runtime before relying on those registers.
>>>
>>> Add an OVS OpenFlow feature probe (OVS_REG32_SUPPORT) that pushes a
>>> discarded bundle containing a flow_mod matching reg16.  An ovs-vswitchd
>>> that does not support 32 registers rejects it with an error; a newer one
>>> accepts it, so the barrier is reached without error.
>>>
>>> ovn-controller advertises the result to the SB Chassis via
>>> other_config:ovn-32-registers, and ovn-northd aggregates it across all
>>> local chassis into chassis_features.reg32.  This lets later features use
>>> registers beyond reg15 only when every chassis supports them, and fall
>>> back otherwise.
>>>
>>> Assisted-by: Claude Opus 4.8, Cursor
>>> Signed-off-by: Han Zhou <[email protected]>
>>> ---
>>
>> Hi Han,
>>
>> This is not really needed for the "Support per-route VNI for learned
>> EVPN routes." patch-set as I see you reworked it without new registers.
>> But I think it would be a nice to have feature.  I'm sure we will need
>> the detection mechanism in the near future.
>>
>> Do you mind posting this one separately as a regular patch?
> 
> Thanks Dumitru. Could you review this patch as a separate one? If it looks
> good, I can merge this one and post the 2nd patch again.
> 

Hi Han,

Sure, sounds good.

> Best,
> Han
> 
>>
>> Regards,
>> Dumitru
>>
>>>  controller/chassis.c      | 12 +++++++
>>>  include/ovn/features.h    |  6 ++++
>>>  lib/features.c            | 75 +++++++++++++++++++++++++++++++++++++++
>>>  northd/en-global-config.c | 13 +++++++
>>>  northd/en-global-config.h |  1 +
>>>  5 files changed, 107 insertions(+)
>>>
>>> diff --git a/controller/chassis.c b/controller/chassis.c
>>> index 0e3bd37d8752..2160c84d5c91 100644
>>> --- a/controller/chassis.c
>>> +++ b/controller/chassis.c
>>> @@ -74,6 +74,8 @@ struct ovs_chassis_cfg {
>>>      bool sample_with_regs;
>>>      /* Does OVS support flushing CT zones using label/mark? */
>>>      bool ct_label_flush;
>>> +    /* Does OVS support 32 registers (reg16..reg31)? */
>>> +    bool reg32;
>>>  };
>>>
>>>  enum chassis_update_status {
>>> @@ -385,6 +387,7 @@ chassis_parse_ovs_config(const struct
> ovsrec_open_vswitch_table *ovs_table,
>>>          ovs_feature_is_supported(OVS_SAMPLE_REG_SUPPORT);
>>>      ovs_cfg->ct_label_flush =
>>>          ovs_feature_is_supported(OVS_CT_LABEL_FLUSH_SUPPORT);
>>> +    ovs_cfg->reg32 = ovs_feature_is_supported(OVS_REG32_SUPPORT);
>>>
>>>      return true;
>>>  }
>>> @@ -424,6 +427,8 @@ chassis_build_other_config(const struct
> ovs_chassis_cfg *ovs_cfg,
>>>      smap_replace(config, OVN_FEATURE_CT_LABEL_FLUSH,
>>>                   ovs_cfg->ct_label_flush ? "true" :"false");
>>>      smap_replace(config, OVN_FEATURE_CT_STATE_SAVE, "true");
>>> +    smap_replace(config, OVN_FEATURE_REG32,
>>> +                 ovs_cfg->reg32 ? "true" : "false");
>>>  }
>>>
>>>  /*
>>> @@ -597,6 +602,12 @@ chassis_other_config_changed(const struct
> ovs_chassis_cfg *ovs_cfg,
>>>          return true;
>>>      }
>>>
>>> +    bool chassis_reg32 =
>>> +        smap_get_bool(&chassis_rec->other_config, OVN_FEATURE_REG32,
> false);
>>> +    if (chassis_reg32 != ovs_cfg->reg32) {
>>> +        return true;
>>> +    }
>>> +
>>>      return false;
>>>  }
>>>
>>> @@ -779,6 +790,7 @@ update_supported_sset(struct sset *supported)
>>>      sset_add(supported, OVN_FEATURE_CT_NEXT_ZONE);
>>>      sset_add(supported, OVN_FEATURE_CT_LABEL_FLUSH);
>>>      sset_add(supported, OVN_FEATURE_CT_STATE_SAVE);
>>> +    sset_add(supported, OVN_FEATURE_REG32);
>>>  }
>>>
>>>  static void
>>> diff --git a/include/ovn/features.h b/include/ovn/features.h
>>> index 7207da67fd20..bb7c85ea5cff 100644
>>> --- a/include/ovn/features.h
>>> +++ b/include/ovn/features.h
>>> @@ -27,6 +27,7 @@
>>>  #define OVN_FEATURE_CT_NEXT_ZONE "ct-next-zone"
>>>  #define OVN_FEATURE_CT_LABEL_FLUSH "ct-label-flush"
>>>  #define OVN_FEATURE_CT_STATE_SAVE "ct-state-save"
>>> +#define OVN_FEATURE_REG32 "ovn-32-registers"

Should we also update chassis_features_list() to list the state of the
new feature?  And I guess we should also update the ovn-controller.at
"AT_SETUP([features])" test to exclude this new feature.

>>>
>>>  /* DEPRECATED: The following features can be removed
>>>   * after the next LTS version release. */
>>> @@ -45,6 +46,7 @@ enum ovs_feature_support_bits {
>>>      OVS_OF_GROUP_SUPPORT_BIT,
>>>      OVS_SAMPLE_REG_SUPPORT_BIT,
>>>      OVS_CT_LABEL_FLUSH_BIT,
>>> +    OVS_REG32_SUPPORT_BIT,
>>>  };
>>>
>>>  enum ovs_feature_value {
>>> @@ -55,6 +57,10 @@ enum ovs_feature_value {
>>>      OVS_OF_GROUP_SUPPORT = (1 << OVS_OF_GROUP_SUPPORT_BIT),
>>>      OVS_SAMPLE_REG_SUPPORT = (1 << OVS_SAMPLE_REG_SUPPORT_BIT),
>>>      OVS_CT_LABEL_FLUSH_SUPPORT = (1 << OVS_CT_LABEL_FLUSH_BIT),
>>> +    /* OVS (and its OpenFlow interface) supports 32 32-bit registers,
>>> +     * i.e. registers reg16..reg31 (xxreg4..xxreg7) are usable.  Older
> OVS
>>> +     * versions only support 16 registers. */
>>> +    OVS_REG32_SUPPORT = (1 << OVS_REG32_SUPPORT_BIT),
>>>  };
>>>
>>>  void ovs_feature_support_destroy(void);
>>> diff --git a/lib/features.c b/lib/features.c
>>> index 7bee1c3806e6..b787bf7e8529 100644
>>> --- a/lib/features.c
>>> +++ b/lib/features.c
>>> @@ -269,6 +269,73 @@ sample_with_reg_handle_barrier(struct
> ovs_openflow_feature *feature OVS_UNUSED)
>>>      return true;
>>>  }
>>>
>>> +static void
>>> +reg32_send_request(struct ovs_openflow_feature *feature)
>>> +{
>>> +    struct ofputil_bundle_ctrl_msg ctrl = {
>>> +        .bundle_id = 0,
>>> +        .flags     = OFPBF_ORDERED | OFPBF_ATOMIC,
>>> +        .type      = OFPBCT_OPEN_REQUEST,
>>> +    };
>>> +    rconn_send(swconn,
>>> +               ofputil_encode_bundle_ctrl_request(OFP15_VERSION,
> &ctrl), NULL);
>>> +
>>> +    struct ofputil_flow_mod fm = {
>>> +        .priority = 0,
>>> +        .table_id = 0,
>>> +        .ofpacts = NULL,
>>> +        .ofpacts_len = 0,
>>> +        .command = OFPFC_ADD,
>>> +        .new_cookie = htonll(0),
>>> +        .buffer_id = UINT32_MAX,
>>> +        .out_port = OFPP_ANY,
>>> +        .out_group = OFPG_ANY,
>>> +    };
>>> +
>>> +    /* Match on reg16, which only exists when the running OVS supports
> 32
>>> +     * registers.  Older OVS versions reject the flow_mod with an
> error. */
>>> +    struct match match;
>>> +    match_init_catchall(&match);
>>> +    match_set_reg(&match, MFF_REG16 - MFF_REG0, 1);

Maybe it's safer to match on MFF_REG31 instead?  What do you think?

>>> +    minimatch_init(&fm.match, &match);
>>> +
>>> +    struct ofpbuf *fm_msg = ofputil_encode_flow_mod(&fm,
> OFPUTIL_P_OF15_OXM);
>>> +
>>> +    struct ofputil_bundle_add_msg bam = {
>>> +        .bundle_id = ctrl.bundle_id,
>>> +        .flags = ctrl.flags,
>>> +        .msg = fm_msg->data,
>>> +    };
>>> +    struct ofpbuf *msg = ofputil_encode_bundle_add(OFP15_VERSION,
> &bam);
>>> +
>>> +    feature->xid = ((struct ofp_header *) msg->data)->xid;
>>> +    rconn_send(swconn, msg, NULL);
>>> +
>>> +    ctrl.type = OFPBCT_DISCARD_REQUEST;
>>> +    rconn_send(swconn,
>>> +               ofputil_encode_bundle_ctrl_request(OFP15_VERSION,
> &ctrl), NULL);
>>> +
>>> +    minimatch_destroy(&fm.match);
>>> +    ofpbuf_delete(fm_msg);
>>> +}
>>> +
>>> +static bool
>>> +reg32_handle_response(struct ovs_openflow_feature *feature,
>>> +                      enum ofptype type, const struct ofp_header *oh)
>>> +{
>>> +    if (type != OFPTYPE_ERROR) {
>>> +        log_unexpected_reply(feature, oh);
>>> +    }
>>> +
>>> +    return false;
>>> +}
>>> +
>>> +static bool
>>> +reg32_handle_barrier(struct ovs_openflow_feature *feature OVS_UNUSED)
>>> +{
>>> +    return true;
>>> +}
>>> +
>>>  static void
>>>  ct_label_flush_send_request(struct ovs_openflow_feature *feature)
>>>  {
>>> @@ -345,6 +412,13 @@ static struct ovs_openflow_feature
> all_openflow_features[] = {
>>>              .handle_response = ct_label_flush_handle_response,
>>>              .handle_barrier = ct_label_flush_handle_barrier,
>>>          },
>>> +        {
>>> +            .value = OVS_REG32_SUPPORT,
>>> +            .name = "reg32",
>>> +            .send_request = reg32_send_request,
>>> +            .handle_response = reg32_handle_response,
>>> +            .handle_barrier = reg32_handle_barrier,
>>> +        },
>>>  };
>>>
>>>  static bool
>>> @@ -418,6 +492,7 @@ ovs_feature_is_valid(enum ovs_feature_value feature)
>>>      case OVS_OF_GROUP_SUPPORT:
>>>      case OVS_SAMPLE_REG_SUPPORT:
>>>      case OVS_CT_LABEL_FLUSH_SUPPORT:
>>> +    case OVS_REG32_SUPPORT:
>>>          return true;
>>>      default:
>>>          return false;
>>> diff --git a/northd/en-global-config.c b/northd/en-global-config.c
>>> index 4e6b07ebe50e..0667e11ffe8a 100644
>>> --- a/northd/en-global-config.c
>>> +++ b/northd/en-global-config.c
>>> @@ -520,6 +520,7 @@ northd_enable_all_features(struct
> ed_type_global_config *data)
>>>          .ct_next_zone = true,
>>>          .ct_label_flush = true,
>>>          .ct_state_save = true,
>>> +        .reg32 = true,
>>>      };
>>>  }
>>>
>>> @@ -590,6 +591,14 @@ build_chassis_features(const struct
> sbrec_chassis_table *sbrec_chassis_table,
>>>              chassis_features->ct_state_save) {
>>>              chassis_features->ct_state_save = false;
>>>          }
>>> +
>>> +        bool reg32 =
>>> +                smap_get_bool(&chassis->other_config,
>>> +                              OVN_FEATURE_REG32,
>>> +                              false);

The indentation is weird here but it was weird for the rest of the
features above so let's keep it as is.

>>> +        if (!reg32 && chassis_features->reg32) {
>>> +            chassis_features->reg32 = false;
>>> +        }
>>>      }
>>>  }
>>>
>>> @@ -747,6 +756,10 @@ chassis_features_changed(const struct
> chassis_features *present,
>>>          return true;
>>>      }
>>>
>>> +    if (present->reg32 != updated->reg32) {
>>> +        return true;
>>> +    }
>>> +
>>>      return false;
>>>  }
>>>
>>> diff --git a/northd/en-global-config.h b/northd/en-global-config.h
>>> index 5a7b7ecda766..9b75ecff3d21 100644
>>> --- a/northd/en-global-config.h
>>> +++ b/northd/en-global-config.h
>>> @@ -20,6 +20,7 @@ struct chassis_features {
>>>      bool ct_next_zone;
>>>      bool ct_label_flush;
>>>      bool ct_state_save;
>>> +    bool reg32;
>>>  };
>>>
>>>  struct global_config_tracked_data {
> 

Regards,
Dumitru

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

Reply via email to