/*
- * 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.
#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
}
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 *
/* 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;
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. */
* 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)
{
}
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);
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;
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,
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++;
}
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)
{
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;
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);
+}
+
\f
/* Router ports. */
/* 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;
/* 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);
string->length += strlen(dst);
}
+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)
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,
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);
/* 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);
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));
}
}