bridge: Add vlan id to multicast groups

Add vlan_id to multicasts groups so that we know which vlan
each group belongs to and can correctly forward to appropriate vlan.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Vlad Yasevich 2013-02-13 12:00:17 +00:00 committed by David S. Miller
parent 2ba071ecb6
commit b0e9a30dd6
2 changed files with 50 additions and 20 deletions

View File

@ -39,6 +39,8 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
{ {
if (a->proto != b->proto) if (a->proto != b->proto)
return 0; return 0;
if (a->vid != b->vid)
return 0;
switch (a->proto) { switch (a->proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
return a->u.ip4 == b->u.ip4; return a->u.ip4 == b->u.ip4;
@ -50,16 +52,19 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
return 0; return 0;
} }
static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip) static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip,
__u16 vid)
{ {
return jhash_1word(mdb->secret, (__force u32)ip) & (mdb->max - 1); return jhash_2words((__force u32)ip, vid, mdb->secret) & (mdb->max - 1);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb, static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
const struct in6_addr *ip) const struct in6_addr *ip,
__u16 vid)
{ {
return jhash2((__force u32 *)ip->s6_addr32, 4, mdb->secret) & (mdb->max - 1); return jhash_2words(ipv6_addr_hash(ip), vid,
mdb->secret) & (mdb->max - 1);
} }
#endif #endif
@ -68,10 +73,10 @@ static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
{ {
switch (ip->proto) { switch (ip->proto) {
case htons(ETH_P_IP): case htons(ETH_P_IP):
return __br_ip4_hash(mdb, ip->u.ip4); return __br_ip4_hash(mdb, ip->u.ip4, ip->vid);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): case htons(ETH_P_IPV6):
return __br_ip6_hash(mdb, &ip->u.ip6); return __br_ip6_hash(mdb, &ip->u.ip6, ip->vid);
#endif #endif
} }
return 0; return 0;
@ -101,24 +106,27 @@ struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge_mdb_htable *mdb,
} }
static struct net_bridge_mdb_entry *br_mdb_ip4_get( static struct net_bridge_mdb_entry *br_mdb_ip4_get(
struct net_bridge_mdb_htable *mdb, __be32 dst) struct net_bridge_mdb_htable *mdb, __be32 dst, __u16 vid)
{ {
struct br_ip br_dst; struct br_ip br_dst;
br_dst.u.ip4 = dst; br_dst.u.ip4 = dst;
br_dst.proto = htons(ETH_P_IP); br_dst.proto = htons(ETH_P_IP);
br_dst.vid = vid;
return br_mdb_ip_get(mdb, &br_dst); return br_mdb_ip_get(mdb, &br_dst);
} }
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static struct net_bridge_mdb_entry *br_mdb_ip6_get( static struct net_bridge_mdb_entry *br_mdb_ip6_get(
struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst) struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst,
__u16 vid)
{ {
struct br_ip br_dst; struct br_ip br_dst;
br_dst.u.ip6 = *dst; br_dst.u.ip6 = *dst;
br_dst.proto = htons(ETH_P_IPV6); br_dst.proto = htons(ETH_P_IPV6);
br_dst.vid = vid;
return br_mdb_ip_get(mdb, &br_dst); return br_mdb_ip_get(mdb, &br_dst);
} }
@ -694,7 +702,8 @@ static int br_multicast_add_group(struct net_bridge *br,
static int br_ip4_multicast_add_group(struct net_bridge *br, static int br_ip4_multicast_add_group(struct net_bridge *br,
struct net_bridge_port *port, struct net_bridge_port *port,
__be32 group) __be32 group,
__u16 vid)
{ {
struct br_ip br_group; struct br_ip br_group;
@ -703,6 +712,7 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
br_group.u.ip4 = group; br_group.u.ip4 = group;
br_group.proto = htons(ETH_P_IP); br_group.proto = htons(ETH_P_IP);
br_group.vid = vid;
return br_multicast_add_group(br, port, &br_group); return br_multicast_add_group(br, port, &br_group);
} }
@ -710,7 +720,8 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static int br_ip6_multicast_add_group(struct net_bridge *br, static int br_ip6_multicast_add_group(struct net_bridge *br,
struct net_bridge_port *port, struct net_bridge_port *port,
const struct in6_addr *group) const struct in6_addr *group,
__u16 vid)
{ {
struct br_ip br_group; struct br_ip br_group;
@ -719,6 +730,7 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
br_group.u.ip6 = *group; br_group.u.ip6 = *group;
br_group.proto = htons(ETH_P_IPV6); br_group.proto = htons(ETH_P_IPV6);
br_group.vid = vid;
return br_multicast_add_group(br, port, &br_group); return br_multicast_add_group(br, port, &br_group);
} }
@ -895,10 +907,12 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
int type; int type;
int err = 0; int err = 0;
__be32 group; __be32 group;
u16 vid = 0;
if (!pskb_may_pull(skb, sizeof(*ih))) if (!pskb_may_pull(skb, sizeof(*ih)))
return -EINVAL; return -EINVAL;
br_vlan_get_tag(skb, &vid);
ih = igmpv3_report_hdr(skb); ih = igmpv3_report_hdr(skb);
num = ntohs(ih->ngrec); num = ntohs(ih->ngrec);
len = sizeof(*ih); len = sizeof(*ih);
@ -930,7 +944,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
continue; continue;
} }
err = br_ip4_multicast_add_group(br, port, group); err = br_ip4_multicast_add_group(br, port, group, vid);
if (err) if (err)
break; break;
} }
@ -949,10 +963,12 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
int len; int len;
int num; int num;
int err = 0; int err = 0;
u16 vid = 0;
if (!pskb_may_pull(skb, sizeof(*icmp6h))) if (!pskb_may_pull(skb, sizeof(*icmp6h)))
return -EINVAL; return -EINVAL;
br_vlan_get_tag(skb, &vid);
icmp6h = icmp6_hdr(skb); icmp6h = icmp6_hdr(skb);
num = ntohs(icmp6h->icmp6_dataun.un_data16[1]); num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
len = sizeof(*icmp6h); len = sizeof(*icmp6h);
@ -990,7 +1006,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
continue; continue;
} }
err = br_ip6_multicast_add_group(br, port, &grec->grec_mca); err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
vid);
if (!err) if (!err)
break; break;
} }
@ -1074,6 +1091,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
unsigned long now = jiffies; unsigned long now = jiffies;
__be32 group; __be32 group;
int err = 0; int err = 0;
u16 vid = 0;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
if (!netif_running(br->dev) || if (!netif_running(br->dev) ||
@ -1108,7 +1126,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
if (!group) if (!group)
goto out; goto out;
mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group); br_vlan_get_tag(skb, &vid);
mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group, vid);
if (!mp) if (!mp)
goto out; goto out;
@ -1149,6 +1168,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
unsigned long now = jiffies; unsigned long now = jiffies;
const struct in6_addr *group = NULL; const struct in6_addr *group = NULL;
int err = 0; int err = 0;
u16 vid = 0;
spin_lock(&br->multicast_lock); spin_lock(&br->multicast_lock);
if (!netif_running(br->dev) || if (!netif_running(br->dev) ||
@ -1180,7 +1200,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
if (!group) if (!group)
goto out; goto out;
mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group); br_vlan_get_tag(skb, &vid);
mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid);
if (!mp) if (!mp)
goto out; goto out;
@ -1286,7 +1307,8 @@ static void br_multicast_leave_group(struct net_bridge *br,
static void br_ip4_multicast_leave_group(struct net_bridge *br, static void br_ip4_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port, struct net_bridge_port *port,
__be32 group) __be32 group,
__u16 vid)
{ {
struct br_ip br_group; struct br_ip br_group;
@ -1295,6 +1317,7 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
br_group.u.ip4 = group; br_group.u.ip4 = group;
br_group.proto = htons(ETH_P_IP); br_group.proto = htons(ETH_P_IP);
br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group); br_multicast_leave_group(br, port, &br_group);
} }
@ -1302,7 +1325,8 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
static void br_ip6_multicast_leave_group(struct net_bridge *br, static void br_ip6_multicast_leave_group(struct net_bridge *br,
struct net_bridge_port *port, struct net_bridge_port *port,
const struct in6_addr *group) const struct in6_addr *group,
__u16 vid)
{ {
struct br_ip br_group; struct br_ip br_group;
@ -1311,6 +1335,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
br_group.u.ip6 = *group; br_group.u.ip6 = *group;
br_group.proto = htons(ETH_P_IPV6); br_group.proto = htons(ETH_P_IPV6);
br_group.vid = vid;
br_multicast_leave_group(br, port, &br_group); br_multicast_leave_group(br, port, &br_group);
} }
@ -1326,6 +1351,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
unsigned int len; unsigned int len;
unsigned int offset; unsigned int offset;
int err; int err;
u16 vid = 0;
/* We treat OOM as packet loss for now. */ /* We treat OOM as packet loss for now. */
if (!pskb_may_pull(skb, sizeof(*iph))) if (!pskb_may_pull(skb, sizeof(*iph)))
@ -1386,6 +1412,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
err = 0; err = 0;
br_vlan_get_tag(skb2, &vid);
BR_INPUT_SKB_CB(skb)->igmp = 1; BR_INPUT_SKB_CB(skb)->igmp = 1;
ih = igmp_hdr(skb2); ih = igmp_hdr(skb2);
@ -1393,7 +1420,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
case IGMP_HOST_MEMBERSHIP_REPORT: case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV2_HOST_MEMBERSHIP_REPORT:
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
err = br_ip4_multicast_add_group(br, port, ih->group); err = br_ip4_multicast_add_group(br, port, ih->group, vid);
break; break;
case IGMPV3_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT:
err = br_ip4_multicast_igmp3_report(br, port, skb2); err = br_ip4_multicast_igmp3_report(br, port, skb2);
@ -1402,7 +1429,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
err = br_ip4_multicast_query(br, port, skb2); err = br_ip4_multicast_query(br, port, skb2);
break; break;
case IGMP_HOST_LEAVE_MESSAGE: case IGMP_HOST_LEAVE_MESSAGE:
br_ip4_multicast_leave_group(br, port, ih->group); br_ip4_multicast_leave_group(br, port, ih->group, vid);
break; break;
} }
@ -1427,6 +1454,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
unsigned int len; unsigned int len;
int offset; int offset;
int err; int err;
u16 vid = 0;
if (!pskb_may_pull(skb, sizeof(*ip6h))) if (!pskb_may_pull(skb, sizeof(*ip6h)))
return -EINVAL; return -EINVAL;
@ -1510,6 +1538,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
err = 0; err = 0;
br_vlan_get_tag(skb, &vid);
BR_INPUT_SKB_CB(skb)->igmp = 1; BR_INPUT_SKB_CB(skb)->igmp = 1;
switch (icmp6_type) { switch (icmp6_type) {
@ -1522,7 +1551,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
} }
mld = (struct mld_msg *)skb_transport_header(skb2); mld = (struct mld_msg *)skb_transport_header(skb2);
BR_INPUT_SKB_CB(skb)->mrouters_only = 1; BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
err = br_ip6_multicast_add_group(br, port, &mld->mld_mca); err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
break; break;
} }
case ICMPV6_MLD2_REPORT: case ICMPV6_MLD2_REPORT:
@ -1539,7 +1568,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
goto out; goto out;
} }
mld = (struct mld_msg *)skb_transport_header(skb2); mld = (struct mld_msg *)skb_transport_header(skb2);
br_ip6_multicast_leave_group(br, port, &mld->mld_mca); br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
} }
} }

View File

@ -63,6 +63,7 @@ struct br_ip
#endif #endif
} u; } u;
__be16 proto; __be16 proto;
__u16 vid;
}; };
struct net_port_vlans { struct net_port_vlans {