bridge: Add vlan id to multicast groups
Vlad Yasevich [Wed, 13 Feb 2013 12:00:17 +0000 (12:00 +0000)]
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>

net/bridge/br_multicast.c
net/bridge/br_private.h

index 6d6f265..7d886b0 100644 (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)
                return 0;
+       if (a->vid != b->vid)
+               return 0;
        switch (a->proto) {
        case htons(ETH_P_IP):
                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;
 }
 
-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)
 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
 
@@ -68,10 +73,10 @@ static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
 {
        switch (ip->proto) {
        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)
        case htons(ETH_P_IPV6):
-               return __br_ip6_hash(mdb, &ip->u.ip6);
+               return __br_ip6_hash(mdb, &ip->u.ip6, ip->vid);
 #endif
        }
        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(
-       struct net_bridge_mdb_htable *mdb, __be32 dst)
+       struct net_bridge_mdb_htable *mdb, __be32 dst, __u16 vid)
 {
        struct br_ip br_dst;
 
        br_dst.u.ip4 = dst;
        br_dst.proto = htons(ETH_P_IP);
+       br_dst.vid = vid;
 
        return br_mdb_ip_get(mdb, &br_dst);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
 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;
 
        br_dst.u.ip6 = *dst;
        br_dst.proto = htons(ETH_P_IPV6);
+       br_dst.vid = vid;
 
        return br_mdb_ip_get(mdb, &br_dst);
 }
@@ -694,7 +702,8 @@ err:
 
 static int br_ip4_multicast_add_group(struct net_bridge *br,
                                      struct net_bridge_port *port,
-                                     __be32 group)
+                                     __be32 group,
+                                     __u16 vid)
 {
        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.proto = htons(ETH_P_IP);
+       br_group.vid = vid;
 
        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)
 static int br_ip6_multicast_add_group(struct net_bridge *br,
                                      struct net_bridge_port *port,
-                                     const struct in6_addr *group)
+                                     const struct in6_addr *group,
+                                     __u16 vid)
 {
        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.proto = htons(ETH_P_IPV6);
+       br_group.vid = vid;
 
        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 err = 0;
        __be32 group;
+       u16 vid = 0;
 
        if (!pskb_may_pull(skb, sizeof(*ih)))
                return -EINVAL;
 
+       br_vlan_get_tag(skb, &vid);
        ih = igmpv3_report_hdr(skb);
        num = ntohs(ih->ngrec);
        len = sizeof(*ih);
@@ -930,7 +944,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
                        continue;
                }
 
-               err = br_ip4_multicast_add_group(br, port, group);
+               err = br_ip4_multicast_add_group(br, port, group, vid);
                if (err)
                        break;
        }
@@ -949,10 +963,12 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
        int len;
        int num;
        int err = 0;
+       u16 vid = 0;
 
        if (!pskb_may_pull(skb, sizeof(*icmp6h)))
                return -EINVAL;
 
+       br_vlan_get_tag(skb, &vid);
        icmp6h = icmp6_hdr(skb);
        num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
        len = sizeof(*icmp6h);
@@ -990,7 +1006,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
                        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)
                        break;
        }
@@ -1074,6 +1091,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        unsigned long now = jiffies;
        __be32 group;
        int err = 0;
+       u16 vid = 0;
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
@@ -1108,7 +1126,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!group)
                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)
                goto out;
 
@@ -1149,6 +1168,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        unsigned long now = jiffies;
        const struct in6_addr *group = NULL;
        int err = 0;
+       u16 vid = 0;
 
        spin_lock(&br->multicast_lock);
        if (!netif_running(br->dev) ||
@@ -1180,7 +1200,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!group)
                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)
                goto out;
 
@@ -1286,7 +1307,8 @@ out:
 
 static void br_ip4_multicast_leave_group(struct net_bridge *br,
                                         struct net_bridge_port *port,
-                                        __be32 group)
+                                        __be32 group,
+                                        __u16 vid)
 {
        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.proto = htons(ETH_P_IP);
+       br_group.vid = vid;
 
        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)
 static void br_ip6_multicast_leave_group(struct net_bridge *br,
                                         struct net_bridge_port *port,
-                                        const struct in6_addr *group)
+                                        const struct in6_addr *group,
+                                        __u16 vid)
 {
        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.proto = htons(ETH_P_IPV6);
+       br_group.vid = vid;
 
        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 offset;
        int err;
+       u16 vid = 0;
 
        /* We treat OOM as packet loss for now. */
        if (!pskb_may_pull(skb, sizeof(*iph)))
@@ -1386,6 +1412,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
 
        err = 0;
 
+       br_vlan_get_tag(skb2, &vid);
        BR_INPUT_SKB_CB(skb)->igmp = 1;
        ih = igmp_hdr(skb2);
 
@@ -1393,7 +1420,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
        case IGMP_HOST_MEMBERSHIP_REPORT:
        case IGMPV2_HOST_MEMBERSHIP_REPORT:
                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;
        case IGMPV3_HOST_MEMBERSHIP_REPORT:
                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);
                break;
        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;
        }
 
@@ -1427,6 +1454,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
        unsigned int len;
        int offset;
        int err;
+       u16 vid = 0;
 
        if (!pskb_may_pull(skb, sizeof(*ip6h)))
                return -EINVAL;
@@ -1510,6 +1538,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
 
        err = 0;
 
+       br_vlan_get_tag(skb, &vid);
        BR_INPUT_SKB_CB(skb)->igmp = 1;
 
        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);
                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;
            }
        case ICMPV6_MLD2_REPORT:
@@ -1539,7 +1568,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
                        goto out;
                }
                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);
            }
        }
 
index f4ae87b..22915c8 100644 (file)
@@ -63,6 +63,7 @@ struct br_ip
 #endif
        } u;
        __be16          proto;
+       __u16           vid;
 };
 
 struct net_port_vlans {