diff mbox

[ovs-dev] ofproto-dpif-xlate: Fix IGMP megaflow matching.

Message ID 1462728850-16787-1-git-send-email-blp@ovn.org
State Accepted
Headers show

Commit Message

Ben Pfaff May 8, 2016, 5:34 p.m. UTC
IGMP translations wasn't setting enough bits in the wildcards to ensure
different packets were handled differently.

Reported-by: "O'Reilly, Darragh" <darragh.oreilly@hpe.com>
Reported-at: http://openvswitch.org/pipermail/discuss/2016-April/021036.html
Signed-off-by: Ben Pfaff <blp@ovn.org>
---
 AUTHORS                      |  1 +
 lib/flow.h                   | 69 ++++++++++++++++++++++++++++++++------------
 lib/meta-flow.c              | 10 +++----
 lib/nx-match.c               |  4 +--
 lib/odp-util.c               |  4 +--
 ofproto/ofproto-dpif-xlate.c | 28 +++++++++++++-----
 6 files changed, 80 insertions(+), 36 deletions(-)

Comments

Ben Pfaff May 19, 2016, 12:56 a.m. UTC | #1
Jarno, I think that you'd be a good person to review this.  Would you
mind taking a look?

Thanks,

Ben.

On Sun, May 08, 2016 at 10:34:10AM -0700, Ben Pfaff wrote:
> IGMP translations wasn't setting enough bits in the wildcards to ensure
> different packets were handled differently.
> 
> Reported-by: "O'Reilly, Darragh" <darragh.oreilly@hpe.com>
> Reported-at: http://openvswitch.org/pipermail/discuss/2016-April/021036.html
> Signed-off-by: Ben Pfaff <blp@ovn.org>
> ---
>  AUTHORS                      |  1 +
>  lib/flow.h                   | 69 ++++++++++++++++++++++++++++++++------------
>  lib/meta-flow.c              | 10 +++----
>  lib/nx-match.c               |  4 +--
>  lib/odp-util.c               |  4 +--
>  ofproto/ofproto-dpif-xlate.c | 28 +++++++++++++-----
>  6 files changed, 80 insertions(+), 36 deletions(-)
> 
> diff --git a/AUTHORS b/AUTHORS
> index cc82388..22f527c 100644
> --- a/AUTHORS
> +++ b/AUTHORS
> @@ -292,6 +292,7 @@ Christian Stigen Larsen cslarsen@gmail.com
>  Christopher Paggen      cpaggen@cisco.com
>  Chunhe Li               lichunhe@huawei.com
>  Daniel Badea            daniel.badea@windriver.com
> +Darragh O'Reilly        darragh.oreilly@hpe.com
>  Dave Walker             DaveWalker@ubuntu.com
>  David Evans             davidjoshuaevans@gmail.com
>  David Palma             palma@onesource.pt
> diff --git a/lib/flow.h b/lib/flow.h
> index 0196ee7..22b245c 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -832,41 +832,72 @@ static inline bool is_ip_any(const struct flow *flow)
>      return dl_type_is_ip_any(flow->dl_type);
>  }
>  
> -static inline bool is_icmpv4(const struct flow *flow)
> +static inline bool is_icmpv4(const struct flow *flow,
> +                             struct flow_wildcards *wc)
>  {
> -    return (flow->dl_type == htons(ETH_TYPE_IP)
> -            && flow->nw_proto == IPPROTO_ICMP);
> +    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +        if (wc) {
> +            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> +        }
> +        return flow->nw_proto == IPPROTO_ICMP;
> +    }
> +    return false;
>  }
>  
> -static inline bool is_icmpv6(const struct flow *flow)
> +static inline bool is_icmpv6(const struct flow *flow,
> +                             struct flow_wildcards *wc)
>  {
> -    return (flow->dl_type == htons(ETH_TYPE_IPV6)
> -            && flow->nw_proto == IPPROTO_ICMPV6);
> +    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
> +        if (wc) {
> +            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> +        }
> +        return flow->nw_proto == IPPROTO_ICMPV6;
> +    }
> +    return false;
>  }
>  
> -static inline bool is_igmp(const struct flow *flow)
> +static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc)
>  {
> -    return (flow->dl_type == htons(ETH_TYPE_IP)
> -            && flow->nw_proto == IPPROTO_IGMP);
> +    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +        if (wc) {
> +            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
> +        }
> +        return flow->nw_proto == IPPROTO_IGMP;
> +    }
> +    return false;
>  }
>  
> -static inline bool is_mld(const struct flow *flow)
> +static inline bool is_mld(const struct flow *flow,
> +                          struct flow_wildcards *wc)
>  {
> -    return is_icmpv6(flow)
> -           && (flow->tp_src == htons(MLD_QUERY)
> -               || flow->tp_src == htons(MLD_REPORT)
> -               || flow->tp_src == htons(MLD_DONE)
> -               || flow->tp_src == htons(MLD2_REPORT));
> +    if (is_icmpv6(flow, wc)) {
> +        if (wc) {
> +            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
> +        }
> +        return (flow->tp_src == htons(MLD_QUERY)
> +                || flow->tp_src == htons(MLD_REPORT)
> +                || flow->tp_src == htons(MLD_DONE)
> +                || flow->tp_src == htons(MLD2_REPORT));
> +    }
> +    return false;
>  }
>  
> -static inline bool is_mld_query(const struct flow *flow)
> +static inline bool is_mld_query(const struct flow *flow,
> +                                struct flow_wildcards *wc)
>  {
> -    return is_icmpv6(flow) && flow->tp_src == htons(MLD_QUERY);
> +    if (is_icmpv6(flow, wc)) {
> +        if (wc) {
> +            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
> +        }
> +        return flow->tp_src == htons(MLD_QUERY);
> +    }
> +    return false;
>  }
>  
> -static inline bool is_mld_report(const struct flow *flow)
> +static inline bool is_mld_report(const struct flow *flow,
> +                                 struct flow_wildcards *wc)
>  {
> -    return is_mld(flow) && !is_mld_query(flow);
> +    return is_mld(flow, wc) && !is_mld_query(flow, wc);
>  }
>  
>  static inline bool is_stp(const struct flow *flow)
> diff --git a/lib/meta-flow.c b/lib/meta-flow.c
> index ce60f22..a23c01f 100644
> --- a/lib/meta-flow.c
> +++ b/lib/meta-flow.c
> @@ -393,21 +393,21 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
>          return is_ip_any(flow) && flow->nw_proto == IPPROTO_SCTP
>              && !(flow->nw_frag & FLOW_NW_FRAG_LATER);
>      case MFP_ICMPV4:
> -        return is_icmpv4(flow);
> +        return is_icmpv4(flow, NULL);
>      case MFP_ICMPV6:
> -        return is_icmpv6(flow);
> +        return is_icmpv6(flow, NULL);
>  
>      case MFP_ND:
> -        return (is_icmpv6(flow)
> +        return (is_icmpv6(flow, NULL)
>                  && flow->tp_dst == htons(0)
>                  && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
>                      flow->tp_src == htons(ND_NEIGHBOR_ADVERT)));
>      case MFP_ND_SOLICIT:
> -        return (is_icmpv6(flow)
> +        return (is_icmpv6(flow, NULL)
>                  && flow->tp_dst == htons(0)
>                  && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)));
>      case MFP_ND_ADVERT:
> -        return (is_icmpv6(flow)
> +        return (is_icmpv6(flow, NULL)
>                  && flow->tp_dst == htons(0)
>                  && (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)));
>      }
> diff --git a/lib/nx-match.c b/lib/nx-match.c
> index 3c48570..aad6e02 100644
> --- a/lib/nx-match.c
> +++ b/lib/nx-match.c
> @@ -861,7 +861,7 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
>                          match->wc.masks.tp_src);
>              nxm_put_16m(b, MFF_SCTP_DST, oxm, flow->tp_dst,
>                          match->wc.masks.tp_dst);
> -        } else if (is_icmpv4(flow)) {
> +        } else if (is_icmpv4(flow, NULL)) {
>              if (match->wc.masks.tp_src) {
>                  nxm_put_8(b, MFF_ICMPV4_TYPE, oxm,
>                            ntohs(flow->tp_src));
> @@ -870,7 +870,7 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
>                  nxm_put_8(b, MFF_ICMPV4_CODE, oxm,
>                            ntohs(flow->tp_dst));
>              }
> -        } else if (is_icmpv6(flow)) {
> +        } else if (is_icmpv6(flow, NULL)) {
>              if (match->wc.masks.tp_src) {
>                  nxm_put_8(b, MFF_ICMPV6_TYPE, oxm,
>                            ntohs(flow->tp_src));
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index e0a1ad4..9144e56 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -5719,9 +5719,9 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow,
>      struct ovs_key_icmp key, mask, base;
>      enum ovs_key_attr attr;
>  
> -    if (is_icmpv4(flow)) {
> +    if (is_icmpv4(flow, NULL)) {
>          attr = OVS_KEY_ATTR_ICMP;
> -    } else if (is_icmpv6(flow)) {
> +    } else if (is_icmpv6(flow, NULL)) {
>          attr = OVS_KEY_ATTR_ICMPV6;
>      } else {
>          return 0;
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index cdf5a83..08eabf5 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -2359,6 +2359,20 @@ xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
>      ctx->nf_output_iface = NF_OUT_FLOOD;
>  }
>  
> +static bool
> +is_ip_local_multicast(const struct flow *flow, struct flow_wildcards *wc)
> +{
> +    if (flow->dl_type == htons(ETH_TYPE_IP)) {
> +        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
> +        return ip_is_local_multicast(flow->nw_dst);
> +    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
> +        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
> +        return ipv6_is_all_hosts(&flow->ipv6_dst);
> +    } else {
> +        return false;
> +    }
> +}
> +
>  static void
>  xlate_normal(struct xlate_ctx *ctx)
>  {
> @@ -2442,7 +2456,8 @@ xlate_normal(struct xlate_ctx *ctx)
>          struct mcast_snooping *ms = ctx->xbridge->ms;
>          struct mcast_group *grp = NULL;
>  
> -        if (is_igmp(flow)) {
> +        if (is_igmp(flow, wc)) {
> +            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
>              if (mcast_snooping_is_membership(flow->tp_src) ||
>                  mcast_snooping_is_query(flow->tp_src)) {
>                  if (ctx->xin->may_learn && ctx->xin->packet) {
> @@ -2475,13 +2490,13 @@ xlate_normal(struct xlate_ctx *ctx)
>                  xlate_normal_flood(ctx, in_xbundle, vlan);
>              }
>              return;
> -        } else if (is_mld(flow)) {
> +        } else if (is_mld(flow, wc)) {
>              ctx->xout->slow |= SLOW_ACTION;
>              if (ctx->xin->may_learn && ctx->xin->packet) {
>                  update_mcast_snooping_table(ctx->xbridge, flow, vlan,
>                                              in_xbundle, ctx->xin->packet);
>              }
> -            if (is_mld_report(flow)) {
> +            if (is_mld_report(flow, wc)) {
>                  ovs_rwlock_rdlock(&ms->rwlock);
>                  xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
>                  xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
> @@ -2491,10 +2506,7 @@ xlate_normal(struct xlate_ctx *ctx)
>                  xlate_normal_flood(ctx, in_xbundle, vlan);
>              }
>          } else {
> -            if ((flow->dl_type == htons(ETH_TYPE_IP)
> -                 && ip_is_local_multicast(flow->nw_dst))
> -                || (flow->dl_type == htons(ETH_TYPE_IPV6)
> -                    && ipv6_is_all_hosts(&flow->ipv6_dst))) {
> +            if (is_ip_local_multicast(flow, wc)) {
>                  /* RFC4541: section 2.1.2, item 2: Packets with a dst IP
>                   * address in the 224.0.0.x range which are not IGMP must
>                   * be forwarded on all ports */
> @@ -5030,7 +5042,7 @@ xlate_wc_finish(struct xlate_ctx *ctx)
>       * Avoid the problem here by making sure that only the low 8 bits of
>       * either field can be unwildcarded for ICMP.
>       */
> -    if (is_icmpv4(&ctx->xin->flow) || is_icmpv6(&ctx->xin->flow)) {
> +    if (is_icmpv4(&ctx->xin->flow, NULL) || is_icmpv6(&ctx->xin->flow, NULL)) {
>          ctx->wc->masks.tp_src &= htons(UINT8_MAX);
>          ctx->wc->masks.tp_dst &= htons(UINT8_MAX);
>      }
> -- 
> 2.1.3
>
diff mbox

Patch

diff --git a/AUTHORS b/AUTHORS
index cc82388..22f527c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -292,6 +292,7 @@  Christian Stigen Larsen cslarsen@gmail.com
 Christopher Paggen      cpaggen@cisco.com
 Chunhe Li               lichunhe@huawei.com
 Daniel Badea            daniel.badea@windriver.com
+Darragh O'Reilly        darragh.oreilly@hpe.com
 Dave Walker             DaveWalker@ubuntu.com
 David Evans             davidjoshuaevans@gmail.com
 David Palma             palma@onesource.pt
diff --git a/lib/flow.h b/lib/flow.h
index 0196ee7..22b245c 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -832,41 +832,72 @@  static inline bool is_ip_any(const struct flow *flow)
     return dl_type_is_ip_any(flow->dl_type);
 }
 
-static inline bool is_icmpv4(const struct flow *flow)
+static inline bool is_icmpv4(const struct flow *flow,
+                             struct flow_wildcards *wc)
 {
-    return (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IPPROTO_ICMP);
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+        if (wc) {
+            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+        }
+        return flow->nw_proto == IPPROTO_ICMP;
+    }
+    return false;
 }
 
-static inline bool is_icmpv6(const struct flow *flow)
+static inline bool is_icmpv6(const struct flow *flow,
+                             struct flow_wildcards *wc)
 {
-    return (flow->dl_type == htons(ETH_TYPE_IPV6)
-            && flow->nw_proto == IPPROTO_ICMPV6);
+    if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        if (wc) {
+            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+        }
+        return flow->nw_proto == IPPROTO_ICMPV6;
+    }
+    return false;
 }
 
-static inline bool is_igmp(const struct flow *flow)
+static inline bool is_igmp(const struct flow *flow, struct flow_wildcards *wc)
 {
-    return (flow->dl_type == htons(ETH_TYPE_IP)
-            && flow->nw_proto == IPPROTO_IGMP);
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+        if (wc) {
+            memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
+        }
+        return flow->nw_proto == IPPROTO_IGMP;
+    }
+    return false;
 }
 
-static inline bool is_mld(const struct flow *flow)
+static inline bool is_mld(const struct flow *flow,
+                          struct flow_wildcards *wc)
 {
-    return is_icmpv6(flow)
-           && (flow->tp_src == htons(MLD_QUERY)
-               || flow->tp_src == htons(MLD_REPORT)
-               || flow->tp_src == htons(MLD_DONE)
-               || flow->tp_src == htons(MLD2_REPORT));
+    if (is_icmpv6(flow, wc)) {
+        if (wc) {
+            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+        }
+        return (flow->tp_src == htons(MLD_QUERY)
+                || flow->tp_src == htons(MLD_REPORT)
+                || flow->tp_src == htons(MLD_DONE)
+                || flow->tp_src == htons(MLD2_REPORT));
+    }
+    return false;
 }
 
-static inline bool is_mld_query(const struct flow *flow)
+static inline bool is_mld_query(const struct flow *flow,
+                                struct flow_wildcards *wc)
 {
-    return is_icmpv6(flow) && flow->tp_src == htons(MLD_QUERY);
+    if (is_icmpv6(flow, wc)) {
+        if (wc) {
+            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
+        }
+        return flow->tp_src == htons(MLD_QUERY);
+    }
+    return false;
 }
 
-static inline bool is_mld_report(const struct flow *flow)
+static inline bool is_mld_report(const struct flow *flow,
+                                 struct flow_wildcards *wc)
 {
-    return is_mld(flow) && !is_mld_query(flow);
+    return is_mld(flow, wc) && !is_mld_query(flow, wc);
 }
 
 static inline bool is_stp(const struct flow *flow)
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index ce60f22..a23c01f 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -393,21 +393,21 @@  mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
         return is_ip_any(flow) && flow->nw_proto == IPPROTO_SCTP
             && !(flow->nw_frag & FLOW_NW_FRAG_LATER);
     case MFP_ICMPV4:
-        return is_icmpv4(flow);
+        return is_icmpv4(flow, NULL);
     case MFP_ICMPV6:
-        return is_icmpv6(flow);
+        return is_icmpv6(flow, NULL);
 
     case MFP_ND:
-        return (is_icmpv6(flow)
+        return (is_icmpv6(flow, NULL)
                 && flow->tp_dst == htons(0)
                 && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
                     flow->tp_src == htons(ND_NEIGHBOR_ADVERT)));
     case MFP_ND_SOLICIT:
-        return (is_icmpv6(flow)
+        return (is_icmpv6(flow, NULL)
                 && flow->tp_dst == htons(0)
                 && (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)));
     case MFP_ND_ADVERT:
-        return (is_icmpv6(flow)
+        return (is_icmpv6(flow, NULL)
                 && flow->tp_dst == htons(0)
                 && (flow->tp_src == htons(ND_NEIGHBOR_ADVERT)));
     }
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 3c48570..aad6e02 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -861,7 +861,7 @@  nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
                         match->wc.masks.tp_src);
             nxm_put_16m(b, MFF_SCTP_DST, oxm, flow->tp_dst,
                         match->wc.masks.tp_dst);
-        } else if (is_icmpv4(flow)) {
+        } else if (is_icmpv4(flow, NULL)) {
             if (match->wc.masks.tp_src) {
                 nxm_put_8(b, MFF_ICMPV4_TYPE, oxm,
                           ntohs(flow->tp_src));
@@ -870,7 +870,7 @@  nxm_put_ip(struct ofpbuf *b, const struct match *match, enum ofp_version oxm)
                 nxm_put_8(b, MFF_ICMPV4_CODE, oxm,
                           ntohs(flow->tp_dst));
             }
-        } else if (is_icmpv6(flow)) {
+        } else if (is_icmpv6(flow, NULL)) {
             if (match->wc.masks.tp_src) {
                 nxm_put_8(b, MFF_ICMPV6_TYPE, oxm,
                           ntohs(flow->tp_src));
diff --git a/lib/odp-util.c b/lib/odp-util.c
index e0a1ad4..9144e56 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -5719,9 +5719,9 @@  commit_set_icmp_action(const struct flow *flow, struct flow *base_flow,
     struct ovs_key_icmp key, mask, base;
     enum ovs_key_attr attr;
 
-    if (is_icmpv4(flow)) {
+    if (is_icmpv4(flow, NULL)) {
         attr = OVS_KEY_ATTR_ICMP;
-    } else if (is_icmpv6(flow)) {
+    } else if (is_icmpv6(flow, NULL)) {
         attr = OVS_KEY_ATTR_ICMPV6;
     } else {
         return 0;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index cdf5a83..08eabf5 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2359,6 +2359,20 @@  xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
     ctx->nf_output_iface = NF_OUT_FLOOD;
 }
 
+static bool
+is_ip_local_multicast(const struct flow *flow, struct flow_wildcards *wc)
+{
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+        memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
+        return ip_is_local_multicast(flow->nw_dst);
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        memset(&wc->masks.ipv6_dst, 0xff, sizeof wc->masks.ipv6_dst);
+        return ipv6_is_all_hosts(&flow->ipv6_dst);
+    } else {
+        return false;
+    }
+}
+
 static void
 xlate_normal(struct xlate_ctx *ctx)
 {
@@ -2442,7 +2456,8 @@  xlate_normal(struct xlate_ctx *ctx)
         struct mcast_snooping *ms = ctx->xbridge->ms;
         struct mcast_group *grp = NULL;
 
-        if (is_igmp(flow)) {
+        if (is_igmp(flow, wc)) {
+            memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
             if (mcast_snooping_is_membership(flow->tp_src) ||
                 mcast_snooping_is_query(flow->tp_src)) {
                 if (ctx->xin->may_learn && ctx->xin->packet) {
@@ -2475,13 +2490,13 @@  xlate_normal(struct xlate_ctx *ctx)
                 xlate_normal_flood(ctx, in_xbundle, vlan);
             }
             return;
-        } else if (is_mld(flow)) {
+        } else if (is_mld(flow, wc)) {
             ctx->xout->slow |= SLOW_ACTION;
             if (ctx->xin->may_learn && ctx->xin->packet) {
                 update_mcast_snooping_table(ctx->xbridge, flow, vlan,
                                             in_xbundle, ctx->xin->packet);
             }
-            if (is_mld_report(flow)) {
+            if (is_mld_report(flow, wc)) {
                 ovs_rwlock_rdlock(&ms->rwlock);
                 xlate_normal_mcast_send_mrouters(ctx, ms, in_xbundle, vlan);
                 xlate_normal_mcast_send_rports(ctx, ms, in_xbundle, vlan);
@@ -2491,10 +2506,7 @@  xlate_normal(struct xlate_ctx *ctx)
                 xlate_normal_flood(ctx, in_xbundle, vlan);
             }
         } else {
-            if ((flow->dl_type == htons(ETH_TYPE_IP)
-                 && ip_is_local_multicast(flow->nw_dst))
-                || (flow->dl_type == htons(ETH_TYPE_IPV6)
-                    && ipv6_is_all_hosts(&flow->ipv6_dst))) {
+            if (is_ip_local_multicast(flow, wc)) {
                 /* RFC4541: section 2.1.2, item 2: Packets with a dst IP
                  * address in the 224.0.0.x range which are not IGMP must
                  * be forwarded on all ports */
@@ -5030,7 +5042,7 @@  xlate_wc_finish(struct xlate_ctx *ctx)
      * Avoid the problem here by making sure that only the low 8 bits of
      * either field can be unwildcarded for ICMP.
      */
-    if (is_icmpv4(&ctx->xin->flow) || is_icmpv6(&ctx->xin->flow)) {
+    if (is_icmpv4(&ctx->xin->flow, NULL) || is_icmpv6(&ctx->xin->flow, NULL)) {
         ctx->wc->masks.tp_src &= htons(UINT8_MAX);
         ctx->wc->masks.tp_dst &= htons(UINT8_MAX);
     }