struct ofport_dpif;
struct ofproto_dpif;
struct flow_miss;
+struct facet;
struct rule_dpif {
struct rule up;
static void rule_credit_stats(struct rule_dpif *,
const struct dpif_flow_stats *);
-static void flow_push_stats(struct rule_dpif *, const struct flow *,
- const struct dpif_flow_stats *);
+static void flow_push_stats(struct facet *, const struct dpif_flow_stats *);
static tag_type rule_calculate_tag(const struct flow *,
const struct minimask *, uint32_t basis);
static void rule_invalidate(const struct rule_dpif *);
* this flow when actions change header fields. */
struct flow flow;
+ /* stack for the push and pop actions.
+ * Each stack element is of the type "union mf_subvalue". */
+ struct ofpbuf stack;
+ union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)];
+
/* The packet corresponding to 'flow', or a null pointer if we are
* revalidating without a packet to refer to. */
const struct ofpbuf *packet;
bool exit; /* No further actions should be processed. */
};
+/* Initial values of fields of the packet that may be changed during
+ * flow processing and needed later. */
+struct initial_vals {
+ /* This is the value of vlan_tci in the packet as actually received from
+ * dpif. This is the same as the facet's flow.vlan_tci unless the packet
+ * was received via a VLAN splinter. In that case, this value is 0
+ * (because the packet as actually received from the dpif had no 802.1Q
+ * tag) but the facet's flow.vlan_tci is set to the VLAN that the splinter
+ * represents.
+ *
+ * This member should be removed when the VLAN splinters feature is no
+ * longer needed. */
+ ovs_be16 vlan_tci;
+
+ /* If received on a tunnel, the IP TOS value of the tunnel. */
+ uint8_t tunnel_ip_tos;
+};
+
static void action_xlate_ctx_init(struct action_xlate_ctx *,
struct ofproto_dpif *, const struct flow *,
- ovs_be16 initial_tci, struct rule_dpif *,
+ const struct initial_vals *initial_vals,
+ struct rule_dpif *,
uint8_t tcp_flags, const struct ofpbuf *);
static void xlate_actions(struct action_xlate_ctx *,
const struct ofpact *ofpacts, size_t ofpacts_len,
enum slow_path_reason slow; /* 0 if fast path may be used. */
enum subfacet_path path; /* 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. */
+ /* Initial values of the packet that may be needed later. */
+ struct initial_vals initial_vals;
/* Datapath port the packet arrived on. This is needed to remove
* flows for ports that are no longer part of the bridge. Since the
static struct ofport_dpif *get_odp_port(const struct ofproto_dpif *,
uint32_t odp_port);
static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
- const struct ofpbuf *, ovs_be16 initial_tci,
- struct ds *);
+ const struct ofpbuf *,
+ const struct initial_vals *, struct ds *);
/* Packet processing. */
static void update_learning_table(struct ofproto_dpif *,
return error;
}
-static int
-get_cfm_fault(const struct ofport *ofport_)
-{
- struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
- return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_opup(const struct ofport *ofport_)
-{
- struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
- return ofport->cfm ? cfm_get_opup(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps,
- size_t *n_rmps)
+static bool
+get_cfm_status(const struct ofport *ofport_,
+ struct ofproto_cfm_status *status)
{
struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
if (ofport->cfm) {
- cfm_get_remote_mpids(ofport->cfm, rmps, n_rmps);
- return 0;
+ status->faults = cfm_get_fault(ofport->cfm);
+ status->remote_opstate = cfm_get_opup(ofport->cfm);
+ status->health = cfm_get_health(ofport->cfm);
+ cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
+ return true;
} else {
- return -1;
+ return false;
}
}
-
-static int
-get_cfm_health(const struct ofport *ofport_)
-{
- struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
- return ofport->cfm ? cfm_get_health(ofport->cfm) : -1;
-}
\f
/* Spanning Tree. */
enum odp_key_fitness key_fitness;
const struct nlattr *key;
size_t key_len;
- ovs_be16 initial_tci;
+ struct initial_vals initial_vals;
struct list packets;
enum dpif_upcall_type upcall_type;
uint32_t odp_in_port;
init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
struct flow_miss_op *op)
{
- if (miss->flow.vlan_tci != miss->initial_tci) {
+ if (miss->flow.vlan_tci != miss->initial_vals.vlan_tci) {
/* This packet was received on a VLAN splinter port. We
* added a VLAN to the packet to make the packet resemble
* the flow, but the actions were composed assuming that
dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
rule_credit_stats(rule, &stats);
- action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci,
- rule, 0, packet);
+ action_xlate_ctx_init(&ctx, ofproto, &miss->flow,
+ &miss->initial_vals, rule, 0, packet);
ctx.resubmit_stats = &stats;
xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
&odp_actions);
* flow->vlan_tci correctly for the VLAN of the VLAN splinter port, and pushes
* a VLAN header onto 'packet' (if it is nonnull).
*
- * Optionally, if nonnull, sets '*initial_tci' to the VLAN TCI with which the
- * packet was really received, that is, the actual VLAN TCI extracted by
- * odp_flow_key_to_flow(). (This differs from the value returned in
- * flow->vlan_tci only for packets received on VLAN splinters.)
+ * Optionally, if 'initial_vals' is nonnull, sets 'initial_vals->vlan_tci'
+ * to the VLAN TCI with which the packet was really received, that is, the
+ * actual VLAN TCI extracted by odp_flow_key_to_flow(). (This differs from
+ * the value returned in flow->vlan_tci only for packets received on
+ * VLAN splinters.) Also, if received on an IP tunnel, sets
+ * 'initial_vals->tunnel_ip_tos' to the tunnel's IP TOS.
*
* Similarly, this function also includes some logic to help with tunnels. It
* may modify 'flow' as necessary to make the tunneling implementation
const struct nlattr *key, size_t key_len,
struct flow *flow, enum odp_key_fitness *fitnessp,
struct ofproto_dpif **ofproto, uint32_t *odp_in_port,
- ovs_be16 *initial_tci)
+ struct initial_vals *initial_vals)
{
const struct ofport_dpif *port;
enum odp_key_fitness fitness;
goto exit;
}
- if (initial_tci) {
- *initial_tci = flow->vlan_tci;
+ if (initial_vals) {
+ initial_vals->vlan_tci = flow->vlan_tci;
+ initial_vals->tunnel_ip_tos = flow->tunnel.ip_tos;
}
if (odp_in_port) {
error = ofproto_receive(backer, upcall->packet, upcall->key,
upcall->key_len, &flow, &miss->key_fitness,
- &ofproto, &odp_in_port, &miss->initial_tci);
+ &ofproto, &odp_in_port, &miss->initial_vals);
if (error == ENODEV) {
struct drop_key *drop_key;
facet_learn(struct facet *facet)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+ struct subfacet *subfacet= CONTAINER_OF(list_front(&facet->subfacets),
+ struct subfacet, list_node);
struct action_xlate_ctx ctx;
if (!facet->has_learn
}
action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
- facet->flow.vlan_tci,
+ &subfacet->initial_vals,
facet->rule, facet->tcp_flags, NULL);
ctx.may_learn = true;
xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts,
struct ds s;
action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
- subfacet->initial_tci, rule, 0, NULL);
+ &subfacet->initial_vals, rule, 0, NULL);
xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
&odp_actions);
enum slow_path_reason slow;
action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
- subfacet->initial_tci, new_rule, 0, NULL);
+ &subfacet->initial_vals, new_rule, 0, NULL);
xlate_actions(&ctx, new_rule->up.ofpacts, new_rule->up.ofpacts_len,
&odp_actions);
facet->prev_byte_count = facet->byte_count;
facet->prev_used = facet->used;
- flow_push_stats(facet->rule, &facet->flow, &stats);
+ flow_push_stats(facet, &stats);
update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
facet->mirrors, stats.n_packets, stats.n_bytes);
ofproto_rule_update_used(&rule->up, stats->used);
}
-/* Pushes flow statistics to the rules which 'flow' resubmits into given
- * 'rule''s actions and mirrors. */
+/* Pushes flow statistics to the rules which 'facet->flow' resubmits
+ * into given 'facet->rule''s actions and mirrors. */
static void
-flow_push_stats(struct rule_dpif *rule,
- const struct flow *flow, const struct dpif_flow_stats *stats)
+flow_push_stats(struct facet *facet, const struct dpif_flow_stats *stats)
{
+ struct rule_dpif *rule = facet->rule;
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+ struct subfacet *subfacet = CONTAINER_OF(list_front(&facet->subfacets),
+ struct subfacet, list_node);
struct action_xlate_ctx ctx;
ofproto_rule_update_used(&rule->up, stats->used);
- action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, rule,
- 0, NULL);
+ action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+ &subfacet->initial_vals, rule, 0, NULL);
ctx.resubmit_stats = stats;
xlate_actions_for_side_effects(&ctx, rule->up.ofpacts,
rule->up.ofpacts_len);
? SLOW_MATCH
: 0);
subfacet->path = SF_NOT_INSTALLED;
- subfacet->initial_tci = miss->initial_tci;
+ subfacet->initial_vals = miss->initial_vals;
subfacet->odp_in_port = miss->odp_in_port;
return subfacet;
struct action_xlate_ctx ctx;
- action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
- rule, 0, packet);
+ 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);
facet->tags = ctx.tags;
facet->has_learn = ctx.has_learn;
struct ofpbuf *packet)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
+ struct initial_vals initial_vals;
struct dpif_flow_stats stats;
-
struct action_xlate_ctx ctx;
uint64_t odp_actions_stub[1024 / 8];
struct ofpbuf odp_actions;
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
rule_credit_stats(rule, &stats);
+ initial_vals.vlan_tci = flow->vlan_tci;
+ initial_vals.tunnel_ip_tos = flow->tunnel.ip_tos;
ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
- action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
+ action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals,
rule, stats.tcp_flags, packet);
ctx.resubmit_stats = &stats;
xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions);
}
}
+static bool
+execute_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl)
+{
+ if (!eth_type_mpls(ctx->flow.dl_type)) {
+ return true;
+ }
+
+ set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+ return false;
+}
+
+static bool
+execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx)
+{
+ uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse);
+
+ if (!eth_type_mpls(ctx->flow.dl_type)) {
+ return false;
+ }
+
+ if (ttl > 0) {
+ ttl--;
+ set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+ return false;
+ } else {
+ execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+
+ /* Stop processing for current table. */
+ return true;
+ }
+}
+
static void
xlate_output_action(struct action_xlate_ctx *ctx,
uint16_t port, uint16_t max_len, bool may_packet_in)
nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
break;
+ case OFPACT_STACK_PUSH:
+ nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow,
+ &ctx->stack);
+ break;
+
+ case OFPACT_STACK_POP:
+ nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow,
+ &ctx->stack);
+ break;
+
case OFPACT_PUSH_MPLS:
execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype);
break;
execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
break;
+ case OFPACT_SET_MPLS_TTL:
+ if (execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) {
+ goto out;
+ }
+ break;
+
+ case OFPACT_DEC_MPLS_TTL:
+ if (execute_dec_mpls_ttl_action(ctx)) {
+ goto out;
+ }
+ break;
+
case OFPACT_DEC_TTL:
if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
goto out;
static void
action_xlate_ctx_init(struct action_xlate_ctx *ctx,
struct ofproto_dpif *ofproto, const struct flow *flow,
- ovs_be16 initial_tci, struct rule_dpif *rule,
+ const struct initial_vals *initial_vals,
+ struct rule_dpif *rule,
uint8_t tcp_flags, const struct ofpbuf *packet)
{
ovs_be64 initial_tun_id = flow->tunnel.tun_id;
ctx->flow = *flow;
memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
ctx->base_flow = ctx->flow;
- ctx->base_flow.vlan_tci = initial_tci;
+ ctx->base_flow.vlan_tci = initial_vals->vlan_tci;
+ ctx->base_flow.tunnel.ip_tos = initial_vals->tunnel_ip_tos;
ctx->flow.tunnel.tun_id = initial_tun_id;
ctx->rule = rule;
ctx->packet = packet;
ctx->table_id = 0;
ctx->exit = false;
+ ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack);
+
if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
/* Do this conditionally because the copy is expensive enough that it
* shows up in profiles. */
ctx->slow |= special;
} else {
static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1);
- ovs_be16 initial_tci = ctx->base_flow.vlan_tci;
+ struct initial_vals initial_vals;
uint32_t local_odp_port;
+ initial_vals.vlan_tci = ctx->base_flow.vlan_tci;
+ initial_vals.tunnel_ip_tos = ctx->base_flow.tunnel.ip_tos;
+
add_sflow_action(ctx);
if (!in_port || may_receive(in_port, ctx)) {
struct ds ds = DS_EMPTY_INITIALIZER;
ofproto_trace(ctx->ofproto, &orig_flow, ctx->packet,
- initial_tci, &ds);
+ &initial_vals, &ds);
VLOG_ERR("Trace triggered by excessive resubmit "
"recursion:\n%s", ds_cstr(&ds));
ds_destroy(&ds);
}
fix_sflow_action(ctx);
}
+
+ ofpbuf_uninit(&ctx->stack);
}
/* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
const struct ofpact *ofpacts, size_t ofpacts_len)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct initial_vals initial_vals;
struct odputil_keybuf keybuf;
struct dpif_flow_stats stats;
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
- action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL,
+ initial_vals.vlan_tci = flow->vlan_tci;
+ initial_vals.tunnel_ip_tos = 0;
+ action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, NULL,
packet_get_tcp_flags(packet, flow), packet);
ctx.resubmit_stats = &stats;
struct ofproto_dpif *ofproto;
struct ofpbuf odp_key;
struct ofpbuf *packet;
- ovs_be16 initial_tci;
+ struct initial_vals initial_vals;
struct ds result;
struct flow flow;
char *s;
* ability to specify the ofproto. */
if (ofproto_receive(ofproto->backer, NULL, odp_key.data,
odp_key.size, &flow, NULL, NULL, NULL,
- &initial_tci)) {
+ &initial_vals)) {
unixctl_command_reply_error(conn, "Invalid flow");
goto exit;
}
goto exit;
}
- initial_tci = flow.vlan_tci;
+ initial_vals.vlan_tci = flow.vlan_tci;
+ initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos;
}
/* Generate a packet, if requested. */
flow_extract(packet, priority, mark, NULL, in_port, &flow);
flow.tunnel.tun_id = tun_id;
- initial_tci = flow.vlan_tci;
+ initial_vals.vlan_tci = flow.vlan_tci;
+ initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos;
} else {
unixctl_command_reply_error(conn, "Bad command syntax");
goto exit;
}
- ofproto_trace(ofproto, &flow, packet, initial_tci, &result);
+ ofproto_trace(ofproto, &flow, packet, &initial_vals, &result);
unixctl_command_reply(conn, ds_cstr(&result));
exit:
static void
ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
- const struct ofpbuf *packet, ovs_be16 initial_tci,
- struct ds *ds)
+ const struct ofpbuf *packet,
+ const struct initial_vals *initial_vals, struct ds *ds)
{
struct rule_dpif *rule;
trace.flow = *flow;
ofpbuf_use_stub(&odp_actions,
odp_actions_stub, sizeof odp_actions_stub);
- action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_tci,
+ action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_vals,
rule, tcp_flags, packet);
trace.ctx.resubmit_hook = trace_resubmit;
trace.ctx.report_hook = trace_report;
get_netflow_ids,
set_sflow,
set_cfm,
- get_cfm_fault,
- get_cfm_opup,
- get_cfm_remote_mpids,
- get_cfm_health,
+ get_cfm_status,
set_stp,
get_stp_status,
set_stp_port,