struct xlate_ctx ctx;
size_t ofpacts_len;
bool tnl_may_send;
+ bool is_icmp;
COVERAGE_INC(xlate_actions);
if (is_ip_any(flow)) {
wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
}
+ is_icmp = is_icmpv4(flow) || is_icmpv6(flow);
tnl_may_send = tnl_xlate_init(&ctx.base_flow, flow, wc);
if (ctx.xbridge->netflow) {
* use non-header fields as part of the cache. */
flow_wildcards_clear_non_packet_fields(wc);
+ /* ICMPv4 and ICMPv6 have 8-bit "type" and "code" fields. struct flow uses
+ * the low 8 bits of the 16-bit tp_src and tp_dst members to represent
+ * these fields. The datapath interface, on the other hand, represents
+ * them with just 8 bits each. This means that if the high 8 bits of the
+ * masks for these fields somehow become set, then they will get chopped
+ * off by a round trip through the datapath, and revalidation will spot
+ * that as an inconsistency and delete the flow. Avoid the problem here by
+ * making sure that only the low 8 bits of either field can be unwildcarded
+ * for ICMP.
+ */
+ if (is_icmp) {
+ wc->masks.tp_src &= htons(UINT8_MAX);
+ wc->masks.tp_dst &= htons(UINT8_MAX);
+ }
+
out:
rule_actions_unref(actions);
rule_dpif_unref(rule);