=====================================================================
@@ -64,6 +64,7 @@ static int __init br_init(void)
brioctl_set(br_ioctl_deviceless_stub);
br_handle_frame_hook = br_handle_frame;
+ br_hard_xmit_hook = br_hard_xmit;
br_fdb_get_hook = br_fdb_get;
br_fdb_put_hook = br_fdb_put;
@@ -99,6 +100,7 @@ static void __exit br_deinit(void)
br_fdb_put_hook = NULL;
br_handle_frame_hook = NULL;
+ br_hard_xmit_hook = NULL;
br_fdb_fini();
}
=====================================================================
@@ -32,6 +32,8 @@ int br_dev_xmit(struct sk_buff *skb, str
skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN);
+ skb->br_seen = 1;
+
if (is_multicast_ether_addr(dest))
br_flood_deliver(br, skb);
else if ((dst = __br_fdb_get(br, dest)) != NULL)
@@ -42,6 +44,41 @@ int br_dev_xmit(struct sk_buff *skb, str
return 0;
}
+int br_hard_xmit(struct sk_buff *skb, struct net_bridge_port *port)
+{
+ struct net_bridge *br = port->br;
+ const unsigned char *dest = skb->data;
+ struct net_bridge_fdb_entry *dst;
+ struct sk_buff *skb2;
+
+ /* forward via master device only */
+ if (!br->via_phys_dev || br->master_dev != port->dev)
+ return 0;
+
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2) {
+ br->dev->stats.tx_dropped++;
+ return 0;
+ }
+
+ br->dev->stats.tx_packets++;
+ br->dev->stats.tx_bytes += skb2->len;
+
+ skb_reset_mac_header(skb2);
+ skb_pull(skb2, ETH_HLEN);
+
+ skb2->br_seen = 1;
+
+ if (is_multicast_ether_addr(dest))
+ br_flood_deliver(br, skb2);
+ else if ((dst = __br_fdb_get(br, dest)) != NULL)
+ br_deliver(dst->dst, skb2);
+ else
+ br_flood_deliver(br, skb2);
+
+ return 0;
+}
+
static int br_dev_open(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
=====================================================================
@@ -148,5 +148,6 @@ void br_flood_deliver(struct net_bridge
/* called under bridge lock */
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
{
+ skb->br_seen = 1;
br_flood(br, skb, __br_forward);
}
=====================================================================
@@ -28,7 +28,15 @@ static void br_pass_frame_up(struct net_
brdev->stats.rx_bytes += skb->len;
indev = skb->dev;
- skb->dev = brdev;
+
+ if (br->via_phys_dev) {
+ skb->br_seen = 1;
+ if (likely(br->master_dev))
+ skb->dev = br->master_dev;
+ else
+ skb->dev = brdev;
+ } else
+ skb->dev = brdev;
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
netif_receive_skb);
@@ -151,6 +159,10 @@ struct sk_buff *br_handle_frame(struct n
}
/* fall through */
case BR_STATE_LEARNING:
+ /* if we saw this skb earlier just pass it up */
+ if (skb->br_seen)
+ return skb;
+
if (!compare_ether_addr(p->br->dev->dev_addr, dest))
skb->pkt_type = PACKET_HOST;
=====================================================================
@@ -144,6 +144,7 @@ static inline int br_is_root_bridge(cons
/* br_device.c */
extern void br_dev_setup(struct net_device *dev);
extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
+extern int br_hard_xmit(struct sk_buff *skb, struct net_bridge_port *port);
/* br_fdb.c */
extern int br_fdb_init(void);