Use IPv6 internally for storing multicast addresses. IPv4 addresses are translated to their IPv4-mapped equivalent.
v2: * Print mapped IPv4 addresses like IPv4 addresses. * Fix alignment and other issues pointed out by clang, sparse and Ben Pfaff. Signed-off-by: Thadeu Lima de Souza Cascardo <casca...@redhat.com> Cc: Flavio Leitner <f...@redhat.com> Cc: Ben Pfaff <b...@nicira.com> --- lib/mcast-snooping.c | 69 +++++++++++++++++++++++++++++++++++--------- lib/mcast-snooping.h | 24 +++++++++++---- lib/packets.c | 11 +++++++ lib/packets.h | 1 + ofproto/ofproto-dpif-xlate.c | 6 ++-- ofproto/ofproto-dpif.c | 5 ++-- 6 files changed, 91 insertions(+), 25 deletions(-) diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c index 7b927aa..39463fa 100644 --- a/lib/mcast-snooping.c +++ b/lib/mcast-snooping.c @@ -87,10 +87,11 @@ mcast_bundle_age(const struct mcast_snooping *ms, } static uint32_t -mcast_table_hash(const struct mcast_snooping *ms, ovs_be32 grp_ip4, - uint16_t vlan) +mcast_table_hash(const struct mcast_snooping *ms, + const struct in6_addr *grp_addr, uint16_t vlan) { - return hash_3words((OVS_FORCE uint32_t) grp_ip4, vlan, ms->secret); + return hash_bytes(grp_addr->s6_addr, 16, + hash_2words(ms->secret, vlan)); } static struct mcast_group_bundle * @@ -108,8 +109,8 @@ mcast_group_from_lru_node(struct ovs_list *list) /* Searches 'ms' for and returns an mcast group for destination address * 'dip' in 'vlan'. */ struct mcast_group * -mcast_snooping_lookup(const struct mcast_snooping *ms, ovs_be32 dip, - uint16_t vlan) +mcast_snooping_lookup(const struct mcast_snooping *ms, + const struct in6_addr *dip, uint16_t vlan) OVS_REQ_RDLOCK(ms->rwlock) { struct mcast_group *grp; @@ -117,13 +118,32 @@ mcast_snooping_lookup(const struct mcast_snooping *ms, ovs_be32 dip, hash = mcast_table_hash(ms, dip, vlan); HMAP_FOR_EACH_WITH_HASH (grp, hmap_node, hash, &ms->table) { - if (grp->vlan == vlan && grp->ip4 == dip) { + if (grp->vlan == vlan && ipv6_addr_equals(&grp->addr, dip)) { return grp; } } return NULL; } +static inline void +in6_addr_set_mapped_ipv4(struct in6_addr *addr, ovs_be32 ip4) +{ + union ovs_16aligned_in6_addr *taddr = (void *) addr; + memset(taddr->be16, 0, sizeof(taddr->be16)); + taddr->be16[5] = OVS_BE16_MAX; + put_16aligned_be32(&taddr->be32[3], ip4); +} + +struct mcast_group * +mcast_snooping_lookup4(const struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan) + OVS_REQ_RDLOCK(ms->rwlock) +{ + struct in6_addr addr; + in6_addr_set_mapped_ipv4(&addr, ip4); + return mcast_snooping_lookup(ms, &addr, vlan); +} + /* If the LRU list is not empty, stores the least-recently-used entry * in '*e' and returns true. Otherwise, if the LRU list is empty, * stores NULL in '*e' and return false. */ @@ -376,7 +396,8 @@ mcast_snooping_prune_expired(struct mcast_snooping *ms, * move to the last position in the LRU list. */ bool -mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4, +mcast_snooping_add_group(struct mcast_snooping *ms, + const struct in6_addr *addr, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock) { @@ -390,9 +411,9 @@ mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4, } learned = false; - grp = mcast_snooping_lookup(ms, ip4, vlan); + grp = mcast_snooping_lookup(ms, addr, vlan); if (!grp) { - uint32_t hash = mcast_table_hash(ms, ip4, vlan); + uint32_t hash = mcast_table_hash(ms, addr, vlan); if (hmap_count(&ms->table) >= ms->max_entries) { group_get_lru(ms, &grp); @@ -401,7 +422,7 @@ mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4, grp = xmalloc(sizeof *grp); hmap_insert(&ms->table, &grp->hmap_node, hash); - grp->ip4 = ip4; + grp->addr = *addr; grp->vlan = vlan; list_init(&grp->bundle_lru); learned = true; @@ -417,6 +438,16 @@ mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4, return learned; } +bool +mcast_snooping_add_group4(struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan, void *port) + OVS_REQ_WRLOCK(ms->rwlock) +{ + struct in6_addr addr; + in6_addr_set_mapped_ipv4(&addr, ip4); + return mcast_snooping_add_group(ms, &addr, vlan, port); +} + int mcast_snooping_add_report(struct mcast_snooping *ms, const struct dp_packet *p, @@ -455,9 +486,9 @@ mcast_snooping_add_report(struct mcast_snooping *ms, if (ntohs(record->nsrcs) == 0 && (record->type == IGMPV3_MODE_IS_INCLUDE || record->type == IGMPV3_CHANGE_TO_INCLUDE_MODE)) { - ret = mcast_snooping_leave_group(ms, ip4, vlan, port); + ret = mcast_snooping_leave_group4(ms, ip4, vlan, port); } else { - ret = mcast_snooping_add_group(ms, ip4, vlan, port); + ret = mcast_snooping_add_group4(ms, ip4, vlan, port); } if (ret) { count++; @@ -469,7 +500,8 @@ mcast_snooping_add_report(struct mcast_snooping *ms, } bool -mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4, +mcast_snooping_leave_group(struct mcast_snooping *ms, + const struct in6_addr *addr, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock) { @@ -482,7 +514,7 @@ mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4, return false; } - grp = mcast_snooping_lookup(ms, ip4, vlan); + grp = mcast_snooping_lookup(ms, addr, vlan); if (grp && mcast_group_delete_bundle(ms, grp, port)) { ms->need_revalidate = true; return true; @@ -490,6 +522,15 @@ mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4, return false; } +bool +mcast_snooping_leave_group4(struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan, void *port) +{ + struct in6_addr addr; + in6_addr_set_mapped_ipv4(&addr, ip4); + return mcast_snooping_leave_group(ms, &addr, vlan, port); +} + /* Router ports. */ diff --git a/lib/mcast-snooping.h b/lib/mcast-snooping.h index f4bc8fb..e3d15e4 100644 --- a/lib/mcast-snooping.h +++ b/lib/mcast-snooping.h @@ -45,8 +45,8 @@ struct mcast_group { /* Node in parent struct mcast_snooping hmap. */ struct hmap_node hmap_node; - /* Multicast group IPv4 address. */ - ovs_be32 ip4; + /* Multicast group IPv6/IPv4 address. */ + struct in6_addr addr; /* VLAN tag. */ uint16_t vlan; @@ -174,21 +174,33 @@ void mcast_snooping_set_port_flood_reports(struct mcast_snooping *ms, /* Lookup. */ struct mcast_group * -mcast_snooping_lookup(const struct mcast_snooping *ms, ovs_be32 dip, - uint16_t vlan) +mcast_snooping_lookup(const struct mcast_snooping *ms, + const struct in6_addr *dip, uint16_t vlan) + OVS_REQ_RDLOCK(ms->rwlock); +struct mcast_group * +mcast_snooping_lookup4(const struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan) OVS_REQ_RDLOCK(ms->rwlock); /* Learning. */ -bool mcast_snooping_add_group(struct mcast_snooping *ms, ovs_be32 ip4, +bool mcast_snooping_add_group(struct mcast_snooping *ms, + const struct in6_addr *addr, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock); +bool mcast_snooping_add_group4(struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan, void *port) + OVS_REQ_WRLOCK(ms->rwlock); int mcast_snooping_add_report(struct mcast_snooping *ms, const struct dp_packet *p, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock); -bool mcast_snooping_leave_group(struct mcast_snooping *ms, ovs_be32 ip4, +bool mcast_snooping_leave_group(struct mcast_snooping *ms, + const struct in6_addr *addr, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock); +bool mcast_snooping_leave_group4(struct mcast_snooping *ms, ovs_be32 ip4, + uint16_t vlan, void *port) + OVS_REQ_WRLOCK(ms->rwlock); bool mcast_snooping_add_mrouter(struct mcast_snooping *ms, uint16_t vlan, void *port) OVS_REQ_WRLOCK(ms->rwlock); diff --git a/lib/packets.c b/lib/packets.c index d04fffc..d0ad0b6 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -438,6 +438,17 @@ print_ipv6_addr(struct ds *string, const struct in6_addr *addr) } void +print_ipv6_mapped(struct ds *s, const struct in6_addr *addr) +{ + if (IN6_IS_ADDR_V4MAPPED(addr)) { + ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } else { + print_ipv6_addr(s, addr); + } +} + +void print_ipv6_masked(struct ds *s, const struct in6_addr *addr, const struct in6_addr *mask) { diff --git a/lib/packets.h b/lib/packets.h index c401d4e..275ed12 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -819,6 +819,7 @@ struct vxlanhdr { void format_ipv6_addr(char *addr_str, const struct in6_addr *addr); void print_ipv6_addr(struct ds *string, const struct in6_addr *addr); +void print_ipv6_mapped(struct ds *string, const struct in6_addr *addr); void print_ipv6_masked(struct ds *string, const struct in6_addr *addr, const struct in6_addr *mask); struct in6_addr ipv6_addr_bitand(const struct in6_addr *src, diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index ca6b357..aa48662 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2012,14 +2012,14 @@ update_mcast_snooping_table__(const struct xbridge *xbridge, switch (ntohs(flow->tp_src)) { case IGMP_HOST_MEMBERSHIP_REPORT: case IGMPV2_HOST_MEMBERSHIP_REPORT: - if (mcast_snooping_add_group(ms, ip4, vlan, in_xbundle->ofbundle)) { + if (mcast_snooping_add_group4(ms, ip4, vlan, in_xbundle->ofbundle)) { VLOG_DBG_RL(&rl, "bridge %s: multicast snooping learned that " IP_FMT" is on port %s in VLAN %d", xbridge->name, IP_ARGS(ip4), in_xbundle->name, vlan); } break; case IGMP_HOST_LEAVE_MESSAGE: - if (mcast_snooping_leave_group(ms, ip4, vlan, in_xbundle->ofbundle)) { + if (mcast_snooping_leave_group4(ms, ip4, vlan, in_xbundle->ofbundle)) { VLOG_DBG_RL(&rl, "bridge %s: multicast snooping leaving " IP_FMT" is on port %s in VLAN %d", xbridge->name, IP_ARGS(ip4), in_xbundle->name, vlan); @@ -2330,7 +2330,7 @@ xlate_normal(struct xlate_ctx *ctx) /* forwarding to group base ports */ ovs_rwlock_rdlock(&ms->rwlock); - grp = mcast_snooping_lookup(ms, flow->nw_dst, vlan); + grp = mcast_snooping_lookup4(ms, flow->nw_dst, vlan); if (grp) { xlate_normal_mcast_send_group(ctx, ms, grp, in_xbundle, vlan); xlate_normal_mcast_send_fports(ctx, ms, in_xbundle, vlan); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 13d2f21..1d19cdf 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4430,8 +4430,9 @@ ofproto_unixctl_mcast_snooping_show(struct unixctl_conn *conn, bundle = b->port; ofputil_port_to_string(ofbundle_get_a_port(bundle)->up.ofp_port, name, sizeof name); - ds_put_format(&ds, "%5s %4d "IP_FMT" %3d\n", - name, grp->vlan, IP_ARGS(grp->ip4), + ds_put_format(&ds, "%5s %4d ", name, grp->vlan); + print_ipv6_mapped(&ds, &grp->addr); + ds_put_format(&ds, " %3d\n", mcast_bundle_age(ofproto->ms, b)); } } -- 2.4.2 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev