diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2010-02-27 14:41:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-28 03:49:45 -0500 |
commit | 0909e11758bd28848aeb6646e021ec1e031a3f0f (patch) | |
tree | a4ae57a59c6ff52f013bbfc29594715c383300d6 /net/bridge/br_multicast.c | |
parent | c4fcb78cf8ae55667809e54e54872a21025dd073 (diff) |
bridge: Add multicast_router sysfs entries
This patch allows the user to forcibly enable/disable ports as
having multicast routers attached. A port with a multicast router
will receive all multicast traffic.
The value 0 disables it completely. The default is 1 which lets
the system automatically detect the presence of routers (currently
this is limited to picking up queries), and 2 means that the port
will always receive all multicast traffic.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_multicast.c')
-rw-r--r-- | net/bridge/br_multicast.c | 105 |
1 files changed, 91 insertions, 14 deletions
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 746b5a611aae..674224b6729d 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -746,12 +746,30 @@ static int br_multicast_igmp3_report(struct net_bridge *br, | |||
746 | return err; | 746 | return err; |
747 | } | 747 | } |
748 | 748 | ||
749 | static void br_multicast_add_router(struct net_bridge *br, | ||
750 | struct net_bridge_port *port) | ||
751 | { | ||
752 | struct hlist_node *p; | ||
753 | struct hlist_node **h; | ||
754 | |||
755 | for (h = &br->router_list.first; | ||
756 | (p = *h) && | ||
757 | (unsigned long)container_of(p, struct net_bridge_port, rlist) > | ||
758 | (unsigned long)port; | ||
759 | h = &p->next) | ||
760 | ; | ||
761 | |||
762 | port->rlist.pprev = h; | ||
763 | port->rlist.next = p; | ||
764 | rcu_assign_pointer(*h, &port->rlist); | ||
765 | if (p) | ||
766 | p->pprev = &port->rlist.next; | ||
767 | } | ||
768 | |||
749 | static void br_multicast_mark_router(struct net_bridge *br, | 769 | static void br_multicast_mark_router(struct net_bridge *br, |
750 | struct net_bridge_port *port) | 770 | struct net_bridge_port *port) |
751 | { | 771 | { |
752 | unsigned long now = jiffies; | 772 | unsigned long now = jiffies; |
753 | struct hlist_node *p; | ||
754 | struct hlist_node **h; | ||
755 | 773 | ||
756 | if (!port) { | 774 | if (!port) { |
757 | if (br->multicast_router == 1) | 775 | if (br->multicast_router == 1) |
@@ -766,18 +784,7 @@ static void br_multicast_mark_router(struct net_bridge *br, | |||
766 | if (!hlist_unhashed(&port->rlist)) | 784 | if (!hlist_unhashed(&port->rlist)) |
767 | goto timer; | 785 | goto timer; |
768 | 786 | ||
769 | for (h = &br->router_list.first; | 787 | br_multicast_add_router(br, port); |
770 | (p = *h) && | ||
771 | (unsigned long)container_of(p, struct net_bridge_port, rlist) > | ||
772 | (unsigned long)port; | ||
773 | h = &p->next) | ||
774 | ; | ||
775 | |||
776 | port->rlist.pprev = h; | ||
777 | port->rlist.next = p; | ||
778 | rcu_assign_pointer(*h, &port->rlist); | ||
779 | if (p) | ||
780 | p->pprev = &port->rlist.next; | ||
781 | 788 | ||
782 | timer: | 789 | timer: |
783 | mod_timer(&port->multicast_router_timer, | 790 | mod_timer(&port->multicast_router_timer, |
@@ -1133,3 +1140,73 @@ void br_multicast_stop(struct net_bridge *br) | |||
1133 | out: | 1140 | out: |
1134 | spin_unlock_bh(&br->multicast_lock); | 1141 | spin_unlock_bh(&br->multicast_lock); |
1135 | } | 1142 | } |
1143 | |||
1144 | int br_multicast_set_router(struct net_bridge *br, unsigned long val) | ||
1145 | { | ||
1146 | int err = -ENOENT; | ||
1147 | |||
1148 | spin_lock_bh(&br->multicast_lock); | ||
1149 | if (!netif_running(br->dev)) | ||
1150 | goto unlock; | ||
1151 | |||
1152 | switch (val) { | ||
1153 | case 0: | ||
1154 | case 2: | ||
1155 | del_timer(&br->multicast_router_timer); | ||
1156 | /* fall through */ | ||
1157 | case 1: | ||
1158 | br->multicast_router = val; | ||
1159 | err = 0; | ||
1160 | break; | ||
1161 | |||
1162 | default: | ||
1163 | err = -EINVAL; | ||
1164 | break; | ||
1165 | } | ||
1166 | |||
1167 | unlock: | ||
1168 | spin_unlock_bh(&br->multicast_lock); | ||
1169 | |||
1170 | return err; | ||
1171 | } | ||
1172 | |||
1173 | int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) | ||
1174 | { | ||
1175 | struct net_bridge *br = p->br; | ||
1176 | int err = -ENOENT; | ||
1177 | |||
1178 | spin_lock(&br->multicast_lock); | ||
1179 | if (!netif_running(br->dev) || p->state == BR_STATE_DISABLED) | ||
1180 | goto unlock; | ||
1181 | |||
1182 | switch (val) { | ||
1183 | case 0: | ||
1184 | case 1: | ||
1185 | case 2: | ||
1186 | p->multicast_router = val; | ||
1187 | err = 0; | ||
1188 | |||
1189 | if (val < 2 && !hlist_unhashed(&p->rlist)) | ||
1190 | hlist_del_init_rcu(&p->rlist); | ||
1191 | |||
1192 | if (val == 1) | ||
1193 | break; | ||
1194 | |||
1195 | del_timer(&p->multicast_router_timer); | ||
1196 | |||
1197 | if (val == 0) | ||
1198 | break; | ||
1199 | |||
1200 | br_multicast_add_router(br, p); | ||
1201 | break; | ||
1202 | |||
1203 | default: | ||
1204 | err = -EINVAL; | ||
1205 | break; | ||
1206 | } | ||
1207 | |||
1208 | unlock: | ||
1209 | spin_unlock(&br->multicast_lock); | ||
1210 | |||
1211 | return err; | ||
1212 | } | ||