ofproto-dpif: Tighten up megaflow wildcard handling.
authorJustin Pettit <jpettit@nicira.com>
Wed, 19 Jun 2013 06:55:47 +0000 (23:55 -0700)
committerJustin Pettit <jpettit@nicira.com>
Thu, 20 Jun 2013 06:21:00 +0000 (23:21 -0700)
A number of use-cases weren't handled properly when determining what can
be wildcarded for megaflows.  This commit both catches additional fields
that cannot be wildcarded and loosens a few other cases.

Bug #17979

Signed-off-by: Justin Pettit <jpettit@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
lib/flow.c
lib/odp-util.c
lib/odp-util.h
ofproto/netflow.c
ofproto/netflow.h
ofproto/ofproto-dpif.c
tests/ofproto-dpif.at

index 2abc642..b1c0570 100644 (file)
@@ -788,12 +788,12 @@ flow_mask_hash_fields(struct flow_wildcards *wc, enum nx_hash_fields fields)
         memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
         memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
         memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
-        memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
         memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
         memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
         memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
         memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
         memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+        wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
         break;
 
     default:
index bfedfe1..3b8b437 100644 (file)
@@ -2220,7 +2220,8 @@ commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_ether_addr_action(const struct flow *flow, struct flow *base,
-                             struct ofpbuf *odp_actions)
+                             struct ofpbuf *odp_actions,
+                             struct flow_wildcards *wc)
 {
     struct ovs_key_ethernet eth_key;
 
@@ -2229,6 +2230,9 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base,
         return;
     }
 
+    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+
     memcpy(base->dl_src, flow->dl_src, ETH_ADDR_LEN);
     memcpy(base->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
 
@@ -2241,12 +2245,14 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_vlan_action(const struct flow *flow, struct flow *base,
-                   struct ofpbuf *odp_actions)
+                   struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     if (base->vlan_tci == flow->vlan_tci) {
         return;
     }
 
+    memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+
     if (base->vlan_tci & htons(VLAN_CFI)) {
         nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN);
     }
@@ -2264,13 +2270,15 @@ commit_vlan_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_mpls_action(const struct flow *flow, struct flow *base,
-                   struct ofpbuf *odp_actions)
+                   struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     if (flow->mpls_lse == base->mpls_lse &&
         flow->mpls_depth == base->mpls_depth) {
         return;
     }
 
+    memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+
     if (flow->mpls_depth < base->mpls_depth) {
         if (base->mpls_depth - flow->mpls_depth > 1) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
@@ -2308,7 +2316,7 @@ commit_mpls_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_ipv4_action(const struct flow *flow, struct flow *base,
-                     struct ofpbuf *odp_actions)
+                     struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     struct ovs_key_ipv4 ipv4_key;
 
@@ -2320,6 +2328,13 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base,
         return;
     }
 
+    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+    memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+    memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+    memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+
     ipv4_key.ipv4_src = base->nw_src = flow->nw_src;
     ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst;
     ipv4_key.ipv4_tos = base->nw_tos = flow->nw_tos;
@@ -2333,7 +2348,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_ipv6_action(const struct flow *flow, struct flow *base,
-                       struct ofpbuf *odp_actions)
+                       struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     struct ovs_key_ipv6 ipv6_key;
 
@@ -2346,6 +2361,14 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base,
         return;
     }
 
+    memset(&wc->masks.ipv6_src, 0xff, sizeof wc->masks.ipv6_src);
+    memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
+    memset(&wc->masks.ipv6_label, 0xff, sizeof wc->masks.ipv6_label);
+    memset(&wc->masks.nw_tos, 0xff, sizeof wc->masks.nw_tos);
+    memset(&wc->masks.nw_ttl, 0xff, sizeof wc->masks.nw_ttl);
+    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    memset(&wc->masks.nw_frag, 0xff, sizeof wc->masks.nw_frag);
+
     base->ipv6_src = flow->ipv6_src;
     memcpy(&ipv6_key.ipv6_src, &base->ipv6_src, sizeof(ipv6_key.ipv6_src));
     base->ipv6_dst = flow->ipv6_dst;
@@ -2363,7 +2386,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_nw_action(const struct flow *flow, struct flow *base,
-                     struct ofpbuf *odp_actions)
+                     struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     /* Check if flow really have an IP header. */
     if (!flow->nw_proto) {
@@ -2371,15 +2394,15 @@ commit_set_nw_action(const struct flow *flow, struct flow *base,
     }
 
     if (base->dl_type == htons(ETH_TYPE_IP)) {
-        commit_set_ipv4_action(flow, base, odp_actions);
+        commit_set_ipv4_action(flow, base, odp_actions, wc);
     } else if (base->dl_type == htons(ETH_TYPE_IPV6)) {
-        commit_set_ipv6_action(flow, base, odp_actions);
+        commit_set_ipv6_action(flow, base, odp_actions, wc);
     }
 }
 
 static void
 commit_set_port_action(const struct flow *flow, struct flow *base,
-                       struct ofpbuf *odp_actions)
+                       struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
     if (!is_ip_any(base) || (!base->tp_src && !base->tp_dst)) {
         return;
@@ -2390,6 +2413,9 @@ commit_set_port_action(const struct flow *flow, struct flow *base,
         return;
     }
 
+    memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+    memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+
     if (flow->nw_proto == IPPROTO_TCP) {
         struct ovs_key_tcp port_key;
 
@@ -2412,11 +2438,14 @@ commit_set_port_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_priority_action(const struct flow *flow, struct flow *base,
-                           struct ofpbuf *odp_actions)
+                           struct ofpbuf *odp_actions,
+                           struct flow_wildcards *wc)
 {
     if (base->skb_priority == flow->skb_priority) {
         return;
     }
+
+    memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
     base->skb_priority = flow->skb_priority;
 
     commit_set_action(odp_actions, OVS_KEY_ATTR_PRIORITY,
@@ -2425,11 +2454,14 @@ commit_set_priority_action(const struct flow *flow, struct flow *base,
 
 static void
 commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
-                           struct ofpbuf *odp_actions)
+                           struct ofpbuf *odp_actions,
+                           struct flow_wildcards *wc)
 {
     if (base->skb_mark == flow->skb_mark) {
         return;
     }
+
+    memset(&wc->masks.skb_mark, 0xff, sizeof wc->masks.skb_mark);
     base->skb_mark = flow->skb_mark;
 
     odp_put_skb_mark_action(base->skb_mark, odp_actions);
@@ -2438,20 +2470,21 @@ commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
  * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
  * key from 'base' into 'flow', and then changes 'base' the same way.  Does not
  * commit set_tunnel actions.  Users should call commit_odp_tunnel_action()
- * in addition to this function if needed. */
+ * in addition to this function if needed.  Sets fields in 'wc' that are
+ * used as part of the action. */
 void
 commit_odp_actions(const struct flow *flow, struct flow *base,
-                   struct ofpbuf *odp_actions)
+                   struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
-    commit_set_ether_addr_action(flow, base, odp_actions);
-    commit_vlan_action(flow, base, odp_actions);
-    commit_set_nw_action(flow, base, odp_actions);
-    commit_set_port_action(flow, base, odp_actions);
-    /* Commiting MPLS actions should occur after committing nw and port
+    commit_set_ether_addr_action(flow, base, odp_actions, wc);
+    commit_vlan_action(flow, base, odp_actions, wc);
+    commit_set_nw_action(flow, base, odp_actions, wc);
+    commit_set_port_action(flow, base, odp_actions, wc);
+    /* Committing MPLS actions should occur after committing nw and port
      * actions. This is because committing MPLS actions may alter a packet so
      * that it is no longer IP and thus nw and port actions are no longer valid.
      */
-    commit_mpls_action(flow, base, odp_actions);
-    commit_set_priority_action(flow, base, odp_actions);
-    commit_set_skb_mark_action(flow, base, odp_actions);
+    commit_mpls_action(flow, base, odp_actions, wc);
+    commit_set_priority_action(flow, base, odp_actions, wc);
+    commit_set_skb_mark_action(flow, base, odp_actions, wc);
 }
index baee7a1..2f0789a 100644 (file)
@@ -29,6 +29,7 @@
 struct ds;
 struct flow;
 struct flow_tnl;
+struct flow_wildcards;
 struct nlattr;
 struct ofpbuf;
 struct simap;
@@ -116,7 +117,8 @@ const char *odp_key_fitness_to_string(enum odp_key_fitness);
 void commit_odp_tunnel_action(const struct flow *, struct flow *base,
                               struct ofpbuf *odp_actions);
 void commit_odp_actions(const struct flow *, struct flow *base,
-                        struct ofpbuf *odp_actions);
+                        struct ofpbuf *odp_actions,
+                        struct flow_wildcards *wc);
 \f
 /* ofproto-dpif interface.
  *
index aec3968..7aff155 100644 (file)
@@ -51,6 +51,18 @@ struct netflow {
     long long int reconfig_time;  /* When we reconfigured the timeouts. */
 };
 
+void
+netflow_mask_wc(struct flow_wildcards *wc)
+{
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+    memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+    memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
+    memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+    memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+    memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
+    wc->masks.nw_tos |= IP_DSCP_MASK;
+}
+
 static void
 gen_netflow_rec(struct netflow *nf, struct netflow_flow *nf_flow,
                 struct ofexpired *expired,
index c01ff15..9691545 100644 (file)
@@ -64,6 +64,8 @@ void netflow_expire(struct netflow *, struct netflow_flow *,
 bool netflow_run(struct netflow *);
 void netflow_wait(struct netflow *);
 
+void netflow_mask_wc(struct flow_wildcards *);
+
 void netflow_flow_init(struct netflow_flow *);
 void netflow_flow_clear(struct netflow_flow *);
 void netflow_flow_update_time(struct netflow *, struct netflow_flow *,
index 9d0462e..362cbc0 100644 (file)
@@ -3590,6 +3590,7 @@ process_special(struct xlate_ctx *ctx, const struct flow *flow,
         return SLOW_CFM;
     } else if (ofport->bundle && ofport->bundle->lacp
                && flow->dl_type == htons(ETH_TYPE_LACP)) {
+        memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
         if (packet) {
             lacp_process_packet(ofport->bundle->lacp, ofport, packet);
         }
@@ -5497,6 +5498,10 @@ rule_dpif_lookup__(struct ofproto_dpif *ofproto, const struct flow *flow,
         return NULL;
     }
 
+    if (wc) {
+        wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
+    }
+
     cls = &ofproto->up.tables[table_id].cls;
     frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0;
     if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
@@ -5993,6 +5998,7 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port,
                         bool check_stp)
 {
     const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port);
+    struct flow_wildcards *wc = &ctx->xout->wc;
     ovs_be16 flow_vlan_tci;
     uint32_t flow_skb_mark;
     uint8_t flow_nw_tos;
@@ -6074,6 +6080,7 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port,
 
     pdscp = get_priority(ofport, ctx->xin->flow.skb_priority);
     if (pdscp) {
+        wc->masks.nw_tos |= IP_ECN_MASK;
         ctx->xin->flow.nw_tos &= ~IP_DSCP_MASK;
         ctx->xin->flow.nw_tos |= pdscp->dscp;
     }
@@ -6100,7 +6107,11 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port,
         ctx->xin->flow.tunnel = flow_tnl; /* Restore tunnel metadata */
     } else {
         uint16_t vlandev_port;
+
         odp_port = ofport->odp_port;
+        if (!hmap_is_empty(&ctx->ofproto->realdev_vid_map)) {
+            wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
+        }
         vlandev_port = vsp_realdev_to_vlandev(ctx->ofproto, ofp_port,
                                               ctx->xin->flow.vlan_tci);
         if (vlandev_port == ofp_port) {
@@ -6112,7 +6123,7 @@ compose_output_action__(struct xlate_ctx *ctx, uint16_t ofp_port,
         ctx->xin->flow.skb_mark &= ~IPSEC_MARK;
     }
     commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
-                       &ctx->xout->odp_actions);
+                       &ctx->xout->odp_actions, &ctx->xout->wc);
     nl_msg_put_u32(&ctx->xout->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port);
 
     ctx->sflow_odp_port = odp_port;
@@ -6336,14 +6347,12 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
 static void
 execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
 {
+    struct flow_wildcards *wc = &ctx->xout->wc;
     ovs_assert(eth_type_mpls(eth_type));
 
-    memset(&ctx->xout->wc.masks.dl_type, 0xff,
-               sizeof ctx->xout->wc.masks.dl_type);
-    memset(&ctx->xout->wc.masks.mpls_lse, 0xff,
-               sizeof ctx->xout->wc.masks.mpls_lse);
-    memset(&ctx->xout->wc.masks.mpls_depth, 0xff,
-               sizeof ctx->xout->wc.masks.mpls_depth);
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+    memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+    memset(&wc->masks.mpls_depth, 0xff, sizeof wc->masks.mpls_depth);
 
     if (ctx->base_flow.mpls_depth) {
         ctx->xin->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK);
@@ -6357,6 +6366,8 @@ execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
         } else {
             label = htonl(0x0); /* IPV4 Explicit Null. */
         }
+        wc->masks.nw_tos |= IP_DSCP_MASK;
+        wc->masks.nw_ttl = 0xff;
         tc = (ctx->xin->flow.nw_tos & IP_DSCP_MASK) >> 2;
         ttl = ctx->xin->flow.nw_ttl ? ctx->xin->flow.nw_ttl : 0x40;
         ctx->xin->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label);
@@ -6368,15 +6379,14 @@ execute_mpls_push_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
 static void
 execute_mpls_pop_action(struct xlate_ctx *ctx, ovs_be16 eth_type)
 {
+    struct flow_wildcards *wc = &ctx->xout->wc;
+
     ovs_assert(eth_type_mpls(ctx->xin->flow.dl_type));
     ovs_assert(!eth_type_mpls(eth_type));
 
-    memset(&ctx->xout->wc.masks.dl_type, 0xff,
-               sizeof ctx->xout->wc.masks.dl_type);
-    memset(&ctx->xout->wc.masks.mpls_lse, 0xff,
-               sizeof ctx->xout->wc.masks.mpls_lse);
-    memset(&ctx->xout->wc.masks.mpls_depth, 0xff,
-               sizeof ctx->xout->wc.masks.mpls_depth);
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+    memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
+    memset(&wc->masks.mpls_depth, 0xff, sizeof wc->masks.mpls_depth);
 
     if (ctx->xin->flow.mpls_depth) {
         ctx->xin->flow.mpls_depth--;
@@ -6395,6 +6405,7 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
         return false;
     }
 
+    ctx->xout->wc.masks.nw_ttl = 0xff;
     if (ctx->xin->flow.nw_ttl > 1) {
         ctx->xin->flow.nw_ttl--;
         return false;
@@ -6426,6 +6437,10 @@ static bool
 execute_dec_mpls_ttl_action(struct xlate_ctx *ctx)
 {
     uint8_t ttl = mpls_lse_to_ttl(ctx->xin->flow.mpls_lse);
+    struct flow_wildcards *wc = &ctx->xout->wc;
+
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+    memset(&wc->masks.mpls_lse, 0xff, sizeof wc->masks.mpls_lse);
 
     if (!eth_type_mpls(ctx->xin->flow.dl_type)) {
         return false;
@@ -6658,7 +6673,7 @@ xlate_sample_action(struct xlate_ctx *ctx,
   uint32_t probability = (os->probability << 16) | os->probability;
 
   commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
-                     &ctx->xout->odp_actions);
+                     &ctx->xout->odp_actions, &ctx->xout->wc);
 
   compose_flow_sample_cookie(os->probability, os->collector_set_id,
                              os->obs_domain_id, os->obs_point_id, &cookie);
@@ -6840,9 +6855,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_POP_QUEUE:
-            memset(&ctx->xout->wc.masks.skb_priority, 0xff,
-                   sizeof ctx->xout->wc.masks.skb_priority);
-
             ctx->xin->flow.skb_priority = ctx->orig_skb_priority;
             break;
 
@@ -7032,6 +7044,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
      * that in the future we always keep a copy of the original flow for
      * tracing purposes. */
     static bool hit_resubmit_limit;
+    struct flow_wildcards *wc = &xout->wc;
 
     enum slow_path_reason special;
     const struct ofpact *ofpacts;
@@ -7075,34 +7088,17 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
     ctx.base_flow.tunnel.ip_tos = xin->initial_vals.tunnel_ip_tos;
 
     flow_wildcards_init_catchall(&ctx.xout->wc);
-    memset(&ctx.xout->wc.masks.in_port, 0xff,
-           sizeof ctx.xout->wc.masks.in_port);
+    memset(&wc->masks.in_port, 0xff, sizeof wc->masks.in_port);
+    memset(&wc->masks.skb_priority, 0xff, sizeof wc->masks.skb_priority);
+    wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
 
     if (tnl_port_should_receive(&ctx.xin->flow)) {
-        memset(&ctx.xout->wc.masks.tunnel, 0xff,
-               sizeof ctx.xout->wc.masks.tunnel);
+        memset(&wc->masks.tunnel, 0xff, sizeof wc->masks.tunnel);
     }
 
     /* Disable most wildcarding for NetFlow. */
     if (xin->ofproto->netflow) {
-        memset(&ctx.xout->wc.masks.dl_src, 0xff,
-               sizeof ctx.xout->wc.masks.dl_src);
-        memset(&ctx.xout->wc.masks.dl_dst, 0xff,
-               sizeof ctx.xout->wc.masks.dl_dst);
-        memset(&ctx.xout->wc.masks.dl_type, 0xff,
-               sizeof ctx.xout->wc.masks.dl_type);
-        memset(&ctx.xout->wc.masks.vlan_tci, 0xff,
-               sizeof ctx.xout->wc.masks.vlan_tci);
-        memset(&ctx.xout->wc.masks.nw_proto, 0xff,
-               sizeof ctx.xout->wc.masks.nw_proto);
-        memset(&ctx.xout->wc.masks.nw_src, 0xff,
-               sizeof ctx.xout->wc.masks.nw_src);
-        memset(&ctx.xout->wc.masks.nw_dst, 0xff,
-               sizeof ctx.xout->wc.masks.nw_dst);
-        memset(&ctx.xout->wc.masks.tp_src, 0xff,
-               sizeof ctx.xout->wc.masks.tp_src);
-        memset(&ctx.xout->wc.masks.tp_dst, 0xff,
-               sizeof ctx.xout->wc.masks.tp_dst);
+        netflow_mask_wc(wc);
     }
 
     ctx.xout->tags = 0;
@@ -7741,6 +7737,7 @@ is_admissible(struct xlate_ctx *ctx, struct ofport_dpif *in_port,
 static void
 xlate_normal(struct xlate_ctx *ctx)
 {
+    struct flow_wildcards *wc = &ctx->xout->wc;
     struct ofport_dpif *in_port;
     struct ofbundle *in_bundle;
     struct mac_entry *mac;
@@ -7750,15 +7747,10 @@ xlate_normal(struct xlate_ctx *ctx)
     ctx->xout->has_normal = true;
 
     /* Check the dl_type, since we may check for gratuituous ARP. */
-    memset(&ctx->xout->wc.masks.dl_type, 0xff,
-           sizeof ctx->xout->wc.masks.dl_type);
-
-    memset(&ctx->xout->wc.masks.dl_src, 0xff,
-           sizeof ctx->xout->wc.masks.dl_src);
-    memset(&ctx->xout->wc.masks.dl_dst, 0xff,
-           sizeof ctx->xout->wc.masks.dl_dst);
-    memset(&ctx->xout->wc.masks.vlan_tci, 0xff,
-           sizeof ctx->xout->wc.masks.vlan_tci);
+    memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
+    memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
+    memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+    wc->masks.vlan_tci |= htons(VLAN_VID_MASK | VLAN_CFI);
 
     in_bundle = lookup_input_bundle(ctx->ofproto, ctx->xin->flow.in_port,
                                     ctx->xin->packet != NULL, &in_port);
@@ -7807,7 +7799,7 @@ xlate_normal(struct xlate_ctx *ctx)
 
     /* Learn source MAC. */
     if (ctx->xin->may_learn) {
-        update_learning_table(ctx->ofproto, &ctx->xin->flow, &ctx->xout->wc,
+        update_learning_table(ctx->ofproto, &ctx->xin->flow, wc,
                               vlan, in_bundle);
     }
 
index 1f5d0fd..2510606 100644 (file)
@@ -1974,7 +1974,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1, n_subfacets:2, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,nw_frag=no, n_subfacets:2, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -1991,8 +1991,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1,dl_src=50:54:00:00:00:09, n_subfacets:1, used:0.0s, Datapath actions: <del>
-in_port=1,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,dl_src=50:54:00:00:00:09,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,dl_src=50:54:00:00:00:0b,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2009,8 +2009,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-icmp,in_port=1,nw_src=10.0.0.2, n_subfacets:1, used:0.0s, Datapath actions: <del>
-icmp,in_port=1,nw_src=10.0.0.4, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,nw_src=10.0.0.2,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,nw_src=10.0.0.4,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2027,7 +2027,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-icmp,in_port=1,icmp_type=8, n_subfacets:2, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,nw_frag=no,icmp_type=8, n_subfacets:2, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2041,8 +2041,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2060,8 +2060,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0a),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-mpls,in_port=1,dl_src=50:54:00:00:00:09,mpls_label=11,mpls_tc=3,mpls_ttl=64,mpls_bos=1, n_subfacets:1, used:0.0s, Datapath actions: <del>
-mpls,in_port=1,dl_src=50:54:00:00:00:0b,mpls_label=11,mpls_tc=3,mpls_ttl=64,mpls_bos=1, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,mpls,in_port=1,dl_src=50:54:00:00:00:09,mpls_label=11,mpls_tc=3,mpls_ttl=64,mpls_bos=1,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,mpls,in_port=1,dl_src=50:54:00:00:00:0b,mpls_label=11,mpls_tc=3,mpls_ttl=64,mpls_bos=1,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2086,8 +2086,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
-icmp,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,nw_frag=no,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,nw_tos=0,nw_frag=no,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2107,8 +2107,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2128,8 +2128,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2166,8 +2166,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p7 'in_port(1),eth(src=50:54:00:00:00:
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-icmp,in_port=7,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
-icmp,in_port=7,vlan_tci=0x0000,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=7,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_frag=no,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=7,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_dst=50:54:00:00:00:0c,nw_src=10.0.0.4,nw_dst=10.0.0.3,nw_frag=no,icmp_type=8,icmp_code=0, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2185,8 +2185,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,dl_src=50:54:00:00:00:09, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:09,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:0b,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2204,8 +2204,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto= 1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,dl_src=50:54:00:00:00:09, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:09,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:0b,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2223,8 +2223,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,dl_src=50:54:00:00:00:09, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:09,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,dl_src=50:54:00:00:00:0b,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2246,7 +2246,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1, n_subfacets:2, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,nw_frag=no, n_subfacets:2, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2268,8 +2268,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1,dl_vlan=11, n_subfacets:1, used:0.0s, Datapath actions: <del>
-in_port=1,vlan_tci=0x0000/0x1fff, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,dl_vlan=11,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,vlan_tci=0x0000/0x1fff,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2288,8 +2288,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,nw_src=10.0.0.2, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,nw_src=10.0.0.4, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,nw_src=10.0.0.2,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,nw_src=10.0.0.4,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2306,8 +2306,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-ip,in_port=1,nw_src=10.0.0.2, n_subfacets:1, used:0.0s, Datapath actions: <del>
-ip,in_port=1,nw_src=10.0.0.4, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,nw_src=10.0.0.2,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,ip,in_port=1,nw_src=10.0.0.4,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2325,8 +2325,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:
 ])
 dnl The original flow is missing due to a revalidation.
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:09, n_subfacets:1, used:0.0s, Datapath actions: <del>
-in_port=1,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:0b, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:09,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:0b,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -2357,9 +2357,27 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0x1,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
 ])
 AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
-in_port=1,nw_ecn=1, n_subfacets:2, used:0.0s, Datapath actions: <del>
-in_port=3,nw_tos=0,nw_ecn=1,nw_ttl=64, n_subfacets:1, used:0.0s, Datapath actions: <del>
-in_port=3,nw_tos=252,nw_ecn=1,nw_ttl=128, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=1,nw_ecn=1,nw_frag=no, n_subfacets:2, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=3,nw_tos=0,nw_ecn=1,nw_ttl=64,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,in_port=3,nw_tos=252,nw_ecn=1,nw_ttl=128,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif megaflow - dec_ttl])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [2])
+AT_DATA([flows.txt], [dnl
+table=0 in_port=1,icmp,nw_src=10.0.0.4 actions=dec_ttl,output(2)
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'], [0], [success
+])
+AT_CHECK([ovs-appctl dpif/dump-megaflows br0 | STRIP_XOUT], [0], [dnl
+skb_priority=0,icmp,in_port=1,nw_src=10.0.0.2,nw_frag=no, n_subfacets:1, used:0.0s, Datapath actions: <del>
+skb_priority=0,icmp,in_port=1,nw_src=10.0.0.4,nw_dst=10.0.0.3,nw_tos=0,nw_ecn=0,nw_ttl=64, n_subfacets:1, used:0.0s, Datapath actions: <del>
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP