Ahmed AL-Saigh | 1 Apr 2009 10:40
Picon

"#brctl show" command output need to be modified

This command output should be modified " aligned " to fit the text processing tool
to can understand what I mean  please try to cut the interfaces column with any text processing tool
"awk , cut or even python script"
but make sure that you have some bridges with some interfaces
_______________________________________________
Bridge mailing list
Bridge <at> lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/bridge
Stephen Hemminger | 1 Apr 2009 17:52
Favicon

Re: "#brctl show" command output need to be modified

On Wed, 1 Apr 2009 10:40:51 +0200
Ahmed AL-Saigh <shabanadevel <at> gmail.com> wrote:

> This command output should be modified " aligned " to fit the text
> processing tool
> to can understand what I mean  please try to cut the interfaces column with
> any text processing tool
> "awk , cut or even python script"
> but make sure that you have some bridges with some interfaces

Unfortunately existing output format can never be changed because
users already have scripts that parse the existing format.

But, if you want to add a new output format (and option to enable it),
I would be interested in incorporating it. How about:
  brctl --xml show
Jonathan Thibault | 3 Apr 2009 21:49
Favicon

Interesting fragmentation behavior with gretap interface.

I'm trying to bridge a mix of 802.1q tagged and untagged Ethernet frames
through the new Ethernet over GRE functionality in kernel 2.6.28

The hosts handling the tunnel (192.168.200.6, 192.168.200.2) are
connected together through with a simple cross cable through their eth1
interface.  The switches are connected to their respective eth0
interface, which is bridged with their respective gretap interface.

The setup works quite well except when it comes to MTU.  Oddly enough,
802.1q tagged frames get properly fragmented and defragmented, allowing
for a maximum MTU of 1500 (1504 with the tag, I assume).  Untagged
frames larger than 1462 bytes will not make it through the GRE tunnel setup.

                     192.168.200.6       192.168.200.2
(802.1q switch1)<->(eth0-br0-gretap)<->(gretap-br0-eth0)<->(802.1q switch2)

10.0.0.0/12 is my 'untagged' subnet. (default vlan 1, untagged)
192.168.7.0/32 is my tagged subnet. (vlan 800, tagged)

The host I use to test has a NIC in each subnet and is hooked to
switch1, it is pinging hosts on switch2.

First, tagged packets:

$ ping -c 3 -M do -s 1472 192.168.7.175
PING 192.168.7.175 (192.168.7.175) 1472(1500) bytes of data.
1480 bytes from 192.168.7.175: icmp_seq=1 ttl=250 time=36.9 ms
1480 bytes from 192.168.7.175: icmp_seq=2 ttl=250 time=52.1 ms
1480 bytes from 192.168.7.175: icmp_seq=3 ttl=250 time=44.5 ms

--- 192.168.7.175 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 36.994/44.569/52.160/6.191 ms

Normal as can be...  Now untagged:

$ ping -c 3 -M do -s 1472 10.8.1.1
PING 10.8.1.1 (10.8.1.1) 1472(1500) bytes of data.

--- 10.8.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms

Same result all the way down to 1462 bytes, where it actually works:

$ ping -c 3 -M do -s 1434 10.8.1.1
PING 10.8.1.1 (10.8.1.1) 1434(1462) bytes of data.
1442 bytes from 10.8.1.1: icmp_seq=1 ttl=30 time=4.02 ms
1442 bytes from 10.8.1.1: icmp_seq=2 ttl=30 time=4.54 ms
1442 bytes from 10.8.1.1: icmp_seq=3 ttl=30 time=4.22 ms

--- 10.8.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 4.028/4.266/4.547/0.220 ms

It looks suspiciously like this bug:

http://kerneltrap.org/mailarchive/linux-kernel/2007/5/26/96070/thread

Could it be that there now is a special case (as per the suggested
patch) to handle vlan tagged frames, but the special case of
gre-encapsulated non-vlan frames isn't being handled properly?

Hope this makes sense to someone in here...

Jonathan
Tekale Sharad-FHJN78 | 9 Apr 2009 11:46

Out of memory problem

Hi, I'm using linux 2.6.21.5 and our kernel is freeze.
 
The problem is, if I create a Software bridge using $brctl command. and add two interfaces say, eth0.0 and eth0.1 using

$brctl addbr br-lan
$brctl addif br-lan eth0.0
$brctl addif br-lan eth0.1
 
and when i send traffic from a host connected to one port to host connected at other end, soon all the memory is dried up and and kernel crashes,
then oom-killer gets invoked which kills all the processes finally system reboots.
 
I googled for solution or patch, I saw the same defect was reported by some people, but in between only the threaded ended, with no exact solution. Don't know Y???
 
Can any one help me to refer to some patch to point some location in code from where memory is failed to deallocate.
 
Thanks,
Sharad.
_______________________________________________
Bridge mailing list
Bridge <at> lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/bridge
Jiri Pirko | 13 Apr 2009 10:37
Picon
Favicon

[PATCH 0/4] bonding: allow bond in mode balance-alb to work properly in bridge -try5

(resend, updated changelog, completely reworked)

Hi all.

The problem is described in following bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=487763

Basically here's what's going on. In every mode, bonding interface uses the same
mac address for all enslaved devices (except fail_over_mac). Only balance-alb
will simultaneously use multiple MAC addresses across different slaves. When you
put this kind of bond device into a bridge it will only add one of mac adresses
into a hash list of mac addresses, say X. This mac address is marked as local.
But this bonding interface also has mac address Y. Now then packet arrives with
destination address Y, this address is not marked as local and the packed looks
like it needs to be forwarded. This packet is then lost which is wrong.

Notice that interfaces can be added and removed from bond while it is in bridge.

This patchset solves this issue in the best way it can be possibly solved. By
adding all mac addresses of all slave devices to the bridge hash list. To carry
these addresses the new list has to be introduced in struct net_device.

Jirka
Jiri Pirko | 13 Apr 2009 10:38
Picon
Favicon

[PATCH 1/4] net: introduce dev_mac_address_changed

Introducing function dev_mac_address_changed which can be called from driver
which changed his mac address to force notifiers to be called.

Signed-off-by: Jiri Pirko <jpirko <at> redhat.com>
---
 include/linux/netdevice.h |    1 +
 net/core/dev.c            |   12 ++++++++++++
 2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2e7783f..ff8db51 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
 <at>  <at>  -1461,6 +1461,7  <at>  <at>  extern int		dev_change_net_namespace(struct net_device *,
 extern int		dev_set_mtu(struct net_device *, int);
 extern int		dev_set_mac_address(struct net_device *,
 					    struct sockaddr *);
+extern void		dev_mac_address_changed(struct net_device *);
 extern int		dev_hard_start_xmit(struct sk_buff *skb,
 					    struct net_device *dev,
 					    struct netdev_queue *txq);
diff --git a/net/core/dev.c b/net/core/dev.c
index 91d792d..1adc89b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
 <at>  <at>  -3833,6 +3833,18  <at>  <at>  int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
 	return err;
 }

+/**
+ *	dev_mac_address_changed - Notify Media Access Control Address changed
+ *	 <at> dev: device
+ *
+ *	Notifies the change of the hardware (MAC) address of the device
+ */
+void dev_mac_address_changed(struct net_device *dev)
+{
+	call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+}
+EXPORT_SYMBOL(dev_mac_address_changed);
+
 /*
  *	Perform the SIOCxIFxxx calls, inside read_lock(dev_base_lock)
  */
--

-- 
1.6.0.6
Jiri Pirko | 13 Apr 2009 10:42
Picon
Favicon

[PATCH 2/4] net: introduce a list of device addresses dev_addr_list

This patch introduces a new list in struct net_device and brings a set of
functions to handle the work with device address list. The list is a replacement
for the original dev_addr field and because in some situations there is need to
carry several device addresses with the net device. To be backward compatible,
dev_addr is made to point to the first member of the list so original drivers
sees no difference.

Signed-off-by: Jiri Pirko <jpirko <at> redhat.com>
---
 include/linux/netdevice.h |   51 +++++++++-
 net/core/dev.c            |  264 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 313 insertions(+), 2 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ff8db51..8cf62f1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
 <at>  <at>  -210,6 +210,12  <at>  <at>  struct dev_addr_list
 #define dmi_users	da_users
 #define dmi_gusers	da_gusers

+struct hw_addr {
+	struct list_head	list;
+	unsigned char		addr[MAX_ADDR_LEN];
+	int			refcount;
+};
+
 struct hh_cache
 {
 	struct hh_cache *hh_next;	/* Next entry			     */
 <at>  <at>  -776,8 +782,12  <at>  <at>  struct net_device
  */
 	unsigned long		last_rx;	/* Time of last Rx	*/
 	/* Interface address info used in eth_type_trans() */
-	unsigned char		dev_addr[MAX_ADDR_LEN];	/* hw address, (before bcast
-							   because most packets are unicast) */
+	unsigned char		*dev_addr;	/* hw address, (before bcast
+						   because most packets are
+						   unicast) */
+
+	struct list_head	dev_addr_list; /* list of device hw addresses */
+	spinlock_t              dev_addr_list_lock;

 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/

 <at>  <at>  -1779,6 +1789,32  <at>  <at>  static inline void netif_addr_unlock_bh(struct net_device *dev)
 	spin_unlock_bh(&dev->addr_list_lock);
 }

+/* Locking helpers for spinlock guarding dev_addr_list */
+
+static inline void netif_dev_addr_lock(struct net_device *dev)
+{
+	spin_lock(&dev->dev_addr_list_lock);
+}
+
+static inline void netif_dev_addr_lock_bh(struct net_device *dev)
+{
+	spin_lock_bh(&dev->dev_addr_list_lock);
+}
+
+static inline void netif_dev_addr_unlock(struct net_device *dev)
+{
+	spin_unlock(&dev->dev_addr_list_lock);
+}
+
+static inline void netif_dev_addr_unlock_bh(struct net_device *dev)
+{
+	spin_unlock_bh(&dev->dev_addr_list_lock);
+}
+
+/* dev_addr_list walker */
+#define for_each_dev_addr(dev, ha) \
+		list_for_each_entry(ha, &dev->dev_addr_list, list)
+
 /* These functions live elsewhere (drivers/net/net_init.c, but related) */

 extern void		ether_setup(struct net_device *dev);
 <at>  <at>  -1791,6 +1827,17  <at>  <at>  extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 	alloc_netdev_mq(sizeof_priv, name, setup, 1)
 extern int		register_netdev(struct net_device *dev);
 extern void		unregister_netdev(struct net_device *dev);
+
+/* Functions used for device addresses handling */
+extern int		dev_addr_add(struct net_device *dev,
+				     unsigned char *addr);
+extern int		dev_addr_del(struct net_device *dev,
+				     unsigned char *addr);
+extern int		dev_addr_add_multiple(struct net_device *to_dev,
+					      struct net_device *from_dev);
+extern int		dev_addr_del_multiple(struct net_device *to_dev,
+					      struct net_device *from_dev);
+
 /* Functions used for secondary unicast and multicast support */
 extern void		dev_set_rx_mode(struct net_device *dev);
 extern void		__dev_set_rx_mode(struct net_device *dev);
diff --git a/net/core/dev.c b/net/core/dev.c
index 1adc89b..0b154b3 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
 <at>  <at>  -3437,6 +3437,263  <at>  <at>  void dev_set_rx_mode(struct net_device *dev)
 	netif_addr_unlock_bh(dev);
 }

+/* hw addresses list handling functions */
+
+static int __hw_addr_add_ii(struct list_head *list, unsigned char *addr,
+			    int addr_len, int ignore_index)
+{
+	struct hw_addr *ha;
+	int i = 0;
+
+	if (addr_len > MAX_ADDR_LEN)
+		return -EINVAL;
+
+	list_for_each_entry(ha, list, list) {
+		if (i++ != ignore_index &&
+		    !memcmp(ha->addr, addr, addr_len)) {
+			ha->refcount++;
+			return 0;
+		}
+	}
+
+	ha = kzalloc(sizeof(*ha), GFP_ATOMIC);
+	if (!ha)
+		return -ENOMEM;
+	memcpy(ha->addr, addr, addr_len);
+	ha->refcount = 1;
+	list_add_tail(&ha->list, list);
+	return 0;
+}
+
+static inline int __hw_addr_add(struct list_head *list, unsigned char *addr,
+				int addr_len)
+{
+	return __hw_addr_add_ii(list, addr, addr_len, -1);
+}
+
+static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
+			    int addr_len, int ignore_index)
+{
+	struct hw_addr *ha;
+	int i = 0;
+
+	list_for_each_entry(ha, list, list) {
+		if (i++ != ignore_index &&
+		    !memcmp(ha->addr, addr, addr_len)) {
+			if (--ha-≥refcount)
+				return 0;
+			list_del(&ha->list);
+			kfree(ha);
+			return 0;
+		}
+	}
+	return -ENOENT;
+}
+
+static inline int __hw_addr_del(struct list_head *list, unsigned char *addr,
+				int addr_len)
+{
+	return __hw_addr_del_ii(list, addr, addr_len, -1);
+}
+
+static int __hw_addr_add_multiple_ii(struct list_head *to_list,
+				     struct list_head *from_list,
+				     int addr_len, int ignore_index)
+{
+	int err;
+	struct hw_addr *ha, *ha2;
+
+	list_for_each_entry(ha, from_list, list) {
+		err = __hw_addr_add_ii(to_list, ha->addr, addr_len, 0);
+		if (err)
+			goto unroll;
+	}
+	return 0;
+unroll:
+	list_for_each_entry(ha2, from_list, list) {
+		if (ha2 == ha)
+			break;
+		__hw_addr_del_ii(to_list, ha2->addr, addr_len, 0);
+	}
+	return err;
+}
+
+static inline int __hw_addr_add_multiple(struct list_head *to_list,
+					 struct list_head *from_list,
+					 int addr_len)
+{
+	return __hw_addr_add_multiple_ii(to_list, from_list, addr_len, -1);
+}
+
+static void __hw_addr_del_multiple_ii(struct list_head *to_list,
+				      struct list_head *from_list,
+				      int addr_len, int ignore_index)
+{
+	struct hw_addr *ha;
+
+	list_for_each_entry(ha, from_list, list) {
+		__hw_addr_del_ii(to_list, ha->addr, addr_len, 0);
+	}
+}
+
+static inline void __hw_addr_del_multiple(struct list_head *to_list,
+					 struct list_head *from_list,
+					 int addr_len)
+{
+	__hw_addr_del_multiple_ii(to_list, from_list, addr_len, -1);
+}
+
+static void __hw_addr_flush(struct list_head *list)
+{
+	struct hw_addr *ha, *tmp;
+
+	list_for_each_entry_safe(ha, tmp, list, list) {
+		list_del(&ha->list);
+	}
+}
+
+/* Device addresses handling functions */
+
+static void dev_addr_flush(struct net_device *dev)
+{
+	netif_dev_addr_lock_bh(dev);
+	__hw_addr_flush(&dev->dev_addr_list);
+	dev->dev_addr = NULL;
+	netif_dev_addr_unlock_bh(dev);
+}
+
+static int dev_addr_init(struct net_device *dev)
+{
+	unsigned char addr[MAX_ADDR_LEN];
+	struct hw_addr *ha;
+	int err;
+
+	spin_lock_init(&dev->dev_addr_list_lock);
+	INIT_LIST_HEAD(&dev->dev_addr_list);
+	memset(addr, 0, sizeof(*addr));
+	netif_dev_addr_lock_bh(dev);
+	err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr));
+	if (!err) {
+		/*
+		 * Get the first (previously created) address from the list
+		 * and set dev_addr pointer to this location.
+		 */
+		ha = list_first_entry(&dev->dev_addr_list,
+				      struct hw_addr, list);
+		dev->dev_addr = ha->addr;
+	}
+	netif_dev_addr_unlock_bh(dev);
+	return err;
+}
+
+/**
+ *	dev_addr_add	- Add a device address
+ *	 <at> dev: device
+ *	 <at> addr: address to add
+ *
+ *	Add a device address to the device or increase the reference count if
+ *	it already exists.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+int dev_addr_add(struct net_device *dev, unsigned char *addr)
+{
+	int err;
+
+	ASSERT_RTNL();
+
+	netif_dev_addr_lock_bh(dev);
+	err = __hw_addr_add_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
+	netif_dev_addr_unlock_bh(dev);
+	return err;
+}
+EXPORT_SYMBOL(dev_addr_add);
+
+/**
+ *	dev_addr_del	- Release a device address.
+ *	 <at> dev: device
+ *	 <at> addr: address to delete
+ *
+ *	Release reference to a device address and remove it from the device
+ *	if the reference count drops to zero.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+int dev_addr_del(struct net_device *dev, unsigned char *addr)
+{
+	int err;
+
+	ASSERT_RTNL();
+
+	netif_dev_addr_lock_bh(dev);
+	err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
+	netif_dev_addr_unlock_bh(dev);
+	return err;
+}
+EXPORT_SYMBOL(dev_addr_del);
+
+/**
+ *	dev_addr_add_multiple	- Add device addresses from another device
+ *	 <at> to_dev: device to which addresses will be added
+ *	 <at> from_dev: device from which addresses will be added
+ *
+ *	Add device addresses of the one device to another.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+int dev_addr_add_multiple(struct net_device *to_dev,
+			  struct net_device *from_dev)
+{
+	int err;
+
+	ASSERT_RTNL();
+
+	if (from_dev->addr_len != to_dev->addr_len)
+		return -EINVAL;
+
+	netif_dev_addr_lock_bh(from_dev);
+	netif_dev_addr_lock_bh(to_dev);
+	err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
+					&from_dev->dev_addr_list,
+					to_dev->addr_len, 0);
+	netif_dev_addr_unlock_bh(to_dev);
+	netif_dev_addr_unlock_bh(from_dev);
+
+	return err;
+}
+EXPORT_SYMBOL(dev_addr_add_multiple);
+
+/**
+ *	dev_addr_del_multiple	- Delete device addresses by another device
+ *	 <at> to_dev: device where the addresses will be deleted
+ *	 <at> from_dev: device by which addresses the addresses will be deleted
+ *
+ *	Deletes addresses in to device by the list of addresses in from device.
+ *
+ *	The caller must hold the rtnl_mutex.
+ */
+int dev_addr_del_multiple(struct net_device *to_dev,
+			  struct net_device *from_dev)
+{
+	ASSERT_RTNL();
+
+	if (from_dev->addr_len != to_dev->addr_len)
+		return -EINVAL;
+
+	netif_dev_addr_lock_bh(from_dev);
+	netif_dev_addr_lock_bh(to_dev);
+	__hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
+				  &from_dev->dev_addr_list,
+				  to_dev->addr_len, 0);
+	netif_dev_addr_unlock_bh(to_dev);
+	netif_dev_addr_unlock_bh(from_dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(dev_addr_del_multiple);
+
+/* unicast and multicast addresses handling functions */
+
 int __dev_addr_delete(struct dev_addr_list **list, int *count,
 		      void *addr, int alen, int glbl)
 {
 <at>  <at>  -4269,6 +4526,9  <at>  <at>  static void rollback_registered(struct net_device *dev)
 	 */
 	dev_addr_discard(dev);

+	/* Flush device addresses */
+	dev_addr_flush(dev);
+
 	if (dev->netdev_ops->ndo_uninit)
 		dev->netdev_ops->ndo_uninit(dev);

 <at>  <at>  -4791,6 +5051,7  <at>  <at>  struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,

 	dev->gso_max_size = GSO_MAX_SIZE;

+	dev_addr_init(dev);
 	netdev_init_queues(dev);

 	INIT_LIST_HEAD(&dev->napi_list);
 <at>  <at>  -4977,6 +5238,9  <at>  <at>  int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 	 */
 	dev_addr_discard(dev);

+	/* Flush device addresses */
+	dev_addr_flush(dev);
+
 	netdev_unregister_kobject(dev);

 	/* Actually switch the network namespace */
--

-- 
1.6.0.6
Jiri Pirko | 13 Apr 2009 10:44
Picon
Favicon

[PATCH 3/4] net: bridge: use device address list instead of dev_addr

This patch changes the handling of mac addresses of bridge port devices. Now
it uses previously introduced list of device addresses. It allows the bridge to
know more then one local mac address per port which is mandatory for the right
work in some cases.

Signed-off-by: Jiri Pirko <jpirko <at> redhat.com>
---
 net/bridge/br_fdb.c     |  120 +++++++++++++++++++++++++++++++++--------------
 net/bridge/br_if.c      |    2 +-
 net/bridge/br_notify.c  |    2 +-
 net/bridge/br_private.h |    4 +-
 4 files changed, 89 insertions(+), 39 deletions(-)

diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index a48f5ef..6efc556 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
 <at>  <at>  -77,10 +77,45  <at>  <at>  static inline void fdb_delete(struct net_bridge_fdb_entry *f)
 	br_fdb_put(f);
 }

-void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
+/*
+ * Finds out if passed address is one of the addresses assigned to the device.
+ * Returns 1 on positive result
+ */
+static inline int is_dev_addr(struct net_device *dev, unsigned char *addr)
+{
+	struct hw_addr *ha;
+	int ret = 1;
+
+	netif_dev_addr_lock_bh(dev);
+	for_each_dev_addr(dev, ha) {
+		ret = compare_ether_addr(addr, ha->addr);
+		if (!ret)
+			break;
+	}
+	netif_dev_addr_unlock_bh(dev);
+	return !ret ? 1 : 0;
+}
+
+static int another_port_has_addr(const struct net_bridge_port *p,
+				 struct net_bridge_fdb_entry *f)
+{
+	struct net_bridge *br = p->br;
+	struct net_bridge_port *op;
+
+	list_for_each_entry(op, &br->port_list, list) {
+		if (op != p && is_dev_addr(op->dev, f->addr.addr)) {
+			f->dst = op;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void br_fdb_changeaddr(struct net_bridge_port *p, struct net_device *dev)
 {
 	struct net_bridge *br = p->br;
 	int i;
+	struct hw_addr *ha;

 	spin_lock_bh(&br->hash_lock);

 <at>  <at>  -92,26 +127,23  <at>  <at>  void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)

 			f = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
 			if (f->dst == p && f->is_local) {
-				/* maybe another port has same hw addr? */
-				struct net_bridge_port *op;
-				list_for_each_entry(op, &br->port_list, list) {
-					if (op != p &&
-					    !compare_ether_addr(op->dev->dev_addr,
-								f->addr.addr)) {
-						f->dst = op;
-						goto insert;
-					}
-				}
-
-				/* delete old one */
-				fdb_delete(f);
-				goto insert;
+				/*
+				 * maybe another port has same hw addr?,
+				 * if not then delete it
+				 */
+				if (!another_port_has_addr(p, f))
+					fdb_delete(f);
 			}
 		}
 	}
- insert:
-	/* insert new address,  may fail if invalid address or dup. */
-	fdb_insert(br, p, newaddr);
+
+	/* insert device addresses, may fail if invalid address. */
+
+	netif_dev_addr_lock_bh(dev);
+	for_each_dev_addr(dev, ha) {
+		fdb_insert(br, p, ha->addr);
+	}
+	netif_dev_addr_unlock_bh(dev);

 	spin_unlock_bh(&br->hash_lock);
 }
 <at>  <at>  -189,20 +221,9  <at>  <at>  void br_fdb_delete_by_port(struct net_bridge *br,
 			 * then when one port is deleted, assign
 			 * the local entry to other port
 			 */
-			if (f->is_local) {
-				struct net_bridge_port *op;
-				list_for_each_entry(op, &br->port_list, list) {
-					if (op != p &&
-					    !compare_ether_addr(op->dev->dev_addr,
-								f->addr.addr)) {
-						f->dst = op;
-						goto skip_delete;
-					}
-				}
-			}
-
-			fdb_delete(f);
-		skip_delete: ;
+			if (!f->is_local ||
+			    !another_port_has_addr(p, f))
+				fdb_delete(f);
 		}
 	}
 	spin_unlock_bh(&br->hash_lock);
 <at>  <at>  -338,7 +359,7  <at>  <at>  static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
 }

 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
-		  const unsigned char *addr)
+		      const unsigned char *addr)
 {
 	struct hlist_head *head = &br->hash[br_mac_hash(addr)];
 	struct net_bridge_fdb_entry *fdb;
 <at>  <at>  -366,13 +387,42  <at>  <at>  static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 	return 0;
 }

+static int fdb_insert_dev(struct net_bridge *br, struct net_bridge_port *source,
+			  struct net_device *dev)
+{
+	struct hw_addr *ha, *ha2;
+	struct net_bridge_fdb_entry *fdb;
+	struct hlist_head *head;
+	int ret = 0;
+
+	netif_dev_addr_lock_bh(dev);
+	for_each_dev_addr(dev, ha) {
+		ret = fdb_insert(br, source, ha->addr);
+		if (ret)
+			goto unroll;
+	}
+	goto unlock;
+unroll:
+	for_each_dev_addr(dev, ha2) {
+		if (ha2 == ha)
+			break;
+		head = &br->hash[br_mac_hash(ha2->addr)];
+		fdb = fdb_find(head, ha2->addr);
+		if (fdb && fdb->is_local)
+			fdb_delete(fdb);
+	}
+unlock:
+	netif_dev_addr_unlock_bh(dev);
+	return ret;
+}
+
 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
-		  const unsigned char *addr)
+		  struct net_device *dev)
 {
 	int ret;

 	spin_lock_bh(&br->hash_lock);
-	ret = fdb_insert(br, source, addr);
+	ret = fdb_insert_dev(br, source, dev);
 	spin_unlock_bh(&br->hash_lock);
 	return ret;
 }
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 8a96672..789cb30 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
 <at>  <at>  -392,7 +392,7  <at>  <at>  int br_add_if(struct net_bridge *br, struct net_device *dev)
 	if (err)
 		goto err0;

-	err = br_fdb_insert(br, p, dev->dev_addr);
+	err = br_fdb_insert(br, p, dev);
 	if (err)
 		goto err1;

diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 763a3ec..1423541 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
 <at>  <at>  -48,7 +48,7  <at>  <at>  static int br_device_event(struct notifier_block *unused, unsigned long event, v

 	case NETDEV_CHANGEADDR:
 		spin_lock_bh(&br->lock);
-		br_fdb_changeaddr(p, dev->dev_addr);
+		br_fdb_changeaddr(p, dev);
 		br_stp_recalculate_bridge_id(br);
 		spin_unlock_bh(&br->lock);
 		break;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index b6c3b71..65ffe3d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
 <at>  <at>  -148,7 +148,7  <at>  <at>  extern int br_fdb_init(void);
 extern void br_fdb_fini(void);
 extern void br_fdb_flush(struct net_bridge *br);
 extern void br_fdb_changeaddr(struct net_bridge_port *p,
-			      const unsigned char *newaddr);
+			      struct net_device *dev);
 extern void br_fdb_cleanup(unsigned long arg);
 extern void br_fdb_delete_by_port(struct net_bridge *br,
 				  const struct net_bridge_port *p, int do_all);
 <at>  <at>  -161,7 +161,7  <at>  <at>  extern int br_fdb_fillbuf(struct net_bridge *br, void *buf,
 			  unsigned long count, unsigned long off);
 extern int br_fdb_insert(struct net_bridge *br,
 			 struct net_bridge_port *source,
-			 const unsigned char *addr);
+			 struct net_device *dev);
 extern void br_fdb_update(struct net_bridge *br,
 			  struct net_bridge_port *source,
 			  const unsigned char *addr);
--

-- 
1.6.0.6
Jiri Pirko | 13 Apr 2009 10:46
Picon
Favicon

[PATCH 4/4] net: bonding: add slave device addresses in mode alb

When in mode alb, add all device addresses which belong to an enslaved slave
device to the bond device. This ensures that all mac addresses will be
treated as local and bonding in this mode will work fine in bridge.

Signed-off-by: Jiri Pirko <jpirko <at> redhat.com>
---
 drivers/net/bonding/bond_main.c |   30 +++++++++++++++++++++++++++++-
 1 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 99610f3..47795c7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
 <at>  <at>  -1385,6 +1385,11  <at>  <at>  static void bond_setup_by_slave(struct net_device *bond_dev,
 	bond->setup_by_slave = 1;
 }

+static inline int should_copy_dev_addrs(struct bonding *bond)
+{
+	return bond->params.mode == BOND_MODE_ALB ? 1 : 0;
+}
+
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 {
 <at>  <at>  -1510,6 +1515,13  <at>  <at>  int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	 */
 	new_slave->original_flags = slave_dev->flags;

+	if (should_copy_dev_addrs(bond)) {
+		res = dev_addr_add_multiple(bond_dev, slave_dev);
+		if (res)
+			goto err_free;
+		dev_mac_address_changed(bond_dev);
+	}
+
 	/*
 	 * Save slave's original ("permanent") mac address for modes
 	 * that need it, and for restoring it upon release, and then
 <at>  <at>  -1527,7 +1539,7  <at>  <at>  int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		res = dev_set_mac_address(slave_dev, &addr);
 		if (res) {
 			pr_debug("Error %d calling set_mac_address\n", res);
-			goto err_free;
+			goto err_remove_dev_addrs;
 		}
 	}

 <at>  <at>  -1769,6 +1781,12  <at>  <at>  err_restore_mac:
 		dev_set_mac_address(slave_dev, &addr);
 	}

+err_remove_dev_addrs:
+	if (should_copy_dev_addrs(bond)) {
+		dev_addr_del_multiple(bond_dev, slave_dev);
+		dev_mac_address_changed(bond_dev);
+	}
+
 err_free:
 	kfree(new_slave);

 <at>  <at>  -1954,6 +1972,11  <at>  <at>  int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
 	/* close slave before restoring its mac address */
 	dev_close(slave_dev);

+	if (should_copy_dev_addrs(bond)) {
+		dev_addr_del_multiple(bond_dev, slave_dev);
+		dev_mac_address_changed(bond_dev);
+	}
+
 	if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
 		/* restore original ("permanent") mac address */
 		memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
 <at>  <at>  -2090,6 +2113,9  <at>  <at>  static int bond_release_all(struct net_device *bond_dev)
 		/* close slave before restoring its mac address */
 		dev_close(slave_dev);

+		if (should_copy_dev_addrs(bond))
+			dev_addr_del_multiple(bond_dev, slave_dev);
+
 		if (!bond->params.fail_over_mac) {
 			/* restore original ("permanent") mac address*/
 			memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
 <at>  <at>  -2106,6 +2132,8  <at>  <at>  static int bond_release_all(struct net_device *bond_dev)
 		write_lock_bh(&bond->lock);
 	}

+	dev_mac_address_changed(bond_dev);
+
 	/* zero the mac address of the master so it will be
 	 * set by the application to the mac address of the
 	 * first slave
--

-- 
1.6.0.6
Tekale Sharad-FHJN78 | 13 Apr 2009 10:58

Out of memory problem

Hi, I'm using linux 2.6.21.5 and our kernel is freeze.
 
The problem is, if I create a Software bridge using $brctl command. and add two interfaces say, eth0.0 and eth0.1 using

$brctl addbr br-lan
$brctl addif br-lan eth0.0
$brctl addif br-lan eth0.1
 
and when i send traffic from a host connected to one port to host connected at other end, soon all the memory is dried up and and kernel crashes,
then oom-killer gets invoked which kills all the processes finally system reboots.
 
Can any one help me to refer to some patch  or point some location in code from where memory is failed to deallocate.
 
Thanks,
Sharad.
_______________________________________________
Bridge mailing list
Bridge <at> lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/bridge
_______________________________________________
Bridge mailing list
Bridge <at> lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/bridge

Gmane