Skip to content

Commit

Permalink
bridge: Avoid unnecessary clone on forward path
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
herbertx authored and davem330 committed Feb 28, 2010
1 parent 68b7c89 commit b33084b
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 16 deletions.
33 changes: 22 additions & 11 deletions net/bridge/br_forward.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,9 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)

/* called under bridge lock */
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
struct sk_buff *skb0,
void (*__packet_hook)(const struct net_bridge_port *p,
struct sk_buff *skb))
{
struct net_bridge_port *p;
struct net_bridge_port *prev;
Expand All @@ -120,8 +121,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,

if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
br->dev->stats.tx_dropped++;
kfree_skb(skb);
return;
goto out;
}

__packet_hook(prev, skb2);
Expand All @@ -131,23 +131,34 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
}
}

if (prev != NULL) {
__packet_hook(prev, skb);
return;
if (!prev)
goto out;

if (skb0) {
skb = skb_clone(skb, GFP_ATOMIC);
if (!skb) {
br->dev->stats.tx_dropped++;
goto out;
}
}
__packet_hook(prev, skb);
return;

kfree_skb(skb);
out:
if (!skb0)
kfree_skb(skb);
}


/* called with rcu_read_lock */
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
{
br_flood(br, skb, __br_deliver);
br_flood(br, skb, NULL, __br_deliver);
}

/* called under bridge lock */
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
struct sk_buff *skb2)
{
br_flood(br, skb, __br_forward);
br_flood(br, skb, skb2, __br_forward);
}
5 changes: 1 addition & 4 deletions net/bridge/br_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,11 @@ int br_handle_frame_finish(struct sk_buff *skb)
skb = NULL;
}

if (skb2 == skb)
skb2 = skb_clone(skb, GFP_ATOMIC);

if (skb) {
if (dst)
br_forward(dst->dst, skb);
else
br_flood_forward(br, skb);
br_flood_forward(br, skb, skb2);
}

if (skb2)
Expand Down
3 changes: 2 additions & 1 deletion net/bridge/br_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ extern void br_forward(const struct net_bridge_port *to,
struct sk_buff *skb);
extern int br_forward_finish(struct sk_buff *skb);
extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
struct sk_buff *skb2);

/* br_if.c */
extern void br_port_carrier_check(struct net_bridge_port *p);
Expand Down

0 comments on commit b33084b

Please sign in to comment.