aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-02-27 14:41:41 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-28 03:48:43 -0500
commitb33084be192ee1e347d98bb5c9e38a53d98d35e2 (patch)
tree940c62309437ca5fa087275bc64b4ffd677c79c3 /net
parent68b7c895be336b19f4c38d7cb500132fabba0afd (diff)
bridge: Avoid unnecessary clone on forward path
When the packet is delivered to the local bridge device we may end up cloning it unnecessarily if no bridge port can receive the packet in br_flood. This patch avoids this by moving the skb_clone into br_flood. 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.c33
-rw-r--r--net/bridge/br_input.c5
-rw-r--r--net/bridge/br_private.h3
3 files changed, 25 insertions, 16 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index bc1704ac6cd..6cd50c6e57c 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -105,8 +105,9 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
105 105
106/* called under bridge lock */ 106/* called under bridge lock */
107static void br_flood(struct net_bridge *br, struct sk_buff *skb, 107static void br_flood(struct net_bridge *br, struct sk_buff *skb,
108 void (*__packet_hook)(const struct net_bridge_port *p, 108 struct sk_buff *skb0,
109 struct sk_buff *skb)) 109 void (*__packet_hook)(const struct net_bridge_port *p,
110 struct sk_buff *skb))
110{ 111{
111 struct net_bridge_port *p; 112 struct net_bridge_port *p;
112 struct net_bridge_port *prev; 113 struct net_bridge_port *prev;
@@ -120,8 +121,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
120 121
121 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { 122 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
122 br->dev->stats.tx_dropped++; 123 br->dev->stats.tx_dropped++;
123 kfree_skb(skb); 124 goto out;
124 return;
125 } 125 }
126 126
127 __packet_hook(prev, skb2); 127 __packet_hook(prev, skb2);
@@ -131,23 +131,34 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
131 } 131 }
132 } 132 }
133 133
134 if (prev != NULL) { 134 if (!prev)
135 __packet_hook(prev, skb); 135 goto out;
136 return; 136
137 if (skb0) {
138 skb = skb_clone(skb, GFP_ATOMIC);
139 if (!skb) {
140 br->dev->stats.tx_dropped++;
141 goto out;
142 }
137 } 143 }
144 __packet_hook(prev, skb);
145 return;
138 146
139 kfree_skb(skb); 147out:
148 if (!skb0)
149 kfree_skb(skb);
140} 150}
141 151
142 152
143/* called with rcu_read_lock */ 153/* called with rcu_read_lock */
144void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) 154void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
145{ 155{
146 br_flood(br, skb, __br_deliver); 156 br_flood(br, skb, NULL, __br_deliver);
147} 157}
148 158
149/* called under bridge lock */ 159/* called under bridge lock */
150void br_flood_forward(struct net_bridge *br, struct sk_buff *skb) 160void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
161 struct sk_buff *skb2)
151{ 162{
152 br_flood(br, skb, __br_forward); 163 br_flood(br, skb, skb2, __br_forward);
153} 164}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index be5ab8df666..edfdaef4429 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -72,14 +72,11 @@ int br_handle_frame_finish(struct sk_buff *skb)
72 skb = NULL; 72 skb = NULL;
73 } 73 }
74 74
75 if (skb2 == skb)
76 skb2 = skb_clone(skb, GFP_ATOMIC);
77
78 if (skb) { 75 if (skb) {
79 if (dst) 76 if (dst)
80 br_forward(dst->dst, skb); 77 br_forward(dst->dst, skb);
81 else 78 else
82 br_flood_forward(br, skb); 79 br_flood_forward(br, skb, skb2);
83 } 80 }
84 81
85 if (skb2) 82 if (skb2)
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 16513793156..fad5a2669d3 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -180,7 +180,8 @@ extern void br_forward(const struct net_bridge_port *to,
180 struct sk_buff *skb); 180 struct sk_buff *skb);
181extern int br_forward_finish(struct sk_buff *skb); 181extern int br_forward_finish(struct sk_buff *skb);
182extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb); 182extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
183extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb); 183extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
184 struct sk_buff *skb2);
184 185
185/* br_if.c */ 186/* br_if.c */
186extern void br_port_carrier_check(struct net_bridge_port *p); 187extern void br_port_carrier_check(struct net_bridge_port *p);