Acked-by: Ethan Jackson <et...@nicira.com>
On Thu, Sep 12, 2013 at 12:39 AM, Ben Pfaff <b...@nicira.com> wrote: > The ofproto_node member is convenient for collecting lists of rules, but > it is also challenging for concurrency because only a single thread at a > time can put a given rule on a list. This commit eliminates the > ofproto_node member and introduces a new 'struct rule_collection' that > can be use in a thread-safe manner. > > Signed-off-by: Ben Pfaff <b...@nicira.com> > --- > ofproto/connmgr.c | 4 +- > ofproto/connmgr.h | 7 +- > ofproto/ofproto-provider.h | 14 ++- > ofproto/ofproto.c | 216 > ++++++++++++++++++++++++++++++-------------- > 4 files changed, 166 insertions(+), 75 deletions(-) > > diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c > index 2f315e6..f0861fd 100644 > --- a/ofproto/connmgr.c > +++ b/ofproto/connmgr.c > @@ -1951,12 +1951,12 @@ ofmonitor_flush(struct connmgr *mgr) > static void > ofmonitor_resume(struct ofconn *ofconn) > { > + struct rule_collection rules; > struct ofpbuf *resumed; > struct ofmonitor *m; > - struct list rules; > struct list msgs; > > - list_init(&rules); > + rule_collection_init(&rules); > HMAP_FOR_EACH (m, ofconn_node, &ofconn->monitors) { > ofmonitor_collect_resume_rules(m, ofconn->monitor_paused, &rules); > } > diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h > index 72134b0..c487f71 100644 > --- a/ofproto/connmgr.h > +++ b/ofproto/connmgr.h > @@ -190,8 +190,11 @@ void ofmonitor_report(struct connmgr *, struct rule *, > const struct ofconn *abbrev_ofconn, ovs_be32 > abbrev_xid); > void ofmonitor_flush(struct connmgr *); > > + > +struct rule_collection; > void ofmonitor_collect_resume_rules(struct ofmonitor *, uint64_t seqno, > - struct list *rules); > -void ofmonitor_compose_refresh_updates(struct list *rules, struct list > *msgs); > + struct rule_collection *); > +void ofmonitor_compose_refresh_updates(struct rule_collection *rules, > + struct list *msgs); > > #endif /* connmgr.h */ > diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h > index 4cbf47f..d5fec1b 100644 > --- a/ofproto/ofproto-provider.h > +++ b/ofproto/ofproto-provider.h > @@ -217,7 +217,6 @@ struct oftable { > * With few exceptions, ofproto implementations may look at these fields but > * should not modify them. */ > struct rule { > - struct list ofproto_node; /* Owned by ofproto base code. */ > struct ofproto *ofproto; /* The ofproto that contains this rule. */ > struct cls_rule cr; /* In owning ofproto's classifier. */ > > @@ -269,6 +268,19 @@ struct rule { > * is expirable, otherwise empty. */ > }; > > +/* A set of rules to which an OpenFlow operation applies. */ > +struct rule_collection { > + struct rule **rules; /* The rules. */ > + size_t n; /* Number of rules collected. */ > + > + size_t capacity; /* Number of rules that will fit in 'rules'. > */ > + struct rule *stub[64]; /* Preallocated rules to avoid malloc(). */ > +}; > + > +void rule_collection_init(struct rule_collection *); > +void rule_collection_add(struct rule_collection *, struct rule *); > +void rule_collection_destroy(struct rule_collection *); > + > /* Threshold at which to begin flow table eviction. Only affects the > * ofproto-dpif implementation */ > extern unsigned flow_eviction_threshold; > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > index 98a0752..50ab58c 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -242,7 +242,8 @@ static enum ofperr add_flow(struct ofproto *, struct > ofconn *, > const struct ofp_header *); > static enum ofperr modify_flows__(struct ofproto *, struct ofconn *, > struct ofputil_flow_mod *, > - const struct ofp_header *, struct list *); > + const struct ofp_header *, > + const struct rule_collection *); > static void delete_flow__(struct rule *rule, struct ofopgroup *, > enum ofp_flow_removed_reason) > OVS_RELEASES(rule->rwlock); > @@ -2992,9 +2993,46 @@ rule_criteria_destroy(struct rule_criteria *criteria) > cls_rule_destroy(&criteria->cr); > } > > +void > +rule_collection_init(struct rule_collection *rules) > +{ > + rules->rules = rules->stub; > + rules->n = 0; > + rules->capacity = ARRAY_SIZE(rules->stub); > +} > + > +void > +rule_collection_add(struct rule_collection *rules, struct rule *rule) > +{ > + if (rules->n >= rules->capacity) { > + size_t old_size, new_size; > + > + old_size = rules->capacity * sizeof *rules->rules; > + rules->capacity *= 2; > + new_size = rules->capacity * sizeof *rules->rules; > + > + if (rules->rules == rules->stub) { > + rules->rules = xmalloc(new_size); > + memcpy(rules->rules, rules->stub, old_size); > + } else { > + rules->rules = xrealloc(rules->rules, new_size); > + } > + } > + > + rules->rules[rules->n++] = rule; > +} > + > +void > +rule_collection_destroy(struct rule_collection *rules) > +{ > + if (rules->rules != rules->stub) { > + free(rules->rules); > + } > +} > + > static enum ofperr > collect_rule(struct rule *rule, const struct rule_criteria *c, > - struct list *rules) > + struct rule_collection *rules) > { > if (ofproto_rule_is_hidden(rule)) { > return 0; > @@ -3005,7 +3043,7 @@ collect_rule(struct rule *rule, const struct > rule_criteria *c, > && ofproto_rule_has_out_port(rule, c->out_port) > && ofproto_rule_has_out_group(rule, c->out_group) > && !((rule->flow_cookie ^ c->cookie) & c->cookie_mask)) { > - list_push_back(rules, &rule->ofproto_node); > + rule_collection_add(rules, rule); > } > return 0; > } > @@ -3021,18 +3059,19 @@ collect_rule(struct rule *rule, const struct > rule_criteria *c, > * Returns 0 on success, otherwise an OpenFlow error code. */ > static enum ofperr > collect_rules_loose(struct ofproto *ofproto, > - const struct rule_criteria *criteria, struct list *rules) > + const struct rule_criteria *criteria, > + struct rule_collection *rules) > { > struct oftable *table; > enum ofperr error; > > + rule_collection_init(rules); > + > error = check_table_id(ofproto, criteria->table_id); > if (error) { > - return error; > + goto exit; > } > > - list_init(rules); > - > if (criteria->cookie_mask == htonll(UINT64_MAX)) { > struct rule *rule; > > @@ -3063,6 +3102,10 @@ collect_rules_loose(struct ofproto *ofproto, > } > } > > +exit: > + if (error) { > + rule_collection_destroy(rules); > + } > return error; > } > > @@ -3076,18 +3119,19 @@ collect_rules_loose(struct ofproto *ofproto, > * Returns 0 on success, otherwise an OpenFlow error code. */ > static enum ofperr > collect_rules_strict(struct ofproto *ofproto, > - const struct rule_criteria *criteria, struct list > *rules) > + const struct rule_criteria *criteria, > + struct rule_collection *rules) > { > struct oftable *table; > int error; > > + rule_collection_init(rules); > + > error = check_table_id(ofproto, criteria->table_id); > if (error) { > - return error; > + goto exit; > } > > - list_init(rules); > - > if (criteria->cookie_mask == htonll(UINT64_MAX)) { > struct rule *rule; > > @@ -3118,6 +3162,10 @@ collect_rules_strict(struct ofproto *ofproto, > } > } > > +exit: > + if (error) { > + rule_collection_destroy(rules); > + } > return error; > } > > @@ -3138,10 +3186,10 @@ handle_flow_stats_request(struct ofconn *ofconn, > struct ofproto *ofproto = ofconn_get_ofproto(ofconn); > struct ofputil_flow_stats_request fsr; > struct rule_criteria criteria; > + struct rule_collection rules; > struct list replies; > - struct list rules; > - struct rule *rule; > enum ofperr error; > + size_t i; > > error = ofputil_decode_flow_stats_request(&fsr, request); > if (error) { > @@ -3157,7 +3205,8 @@ handle_flow_stats_request(struct ofconn *ofconn, > } > > ofpmp_init(&replies, request); > - LIST_FOR_EACH (rule, ofproto_node, &rules) { > + for (i = 0; i < rules.n; i++) { > + struct rule *rule = rules.rules[i]; > long long int now = time_msec(); > struct ofputil_flow_stats fs; > > @@ -3182,6 +3231,8 @@ handle_flow_stats_request(struct ofconn *ofconn, > > ofputil_append_flow_stats_reply(&fs, &replies); > } > + rule_collection_destroy(&rules); > + > ofconn_send_replies(ofconn, &replies); > > return 0; > @@ -3263,10 +3314,10 @@ handle_aggregate_stats_request(struct ofconn *ofconn, > struct ofputil_aggregate_stats stats; > bool unknown_packets, unknown_bytes; > struct rule_criteria criteria; > + struct rule_collection rules; > struct ofpbuf *reply; > - struct list rules; > - struct rule *rule; > enum ofperr error; > + size_t i; > > error = ofputil_decode_flow_stats_request(&request, oh); > if (error) { > @@ -3284,7 +3335,8 @@ handle_aggregate_stats_request(struct ofconn *ofconn, > > memset(&stats, 0, sizeof stats); > unknown_packets = unknown_bytes = false; > - LIST_FOR_EACH (rule, ofproto_node, &rules) { > + for (i = 0; i < rules.n; i++) { > + struct rule *rule = rules.rules[i]; > uint64_t packet_count; > uint64_t byte_count; > > @@ -3312,6 +3364,8 @@ handle_aggregate_stats_request(struct ofconn *ofconn, > stats.byte_count = UINT64_MAX; > } > > + rule_collection_destroy(&rules); > + > reply = ofputil_encode_aggregate_stats_reply(&stats, oh); > ofconn_send_reply(ofconn, reply); > > @@ -3531,12 +3585,15 @@ add_flow(struct ofproto *ofproto, struct ofconn > *ofconn, > } else if (rule->pending) { > return OFPROTO_POSTPONE; > } else { > - struct list rules; > + struct rule_collection rules; > > - list_init(&rules); > - list_push_back(&rules, &rule->ofproto_node); > + rule_collection_init(&rules); > + rule_collection_add(&rules, rule); > fm->modify_cookie = true; > - return modify_flows__(ofproto, ofconn, fm, request, &rules); > + error = modify_flows__(ofproto, ofconn, fm, request, &rules); > + rule_collection_destroy(&rules); > + > + return error; > } > } > > @@ -3641,17 +3698,18 @@ add_flow(struct ofproto *ofproto, struct ofconn > *ofconn, > static enum ofperr > modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn, > struct ofputil_flow_mod *fm, const struct ofp_header *request, > - struct list *rules) > + const struct rule_collection *rules) > { > enum ofoperation_type type; > struct ofopgroup *group; > - struct rule *rule; > enum ofperr error; > + size_t i; > > type = fm->command == OFPFC_ADD ? OFOPERATION_REPLACE : > OFOPERATION_MODIFY; > group = ofopgroup_create(ofproto, ofconn, request, fm->buffer_id); > error = OFPERR_OFPBRC_EPERM; > - LIST_FOR_EACH (rule, ofproto_node, rules) { > + for (i = 0; i < rules->n; i++) { > + struct rule *rule = rules->rules[i]; > struct ofoperation *op; > bool actions_changed; > bool reset_counters; > @@ -3740,7 +3798,7 @@ modify_flows_loose(struct ofproto *ofproto, struct > ofconn *ofconn, > const struct ofp_header *request) > { > struct rule_criteria criteria; > - struct list rules; > + struct rule_collection rules; > int error; > > rule_criteria_init(&criteria, fm->table_id, &fm->match, 0, > @@ -3748,13 +3806,15 @@ modify_flows_loose(struct ofproto *ofproto, struct > ofconn *ofconn, > error = collect_rules_loose(ofproto, &criteria, &rules); > rule_criteria_destroy(&criteria); > > - if (error) { > - return error; > - } else if (list_is_empty(&rules)) { > - return modify_flows_add(ofproto, ofconn, fm, request); > - } else { > - return modify_flows__(ofproto, ofconn, fm, request, &rules); > + if (!error) { > + error = (rules.n > 0 > + ? modify_flows__(ofproto, ofconn, fm, request, &rules) > + : modify_flows_add(ofproto, ofconn, fm, request)); > } > + > + rule_collection_destroy(&rules); > + > + return error; > } > > /* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error > @@ -3768,7 +3828,7 @@ modify_flow_strict(struct ofproto *ofproto, struct > ofconn *ofconn, > const struct ofp_header *request) > { > struct rule_criteria criteria; > - struct list rules; > + struct rule_collection rules; > int error; > > rule_criteria_init(&criteria, fm->table_id, &fm->match, fm->priority, > @@ -3776,15 +3836,17 @@ modify_flow_strict(struct ofproto *ofproto, struct > ofconn *ofconn, > error = collect_rules_strict(ofproto, &criteria, &rules); > rule_criteria_destroy(&criteria); > > - if (error) { > - return error; > - } else if (list_is_empty(&rules)) { > - return modify_flows_add(ofproto, ofconn, fm, request); > - } else { > - return list_is_singleton(&rules) ? modify_flows__(ofproto, ofconn, > - fm, request, > &rules) > - : 0; > + if (!error) { > + if (rules.n == 0) { > + error = modify_flows_add(ofproto, ofconn, fm, request); > + } else if (rules.n == 1) { > + error = modify_flows__(ofproto, ofconn, fm, request, &rules); > + } > } > + > + rule_collection_destroy(&rules); > + > + return error; > } > > /* OFPFC_DELETE implementation. */ > @@ -3807,14 +3869,16 @@ delete_flow__(struct rule *rule, struct ofopgroup > *group, > * Returns 0 on success, otherwise an OpenFlow error code. */ > static enum ofperr > delete_flows__(struct ofproto *ofproto, struct ofconn *ofconn, > - const struct ofp_header *request, struct list *rules, > + const struct ofp_header *request, > + const struct rule_collection *rules, > enum ofp_flow_removed_reason reason) > { > - struct rule *rule, *next; > struct ofopgroup *group; > + size_t i; > > group = ofopgroup_create(ofproto, ofconn, request, UINT32_MAX); > - LIST_FOR_EACH_SAFE (rule, next, ofproto_node, rules) { > + for (i = 0; i < rules->n; i++) { > + struct rule *rule = rules->rules[i]; > ovs_rwlock_wrlock(&rule->rwlock); > delete_flow__(rule, group, reason); > } > @@ -3830,7 +3894,7 @@ delete_flows_loose(struct ofproto *ofproto, struct > ofconn *ofconn, > const struct ofp_header *request) > { > struct rule_criteria criteria; > - struct list rules; > + struct rule_collection rules; > enum ofperr error; > > rule_criteria_init(&criteria, fm->table_id, &fm->match, 0, > @@ -3839,10 +3903,12 @@ delete_flows_loose(struct ofproto *ofproto, struct > ofconn *ofconn, > error = collect_rules_loose(ofproto, &criteria, &rules); > rule_criteria_destroy(&criteria); > > - return (error ? error > - : !list_is_empty(&rules) ? delete_flows__(ofproto, ofconn, > request, > - &rules, OFPRR_DELETE) > - : 0); > + if (!error && rules.n > 0) { > + error = delete_flows__(ofproto, ofconn, request, &rules, > OFPRR_DELETE); > + } > + rule_collection_destroy(&rules); > + > + return error; > } > > /* Implements OFPFC_DELETE_STRICT. */ > @@ -3852,7 +3918,7 @@ delete_flow_strict(struct ofproto *ofproto, struct > ofconn *ofconn, > const struct ofp_header *request) > { > struct rule_criteria criteria; > - struct list rules; > + struct rule_collection rules; > enum ofperr error; > > rule_criteria_init(&criteria, fm->table_id, &fm->match, fm->priority, > @@ -3861,11 +3927,12 @@ delete_flow_strict(struct ofproto *ofproto, struct > ofconn *ofconn, > error = collect_rules_strict(ofproto, &criteria, &rules); > rule_criteria_destroy(&criteria); > > - return (error ? error > - : list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn, > - request, &rules, > - OFPRR_DELETE) > - : 0); > + if (!error && rules.n > 0) { > + error = delete_flows__(ofproto, ofconn, request, &rules, > OFPRR_DELETE); > + } > + rule_collection_destroy(&rules); > + > + return error; > } > > static void > @@ -4289,11 +4356,13 @@ ofproto_compose_flow_refresh_update(const struct rule > *rule, > } > > void > -ofmonitor_compose_refresh_updates(struct list *rules, struct list *msgs) > +ofmonitor_compose_refresh_updates(struct rule_collection *rules, > + struct list *msgs) > { > - struct rule *rule; > + size_t i; > > - LIST_FOR_EACH (rule, ofproto_node, rules) { > + for (i = 0; i < rules->n; i++) { > + struct rule *rule = rules->rules[i]; > enum nx_flow_monitor_flags flags = rule->monitor_flags; > rule->monitor_flags = 0; > > @@ -4304,7 +4373,7 @@ ofmonitor_compose_refresh_updates(struct list *rules, > struct list *msgs) > static void > ofproto_collect_ofmonitor_refresh_rule(const struct ofmonitor *m, > struct rule *rule, uint64_t seqno, > - struct list *rules) > + struct rule_collection *rules) > { > enum nx_flow_monitor_flags update; > > @@ -4335,7 +4404,7 @@ ofproto_collect_ofmonitor_refresh_rule(const struct > ofmonitor *m, > } > > if (!rule->monitor_flags) { > - list_push_back(rules, &rule->ofproto_node); > + rule_collection_add(rules, rule); > } > rule->monitor_flags |= update | (m->flags & NXFMF_ACTIONS); > } > @@ -4343,7 +4412,7 @@ ofproto_collect_ofmonitor_refresh_rule(const struct > ofmonitor *m, > static void > ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m, > uint64_t seqno, > - struct list *rules) > + struct rule_collection *rules) > { > const struct ofproto *ofproto = ofconn_get_ofproto(m->ofconn); > const struct ofoperation *op; > @@ -4379,7 +4448,7 @@ ofproto_collect_ofmonitor_refresh_rules(const struct > ofmonitor *m, > > static void > ofproto_collect_ofmonitor_initial_rules(struct ofmonitor *m, > - struct list *rules) > + struct rule_collection *rules) > { > if (m->flags & NXFMF_INITIAL) { > ofproto_collect_ofmonitor_refresh_rules(m, 0, rules); > @@ -4388,7 +4457,7 @@ ofproto_collect_ofmonitor_initial_rules(struct > ofmonitor *m, > > void > ofmonitor_collect_resume_rules(struct ofmonitor *m, > - uint64_t seqno, struct list *rules) > + uint64_t seqno, struct rule_collection *rules) > { > ofproto_collect_ofmonitor_refresh_rules(m, seqno, rules); > } > @@ -4399,9 +4468,9 @@ handle_flow_monitor_request(struct ofconn *ofconn, > const struct ofp_header *oh) > struct ofproto *ofproto = ofconn_get_ofproto(ofconn); > struct ofmonitor **monitors; > size_t n_monitors, allocated_monitors; > + struct rule_collection rules; > struct list replies; > enum ofperr error; > - struct list rules; > struct ofpbuf b; > size_t i; > > @@ -4440,13 +4509,15 @@ handle_flow_monitor_request(struct ofconn *ofconn, > const struct ofp_header *oh) > monitors[n_monitors++] = m; > } > > - list_init(&rules); > + rule_collection_init(&rules); > for (i = 0; i < n_monitors; i++) { > ofproto_collect_ofmonitor_initial_rules(monitors[i], &rules); > } > > ofpmp_init(&replies, oh); > ofmonitor_compose_refresh_updates(&rules, &replies); > + rule_collection_destroy(&rules); > + > ofconn_send_replies(ofconn, &replies); > > free(monitors); > @@ -4605,8 +4676,9 @@ handle_delete_meter(struct ofconn *ofconn, const struct > ofp_header *oh, > { > struct ofproto *ofproto = ofconn_get_ofproto(ofconn); > uint32_t meter_id = mm->meter.meter_id; > + struct rule_collection rules; > + enum ofperr error = 0; > uint32_t first, last; > - struct list rules; > > if (meter_id == OFPM13_ALL) { > first = 1; > @@ -4620,7 +4692,7 @@ handle_delete_meter(struct ofconn *ofconn, const struct > ofp_header *oh, > > /* First delete the rules that use this meter. If any of those rules are > * currently being modified, postpone the whole operation until later. */ > - list_init(&rules); > + rule_collection_init(&rules); > for (meter_id = first; meter_id <= last; ++meter_id) { > struct meter *meter = ofproto->meters[meter_id]; > if (meter && !list_is_empty(&meter->rules)) { > @@ -4628,20 +4700,24 @@ handle_delete_meter(struct ofconn *ofconn, const > struct ofp_header *oh, > > LIST_FOR_EACH (rule, meter_list_node, &meter->rules) { > if (rule->pending) { > - return OFPROTO_POSTPONE; > + error = OFPROTO_POSTPONE; > + goto exit; > } > - list_push_back(&rules, &rule->ofproto_node); > + rule_collection_add(&rules, rule); > } > } > } > - if (!list_is_empty(&rules)) { > + if (rules.n > 0) { > delete_flows__(ofproto, ofconn, oh, &rules, OFPRR_METER_DELETE); > } > > /* Delete the meters. */ > meter_delete(ofproto, first, last); > > - return 0; > +exit: > + rule_collection_destroy(&rules); > + > + return error; > } > > static enum ofperr > -- > 1.7.10.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev