From: Ethan Jackson Date: Wed, 9 Oct 2013 20:23:31 +0000 (-0700) Subject: ofproto-dpif-xlate: Do initial rule lookup for callers. X-Git-Tag: v2.1.0~495 X-Git-Url: http://git.cascardo.eti.br/?a=commitdiff_plain;h=10c44245ad673e03c50c03b711f6c4dea1d7f2e2;p=cascardo%2Fovs.git ofproto-dpif-xlate: Do initial rule lookup for callers. None of the functions available in ofproto-dpif.h are thread safe unless holding the xlate_rwlock because one can't know that an ofproto or ofport used as argument will survive during the function call. For this reason, ofproto-dpif-upcall's invocation of rule_dpif_lookup() is unsafe because the ofproto could be destroyed during the call. This patch fixes the problem by optionally doing the initial rule lookup in xlate_actions() so that it can be done while holding the xlate_rwlock. This has the nice side benefit of removing a bunch of boilerplate. Note that this only partially solves the problem, there's still vsp_realdev_to_vlandev() and ofproto_dpif_send_packet_in() which aren't thread safe for the same reason. Signed-off-by: Ethan Jackson --- diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c index 9ec081ac0..74e8e9273 100644 --- a/ofproto/ofproto-dpif-upcall.c +++ b/ofproto/ofproto-dpif-upcall.c @@ -31,7 +31,6 @@ #include "ofpbuf.h" #include "ofproto-dpif-ipfix.h" #include "ofproto-dpif-sflow.h" -#include "ofproto-dpif.h" #include "packets.h" #include "poll-loop.h" #include "vlog.h" @@ -759,23 +758,14 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls) * all the packets in each miss. */ fail_open = false; HMAP_FOR_EACH (miss, hmap_node, &fmb->misses) { - struct flow_wildcards wc; - struct rule_dpif *rule; struct xlate_in xin; - flow_wildcards_init_catchall(&wc); - rule_dpif_lookup(miss->ofproto, &miss->flow, &wc, &rule); - if (rule_dpif_fail_open(rule)) { - fail_open = true; - } - rule_dpif_credit_stats(rule, &miss->stats); - xlate_in_init(&xin, miss->ofproto, &miss->flow, rule, + xlate_in_init(&xin, miss->ofproto, &miss->flow, NULL, miss->stats.tcp_flags, NULL); xin.may_learn = true; xin.resubmit_stats = &miss->stats; xlate_actions(&xin, &miss->xout); - flow_wildcards_or(&miss->xout.wc, &miss->xout.wc, &wc); - rule_dpif_unref(rule); + fail_open = fail_open || miss->xout.fail_open; } /* Now handle the packets individually in order of arrival. In the common @@ -796,13 +786,10 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls) struct ofpbuf *packet = upcall->dpif_upcall.packet; if (miss->xout.slow) { - struct rule_dpif *rule; struct xlate_in xin; - rule_dpif_lookup(miss->ofproto, &miss->flow, NULL, &rule); - xlate_in_init(&xin, miss->ofproto, &miss->flow, rule, 0, packet); + xlate_in_init(&xin, miss->ofproto, &miss->flow, NULL, 0, packet); xlate_actions_for_side_effects(&xin); - rule_dpif_unref(rule); } if (miss->xout.odp_actions.size) { diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index de65f6cc7..29a623f49 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2661,6 +2661,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) { struct flow_wildcards *wc = &xout->wc; struct flow *flow = &xin->flow; + struct rule_dpif *rule = NULL; struct rule_actions *actions = NULL; enum slow_path_reason special; @@ -2735,11 +2736,20 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) ctx.exit = false; ctx.mpls_depth_delta = 0; + if (!xin->ofpacts && !ctx.rule) { + rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc, &rule); + if (ctx.xin->resubmit_stats) { + rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats); + } + ctx.rule = rule; + } + xout->fail_open = ctx.rule && rule_dpif_fail_open(ctx.rule); + if (xin->ofpacts) { ofpacts = xin->ofpacts; ofpacts_len = xin->ofpacts_len; - } else if (xin->rule) { - actions = rule_dpif_get_actions(xin->rule); + } else if (ctx.rule) { + actions = rule_dpif_get_actions(ctx.rule); ofpacts = actions->ofpacts; ofpacts_len = actions->ofpacts_len; } else { @@ -2836,6 +2846,7 @@ xlate_actions__(struct xlate_in *xin, struct xlate_out *xout) out: rule_actions_unref(actions); + rule_dpif_unref(rule); } /* Sends 'packet' out 'ofport'. diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 554d46e90..40712f99c 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -43,6 +43,7 @@ struct xlate_out { struct flow_wildcards wc; enum slow_path_reason slow; /* 0 if fast path may be used. */ + bool fail_open; /* Initial rule is fail open? */ bool has_learn; /* Actions include NXAST_LEARN? */ bool has_normal; /* Actions output to OFPP_NORMAL? */ bool has_fin_timeout; /* Actions include NXAST_FIN_TIMEOUT? */ @@ -72,7 +73,8 @@ struct xlate_in { * not if we are just revalidating. */ bool may_learn; - /* The rule initiating translation or NULL. */ + /* The rule initiating translation or NULL. If both 'rule' and 'ofpacts' + * are NULL, xlate_actions() will do the initial rule lookup itself. */ struct rule_dpif *rule; /* The actions to translate. If 'rule' is not NULL, these may be NULL. */ diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7eff3263a..b8b15e3dc 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4041,15 +4041,11 @@ facet_check_consistency(struct facet *facet) struct xlate_out xout; struct xlate_in xin; - - struct rule_dpif *rule; bool ok; /* Check the datapath actions for consistency. */ - rule_dpif_lookup(facet->ofproto, &facet->flow, NULL, &rule); - xlate_in_init(&xin, facet->ofproto, &facet->flow, rule, 0, NULL); + xlate_in_init(&xin, facet->ofproto, &facet->flow, NULL, 0, NULL); xlate_actions(&xin, &xout); - rule_dpif_unref(rule); ok = ofpbuf_equal(&facet->xout.odp_actions, &xout.odp_actions) && facet->xout.slow == xout.slow; @@ -4201,7 +4197,6 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow, struct dpif_flow_stats *stats, bool may_learn) { struct ofport_dpif *in_port; - struct rule_dpif *rule; struct xlate_in xin; in_port = get_ofp_port(ofproto, flow->in_port.ofp_port); @@ -4209,13 +4204,10 @@ flow_push_stats(struct ofproto_dpif *ofproto, struct flow *flow, netdev_vport_inc_rx(in_port->up.netdev, stats); } - rule_dpif_lookup(ofproto, flow, NULL, &rule); - rule_dpif_credit_stats(rule, stats); - xlate_in_init(&xin, ofproto, flow, rule, stats->tcp_flags, NULL); + xlate_in_init(&xin, ofproto, flow, NULL, stats->tcp_flags, NULL); xin.resubmit_stats = stats; xin.may_learn = may_learn; xlate_actions_for_side_effects(&xin); - rule_dpif_unref(rule); } static void