aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
authorVlad Yasevich <vyasevic@redhat.com>2013-02-13 07:00:17 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-13 19:42:16 -0500
commitb0e9a30dd669a844bb4f74515f8bcd307018ffd0 (patch)
treebc972056a09db99a38fcdb6bdcb5421a96a963ef /net/bridge
parent2ba071ecb6d41ce172f9ccb3996f28cb337b3576 (diff)
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>
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_multicast.c69
-rw-r--r--net/bridge/br_private.h1
2 files changed, 50 insertions, 20 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 6d6f26531de2..7d886b0a8b7b 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -39,6 +39,8 @@ static inline int br_ip_equal(const struct br_ip *a, const struct br_ip *b)
39{ 39{
40 if (a->proto != b->proto) 40 if (a->proto != b->proto)
41 return 0; 41 return 0;
42 if (a->vid != b->vid)
43 return 0;
42 switch (a->proto) { 44 switch (a->proto) {
43 case htons(ETH_P_IP): 45 case htons(ETH_P_IP):
44 return a->u.ip4 == b->u.ip4; 46 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)
50 return 0; 52 return 0;
51} 53}
52 54
53static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip) 55static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip,
56 __u16 vid)
54{ 57{
55 return jhash_1word(mdb->secret, (__force u32)ip) & (mdb->max - 1); 58 return jhash_2words((__force u32)ip, vid, mdb->secret) & (mdb->max - 1);
56} 59}
57 60
58#if IS_ENABLED(CONFIG_IPV6) 61#if IS_ENABLED(CONFIG_IPV6)
59static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb, 62static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb,
60 const struct in6_addr *ip) 63 const struct in6_addr *ip,
64 __u16 vid)
61{ 65{
62 return jhash2((__force u32 *)ip->s6_addr32, 4, mdb->secret) & (mdb->max - 1); 66 return jhash_2words(ipv6_addr_hash(ip), vid,
67 mdb->secret) & (mdb->max - 1);
63} 68}
64#endif 69#endif
65 70
@@ -68,10 +73,10 @@ static inline int br_ip_hash(struct net_bridge_mdb_htable *mdb,
68{ 73{
69 switch (ip->proto) { 74 switch (ip->proto) {
70 case htons(ETH_P_IP): 75 case htons(ETH_P_IP):
71 return __br_ip4_hash(mdb, ip->u.ip4); 76 return __br_ip4_hash(mdb, ip->u.ip4, ip->vid);
72#if IS_ENABLED(CONFIG_IPV6) 77#if IS_ENABLED(CONFIG_IPV6)
73 case htons(ETH_P_IPV6): 78 case htons(ETH_P_IPV6):
74 return __br_ip6_hash(mdb, &ip->u.ip6); 79 return __br_ip6_hash(mdb, &ip->u.ip6, ip->vid);
75#endif 80#endif
76 } 81 }
77 return 0; 82 return 0;
@@ -101,24 +106,27 @@ struct net_bridge_mdb_entry *br_mdb_ip_get(struct net_bridge_mdb_htable *mdb,
101} 106}
102 107
103static struct net_bridge_mdb_entry *br_mdb_ip4_get( 108static struct net_bridge_mdb_entry *br_mdb_ip4_get(
104 struct net_bridge_mdb_htable *mdb, __be32 dst) 109 struct net_bridge_mdb_htable *mdb, __be32 dst, __u16 vid)
105{ 110{
106 struct br_ip br_dst; 111 struct br_ip br_dst;
107 112
108 br_dst.u.ip4 = dst; 113 br_dst.u.ip4 = dst;
109 br_dst.proto = htons(ETH_P_IP); 114 br_dst.proto = htons(ETH_P_IP);
115 br_dst.vid = vid;
110 116
111 return br_mdb_ip_get(mdb, &br_dst); 117 return br_mdb_ip_get(mdb, &br_dst);
112} 118}
113 119
114#if IS_ENABLED(CONFIG_IPV6) 120#if IS_ENABLED(CONFIG_IPV6)
115static struct net_bridge_mdb_entry *br_mdb_ip6_get( 121static struct net_bridge_mdb_entry *br_mdb_ip6_get(
116 struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst) 122 struct net_bridge_mdb_htable *mdb, const struct in6_addr *dst,
123 __u16 vid)
117{ 124{
118 struct br_ip br_dst; 125 struct br_ip br_dst;
119 126
120 br_dst.u.ip6 = *dst; 127 br_dst.u.ip6 = *dst;
121 br_dst.proto = htons(ETH_P_IPV6); 128 br_dst.proto = htons(ETH_P_IPV6);
129 br_dst.vid = vid;
122 130
123 return br_mdb_ip_get(mdb, &br_dst); 131 return br_mdb_ip_get(mdb, &br_dst);
124} 132}
@@ -694,7 +702,8 @@ err:
694 702
695static int br_ip4_multicast_add_group(struct net_bridge *br, 703static int br_ip4_multicast_add_group(struct net_bridge *br,
696 struct net_bridge_port *port, 704 struct net_bridge_port *port,
697 __be32 group) 705 __be32 group,
706 __u16 vid)
698{ 707{
699 struct br_ip br_group; 708 struct br_ip br_group;
700 709
@@ -703,6 +712,7 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
703 712
704 br_group.u.ip4 = group; 713 br_group.u.ip4 = group;
705 br_group.proto = htons(ETH_P_IP); 714 br_group.proto = htons(ETH_P_IP);
715 br_group.vid = vid;
706 716
707 return br_multicast_add_group(br, port, &br_group); 717 return br_multicast_add_group(br, port, &br_group);
708} 718}
@@ -710,7 +720,8 @@ static int br_ip4_multicast_add_group(struct net_bridge *br,
710#if IS_ENABLED(CONFIG_IPV6) 720#if IS_ENABLED(CONFIG_IPV6)
711static int br_ip6_multicast_add_group(struct net_bridge *br, 721static int br_ip6_multicast_add_group(struct net_bridge *br,
712 struct net_bridge_port *port, 722 struct net_bridge_port *port,
713 const struct in6_addr *group) 723 const struct in6_addr *group,
724 __u16 vid)
714{ 725{
715 struct br_ip br_group; 726 struct br_ip br_group;
716 727
@@ -719,6 +730,7 @@ static int br_ip6_multicast_add_group(struct net_bridge *br,
719 730
720 br_group.u.ip6 = *group; 731 br_group.u.ip6 = *group;
721 br_group.proto = htons(ETH_P_IPV6); 732 br_group.proto = htons(ETH_P_IPV6);
733 br_group.vid = vid;
722 734
723 return br_multicast_add_group(br, port, &br_group); 735 return br_multicast_add_group(br, port, &br_group);
724} 736}
@@ -895,10 +907,12 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
895 int type; 907 int type;
896 int err = 0; 908 int err = 0;
897 __be32 group; 909 __be32 group;
910 u16 vid = 0;
898 911
899 if (!pskb_may_pull(skb, sizeof(*ih))) 912 if (!pskb_may_pull(skb, sizeof(*ih)))
900 return -EINVAL; 913 return -EINVAL;
901 914
915 br_vlan_get_tag(skb, &vid);
902 ih = igmpv3_report_hdr(skb); 916 ih = igmpv3_report_hdr(skb);
903 num = ntohs(ih->ngrec); 917 num = ntohs(ih->ngrec);
904 len = sizeof(*ih); 918 len = sizeof(*ih);
@@ -930,7 +944,7 @@ static int br_ip4_multicast_igmp3_report(struct net_bridge *br,
930 continue; 944 continue;
931 } 945 }
932 946
933 err = br_ip4_multicast_add_group(br, port, group); 947 err = br_ip4_multicast_add_group(br, port, group, vid);
934 if (err) 948 if (err)
935 break; 949 break;
936 } 950 }
@@ -949,10 +963,12 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
949 int len; 963 int len;
950 int num; 964 int num;
951 int err = 0; 965 int err = 0;
966 u16 vid = 0;
952 967
953 if (!pskb_may_pull(skb, sizeof(*icmp6h))) 968 if (!pskb_may_pull(skb, sizeof(*icmp6h)))
954 return -EINVAL; 969 return -EINVAL;
955 970
971 br_vlan_get_tag(skb, &vid);
956 icmp6h = icmp6_hdr(skb); 972 icmp6h = icmp6_hdr(skb);
957 num = ntohs(icmp6h->icmp6_dataun.un_data16[1]); 973 num = ntohs(icmp6h->icmp6_dataun.un_data16[1]);
958 len = sizeof(*icmp6h); 974 len = sizeof(*icmp6h);
@@ -990,7 +1006,8 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
990 continue; 1006 continue;
991 } 1007 }
992 1008
993 err = br_ip6_multicast_add_group(br, port, &grec->grec_mca); 1009 err = br_ip6_multicast_add_group(br, port, &grec->grec_mca,
1010 vid);
994 if (!err) 1011 if (!err)
995 break; 1012 break;
996 } 1013 }
@@ -1074,6 +1091,7 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1074 unsigned long now = jiffies; 1091 unsigned long now = jiffies;
1075 __be32 group; 1092 __be32 group;
1076 int err = 0; 1093 int err = 0;
1094 u16 vid = 0;
1077 1095
1078 spin_lock(&br->multicast_lock); 1096 spin_lock(&br->multicast_lock);
1079 if (!netif_running(br->dev) || 1097 if (!netif_running(br->dev) ||
@@ -1108,7 +1126,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
1108 if (!group) 1126 if (!group)
1109 goto out; 1127 goto out;
1110 1128
1111 mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group); 1129 br_vlan_get_tag(skb, &vid);
1130 mp = br_mdb_ip4_get(mlock_dereference(br->mdb, br), group, vid);
1112 if (!mp) 1131 if (!mp)
1113 goto out; 1132 goto out;
1114 1133
@@ -1149,6 +1168,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1149 unsigned long now = jiffies; 1168 unsigned long now = jiffies;
1150 const struct in6_addr *group = NULL; 1169 const struct in6_addr *group = NULL;
1151 int err = 0; 1170 int err = 0;
1171 u16 vid = 0;
1152 1172
1153 spin_lock(&br->multicast_lock); 1173 spin_lock(&br->multicast_lock);
1154 if (!netif_running(br->dev) || 1174 if (!netif_running(br->dev) ||
@@ -1180,7 +1200,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
1180 if (!group) 1200 if (!group)
1181 goto out; 1201 goto out;
1182 1202
1183 mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group); 1203 br_vlan_get_tag(skb, &vid);
1204 mp = br_mdb_ip6_get(mlock_dereference(br->mdb, br), group, vid);
1184 if (!mp) 1205 if (!mp)
1185 goto out; 1206 goto out;
1186 1207
@@ -1286,7 +1307,8 @@ out:
1286 1307
1287static void br_ip4_multicast_leave_group(struct net_bridge *br, 1308static void br_ip4_multicast_leave_group(struct net_bridge *br,
1288 struct net_bridge_port *port, 1309 struct net_bridge_port *port,
1289 __be32 group) 1310 __be32 group,
1311 __u16 vid)
1290{ 1312{
1291 struct br_ip br_group; 1313 struct br_ip br_group;
1292 1314
@@ -1295,6 +1317,7 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
1295 1317
1296 br_group.u.ip4 = group; 1318 br_group.u.ip4 = group;
1297 br_group.proto = htons(ETH_P_IP); 1319 br_group.proto = htons(ETH_P_IP);
1320 br_group.vid = vid;
1298 1321
1299 br_multicast_leave_group(br, port, &br_group); 1322 br_multicast_leave_group(br, port, &br_group);
1300} 1323}
@@ -1302,7 +1325,8 @@ static void br_ip4_multicast_leave_group(struct net_bridge *br,
1302#if IS_ENABLED(CONFIG_IPV6) 1325#if IS_ENABLED(CONFIG_IPV6)
1303static void br_ip6_multicast_leave_group(struct net_bridge *br, 1326static void br_ip6_multicast_leave_group(struct net_bridge *br,
1304 struct net_bridge_port *port, 1327 struct net_bridge_port *port,
1305 const struct in6_addr *group) 1328 const struct in6_addr *group,
1329 __u16 vid)
1306{ 1330{
1307 struct br_ip br_group; 1331 struct br_ip br_group;
1308 1332
@@ -1311,6 +1335,7 @@ static void br_ip6_multicast_leave_group(struct net_bridge *br,
1311 1335
1312 br_group.u.ip6 = *group; 1336 br_group.u.ip6 = *group;
1313 br_group.proto = htons(ETH_P_IPV6); 1337 br_group.proto = htons(ETH_P_IPV6);
1338 br_group.vid = vid;
1314 1339
1315 br_multicast_leave_group(br, port, &br_group); 1340 br_multicast_leave_group(br, port, &br_group);
1316} 1341}
@@ -1326,6 +1351,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1326 unsigned int len; 1351 unsigned int len;
1327 unsigned int offset; 1352 unsigned int offset;
1328 int err; 1353 int err;
1354 u16 vid = 0;
1329 1355
1330 /* We treat OOM as packet loss for now. */ 1356 /* We treat OOM as packet loss for now. */
1331 if (!pskb_may_pull(skb, sizeof(*iph))) 1357 if (!pskb_may_pull(skb, sizeof(*iph)))
@@ -1386,6 +1412,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1386 1412
1387 err = 0; 1413 err = 0;
1388 1414
1415 br_vlan_get_tag(skb2, &vid);
1389 BR_INPUT_SKB_CB(skb)->igmp = 1; 1416 BR_INPUT_SKB_CB(skb)->igmp = 1;
1390 ih = igmp_hdr(skb2); 1417 ih = igmp_hdr(skb2);
1391 1418
@@ -1393,7 +1420,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1393 case IGMP_HOST_MEMBERSHIP_REPORT: 1420 case IGMP_HOST_MEMBERSHIP_REPORT:
1394 case IGMPV2_HOST_MEMBERSHIP_REPORT: 1421 case IGMPV2_HOST_MEMBERSHIP_REPORT:
1395 BR_INPUT_SKB_CB(skb)->mrouters_only = 1; 1422 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
1396 err = br_ip4_multicast_add_group(br, port, ih->group); 1423 err = br_ip4_multicast_add_group(br, port, ih->group, vid);
1397 break; 1424 break;
1398 case IGMPV3_HOST_MEMBERSHIP_REPORT: 1425 case IGMPV3_HOST_MEMBERSHIP_REPORT:
1399 err = br_ip4_multicast_igmp3_report(br, port, skb2); 1426 err = br_ip4_multicast_igmp3_report(br, port, skb2);
@@ -1402,7 +1429,7 @@ static int br_multicast_ipv4_rcv(struct net_bridge *br,
1402 err = br_ip4_multicast_query(br, port, skb2); 1429 err = br_ip4_multicast_query(br, port, skb2);
1403 break; 1430 break;
1404 case IGMP_HOST_LEAVE_MESSAGE: 1431 case IGMP_HOST_LEAVE_MESSAGE:
1405 br_ip4_multicast_leave_group(br, port, ih->group); 1432 br_ip4_multicast_leave_group(br, port, ih->group, vid);
1406 break; 1433 break;
1407 } 1434 }
1408 1435
@@ -1427,6 +1454,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1427 unsigned int len; 1454 unsigned int len;
1428 int offset; 1455 int offset;
1429 int err; 1456 int err;
1457 u16 vid = 0;
1430 1458
1431 if (!pskb_may_pull(skb, sizeof(*ip6h))) 1459 if (!pskb_may_pull(skb, sizeof(*ip6h)))
1432 return -EINVAL; 1460 return -EINVAL;
@@ -1510,6 +1538,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1510 1538
1511 err = 0; 1539 err = 0;
1512 1540
1541 br_vlan_get_tag(skb, &vid);
1513 BR_INPUT_SKB_CB(skb)->igmp = 1; 1542 BR_INPUT_SKB_CB(skb)->igmp = 1;
1514 1543
1515 switch (icmp6_type) { 1544 switch (icmp6_type) {
@@ -1522,7 +1551,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1522 } 1551 }
1523 mld = (struct mld_msg *)skb_transport_header(skb2); 1552 mld = (struct mld_msg *)skb_transport_header(skb2);
1524 BR_INPUT_SKB_CB(skb)->mrouters_only = 1; 1553 BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
1525 err = br_ip6_multicast_add_group(br, port, &mld->mld_mca); 1554 err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
1526 break; 1555 break;
1527 } 1556 }
1528 case ICMPV6_MLD2_REPORT: 1557 case ICMPV6_MLD2_REPORT:
@@ -1539,7 +1568,7 @@ static int br_multicast_ipv6_rcv(struct net_bridge *br,
1539 goto out; 1568 goto out;
1540 } 1569 }
1541 mld = (struct mld_msg *)skb_transport_header(skb2); 1570 mld = (struct mld_msg *)skb_transport_header(skb2);
1542 br_ip6_multicast_leave_group(br, port, &mld->mld_mca); 1571 br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
1543 } 1572 }
1544 } 1573 }
1545 1574
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index f4ae87b5aa6e..22915c8e9961 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -63,6 +63,7 @@ struct br_ip
63#endif 63#endif
64 } u; 64 } u;
65 __be16 proto; 65 __be16 proto;
66 __u16 vid;
66}; 67};
67 68
68struct net_port_vlans { 69struct net_port_vlans {