summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThadeu Lima de Souza Cascardo <cascardo@redhat.com>2015-07-01 16:12:11 -0300
committerBen Pfaff <blp@nicira.com>2015-07-01 16:49:40 -0700
commit964a4d5fd542b7dd4a6fb97fdc8d2a3c6ed41fde (patch)
tree11b183163c75228680f218f00f82d48c8a4d610d
parentd30fa82cd4211d66bab248370d84da803f181e44 (diff)
downloadopenvswitch-964a4d5fd542b7dd4a6fb97fdc8d2a3c6ed41fde.tar.gz
mcast-snooping: Use IPv6 address for MDB
Use IPv6 internally for storing multicast addresses. IPv4 addresses are translated to their IPv4-mapped equivalent. Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@redhat.com> Cc: Flavio Leitner <fbl@redhat.com> Cc: Ben Pfaff <blp@nicira.com> [blp@nicira.com added a "sparse" implementation of IN6_IS_ADDR_V4MAPPED.] Signed-off-by: Ben Pfaff <blp@nicira.com>
-rw-r--r--include/sparse/netinet/in.h16
-rw-r--r--lib/mcast-snooping.c69
-rw-r--r--lib/mcast-snooping.h24
-rw-r--r--lib/packets.c11
-rw-r--r--lib/packets.h1
-rw-r--r--ofproto/ofproto-dpif-xlate.c6
-rw-r--r--ofproto/ofproto-dpif.c5
7 files changed, 106 insertions, 26 deletions
diff --git a/include/sparse/netinet/in.h b/include/sparse/netinet/in.h
index 83ad2cc58..f3ce8b9ca 100644
--- a/include/sparse/netinet/in.h
+++ b/include/sparse/netinet/in.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2011, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -99,6 +99,20 @@ struct sockaddr_in6 {
#define INADDR_LOOPBACK 0x7f000001
#define INADDR_NONE 0xffffffff
+#define IN6_IS_ADDR_V4MAPPED(X) \
+ ((X)->s6_addr[0] == 0 && \
+ (X)->s6_addr[1] == 0 && \
+ (X)->s6_addr[2] == 0 && \
+ (X)->s6_addr[3] == 0 && \
+ (X)->s6_addr[4] == 0 && \
+ (X)->s6_addr[5] == 0 && \
+ (X)->s6_addr[6] == 0 && \
+ (X)->s6_addr[7] == 0 && \
+ (X)->s6_addr[8] == 0 && \
+ (X)->s6_addr[9] == 0 && \
+ (X)->s6_addr[10] == 0xff && \
+ (X)->s6_addr[11] == 0xff)
+
#define INET6_ADDRSTRLEN 46
#define IPV6_TCLASS 67
diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c
index 7b927aa27..39463fa1c 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 f4bc8fb03..e3d15e41c 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 d04fffcb4..d0ad0b614 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 311589cbd..62aa34ea5 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -828,6 +828,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 ca6b35717..aa486624f 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 13d2f21e1..1d19cdf84 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));
}
}