aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-02-27 14:41:43 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-28 03:48:44 -0500
commit025d89c27f54c69cd0e51666d88aada33666bb6c (patch)
tree73063f6189c25d55c71ae6dad96a3711df87b7a6 /net
parent6088a539d8d1666dca6979b5759bf966ee9124ef (diff)
bridge: Split may_deliver/deliver_clone out of br_flood
This patch moves the main loop body in br_flood into the function may_deliver. The code that clones an skb and delivers it is moved into the deliver_clone function. This allows this to be reused by the future multicast forward function. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_forward.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index 2e1cb434f6c..86cd0712d63 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -11,6 +11,7 @@
11 * 2 of the License, or (at your option) any later version. 11 * 2 of the License, or (at your option) any later version.
12 */ 12 */
13 13
14#include <linux/err.h>
14#include <linux/kernel.h> 15#include <linux/kernel.h>
15#include <linux/netdevice.h> 16#include <linux/netdevice.h>
16#include <linux/skbuff.h> 17#include <linux/skbuff.h>
@@ -103,6 +104,44 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
103 kfree_skb(skb); 104 kfree_skb(skb);
104} 105}
105 106
107static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
108 void (*__packet_hook)(const struct net_bridge_port *p,
109 struct sk_buff *skb))
110{
111 skb = skb_clone(skb, GFP_ATOMIC);
112 if (!skb) {
113 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
114
115 dev->stats.tx_dropped++;
116 return -ENOMEM;
117 }
118
119 __packet_hook(prev, skb);
120 return 0;
121}
122
123static struct net_bridge_port *maybe_deliver(
124 struct net_bridge_port *prev, struct net_bridge_port *p,
125 struct sk_buff *skb,
126 void (*__packet_hook)(const struct net_bridge_port *p,
127 struct sk_buff *skb))
128{
129 int err;
130
131 if (!should_deliver(p, skb))
132 return prev;
133
134 if (!prev)
135 goto out;
136
137 err = deliver_clone(prev, skb, __packet_hook);
138 if (err)
139 return ERR_PTR(err);
140
141out:
142 return p;
143}
144
106/* called under bridge lock */ 145/* called under bridge lock */
107static void br_flood(struct net_bridge *br, struct sk_buff *skb, 146static void br_flood(struct net_bridge *br, struct sk_buff *skb,
108 struct sk_buff *skb0, 147 struct sk_buff *skb0,
@@ -111,38 +150,22 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
111{ 150{
112 struct net_bridge_port *p; 151 struct net_bridge_port *p;
113 struct net_bridge_port *prev; 152 struct net_bridge_port *prev;
114 struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
115 153
116 prev = NULL; 154 prev = NULL;
117 155
118 list_for_each_entry_rcu(p, &br->port_list, list) { 156 list_for_each_entry_rcu(p, &br->port_list, list) {
119 if (should_deliver(p, skb)) { 157 prev = maybe_deliver(prev, p, skb, __packet_hook);
120 if (prev != NULL) { 158 if (IS_ERR(prev))
121 struct sk_buff *skb2; 159 goto out;
122
123 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
124 dev->stats.tx_dropped++;
125 goto out;
126 }
127
128 __packet_hook(prev, skb2);
129 }
130
131 prev = p;
132 }
133 } 160 }
134 161
135 if (!prev) 162 if (!prev)
136 goto out; 163 goto out;
137 164
138 if (skb0) { 165 if (skb0)
139 skb = skb_clone(skb, GFP_ATOMIC); 166 deliver_clone(prev, skb, __packet_hook);
140 if (!skb) { 167 else
141 dev->stats.tx_dropped++; 168 __packet_hook(prev, skb);
142 goto out;
143 }
144 }
145 __packet_hook(prev, skb);
146 return; 169 return;
147 170
148out: 171out: