ofproto: Ditch SLOW_IN_BAND slow path reason.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index 1da8ffb..55d030f 100644 (file)
@@ -423,8 +423,7 @@ static void subfacet_update_time(struct subfacet *, long long int used);
 static void subfacet_update_stats(struct subfacet *,
                                   const struct dpif_flow_stats *);
 static void subfacet_make_actions(struct subfacet *,
-                                  const struct ofpbuf *packet,
-                                  struct ofpbuf *odp_actions);
+                                  const struct ofpbuf *packet);
 static int subfacet_install(struct subfacet *,
                             const struct nlattr *actions, size_t actions_len,
                             struct dpif_flow_stats *, enum slow_path_reason);
@@ -515,7 +514,7 @@ static struct facet *facet_find(struct ofproto_dpif *,
                                 const struct flow *, uint32_t hash);
 static struct facet *facet_lookup_valid(struct ofproto_dpif *,
                                         const struct flow *, uint32_t hash);
-static void facet_revalidate(struct facet *);
+static bool facet_revalidate(struct facet *);
 static bool facet_check_consistency(struct facet *);
 
 static void facet_flush_stats(struct facet *);
@@ -606,6 +605,7 @@ ofport_dpif_cast(const struct ofport *ofport)
 static void port_run(struct ofport_dpif *);
 static void port_run_fast(struct ofport_dpif *);
 static void port_wait(struct ofport_dpif *);
+static int set_bfd(struct ofport *, const struct smap *);
 static int set_cfm(struct ofport *, const struct cfm_settings *);
 static void ofport_clear_priorities(struct ofport_dpif *);
 static void run_fast_rl(void);
@@ -1869,6 +1869,7 @@ port_destruct(struct ofport *port_)
     ofproto->backer->need_revalidate = REV_RECONFIGURE;
     bundle_remove(port_);
     set_cfm(port_, NULL);
+    set_bfd(port_, NULL);
     if (ofproto->sflow) {
         dpif_sflow_del_port(ofproto->sflow, port->odp_port);
     }
@@ -1973,7 +1974,7 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 
             ofproto = ofproto_dpif_cast(ofport->up.ofproto);
             ofproto->backer->need_revalidate = REV_RECONFIGURE;
-            ofport->cfm = cfm_create(netdev_get_name(ofport->up.netdev));
+            ofport->cfm = cfm_create(ofport->up.netdev);
         }
 
         if (cfm_configure(ofport->cfm, s)) {
@@ -2472,7 +2473,7 @@ bundle_del_port(struct ofport_dpif *port)
 }
 
 static bool
-bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
+bundle_add_port(struct ofbundle *bundle, uint16_t ofp_port,
                 struct lacp_slave_settings *lacp)
 {
     struct ofport_dpif *port;
@@ -3681,13 +3682,15 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
 
         COVERAGE_INC(facet_suppress);
 
+        handle_flow_miss_common(rule, packet, &miss->flow);
+
         ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub);
 
         dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
         rule_credit_stats(rule, &stats);
 
-        action_xlate_ctx_init(&ctx, ofproto, &miss->flow,
-                              &miss->initial_vals, rule, 0, packet);
+        action_xlate_ctx_init(&ctx, ofproto, &miss->flow, &miss->initial_vals,
+                              rule, stats.tcp_flags, packet);
         ctx.resubmit_stats = &stats;
         xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
                       &odp_actions);
@@ -3731,13 +3734,19 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
     LIST_FOR_EACH (packet, list_node, &miss->packets) {
         struct flow_miss_op *op = &ops[*n_ops];
         struct dpif_flow_stats stats;
-        struct ofpbuf odp_actions;
 
         handle_flow_miss_common(facet->rule, packet, &miss->flow);
 
-        ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub);
-        if (!subfacet->actions || subfacet->slow) {
-            subfacet_make_actions(subfacet, packet, &odp_actions);
+        if (!subfacet->actions) {
+            subfacet_make_actions(subfacet, packet);
+        } else if (subfacet->slow) {
+            struct action_xlate_ctx ctx;
+
+            action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+                                  &subfacet->initial_vals, facet->rule, 0,
+                                  packet);
+            xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts,
+                                           facet->rule->up.ofpacts_len);
         }
 
         dpif_flow_stats_extract(&facet->flow, packet, now, &stats);
@@ -3747,19 +3756,10 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
             struct dpif_execute *execute = &op->dpif_op.u.execute;
 
             init_flow_miss_execute_op(miss, packet, op);
-            if (!subfacet->slow) {
-                execute->actions = subfacet->actions;
-                execute->actions_len = subfacet->actions_len;
-                ofpbuf_uninit(&odp_actions);
-            } else {
-                execute->actions = odp_actions.data;
-                execute->actions_len = odp_actions.size;
-                op->garbage = ofpbuf_get_uninit_pointer(&odp_actions);
-            }
+            execute->actions = subfacet->actions;
+            execute->actions_len = subfacet->actions_len;
 
             (*n_ops)++;
-        } else {
-            ofpbuf_uninit(&odp_actions);
         }
     }
 
@@ -3806,7 +3806,13 @@ handle_flow_miss(struct flow_miss *miss, struct flow_miss_op *ops,
     if (!facet) {
         struct rule_dpif *rule = rule_dpif_lookup(ofproto, &miss->flow);
 
-        if (!flow_miss_should_make_facet(ofproto, miss, hash)) {
+        /* There does not exist a bijection between 'struct flow' and datapath
+         * flow keys with fitness ODP_FIT_TO_LITTLE.  This breaks a fundamental
+         * assumption used throughout the facet and subfacet handling code.
+         * Since we have to handle these misses in userspace anyway, we simply
+         * skip facet creation, avoiding the problem alltogether. */
+        if (miss->key_fitness == ODP_FIT_TOO_LITTLE
+            || !flow_miss_should_make_facet(ofproto, miss, hash)) {
             handle_flow_miss_without_facet(miss, rule, ops, n_ops);
             return;
         }
@@ -4890,10 +4896,8 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow,
     if (facet
         && (ofproto->backer->need_revalidate
             || tag_set_intersects(&ofproto->backer->revalidate_set,
-                                  facet->tags))) {
-        facet_revalidate(facet);
-
-        /* facet_revalidate() may have destroyed 'facet'. */
+                                  facet->tags))
+        && !facet_revalidate(facet)) {
         facet = facet_find(ofproto, flow, hash);
     }
 
@@ -5003,11 +5007,6 @@ facet_check_consistency(struct facet *facet)
         }
 
         want_path = subfacet_want_path(subfacet->slow);
-        if (want_path == SF_SLOW_PATH && subfacet->path == SF_SLOW_PATH) {
-            /* The actions for slow-path flows may legitimately vary from one
-             * packet to the next.  We're done. */
-            continue;
-        }
 
         if (!subfacet_should_install(subfacet, subfacet->slow, &odp_actions)) {
             continue;
@@ -5065,8 +5064,10 @@ facet_check_consistency(struct facet *facet)
  *     where it is and recompiles its actions anyway.
  *
  *   - If any of 'facet''s subfacets correspond to a new flow according to
- *     ofproto_receive(), 'facet' is removed. */
-static void
+ *     ofproto_receive(), 'facet' is removed.
+ *
+ *   Returns true if 'facet' is still valid.  False if 'facet' was removed. */
+static bool
 facet_revalidate(struct facet *facet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
@@ -5101,7 +5102,7 @@ facet_revalidate(struct facet *facet)
             || recv_ofproto != ofproto
             || memcmp(&recv_flow, &facet->flow, sizeof recv_flow)) {
             facet_remove(facet);
-            return;
+            return false;
         }
     }
 
@@ -5120,19 +5121,16 @@ facet_revalidate(struct facet *facet)
     memset(&ctx, 0, sizeof ctx);
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
-        enum slow_path_reason slow;
-
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
                               &subfacet->initial_vals, new_rule, 0, NULL);
         xlate_actions(&ctx, new_rule->up.ofpacts, new_rule->up.ofpacts_len,
                       &odp_actions);
 
-        slow = (subfacet->slow & SLOW_MATCH) | ctx.slow;
-        if (subfacet_should_install(subfacet, slow, &odp_actions)) {
+        if (subfacet_should_install(subfacet, ctx.slow, &odp_actions)) {
             struct dpif_flow_stats stats;
 
-            subfacet_install(subfacet,
-                             odp_actions.data, odp_actions.size, &stats, slow);
+            subfacet_install(subfacet, odp_actions.data, odp_actions.size,
+                             &stats, ctx.slow);
             subfacet_update_stats(subfacet, &stats);
 
             if (!new_actions) {
@@ -5162,7 +5160,7 @@ facet_revalidate(struct facet *facet)
 
     i = 0;
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
-        subfacet->slow = (subfacet->slow & SLOW_MATCH) | ctx.slow;
+        subfacet->slow = ctx.slow;
 
         if (new_actions && new_actions[i].odp_actions) {
             free(subfacet->actions);
@@ -5181,6 +5179,8 @@ facet_revalidate(struct facet *facet)
         facet->used = new_rule->up.created;
         facet->prev_used = facet->used;
     }
+
+    return true;
 }
 
 /* Updates 'facet''s used time.  Caller is responsible for calling
@@ -5359,9 +5359,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
     subfacet->dp_byte_count = 0;
     subfacet->actions_len = 0;
     subfacet->actions = NULL;
-    subfacet->slow = (subfacet->key_fitness == ODP_FIT_TOO_LITTLE
-                      ? SLOW_MATCH
-                      : 0);
+    subfacet->slow = 0;
     subfacet->path = SF_NOT_INSTALLED;
     subfacet->initial_vals = miss->initial_vals;
     subfacet->odp_in_port = miss->odp_in_port;
@@ -5433,22 +5431,22 @@ subfacet_destroy_batch(struct ofproto_dpif *ofproto,
     }
 }
 
-/* Composes the datapath actions for 'subfacet' based on its rule's actions.
- * Translates the actions into 'odp_actions', which the caller must have
- * initialized and is responsible for uninitializing. */
+/* Composes the datapath actions for 'subfacet' based on its rule's actions. */
 static void
-subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
-                      struct ofpbuf *odp_actions)
+subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet)
 {
     struct facet *facet = subfacet->facet;
     struct rule_dpif *rule = facet->rule;
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
 
     struct action_xlate_ctx ctx;
+    struct ofpbuf odp_actions;
+    uint64_t stub[1024 / 8];
 
+    ofpbuf_use_stub(&odp_actions, stub, sizeof stub);
     action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
                           &subfacet->initial_vals, rule, 0, packet);
-    xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, odp_actions);
+    xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions);
     facet->tags = ctx.tags;
     facet->has_learn = ctx.has_learn;
     facet->has_normal = ctx.has_normal;
@@ -5456,13 +5454,11 @@ subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
     facet->nf_flow.output_iface = ctx.nf_output_iface;
     facet->mirrors = ctx.mirrors;
 
-    subfacet->slow = (subfacet->slow & SLOW_MATCH) | ctx.slow;
-    if (subfacet->actions_len != odp_actions->size
-        || memcmp(subfacet->actions, odp_actions->data, odp_actions->size)) {
-        free(subfacet->actions);
-        subfacet->actions_len = odp_actions->size;
-        subfacet->actions = xmemdup(odp_actions->data, odp_actions->size);
-    }
+    subfacet->slow = ctx.slow;
+
+    ovs_assert(!subfacet->actions);
+    subfacet->actions_len = odp_actions.size;
+    subfacet->actions = ofpbuf_steal_data(&odp_actions);
 }
 
 /* Updates 'subfacet''s datapath flow, setting its actions to 'actions_len'
@@ -7161,16 +7157,11 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
 
         local_odp_port = ofp_port_to_odp_port(ctx->ofproto, OFPP_LOCAL);
-        if (!connmgr_may_set_up_flow(ctx->ofproto->up.connmgr, &ctx->flow,
-                                     local_odp_port,
-                                     ctx->odp_actions->data,
-                                     ctx->odp_actions->size)) {
-            ctx->slow |= SLOW_IN_BAND;
-            if (ctx->packet
-                && connmgr_msg_in_hook(ctx->ofproto->up.connmgr, &ctx->flow,
-                                       ctx->packet)) {
-                compose_output_action(ctx, OFPP_LOCAL);
-            }
+        if (!connmgr_must_output_local(ctx->ofproto->up.connmgr, &ctx->flow,
+                                       local_odp_port,
+                                       ctx->odp_actions->data,
+                                       ctx->odp_actions->size)) {
+            compose_output_action(ctx, OFPP_LOCAL);
         }
         if (ctx->ofproto->has_mirrors) {
             add_mirror_actions(ctx, &orig_flow);
@@ -8128,7 +8119,7 @@ static void
 ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                       void *aux OVS_UNUSED)
 {
-    const char *dpname = argv[1];
+    const struct dpif_backer *backer;
     struct ofproto_dpif *ofproto;
     struct ofpbuf odp_key;
     struct ofpbuf *packet;
@@ -8138,101 +8129,102 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
     char *s;
 
     packet = NULL;
-    ofpbuf_init(&odp_key, 0);
+    backer = NULL;
     ds_init(&result);
+    ofpbuf_init(&odp_key, 0);
 
-    ofproto = ofproto_dpif_lookup(dpname);
-    if (!ofproto) {
-        unixctl_command_reply_error(conn, "Unknown ofproto (use ofproto/list "
-                                    "for help)");
-        goto exit;
+    /* Handle "-generate" or a hex string as the last argument. */
+    if (!strcmp(argv[argc - 1], "-generate")) {
+        packet = ofpbuf_new(0);
+        argc--;
+    } else {
+        const char *error = eth_from_hex(argv[argc - 1], &packet);
+        if (!error) {
+            argc--;
+        } else if (argc == 4) {
+            /* The 3-argument form must end in "-generate' or a hex string. */
+            unixctl_command_reply_error(conn, error);
+            goto exit;
+        }
     }
-    if (argc == 3 || (argc == 4 && !strcmp(argv[3], "-generate"))) {
-        /* ofproto/trace dpname flow [-generate] */
-        const char *flow_s = argv[2];
-        const char *generate_s = argv[3];
-
-        /* Allow 'flow_s' to be either a datapath flow or an OpenFlow-like
-         * flow.  We guess which type it is based on whether 'flow_s' contains
-         * an '(', since a datapath flow always contains '(') but an
-         * OpenFlow-like flow should not (in fact it's allowed but I believe
-         * that's not documented anywhere).
-         *
-         * An alternative would be to try to parse 'flow_s' both ways, but then
-         * it would be tricky giving a sensible error message.  After all, do
-         * you just say "syntax error" or do you present both error messages?
-         * Both choices seem lousy. */
-        if (strchr(flow_s, '(')) {
-            int error;
 
-            /* Convert string to datapath key. */
-            ofpbuf_init(&odp_key, 0);
-            error = odp_flow_key_from_string(flow_s, NULL, &odp_key);
-            if (error) {
-                unixctl_command_reply_error(conn, "Bad flow syntax");
-                goto exit;
+    /* Parse the flow and determine whether a datapath or
+     * bridge is specified. If function odp_flow_key_from_string()
+     * returns 0, the flow is a odp_flow. If function
+     * parse_ofp_exact_flow() returns 0, the flow is a br_flow. */
+    if (!odp_flow_key_from_string(argv[argc - 1], NULL, &odp_key)) {
+        /* If the odp_flow is the second argument,
+         * the datapath name is the first argument. */
+        if (argc == 3) {
+            const char *dp_type;
+            if (!strncmp(argv[1], "ovs-", 4)) {
+                dp_type = argv[1] + 4;
+            } else {
+                dp_type = argv[1];
             }
-
-            /* The user might have specified the wrong ofproto but within the
-             * same backer.  That's OK, ofproto_receive() can find the right
-             * one for us. */
-            if (ofproto_receive(ofproto->backer, NULL, odp_key.data,
-                                odp_key.size, &flow, NULL, &ofproto, NULL,
-                                &initial_vals)) {
-                unixctl_command_reply_error(conn, "Invalid flow");
+            backer = shash_find_data(&all_dpif_backers, dp_type);
+            if (!backer) {
+                unixctl_command_reply_error(conn, "Cannot find datapath "
+                               "of this name");
                 goto exit;
             }
-            ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
         } else {
-            char *error_s;
-
-            error_s = parse_ofp_exact_flow(&flow, argv[2]);
-            if (error_s) {
-                unixctl_command_reply_error(conn, error_s);
-                free(error_s);
+            /* No datapath name specified, so there should be only one
+             * datapath. */
+            struct shash_node *node;
+            if (shash_count(&all_dpif_backers) != 1) {
+                unixctl_command_reply_error(conn, "Must specify datapath "
+                         "name, there is more than one type of datapath");
                 goto exit;
             }
-
-            initial_vals.vlan_tci = flow.vlan_tci;
+            node = shash_first(&all_dpif_backers);
+            backer = node->data;
         }
 
-        /* Generate a packet, if requested. */
-        if (generate_s) {
-            packet = ofpbuf_new(0);
-            flow_compose(packet, &flow);
+        /* Extract the ofproto_dpif object from the ofproto_receive()
+         * function. */
+        if (ofproto_receive(backer, NULL, odp_key.data,
+                            odp_key.size, &flow, NULL, &ofproto, NULL,
+                            &initial_vals)) {
+            unixctl_command_reply_error(conn, "Invalid datapath flow");
+            goto exit;
         }
-    } else if (argc == 7) {
-        /* ofproto/trace dpname priority tun_id in_port mark packet */
-        const char *priority_s = argv[2];
-        const char *tun_id_s = argv[3];
-        const char *in_port_s = argv[4];
-        const char *mark_s = argv[5];
-        const char *packet_s = argv[6];
-        uint32_t in_port = atoi(in_port_s);
-        ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
-        uint32_t priority = atoi(priority_s);
-        uint32_t mark = atoi(mark_s);
-        const char *msg;
-
-        msg = eth_from_hex(packet_s, &packet);
-        if (msg) {
-            unixctl_command_reply_error(conn, msg);
+        ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
+    } else if (!parse_ofp_exact_flow(&flow, argv[argc - 1])) {
+        if (argc != 3) {
+            unixctl_command_reply_error(conn, "Must specify bridge name");
             goto exit;
         }
 
-        ds_put_cstr(&result, "Packet: ");
-        s = ofp_packet_to_string(packet->data, packet->size);
-        ds_put_cstr(&result, s);
-        free(s);
-
-        flow_extract(packet, priority, mark, NULL, in_port, &flow);
-        flow.tunnel.tun_id = tun_id;
+        ofproto = ofproto_dpif_lookup(argv[1]);
+        if (!ofproto) {
+            unixctl_command_reply_error(conn, "Unknown bridge name");
+            goto exit;
+        }
         initial_vals.vlan_tci = flow.vlan_tci;
     } else {
-        unixctl_command_reply_error(conn, "Bad command syntax");
+        unixctl_command_reply_error(conn, "Bad flow syntax");
         goto exit;
     }
 
+    /* Generate a packet, if requested. */
+    if (packet) {
+        if (!packet->size) {
+            flow_compose(packet, &flow);
+        } else {
+            ds_put_cstr(&result, "Packet: ");
+            s = ofp_packet_to_string(packet->data, packet->size);
+            ds_put_cstr(&result, s);
+            free(s);
+
+            /* Use the metadata from the flow and the packet argument
+             * to reconstruct the flow. */
+            flow_extract(packet, flow.skb_priority, flow.skb_mark, NULL,
+                         flow.in_port, &flow);
+            initial_vals.vlan_tci = flow.vlan_tci;
+        }
+    }
+
     ofproto_trace(ofproto, &flow, packet, &initial_vals, &result);
     unixctl_command_reply(conn, ds_cstr(&result));
 
@@ -8309,32 +8301,14 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
                 case SLOW_BFD:
                     ds_put_cstr(ds, "\n\t- Consists of BFD packets.");
                     break;
-                case SLOW_IN_BAND:
-                    ds_put_cstr(ds, "\n\t- Needs in-band special case "
-                                "processing.");
-                    if (!packet) {
-                        ds_put_cstr(ds, "\n\t  (The datapath actions are "
-                                    "incomplete--for complete actions, "
-                                    "please supply a packet.)");
-                    }
-                    break;
                 case SLOW_CONTROLLER:
                     ds_put_cstr(ds, "\n\t- Sends \"packet-in\" messages "
                                 "to the OpenFlow controller.");
                     break;
-                case SLOW_MATCH:
-                    ds_put_cstr(ds, "\n\t- Needs more specific matching "
-                                "than the datapath supports.");
-                    break;
                 }
 
                 slow &= ~bit;
             }
-
-            if (slow & ~SLOW_MATCH) {
-                ds_put_cstr(ds, "\nThe datapath actions above do not reflect "
-                            "the special slow-path processing.");
-            }
         }
     }
 }
@@ -8661,8 +8635,8 @@ ofproto_dpif_unixctl_init(void)
 
     unixctl_command_register(
         "ofproto/trace",
-        "bridge {priority tun_id in_port mark packet | odp_flow [-generate]}",
-        2, 6, ofproto_unixctl_trace, NULL);
+        "[dp_name]|bridge odp_flow|br_flow [-generate|packet]",
+        1, 3, ofproto_unixctl_trace, NULL);
     unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
                              ofproto_unixctl_fdb_flush, NULL);
     unixctl_command_register("fdb/show", "bridge", 1, 1,