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);
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 *);
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);
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);
}
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)) {
}
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;
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);
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);
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);
}
}
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;
}
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);
}
}
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;
* 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);
|| recv_ofproto != ofproto
|| memcmp(&recv_flow, &facet->flow, sizeof recv_flow)) {
facet_remove(facet);
- return;
+ return false;
}
}
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) {
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);
facet->used = new_rule->up.created;
facet->prev_used = facet->used;
}
+
+ return true;
}
/* Updates 'facet''s used time. Caller is responsible for calling
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;
}
}
-/* 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;
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'
}
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);
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;
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));
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.");
- }
}
}
}
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,