Skip to content

Commit

Permalink
ofproto-dpif: Use a regular ref instead of try_ref for rule translation.
Browse files Browse the repository at this point in the history
Until now, flow translation has had to use try_ref to take a reference on
a rule, because a competing thread might have released the last reference
and done an RCU-postponed deletion.  Since classifier versioning was
introduced, however, the release of the last reference is itself
RCU-postponed, which means that it is always safe to take the reference
directly.

Changing try_ref to ref means that taking a reference can't fail, which
allows the caller to take a reference in cases where the need to take a
reference was previously passed along a call chain, which simplifies some
code.

Signed-off-by: Ben Pfaff <[email protected]>
Acked-by: Jarno Rajahalme <[email protected]>
  • Loading branch information
blp committed Aug 3, 2015
1 parent 5868eb2 commit 1e1e1d1
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 40 deletions.
5 changes: 3 additions & 2 deletions ofproto/ofproto-dpif-xlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -3133,7 +3133,6 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
rule = rule_dpif_lookup_from_table(ctx->xbridge->ofproto,
ctx->tables_version,
&ctx->xin->flow, ctx->xin->wc,
ctx->xin->xcache != NULL,
ctx->xin->resubmit_stats,
&ctx->table_id, in_port,
may_packet_in, honor_table_miss);
Expand All @@ -3152,6 +3151,7 @@ xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,

entry = xlate_cache_add_entry(ctx->xin->xcache, XC_RULE);
entry->u.rule = rule;
rule_dpif_ref(rule);
}
xlate_recursively(ctx, rule);
}
Expand Down Expand Up @@ -4912,7 +4912,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
if (!xin->ofpacts && !ctx.rule) {
ctx.rule = rule_dpif_lookup_from_table(
ctx.xbridge->ofproto, ctx.tables_version, flow, xin->wc,
ctx.xin->xcache != NULL, ctx.xin->resubmit_stats, &ctx.table_id,
ctx.xin->resubmit_stats, &ctx.table_id,
flow->in_port.ofp_port, true, true);
if (ctx.xin->resubmit_stats) {
rule_dpif_credit_stats(ctx.rule, ctx.xin->resubmit_stats);
Expand All @@ -4922,6 +4922,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)

entry = xlate_cache_add_entry(ctx.xin->xcache, XC_RULE);
entry->u.rule = ctx.rule;
rule_dpif_ref(ctx.rule);
}

if (OVS_UNLIKELY(ctx.xin->resubmit_hook)) {
Expand Down
38 changes: 10 additions & 28 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -3765,29 +3765,19 @@ ofproto_dpif_get_tables_version(struct ofproto_dpif *ofproto OVS_UNUSED)
}

/* The returned rule (if any) is valid at least until the next RCU quiescent
* period. If the rule needs to stay around longer, a non-zero 'take_ref'
* must be passed in to cause a reference to be taken on it.
* period. If the rule needs to stay around longer, the caller should take
* a reference.
*
* 'flow' is non-const to allow for temporary modifications during the lookup.
* Any changes are restored before returning. */
static struct rule_dpif *
rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, cls_version_t version,
uint8_t table_id, struct flow *flow,
struct flow_wildcards *wc, bool take_ref)
struct flow_wildcards *wc)
{
struct classifier *cls = &ofproto->up.tables[table_id].cls;
const struct cls_rule *cls_rule;
struct rule_dpif *rule;

do {
cls_rule = classifier_lookup(cls, version, flow, wc);

rule = rule_dpif_cast(rule_from_cls_rule(cls_rule));

/* Try again if the rule was released before we get the reference. */
} while (rule && take_ref && !rule_dpif_try_ref(rule));

return rule;
return rule_dpif_cast(rule_from_cls_rule(classifier_lookup(cls, version,
flow, wc)));
}

/* Look up 'flow' in 'ofproto''s classifier version 'version', starting from
Expand All @@ -3807,9 +3797,8 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, cls_version_t version,
* '*table_id'.
*
* The rule is returned in '*rule', which is valid at least until the next
* RCU quiescent period. If the '*rule' needs to stay around longer,
* a non-zero 'take_ref' must be passed in to cause a reference to be taken
* on it before this returns.
* RCU quiescent period. If the '*rule' needs to stay around longer, the
* caller must take a reference.
*
* 'in_port' allows the lookup to take place as if the in port had the value
* 'in_port'. This is needed for resubmit action support.
Expand All @@ -3819,7 +3808,7 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, cls_version_t version,
struct rule_dpif *
rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
cls_version_t version, struct flow *flow,
struct flow_wildcards *wc, bool take_ref,
struct flow_wildcards *wc,
const struct dpif_flow_stats *stats,
uint8_t *table_id, ofp_port_t in_port,
bool may_packet_in, bool honor_table_miss)
Expand All @@ -3842,9 +3831,6 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
/* Must be OFPC_FRAG_DROP (we don't have OFPC_FRAG_REASM).
* Use the drop_frags_rule (which cannot disappear). */
rule = ofproto->drop_frags_rule;
if (take_ref) {
rule_dpif_ref(rule);
}
if (stats) {
struct oftable *tbl = &ofproto->up.tables[*table_id];
unsigned long orig;
Expand All @@ -3871,8 +3857,7 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
next_id++, next_id += (next_id == TBL_INTERNAL))
{
*table_id = next_id;
rule = rule_dpif_lookup_in_table(ofproto, version, next_id, flow, wc,
take_ref);
rule = rule_dpif_lookup_in_table(ofproto, version, next_id, flow, wc);
if (stats) {
struct oftable *tbl = &ofproto->up.tables[next_id];
unsigned long orig;
Expand Down Expand Up @@ -3911,9 +3896,6 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto,
rule = ofproto->miss_rule;
}
}
if (take_ref) {
rule_dpif_ref(rule);
}
out:
/* Restore port numbers, as they may have been modified above. */
flow->tp_src = old_tp_src;
Expand Down Expand Up @@ -5520,7 +5502,7 @@ ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto,
rule = rule_dpif_lookup_in_table(ofproto,
ofproto_dpif_get_tables_version(ofproto),
TBL_INTERNAL, &ofm.fm.match.flow,
&ofm.fm.match.wc, false);
&ofm.fm.match.wc);
if (rule) {
*rulep = &rule->up;
} else {
Expand Down
10 changes: 0 additions & 10 deletions ofproto/ofproto-dpif.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ cls_version_t ofproto_dpif_get_tables_version(struct ofproto_dpif *);
struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
cls_version_t, struct flow *,
struct flow_wildcards *,
bool take_ref,
const struct dpif_flow_stats *,
uint8_t *table_id,
ofp_port_t in_port,
Expand Down Expand Up @@ -200,15 +199,6 @@ static inline void rule_dpif_ref(struct rule_dpif *rule)
}
}

static inline bool rule_dpif_try_ref(struct rule_dpif *rule)
{
if (rule) {
return ofproto_rule_try_ref(RULE_CAST(rule));
}
return false;
}


static inline void rule_dpif_unref(struct rule_dpif *rule)
{
if (rule) {
Expand Down

0 comments on commit 1e1e1d1

Please sign in to comment.