static void action_xlate_ctx_init(struct action_xlate_ctx *,
struct ofproto_dpif *, const struct flow *,
- const struct ofpbuf *);
+ ovs_be16 initial_tci, const struct ofpbuf *);
static struct ofpbuf *xlate_actions(struct action_xlate_ctx *,
const union ofp_action *in, size_t n_in);
struct nlattr *actions; /* Datapath actions. */
bool installed; /* Installed in datapath? */
+
+ /* This value is normally the same as ->facet->flow.vlan_tci. Only VLAN
+ * splinters can cause it to differ. This value should be removed when
+ * the VLAN splinters feature is no longer needed. */
+ ovs_be16 initial_tci; /* Initial VLAN TCI value. */
};
static struct subfacet *subfacet_create(struct ofproto_dpif *, struct facet *,
enum odp_key_fitness,
const struct nlattr *key,
- size_t key_len);
+ size_t key_len, ovs_be16 initial_tci);
static struct subfacet *subfacet_find(struct ofproto_dpif *,
const struct nlattr *key, size_t key_len,
const struct flow *);
enum odp_key_fitness key_fitness;
const struct nlattr *key;
size_t key_len;
+ ovs_be16 initial_tci;
struct list packets;
};
static struct flow_miss *
flow_miss_create(struct hmap *todo, const struct flow *flow,
enum odp_key_fitness key_fitness,
- const struct nlattr *key, size_t key_len)
+ const struct nlattr *key, size_t key_len,
+ ovs_be16 initial_tci)
{
uint32_t hash = flow_hash(flow, 0);
struct flow_miss *miss;
miss->key_fitness = key_fitness;
miss->key = key;
miss->key_len = key_len;
+ miss->initial_tci = initial_tci;
list_init(&miss->packets);
return miss;
}
}
subfacet = subfacet_create(ofproto, facet,
- miss->key_fitness, miss->key, miss->key_len);
+ miss->key_fitness, miss->key, miss->key_len,
+ miss->initial_tci);
LIST_FOR_EACH_SAFE (packet, next_packet, list_node, &miss->packets) {
list_remove(&packet->list_node);
}
}
+static enum odp_key_fitness
+ofproto_dpif_extract_flow_key(const struct ofproto_dpif *ofproto OVS_UNUSED,
+ const struct nlattr *key, size_t key_len,
+ struct flow *flow, ovs_be16 *initial_tci)
+{
+ enum odp_key_fitness fitness;
+
+ fitness = odp_flow_key_to_flow(key, key_len, flow);
+ if (fitness == ODP_FIT_ERROR) {
+ return fitness;
+ }
+ *initial_tci = flow->vlan_tci;
+
+ return fitness;
+}
+
static void
handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
size_t n_upcalls)
for (upcall = upcalls; upcall < &upcalls[n_upcalls]; upcall++) {
enum odp_key_fitness fitness;
struct flow_miss *miss;
+ ovs_be16 initial_tci;
struct flow flow;
/* Obtain metadata and check userspace/kernel agreement on flow match,
* then set 'flow''s header pointers. */
- fitness = odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
+ fitness = ofproto_dpif_extract_flow_key(ofproto,
+ upcall->key, upcall->key_len,
+ &flow, &initial_tci);
if (fitness == ODP_FIT_ERROR) {
continue;
}
/* Add other packets to a to-do list. */
miss = flow_miss_create(&todo, &flow, fitness,
- upcall->key, upcall->key_len);
+ upcall->key, upcall->key_len, initial_tci);
list_push_back(&miss->packets, &upcall->packet->list_node);
}
handle_userspace_upcall(struct ofproto_dpif *ofproto,
struct dpif_upcall *upcall)
{
- struct flow flow;
struct user_action_cookie cookie;
+ enum odp_key_fitness fitness;
+ ovs_be16 initial_tci;
+ struct flow flow;
memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+ fitness = ofproto_dpif_extract_flow_key(ofproto, upcall->key,
+ upcall->key_len, &flow,
+ &initial_tci);
+ if (fitness == ODP_FIT_ERROR) {
+ return;
+ }
+
if (cookie.type == USER_ACTION_COOKIE_SFLOW) {
if (ofproto->sflow) {
- odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
- dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, &cookie);
+ dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
+ &cookie);
}
ofpbuf_delete(upcall->packet);
-
} else if (cookie.type == USER_ACTION_COOKIE_CONTROLLER) {
COVERAGE_INC(ofproto_dpif_ctlr_action);
- odp_flow_key_to_flow(upcall->key, upcall->key_len, &flow);
send_packet_in_action(ofproto, upcall->packet, upcall->userdata,
&flow, false);
} else {
if (facet->has_learn || facet->has_normal) {
struct action_xlate_ctx ctx;
- action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL);
+ action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+ facet->flow.vlan_tci, NULL);
ctx.may_learn = true;
ofpbuf_delete(xlate_actions(&ctx, facet->rule->up.actions,
facet->rule->up.n_actions));
struct ofpbuf *odp_actions;
bool should_install;
- action_xlate_ctx_init(&ctx, ofproto, &facet->flow, NULL);
+ action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+ subfacet->initial_tci, NULL);
odp_actions = xlate_actions(&ctx, new_rule->up.actions,
new_rule->up.n_actions);
actions_changed = (subfacet->actions_len != odp_actions->size
push.bytes = bytes;
push.used = used;
- action_xlate_ctx_init(&push.ctx, ofproto, flow, NULL);
+ action_xlate_ctx_init(&push.ctx, ofproto, flow, flow->vlan_tci, NULL);
push.ctx.resubmit_hook = push_resubmit;
ofpbuf_delete(xlate_actions(&push.ctx,
rule->up.actions, rule->up.n_actions));
static struct subfacet *
subfacet_create(struct ofproto_dpif *ofproto, struct facet *facet,
enum odp_key_fitness key_fitness,
- const struct nlattr *key, size_t key_len)
+ const struct nlattr *key, size_t key_len, ovs_be16 initial_tci)
{
uint32_t key_hash = odp_flow_key_hash(key, key_len);
struct subfacet *subfacet;
subfacet->key_len = key_len;
}
subfacet->installed = false;
+ subfacet->initial_tci = initial_tci;
return subfacet;
}
struct ofpbuf *odp_actions;
struct action_xlate_ctx ctx;
- action_xlate_ctx_init(&ctx, p, &facet->flow, packet);
+ action_xlate_ctx_init(&ctx, p, &facet->flow, subfacet->initial_tci,
+ packet);
odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
facet->tags = ctx.tags;
facet->may_install = ctx.may_set_up_flow;
struct ofpbuf *odp_actions;
size_t size;
- action_xlate_ctx_init(&ctx, ofproto, flow, packet);
+ action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
odp_actions = xlate_actions(&ctx, rule->up.actions, rule->up.n_actions);
size = packet->size;
if (execute_odp_actions(ofproto, flow, odp_actions->data,
static void
action_xlate_ctx_init(struct action_xlate_ctx *ctx,
struct ofproto_dpif *ofproto, const struct flow *flow,
- const struct ofpbuf *packet)
+ ovs_be16 initial_tci, const struct ofpbuf *packet)
{
ctx->ofproto = ofproto;
ctx->flow = *flow;
+ ctx->base_flow = ctx->flow;
+ ctx->base_flow.tun_id = 0;
+ ctx->base_flow.vlan_tci = initial_tci;
ctx->packet = packet;
ctx->may_learn = packet != NULL;
ctx->resubmit_hook = NULL;
ctx->nf_output_iface = NF_OUT_DROP;
ctx->recurse = 0;
ctx->original_priority = ctx->flow.priority;
- ctx->base_flow = ctx->flow;
- ctx->base_flow.tun_id = 0;
ctx->table_id = 0;
ctx->exit = false;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
odp_flow_key_from_flow(&key, flow);
- action_xlate_ctx_init(&ctx, ofproto, flow, packet);
+ action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, packet);
odp_actions = xlate_actions(&ctx, ofp_actions, n_ofp_actions);
dpif_execute(ofproto->dpif, key.data, key.size,
odp_actions->data, odp_actions->size, packet);
struct ofpbuf odp_key;
struct ofpbuf *packet;
struct rule_dpif *rule;
+ ovs_be16 initial_tci;
struct ds result;
struct flow flow;
char *s;
ds_init(&result);
dpname = strtok_r(args, " ", &save_ptr);
+ if (!dpname) {
+ unixctl_command_reply(conn, 501, "Bad command syntax");
+ goto exit;
+ }
+
+ ofproto = ofproto_dpif_lookup(dpname);
+ if (!ofproto) {
+ unixctl_command_reply(conn, 501, "Unknown ofproto (use ofproto/list "
+ "for help)");
+ goto exit;
+ }
arg1 = strtok_r(NULL, " ", &save_ptr);
arg2 = strtok_r(NULL, " ", &save_ptr);
arg3 = strtok_r(NULL, " ", &save_ptr);
}
/* Convert odp_key to flow. */
- error = odp_flow_key_to_flow(odp_key.data, odp_key.size, &flow);
- if (error) {
+ error = ofproto_dpif_extract_flow_key(ofproto, odp_key.data,
+ odp_key.size, &flow,
+ &initial_tci);
+ if (error == ODP_FIT_ERROR) {
unixctl_command_reply(conn, 501, "Invalid flow");
goto exit;
}
free(s);
flow_extract(packet, priority, tun_id, in_port, &flow);
+ initial_tci = flow.vlan_tci;
} else {
unixctl_command_reply(conn, 501, "Bad command syntax");
goto exit;
}
- ofproto = ofproto_dpif_lookup(dpname);
- if (!ofproto) {
- unixctl_command_reply(conn, 501, "Unknown ofproto (use ofproto/list "
- "for help)");
- goto exit;
- }
-
ds_put_cstr(&result, "Flow: ");
flow_format(&result, &flow);
ds_put_char(&result, '\n');
trace.result = &result;
trace.flow = flow;
- action_xlate_ctx_init(&trace.ctx, ofproto, &flow, packet);
+ action_xlate_ctx_init(&trace.ctx, ofproto, &flow, initial_tci, packet);
trace.ctx.resubmit_hook = trace_resubmit;
odp_actions = xlate_actions(&trace.ctx,
rule->up.actions, rule->up.n_actions);