summaryrefslogtreecommitdiff
path: root/ofproto/ofproto-dpif.c
diff options
context:
space:
mode:
authorJarno Rajahalme <jarno@ovn.org>2016-09-14 16:51:27 -0700
committerJarno Rajahalme <jarno@ovn.org>2016-09-14 16:51:27 -0700
commit1f4a893366826e392722d5b1ba59e94331bfe5c9 (patch)
tree78c6b3d23395707020e9cb5d41f3d0bc5d616c5f /ofproto/ofproto-dpif.c
parent493f017d8ad57aff226fb26e177b64b02a15cea4 (diff)
downloadopenvswitch-1f4a893366826e392722d5b1ba59e94331bfe5c9.tar.gz
ofproto: Refactor packet_out handling.
Refactor handle_packet_out() to prepare for bundle support for packet outs in a later patch. Two new callbacks are introduced in ofproto-provider class: ->packet_xlate() and ->packet_execute(). ->packet_xlate() translates the packet using the flow and actions provided by the caller, but defers all OpenFlow-visible side-effects (stats, learn actions, actual packet output, etc.) to be explicitly executed with the ->packet_execute() call. Adds a new ofproto_rule_reduce_timeouts__() that must be called with 'ofproto_mutex' held. This is used in the next patch. Signed-off-by: Jarno Rajahalme <jarno@ovn.org> Acked-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'ofproto/ofproto-dpif.c')
-rw-r--r--ofproto/ofproto-dpif.c212
1 files changed, 190 insertions, 22 deletions
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 0df34db21..e96aeb71b 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3748,7 +3748,7 @@ ofproto_dpif_set_packet_odp_port(const struct ofproto_dpif *ofproto,
int
ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto,
- const struct flow *flow,
+ ovs_version_t version, const struct flow *flow,
struct rule_dpif *rule,
const struct ofpact *ofpacts, size_t ofpacts_len,
int indentation, int depth, int resubmits,
@@ -3770,7 +3770,7 @@ ofproto_dpif_execute_actions__(struct ofproto_dpif *ofproto,
uint64_t odp_actions_stub[1024 / 8];
struct ofpbuf odp_actions = OFPBUF_STUB_INITIALIZER(odp_actions_stub);
- xlate_in_init(&xin, ofproto, flow, flow->in_port.ofp_port, rule,
+ xlate_in_init(&xin, ofproto, version, flow, flow->in_port.ofp_port, rule,
stats.tcp_flags, packet, NULL, &odp_actions);
xin.ofpacts = ofpacts;
xin.ofpacts_len = ofpacts_len;
@@ -3808,13 +3808,14 @@ out:
* 'flow' must reflect the data in 'packet'. */
int
ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto,
- const struct flow *flow,
+ ovs_version_t version, const struct flow *flow,
struct rule_dpif *rule,
const struct ofpact *ofpacts, size_t ofpacts_len,
struct dp_packet *packet)
{
- return ofproto_dpif_execute_actions__(ofproto, flow, rule, ofpacts,
- ofpacts_len, 0, 0, 0, packet);
+ return ofproto_dpif_execute_actions__(ofproto, version, flow, rule,
+ ofpacts, ofpacts_len, 0, 0, 0,
+ packet);
}
static void
@@ -3893,7 +3894,7 @@ rule_set_recirc_id(struct rule *rule_, uint32_t id)
}
ovs_version_t
-ofproto_dpif_get_tables_version(struct ofproto_dpif *ofproto OVS_UNUSED)
+ofproto_dpif_get_tables_version(struct ofproto_dpif *ofproto)
{
ovs_version_t version;
@@ -4271,6 +4272,183 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes,
ovs_mutex_unlock(&rule->stats_mutex);
}
+struct ofproto_dpif_packet_out {
+ struct xlate_cache xcache;
+ struct ofpbuf odp_actions;
+ struct recirc_refs rr;
+ bool needs_help;
+};
+
+
+static struct ofproto_dpif_packet_out *
+ofproto_dpif_packet_out_new(void)
+{
+ struct ofproto_dpif_packet_out *aux = xmalloc(sizeof *aux);
+ xlate_cache_init(&aux->xcache);
+ ofpbuf_init(&aux->odp_actions, 64);
+ aux->rr = RECIRC_REFS_EMPTY_INITIALIZER;
+ aux->needs_help = false;
+
+ return aux;
+}
+
+static void
+ofproto_dpif_packet_out_delete(struct ofproto_dpif_packet_out *aux)
+{
+ if (aux) {
+ xlate_cache_uninit(&aux->xcache);
+ ofpbuf_uninit(&aux->odp_actions);
+ recirc_refs_unref(&aux->rr);
+ free(aux);
+ }
+}
+
+static enum ofperr
+packet_xlate(struct ofproto *ofproto_, struct ofproto_packet_out *opo)
+ OVS_REQUIRES(ofproto_mutex)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct xlate_out xout;
+ struct xlate_in xin;
+ enum ofperr error = 0;
+
+ struct ofproto_dpif_packet_out *aux = ofproto_dpif_packet_out_new();
+
+ xlate_in_init(&xin, ofproto, opo->version, opo->flow,
+ opo->flow->in_port.ofp_port, NULL, 0, opo->packet, NULL,
+ &aux->odp_actions);
+ xin.ofpacts = opo->ofpacts;
+ xin.ofpacts_len = opo->ofpacts_len;
+ /* No learning or stats, but collect side effects to xcache. */
+ xin.allow_side_effects = false;
+ xin.resubmit_stats = NULL;
+ xin.xcache = &aux->xcache;
+
+ if (xlate_actions(&xin, &xout) != XLATE_OK) {
+ error = OFPERR_OFPFMFC_UNKNOWN; /* Error processing actions. */
+ goto error_out;
+ } else {
+ /* Prepare learn actions. */
+ struct xc_entry *entry;
+ struct ofpbuf entries = aux->xcache.entries;
+
+ XC_ENTRY_FOR_EACH (entry, &entries) {
+ if (entry->type == XC_LEARN) {
+ struct ofproto_flow_mod *ofm = entry->learn.ofm;
+
+ error = ofproto_flow_mod_learn_refresh(ofm);
+ if (error) {
+ goto error_out;
+ }
+ struct rule *rule = ofm->temp_rule;
+ ofm->learn_adds_rule = (rule->state == RULE_INITIALIZED);
+ if (ofm->learn_adds_rule) {
+ /* If learning on a different bridge, must use its next
+ * version number. */
+ ofm->version = (rule->ofproto == ofproto_)
+ ? opo->version : rule->ofproto->tables_version + 1;
+ error = ofproto_flow_mod_learn_start(ofm);
+ if (error) {
+ goto error_out;
+ }
+ }
+ }
+ }
+
+ /* Success. */
+ aux->needs_help = (xout.slow & SLOW_ACTION) != 0;
+ recirc_refs_swap(&aux->rr, &xout.recircs); /* Hold recirc refs. */
+ }
+ xlate_out_uninit(&xout);
+ opo->aux = aux;
+ return 0;
+
+error_out:
+ xlate_out_uninit(&xout);
+ ofproto_dpif_packet_out_delete(aux);
+ opo->aux = NULL;
+ return error;
+}
+
+/* Push stats and perform side effects of flow translation. */
+static void
+ofproto_dpif_xcache_execute(struct ofproto_dpif *ofproto,
+ struct xlate_cache *xcache,
+ const struct dpif_flow_stats *stats)
+ OVS_REQUIRES(ofproto_mutex)
+{
+ struct xc_entry *entry;
+ struct ofpbuf entries = xcache->entries;
+
+ XC_ENTRY_FOR_EACH (entry, &entries) {
+ switch (entry->type) {
+ case XC_LEARN:
+ /* Finish the learned flows. */
+ if (entry->learn.ofm->learn_adds_rule) {
+ ofproto_flow_mod_learn_finish(entry->learn.ofm, &ofproto->up);
+ }
+ break;
+ case XC_FIN_TIMEOUT:
+ if (stats->tcp_flags & (TCP_FIN | TCP_RST)) {
+ /* 'ofproto_mutex' already held */
+ ofproto_rule_reduce_timeouts__(&entry->fin.rule->up,
+ entry->fin.idle,
+ entry->fin.hard);
+ }
+ break;
+ /* All the rest can be dealt with by the xlate layer. */
+ case XC_TABLE:
+ case XC_RULE:
+ case XC_BOND:
+ case XC_NETDEV:
+ case XC_NETFLOW:
+ case XC_MIRROR:
+ case XC_NORMAL:
+ case XC_GROUP:
+ case XC_TNL_NEIGH:
+ case XC_CONTROLLER:
+ xlate_push_stats_entry(entry, stats);
+ break;
+ default:
+ OVS_NOT_REACHED();
+ }
+ }
+}
+
+static void
+packet_execute(struct ofproto *ofproto_, struct ofproto_packet_out *opo)
+ OVS_REQUIRES(ofproto_mutex)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct dpif_flow_stats stats;
+ struct dpif_execute execute;
+
+ struct ofproto_dpif_packet_out *aux = opo->aux;
+ ovs_assert(aux);
+
+ /* Run the side effects from the xcache. */
+ dpif_flow_stats_extract(opo->flow, opo->packet, time_msec(), &stats);
+ ofproto_dpif_xcache_execute(ofproto, &aux->xcache, &stats);
+
+ execute.actions = aux->odp_actions.data;
+ execute.actions_len = aux->odp_actions.size;
+
+ pkt_metadata_from_flow(&opo->packet->md, opo->flow);
+ execute.packet = opo->packet;
+ execute.flow = opo->flow;
+ execute.needs_help = aux->needs_help;
+ execute.probe = false;
+ execute.mtu = 0;
+
+ /* Fix up in_port. */
+ ofproto_dpif_set_packet_odp_port(ofproto, opo->flow->in_port.ofp_port,
+ opo->packet);
+
+ dpif_execute(ofproto->backer->dpif, &execute);
+ ofproto_dpif_packet_out_delete(aux);
+ opo->aux = NULL;
+}
+
static struct group_dpif *group_dpif_cast(const struct ofgroup *group)
{
return group ? CONTAINER_OF(group, struct group_dpif, up) : NULL;
@@ -4469,18 +4647,6 @@ set_frag_handling(struct ofproto *ofproto_,
}
static enum ofperr
-packet_out(struct ofproto *ofproto_, struct dp_packet *packet,
- const struct flow *flow,
- const struct ofpact *ofpacts, size_t ofpacts_len)
-{
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
-
- ofproto_dpif_execute_actions(ofproto, flow, NULL, ofpacts,
- ofpacts_len, packet);
- return 0;
-}
-
-static enum ofperr
nxt_resume(struct ofproto *ofproto_,
const struct ofputil_packet_in_private *pin)
{
@@ -5161,9 +5327,10 @@ ofproto_trace(struct ofproto_dpif *ofproto, struct flow *flow,
trace.result = ds;
trace.key = flow; /* Original flow key, used for megaflow. */
trace.flow = *flow; /* May be modified by actions. */
- xlate_in_init(&trace.xin, ofproto, flow, flow->in_port.ofp_port, NULL,
- ntohs(flow->tcp_flags), packet, &trace.wc,
- &trace.odp_actions);
+ xlate_in_init(&trace.xin, ofproto,
+ ofproto_dpif_get_tables_version(ofproto), flow,
+ flow->in_port.ofp_port, NULL, ntohs(flow->tcp_flags),
+ packet, &trace.wc, &trace.odp_actions);
trace.xin.ofpacts = ofpacts;
trace.xin.ofpacts_len = ofpacts_len;
trace.xin.resubmit_hook = trace_resubmit;
@@ -5656,8 +5823,9 @@ const struct ofproto_class ofproto_dpif_class = {
rule_destruct,
rule_dealloc,
rule_get_stats,
+ packet_xlate,
+ packet_execute,
set_frag_handling,
- packet_out,
nxt_resume,
set_netflow,
get_netflow_ids,