[PATCH] 2.6.12 Ethernet bridge over bonding interfaces
From: Garik E
Date:  Thu Jun 23 2005 - 06:38:11 EST
Ethernet bridge configured over bonding interfaces dead loops and
multiplies ethernet broadcast packets (ARP requests)
The following patch solves this problem.
Signed-off-by: Garik E. <kiragon@xxxxxxxxx>
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -605,6 +605,7 @@ static struct bond_parm_tbl bond_mode_tb
 { "802.3ad",  BOND_MODE_8023AD},
 { "balance-tlb",  BOND_MODE_TLB},
 { "balance-alb",  BOND_MODE_ALB},
+{ "bridge-active-backup", BOND_MODE_BRACBP},
 { NULL,   -1},
 };
@@ -631,6 +632,8 @@ static const char *bond_mode_name(int mo
   return "transmit load balancing";
  case BOND_MODE_ALB:
   return "adaptive load balancing";
+ case BOND_MODE_BRACBP:
+  return "bridge fault-tolerance (active-backup)";
  default:
   return "unknown";
  }
@@ -4203,6 +4206,36 @@ out:
  return 0;
 }
+static int bond_xmit_bridge(struct sk_buff *skb, struct net_device *bond_dev)
+{
+ struct bonding *bond = bond_dev->priv;
+ int res = 1;
+
+ read_lock(&bond->lock);
+
+ if (!BOND_IS_OK(bond)) {
+  goto out;
+ }
+
+ if (bond->params.mode == BOND_MODE_BRACBP) {
+  read_lock(&bond->curr_slave_lock);
+  if (bond->curr_active_slave) { /* one usable interface */
+   res = bond_dev_queue_xmit(bond, skb,
+     bond->curr_active_slave->dev);
+  }
+  read_unlock(&bond->curr_slave_lock);
+ }
+
+out:
+ if (res) {
+  /* no suitable interface, frame not sent */
+  dev_kfree_skb(skb);
+ }
+
+ read_unlock(&bond->lock);
+ return 0;
+}
+
 /*------------------------- Device initialization ---------------------------*/
 /*
@@ -4231,6 +4264,9 @@ static inline void bond_set_mode_ops(str
   bond_dev->hard_start_xmit = bond_alb_xmit;
   bond_dev->set_mac_address = bond_alb_set_mac_address;
   break;
+ case BOND_MODE_BRACBP:
+  bond_dev->hard_start_xmit = bond_xmit_bridge;
+  break;
  default:
   /* Should never happen, mode already checked */
   printk(KERN_ERR DRV_NAME
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -79,7 +79,8 @@
 #define USES_PRIMARY(mode)    \
   (((mode) == BOND_MODE_ACTIVEBACKUP) || \
    ((mode) == BOND_MODE_TLB)          || \
-   ((mode) == BOND_MODE_ALB))
+   ((mode) == BOND_MODE_ALB)          || \
+   ((mode) == BOND_MODE_BRACBP))
 /*
  * Less bad way to call ioctl from within the kernel; this needs to be
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -67,6 +67,7 @@
 #define BOND_MODE_8023AD        4
 #define BOND_MODE_TLB           5
 #define BOND_MODE_ALB  6 /* TLB + RLB (receive load balancing) */
+#define BOND_MODE_BRACBP 7 /* Active Backup for bridge */
 /* each slave's link has 4 states */
 #define BOND_LINK_UP    0           /* link is up and running */
diff --git a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1597,6 +1597,11 @@ static __inline__ int handle_bridge(stru
      (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
   return 0;
+ if ((*pskb)->real_dev && !((*pskb)->real_dev->flags & IFF_PROMISC)) {
+  kfree_skb(*pskb);
+  return 1;
+ }
+
  if (*pt_prev) {
   *ret = deliver_skb(*pskb, *pt_prev);
   *pt_prev = NULL;
-------------------------------------------------------
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/