diff options
author | Vlad Yasevich <vyasevic@redhat.com> | 2013-02-13 07:00:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-13 19:42:16 -0500 |
commit | b0e9a30dd669a844bb4f74515f8bcd307018ffd0 (patch) | |
tree | bc972056a09db99a38fcdb6bdcb5421a96a963ef /net/bridge | |
parent | 2ba071ecb6d41ce172f9ccb3996f28cb337b3576 (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.c | 69 | ||||
-rw-r--r-- | net/bridge/br_private.h | 1 |
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 | ||
53 | static inline int __br_ip4_hash(struct net_bridge_mdb_htable *mdb, __be32 ip) | 55 | static 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) |
59 | static inline int __br_ip6_hash(struct net_bridge_mdb_htable *mdb, | 62 | static 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 | ||
103 | static struct net_bridge_mdb_entry *br_mdb_ip4_get( | 108 | static 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) |
115 | static struct net_bridge_mdb_entry *br_mdb_ip6_get( | 121 | static 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 | ||
695 | static int br_ip4_multicast_add_group(struct net_bridge *br, | 703 | static 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) |
711 | static int br_ip6_multicast_add_group(struct net_bridge *br, | 721 | static 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 | ||
1287 | static void br_ip4_multicast_leave_group(struct net_bridge *br, | 1308 | static 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) |
1303 | static void br_ip6_multicast_leave_group(struct net_bridge *br, | 1326 | static 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 | ||
68 | struct net_port_vlans { | 69 | struct net_port_vlans { |