Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b33084be authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 68b7c895
Loading
Loading
Loading
Loading
+22 −11
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ 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,
		     struct sk_buff *skb0,
		     void (*__packet_hook)(const struct net_bridge_port *p,
					   struct sk_buff *skb))
{
@@ -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);
@@ -131,11 +131,21 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
		}
	}

	if (prev != NULL) {
	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;
	}

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

@@ -143,11 +153,12 @@ static void br_flood(struct net_bridge *br, struct sk_buff *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);
}
+1 −4
Original line number Diff line number Diff line
@@ -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)
+2 −1
Original line number Diff line number Diff line
@@ -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);