ofproto-dpif: Add helper function to retrieve a subfacet from a facet.
[sliver-openvswitch.git] / ofproto / ofproto-dpif.c
index ea6104a..56b55f6 100644 (file)
@@ -78,6 +78,7 @@ BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);
 struct ofport_dpif;
 struct ofproto_dpif;
 struct flow_miss;
+struct facet;
 
 struct rule_dpif {
     struct rule up;
@@ -118,8 +119,7 @@ static struct rule_dpif *rule_dpif_miss_rule(struct ofproto_dpif *ofproto,
 
 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 *);
@@ -216,6 +216,11 @@ struct action_xlate_ctx {
      * 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;
@@ -285,9 +290,28 @@ struct action_xlate_ctx {
     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,
@@ -360,10 +384,8 @@ struct subfacet {
     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
@@ -465,7 +487,9 @@ struct facet {
 
     /* Storage for a single subfacet, to reduce malloc() time and space
      * overhead.  (A facet always has at least one subfacet and in the common
-     * case has exactly one subfacet.) */
+     * case has exactly one subfacet.  However, 'one_subfacet' may not
+     * always be valid, since it could have been removed after newer
+     * subfacets were pushed onto the 'subfacets' list.) */
     struct subfacet one_subfacet;
 };
 
@@ -489,6 +513,8 @@ static void facet_push_stats(struct facet *);
 static void facet_learn(struct facet *);
 static void facet_account(struct facet *);
 
+static struct subfacet *facet_get_subfacet(struct facet *);
+
 static bool facet_is_controller_flow(struct facet *);
 
 struct ofport_dpif {
@@ -711,8 +737,8 @@ static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *,
 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 *,
@@ -1778,43 +1804,22 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
     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. */
 
@@ -3280,7 +3285,7 @@ struct flow_miss {
     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;
@@ -3367,7 +3372,7 @@ static void
 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
@@ -3459,8 +3464,8 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
         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);
@@ -3650,10 +3655,12 @@ drop_key_clear(struct dpif_backer *backer)
  * 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
@@ -3666,7 +3673,7 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
                 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;
@@ -3678,8 +3685,9 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
         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) {
@@ -3783,7 +3791,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
 
         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;
 
@@ -4412,6 +4420,8 @@ static void
 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
@@ -4422,7 +4432,7 @@ facet_learn(struct facet *facet)
     }
 
     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,
@@ -4433,7 +4443,7 @@ static void
 facet_account(struct facet *facet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
-    struct subfacet *subfacet;
+    struct subfacet *subfacet = facet_get_subfacet(facet);
     const struct nlattr *a;
     unsigned int left;
     ovs_be16 vlan_tci;
@@ -4452,8 +4462,6 @@ facet_account(struct facet *facet)
      *
      * We use the actions from an arbitrary subfacet because they should all
      * be equally valid for our purpose. */
-    subfacet = CONTAINER_OF(list_front(&facet->subfacets),
-                            struct subfacet, list_node);
     vlan_tci = facet->flow.vlan_tci;
     NL_ATTR_FOR_EACH_UNSAFE (a, left,
                              subfacet->actions, subfacet->actions_len) {
@@ -4590,6 +4598,14 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow,
     return facet;
 }
 
+/* Return a subfacet from 'facet'.  A facet consists of one or more
+ * subfacets, and this function returns one of them. */
+static struct subfacet *facet_get_subfacet(struct facet *facet)
+{
+    return CONTAINER_OF(list_front(&facet->subfacets), struct subfacet,
+                        list_node);
+}
+
 static const char *
 subfacet_path_to_string(enum subfacet_path path)
 {
@@ -4674,7 +4690,7 @@ facet_check_consistency(struct facet *facet)
         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);
 
@@ -4805,7 +4821,7 @@ facet_revalidate(struct facet *facet)
         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);
 
@@ -4907,7 +4923,7 @@ facet_push_stats(struct facet *facet)
         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);
@@ -4922,19 +4938,20 @@ rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
     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 = facet_get_subfacet(facet);
     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);
@@ -5012,7 +5029,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
                       ? 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;
@@ -5089,8 +5106,8 @@ subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
 
     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;
@@ -5408,9 +5425,8 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
                   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;
@@ -5418,8 +5434,10 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
     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);
@@ -6058,6 +6076,17 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
     }
 }
 
+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)
 {
@@ -6067,7 +6096,7 @@ execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx)
         return false;
     }
 
-    if (ttl > 0) {
+    if (ttl > 1) {
         ttl--;
         set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
         return false;
@@ -6297,6 +6326,24 @@ may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
     return true;
 }
 
+static bool
+tunnel_ecn_ok(struct action_xlate_ctx *ctx)
+{
+    if (is_ip_any(&ctx->base_flow)
+        && (ctx->base_flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
+        if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
+            VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
+                         " but is not ECN capable");
+            return false;
+        } else {
+            /* Set the ECN CE value in the tunneled packet. */
+            ctx->flow.nw_tos |= IP_ECN_CE;
+        }
+    }
+
+    return true;
+}
+
 static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct action_xlate_ctx *ctx)
@@ -6414,6 +6461,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             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;
@@ -6422,6 +6479,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             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;
@@ -6501,7 +6564,8 @@ 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;
@@ -6531,7 +6595,8 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     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;
@@ -6577,6 +6642,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
     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. */
@@ -6612,12 +6679,15 @@ xlate_actions(struct action_xlate_ctx *ctx,
         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)) {
+        if (tunnel_ecn_ok(ctx) && (!in_port || may_receive(in_port, ctx))) {
             do_xlate_actions(ofpacts, ofpacts_len, ctx);
 
             /* We've let OFPP_NORMAL and the learning action look at the
@@ -6637,7 +6707,7 @@ xlate_actions(struct action_xlate_ctx *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);
@@ -6661,6 +6731,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
         fix_sflow_action(ctx);
     }
+
+    ofpbuf_uninit(&ctx->stack);
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
@@ -7357,6 +7429,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
            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;
 
@@ -7372,7 +7445,9 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
 
     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;
 
@@ -7612,7 +7687,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
     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;
@@ -7659,7 +7734,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
              * 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;
             }
@@ -7673,7 +7748,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                 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. */
@@ -7707,13 +7783,14 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
 
         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:
@@ -7724,8 +7801,8 @@ 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;
 
@@ -7755,7 +7832,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         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;
@@ -8397,10 +8474,7 @@ const struct ofproto_class ofproto_dpif_class = {
     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,