Avoid learning Link-Local reserved multicast addresses if advertised in a MLD reports since this interferes with Slaac IPv6 address resolution implemented in OVN.
Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2154930 Tested-by: Eduardo Olivares <eoliv...@redhat.com> Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com> --- lib/mcast-snooping.c | 69 ++++++++++++++++++++++++++++++++------------ lib/packets.c | 11 +++++++ lib/packets.h | 13 +++++++++ 3 files changed, 74 insertions(+), 19 deletions(-) diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c index 029ca2855..a9d2e7900 100644 --- a/lib/mcast-snooping.c +++ b/lib/mcast-snooping.c @@ -38,6 +38,8 @@ COVERAGE_DEFINE(mcast_snooping_learned); COVERAGE_DEFINE(mcast_snooping_expired); +VLOG_DEFINE_THIS_MODULE(mcast_snooping); + static struct mcast_port_bundle * mcast_snooping_port_lookup(struct ovs_list *list, void *port); static struct mcast_mrouter_bundle * @@ -489,6 +491,28 @@ mcast_snooping_add_report(struct mcast_snooping *ms, return count; } +static bool +mcast_snooping_should_learn_mld_group(struct in6_addr *addr) +{ + /* we should learn multicast group from the following IPv6 multicast + * groups: + * - All Nodes Address (ff02::1) + * - All Router Address (ff02::2) + * - All Site Router Address (ff05::2) + * - Solicited-Node Address (ff02::1:ff00:0000/104) + */ + if (in6_addr_is_solicited_node(addr) || ipv6_is_all_hosts(addr) || + ipv6_is_all_router(addr) || ipv6_is_all_site_router(addr)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + char ip_str[INET6_ADDRSTRLEN + 1]; + + ipv6_string_mapped(ip_str, addr); + VLOG_DBG_RL(&rl, "Invalid Multicast group %s", ip_str); + return false; + } + return true; +} + int mcast_snooping_add_mld(struct mcast_snooping *ms, const struct dp_packet *p, @@ -531,26 +555,33 @@ mcast_snooping_add_mld(struct mcast_snooping *ms, break; } /* Only consider known record types. */ - if (record->type >= IGMPV3_MODE_IS_INCLUDE - && record->type <= IGMPV3_BLOCK_OLD_SOURCES) { - struct in6_addr maddr; - memcpy(maddr.s6_addr, record->maddr.be16, 16); - addr = &maddr; - /* - * If record is INCLUDE MODE and there are no sources, it's - * equivalent to a LEAVE. - */ - if (record->nsrcs == htons(0) - && (record->type == IGMPV3_MODE_IS_INCLUDE - || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) { - ret = mcast_snooping_leave_group(ms, addr, vlan, port); - } else { - ret = mcast_snooping_add_group(ms, addr, vlan, port); - } - if (ret) { - count++; - } + if (record->type < IGMPV3_MODE_IS_INCLUDE || + record->type > IGMPV3_BLOCK_OLD_SOURCES) { + goto next; + } + + struct in6_addr maddr; + memcpy(maddr.s6_addr, record->maddr.be16, 16); + if (!mcast_snooping_should_learn_mld_group(&maddr)) { + goto next; + } + + /* + * If record is INCLUDE MODE and there are no sources, it's + * equivalent to a LEAVE. + */ + addr = &maddr; + if (record->nsrcs == htons(0) + && (record->type == IGMPV3_MODE_IS_INCLUDE + || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) { + ret = mcast_snooping_leave_group(ms, addr, vlan, port); + } else { + ret = mcast_snooping_add_group(ms, addr, vlan, port); + } + if (ret) { + count++; } +next: offset += sizeof(*record) + ntohs(record->nsrcs) * sizeof(struct in6_addr) + record->aux_len; diff --git a/lib/packets.c b/lib/packets.c index 06f516cb1..b43f78bc1 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -38,6 +38,7 @@ const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; const struct in6_addr in6addr_all_hosts = IN6ADDR_ALL_HOSTS_INIT; const struct in6_addr in6addr_all_routers = IN6ADDR_ALL_ROUTERS_INIT; +const struct in6_addr in6addr_all_site_routers = IN6ADDR_ALL_SITE_ROUTERS_INIT; struct in6_addr flow_tnl_dst(const struct flow_tnl *tnl) @@ -605,6 +606,16 @@ in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6) memcpy(&addr->s6_addr[13], &ip6->s6_addr[13], 3); } +bool +in6_addr_is_solicited_node(struct in6_addr *addr) +{ + union ovs_16aligned_in6_addr *taddr = + (union ovs_16aligned_in6_addr *) addr; + return taddr->be16[0] == htons(0xff02) && + taddr->be16[5] == htons(0x1) && + taddr->be16[6] == htons(0xff00); +} + /* * Generates ipv6 EUI64 address from the given eth addr * and prefix and stores it in 'lla' diff --git a/lib/packets.h b/lib/packets.h index 8626aac8d..e88753456 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1146,6 +1146,10 @@ extern const struct in6_addr in6addr_all_routers; #define IN6ADDR_ALL_ROUTERS_INIT { { { 0xff,0x02,0x00,0x00,0x00,0x00,0x00,0x00, \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } +extern const struct in6_addr in6addr_all_site_routers; +#define IN6ADDR_ALL_SITE_ROUTERS_INIT { { { 0xff,0x05,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02 } } } + static inline bool ipv6_addr_equals(const struct in6_addr *a, const struct in6_addr *b) { @@ -1169,6 +1173,14 @@ static inline bool ipv6_is_all_hosts(const struct in6_addr *addr) { return ipv6_addr_equals(addr, &in6addr_all_hosts); } +static inline bool ipv6_is_all_router(const struct in6_addr *addr) { + return ipv6_addr_equals(addr, &in6addr_all_routers); +} + +static inline bool ipv6_is_all_site_router(const struct in6_addr *addr) { + return ipv6_addr_equals(addr, &in6addr_all_site_routers); +} + static inline bool ipv6_addr_is_set(const struct in6_addr *addr) { return !ipv6_addr_equals(addr, &in6addr_any); } @@ -1207,6 +1219,7 @@ in6_addr_get_mapped_ipv4(const struct in6_addr *addr) void in6_addr_solicited_node(struct in6_addr *addr, const struct in6_addr *ip6); +bool in6_addr_is_solicited_node(struct in6_addr *addr); void in6_generate_eui64(struct eth_addr ea, const struct in6_addr *prefix, struct in6_addr *lla); -- 2.39.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev