[ovs-dev] [PATCH] ofproto: Return error codes for Rule insertions
Aravind Prasad
raja.avi at gmail.com
Thu Jul 12 14:41:08 UTC 2018
> Currently, rule_insert() API doesnot have return value. There are some
possible
> scenarios where rule insertions can fail at run-time even though the
static
> checks during rule_construct() had passed previously.
> Some possible scenarios for failure of rule insertions:
> **) Rule insertions can fail dynamically in Hybrid mode (both Openflow and
> Normal switch functioning coexist) where the CAM space could get suddenly
> filled up by Normal switch functioning and Openflow gets devoid of
> available space.
> **) Some deployments could have separate independent layers for HW rule
> insertions and application layer to interact with OVS. HW layer
> could face any dynamic issue during rule handling which application could
> not have predicted/captured in rule-construction phase.
> Rule-insert errors for bundles are also handled in this patch.
Hi Ben/All,
Sorry for re-sending the patch. Handled rule-insertion failures in
bundle-scenario too with this patch. Thought it could be better
if the entire set of changes are provided in a single patch for
review.
Kindly review and let me know your views.
Thanks,
Aravind Prasad S
On Thu, Jul 12, 2018 at 7:57 PM, Aravind Prasad S <raja.avi at gmail.com>
wrote:
> Currently, rule_insert() API doesnot have return value. There are some
> possible
> scenarios where rule insertions can fail at run-time even though the
> static
> checks during rule_construct() had passed previously.
> Some possible scenarios for failure of rule insertions:
> **) Rule insertions can fail dynamically in Hybrid mode (both Openflow and
> Normal switch functioning coexist) where the CAM space could get suddenly
> filled up by Normal switch functioning and Openflow gets devoid of
> available space.
> **) Some deployments could have separate independent layers for HW rule
> insertions and application layer to interact with OVS. HW layer
> could face any dynamic issue during rule handling which application could
> not have predicted/captured in rule-construction phase.
> Rule-insert errors for bundles are also handled in this patch.
>
> Signed-off-by: Aravind Prasad S <raja.avi at gmail.com>
> ---
> ofproto/ofproto-dpif.c | 4 +-
> ofproto/ofproto-provider.h | 6 +--
> ofproto/ofproto.c | 100 ++++++++++++++++++++++++++++++
> +++++----------
> 3 files changed, 84 insertions(+), 26 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index ad1e8af..d1678ed 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -4443,7 +4443,7 @@ rule_construct(struct rule *rule_)
> return 0;
> }
>
> -static void
> +static enum ofperr
> rule_insert(struct rule *rule_, struct rule *old_rule_, bool
> forward_counts)
> OVS_REQUIRES(ofproto_mutex)
> {
> @@ -4473,6 +4473,8 @@ rule_insert(struct rule *rule_, struct rule
> *old_rule_, bool forward_counts)
> ovs_mutex_unlock(&rule->stats_mutex);
> ovs_mutex_unlock(&old_rule->stats_mutex);
> }
> +
> + return 0;
> }
>
> static void
> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
> index 2b77b89..3f3d110 100644
> --- a/ofproto/ofproto-provider.h
> +++ b/ofproto/ofproto-provider.h
> @@ -1297,8 +1297,8 @@ struct ofproto_class {
> struct rule *(*rule_alloc)(void);
> enum ofperr (*rule_construct)(struct rule *rule)
> /* OVS_REQUIRES(ofproto_mutex) */;
> - void (*rule_insert)(struct rule *rule, struct rule *old_rule,
> - bool forward_counts)
> + enum ofperr (*rule_insert)(struct rule *rule, struct rule *old_rule,
> + bool forward_counts)
> /* OVS_REQUIRES(ofproto_mutex) */;
> void (*rule_delete)(struct rule *rule) /* OVS_REQUIRES(ofproto_mutex)
> */;
> void (*rule_destruct)(struct rule *rule);
> @@ -1952,7 +1952,7 @@ enum ofperr ofproto_flow_mod_learn_start(struct
> ofproto_flow_mod *ofm)
> OVS_REQUIRES(ofproto_mutex);
> void ofproto_flow_mod_learn_revert(struct ofproto_flow_mod *ofm)
> OVS_REQUIRES(ofproto_mutex);
> -void ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm,
> +enum ofperr ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm,
> struct ofproto *orig_ofproto)
> OVS_REQUIRES(ofproto_mutex);
> void ofproto_add_flow(struct ofproto *, const struct match *, int
> priority,
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index f946e27..03597dc 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -245,10 +245,12 @@ static void replace_rule_revert(struct ofproto *,
> struct rule *old_rule,
> struct rule *new_rule)
> OVS_REQUIRES(ofproto_mutex);
>
> -static void replace_rule_finish(struct ofproto *, struct ofproto_flow_mod
> *,
> - const struct openflow_mod_requester *,
> - struct rule *old_rule, struct rule
> *new_rule,
> - struct ovs_list *dead_cookies)
> +static enum ofperr replace_rule_finish(struct ofproto *,
> + struct ofproto_flow_mod *,
> + const struct
> openflow_mod_requester *,
> + struct rule *old_rule,
> + struct rule *new_rule,
> + struct ovs_list *dead_cookies)
> OVS_REQUIRES(ofproto_mutex);
> static void delete_flows__(struct rule_collection *,
> enum ofp_flow_removed_reason,
> @@ -270,7 +272,7 @@ static enum ofperr ofproto_flow_mod_start(struct
> ofproto *,
> static void ofproto_flow_mod_revert(struct ofproto *,
> struct ofproto_flow_mod *)
> OVS_REQUIRES(ofproto_mutex);
> -static void ofproto_flow_mod_finish(struct ofproto *,
> +static enum ofperr ofproto_flow_mod_finish(struct ofproto *,
> struct ofproto_flow_mod *,
> const struct openflow_mod_requester *)
> OVS_REQUIRES(ofproto_mutex);
> @@ -4855,7 +4857,7 @@ add_flow_revert(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm)
> }
>
> /* To be called after version bump. */
> -static void
> +static enum ofperr
> add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
> const struct openflow_mod_requester *req)
> OVS_REQUIRES(ofproto_mutex)
> @@ -4864,8 +4866,14 @@ add_flow_finish(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm,
> ? rule_collection_rules(&ofm->old_rules)[0] : NULL;
> struct rule *new_rule = rule_collection_rules(&ofm->new_rules)[0];
> struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_cookies);
> + enum ofperr error = 0;
> +
> + error = replace_rule_finish(ofproto, ofm, req, old_rule, new_rule,
> + &dead_cookies);
> + if (error) {
> + return error;
> + }
>
> - replace_rule_finish(ofproto, ofm, req, old_rule, new_rule,
> &dead_cookies);
> learned_cookies_flush(ofproto, &dead_cookies);
>
> if (old_rule) {
> @@ -4878,6 +4886,8 @@ add_flow_finish(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm,
> /* Send Vacancy Events for OF1.4+. */
> send_table_status(ofproto, new_rule->table_id);
> }
> +
> + return error;
> }
>
> /* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */
> @@ -5074,22 +5084,25 @@ ofproto_flow_mod_learn_revert(struct
> ofproto_flow_mod *ofm)
> ofproto_flow_mod_revert(rule->ofproto, ofm);
> }
>
> -void
> +enum ofperr
> ofproto_flow_mod_learn_finish(struct ofproto_flow_mod *ofm,
> struct ofproto *orig_ofproto)
> OVS_REQUIRES(ofproto_mutex)
> {
> struct rule *rule = rule_collection_rules(&ofm->new_rules)[0];
> + enum ofperr error = 0;
>
> /* If learning on a different bridge, must bump its version
> * number and flush connmgr afterwards. */
> if (rule->ofproto != orig_ofproto) {
> ofproto_bump_tables_version(rule->ofproto);
> }
> - ofproto_flow_mod_finish(rule->ofproto, ofm, NULL);
> + error = ofproto_flow_mod_finish(rule->ofproto, ofm, NULL);
> if (rule->ofproto != orig_ofproto) {
> ofmonitor_flush(rule->ofproto->connmgr);
> }
> +
> + return error;
> }
>
> /* Refresh 'ofm->temp_rule', for which the caller holds a reference, if
> already
> @@ -5144,7 +5157,7 @@ ofproto_flow_mod_learn(struct ofproto_flow_mod *ofm,
> bool keep_ref,
>
> error = ofproto_flow_mod_learn_start(ofm);
> if (!error) {
> - ofproto_flow_mod_learn_finish(ofm, NULL);
> + error = ofproto_flow_mod_learn_finish(ofm, NULL);
> }
> } else {
> static struct vlog_rate_limit rll = VLOG_RATE_LIMIT_INIT(1,
> 5);
> @@ -5244,7 +5257,7 @@ replace_rule_revert(struct ofproto *ofproto,
> }
>
> /* Adds the 'new_rule', replacing the 'old_rule'. */
> -static void
> +static enum ofperr
> replace_rule_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
> const struct openflow_mod_requester *req,
> struct rule *old_rule, struct rule *new_rule,
> @@ -5252,6 +5265,8 @@ replace_rule_finish(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm,
> OVS_REQUIRES(ofproto_mutex)
> {
> struct rule *replaced_rule;
> + enum ofperr error = 0;
> + struct oftable *table = &ofproto->tables[new_rule->table_id];
>
> replaced_rule = (old_rule && old_rule->removed_reason !=
> OFPRR_EVICTION)
> ? old_rule : NULL;
> @@ -5261,8 +5276,15 @@ replace_rule_finish(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm,
> * link the packet and byte counts from the old rule to the new one if
> * 'modify_keep_counts' is 'true'. The 'replaced_rule' will be
> deleted
> * right after this call. */
> - ofproto->ofproto_class->rule_insert(new_rule, replaced_rule,
> - ofm->modify_keep_counts);
> + error = ofproto->ofproto_class->rule_insert(new_rule, replaced_rule,
> + ofm->modify_keep_counts);
> + if (error) {
> + if (classifier_remove(&table->cls, &new_rule->cr)) {
> + ofproto_rule_destroy__(new_rule);
> + }
> + return error;
> + }
> +
> learned_cookies_inc(ofproto, rule_get_actions(new_rule));
>
> if (old_rule) {
> @@ -5298,6 +5320,8 @@ replace_rule_finish(struct ofproto *ofproto, struct
> ofproto_flow_mod *ofm,
> req ? req->request->xid : 0, NULL);
> }
> }
> +
> + return error;
> }
>
> /* ofm->temp_rule is consumed only in the successful case. */
> @@ -5448,17 +5472,18 @@ modify_flows_revert(struct ofproto *ofproto,
> struct ofproto_flow_mod *ofm)
> }
> }
>
> -static void
> +static enum ofperr
> modify_flows_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
> const struct openflow_mod_requester *req)
> OVS_REQUIRES(ofproto_mutex)
> {
> struct rule_collection *old_rules = &ofm->old_rules;
> struct rule_collection *new_rules = &ofm->new_rules;
> + enum ofperr error = 0;
>
> if (rule_collection_n(old_rules) == 0
> && rule_collection_n(new_rules) == 1) {
> - add_flow_finish(ofproto, ofm, req);
> + error = add_flow_finish(ofproto, ofm, req);
> } else if (rule_collection_n(old_rules) > 0) {
> struct ovs_list dead_cookies = OVS_LIST_INITIALIZER(&dead_
> cookies);
>
> @@ -5467,12 +5492,17 @@ modify_flows_finish(struct ofproto *ofproto,
> struct ofproto_flow_mod *ofm,
>
> struct rule *old_rule, *new_rule;
> RULE_COLLECTIONS_FOR_EACH (old_rule, new_rule, old_rules,
> new_rules) {
> - replace_rule_finish(ofproto, ofm, req, old_rule, new_rule,
> - &dead_cookies);
> + error = replace_rule_finish(ofproto, ofm, req, old_rule,
> new_rule,
> + &dead_cookies);
> + if (error) {
> + return error;
> + }
> }
> learned_cookies_flush(ofproto, &dead_cookies);
> remove_rules_postponed(old_rules);
> }
> +
> + return error;
> }
>
> static enum ofperr
> @@ -5838,7 +5868,7 @@ handle_flow_mod__(struct ofproto *ofproto, const
> struct ofputil_flow_mod *fm,
> error = ofproto_flow_mod_start(ofproto, &ofm);
> if (!error) {
> ofproto_bump_tables_version(ofproto);
> - ofproto_flow_mod_finish(ofproto, &ofm, req);
> + error = ofproto_flow_mod_finish(ofproto, &ofm, req);
> ofmonitor_flush(ofproto->connmgr);
> }
> ovs_mutex_unlock(&ofproto_mutex);
> @@ -7668,19 +7698,21 @@ ofproto_flow_mod_revert(struct ofproto *ofproto,
> struct ofproto_flow_mod *ofm)
> rule_collection_destroy(&ofm->new_rules);
> }
>
> -static void
> +static enum ofperr
> ofproto_flow_mod_finish(struct ofproto *ofproto, struct ofproto_flow_mod
> *ofm,
> const struct openflow_mod_requester *req)
> OVS_REQUIRES(ofproto_mutex)
> {
> + enum ofperr error = 0;
> +
> switch (ofm->command) {
> case OFPFC_ADD:
> - add_flow_finish(ofproto, ofm, req);
> + error = add_flow_finish(ofproto, ofm, req);
> break;
>
> case OFPFC_MODIFY:
> case OFPFC_MODIFY_STRICT:
> - modify_flows_finish(ofproto, ofm, req);
> + error = modify_flows_finish(ofproto, ofm, req);
> break;
>
> case OFPFC_DELETE:
> @@ -7698,6 +7730,8 @@ ofproto_flow_mod_finish(struct ofproto *ofproto,
> struct ofproto_flow_mod *ofm,
> if (req) {
> ofconn_report_flow_mod(req->ofconn, ofm->command);
> }
> +
> + return error;
> }
>
> /* Commit phases (all while locking ofproto_mutex):
> @@ -7827,13 +7861,35 @@ do_bundle_commit(struct ofconn *ofconn, uint32_t
> id, uint16_t flags)
> struct openflow_mod_requester req = { ofconn, be->msg
> };
>
> if (be->type == OFPTYPE_FLOW_MOD) {
> - ofproto_flow_mod_finish(ofproto, &be->ofm, &req);
> + error = ofproto_flow_mod_finish(ofproto,
> &be->ofm,
> + &req);
> } else if (be->type == OFPTYPE_GROUP_MOD) {
> ofproto_group_mod_finish(ofproto, &be->ogm,
> &req);
> } else if (be->type == OFPTYPE_PACKET_OUT) {
> ofproto_packet_out_finish(ofproto, &be->opo);
> }
> }
> + if (error) {
> + break;
> + }
> + }
> + if (error) {
> + /* Send error referring to the original message. */
> + if (error) {
> + ofconn_send_error(ofconn, be->msg, error);
> + error = OFPERR_OFPBFC_MSG_FAILED;
> + }
> + /* Revert. Undo all the changes made above. */
> + LIST_FOR_EACH_REVERSE_CONTINUE (be, node,
> &bundle->msg_list) {
> + if (be->type == OFPTYPE_FLOW_MOD) {
> + ofproto_flow_mod_revert(ofproto, &be->ofm);
> + } else if (be->type == OFPTYPE_GROUP_MOD) {
> + ofproto_group_mod_revert(ofproto, &be->ogm);
> + } else if (be->type == OFPTYPE_PACKET_OUT) {
> + ofproto_packet_out_revert(ofproto, &be->opo);
> + }
> + /* Nothing needs to be reverted for a port mod. */
> + }
> }
> }
>
> --
> 1.9.1
>
>
More information about the dev
mailing list