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]> --- 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" /* 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); + 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); + 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 { -- 2.38.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
