All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jiri Pirko <jpirko@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: netdev@vger.kernel.org, jgarzik@pobox.com, davem@davemloft.net,
	shemminger@linux-foundation.org,
	bridge@lists.linux-foundation.org, fubar@us.ibm.com,
	bonding-devel@lists.sourceforge.net, kaber@trash.net,
	mschmidt@redhat.com, dada1@cosmosbay.com, ivecera@redhat.com
Subject: Re: [PATCH 1/3] net: introduce a list of device addresses dev_addr_list (v4)
Date: Thu, 23 Apr 2009 10:09:55 +0200	[thread overview]
Message-ID: <20090423080954.GC29268@psychotron.englab.brq.redhat.com> (raw)
In-Reply-To: <20090420161156.GC24584@psychotron.englab.brq.redhat.com>

Mon, Apr 20, 2009 at 06:11:56PM CEST, jpirko@redhat.com wrote:
>How about this (and another 2 patches in patchset)? What's your opinion guys?

Eric, Stephen, Patrick? Can you please look at this? Any objections?
>
>Thanks,
>
>Jirka
>
>Sat, Apr 18, 2009 at 10:58:49AM CEST, jpirko@redhat.com wrote:
>>v3 -> v4 (current):
>>-changed kzalloc to kmalloc in __hw_addr_add_ii()
>>-ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init()
>>
>>v2 -> v3:
>>-removed unnecessary rcu read locking
>>-moved dev_addr_flush() calling to ensure no null dereference of dev_addr
>>
>>v1 -> v2:
>>-added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush
>>-removed unnecessary rcu_read locking in dev_addr_init
>>-use compare_ether_addr_64bits instead of compare_ether_addr
>>-use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr
>>-use call_rcu instead of rcu_synchronize
>>-moved is_etherdev_addr into __KERNEL__ ifdef
>>
>>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@redhat.com>
>>---
>> include/linux/etherdevice.h |   27 +++++
>> include/linux/netdevice.h   |   32 +++++-
>> net/core/dev.c              |  261 +++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 318 insertions(+), 2 deletions(-)
>>
>>diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
>>index a1f17ab..3d7a668 100644
>>--- a/include/linux/etherdevice.h
>>+++ b/include/linux/etherdevice.h
>>@@ -182,6 +182,33 @@ static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2],
>> 	return compare_ether_addr(addr1, addr2);
>> #endif
>> }
>>+
>>+/**
>>+ * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
>>+ * @dev: Pointer to a device structure
>>+ * @addr: Pointer to a six-byte array containing the Ethernet address
>>+ *
>>+ * Compare passed address with all addresses of the device. Return true if the
>>+ * address if one of the device addresses.
>>+ *
>>+ * Note that this function calls compare_ether_addr_64bits() so take care of
>>+ * the right padding.
>>+ */
>>+static inline bool is_etherdev_addr(const struct net_device *dev,
>>+				    const u8 addr[6 + 2])
>>+{
>>+	struct netdev_hw_addr *ha;
>>+	int res = 1;
>>+
>>+	rcu_read_lock();
>>+	for_each_dev_addr(dev, ha) {
>>+		res = compare_ether_addr_64bits(addr, ha->addr);
>>+		if (!res)
>>+			break;
>>+	}
>>+	rcu_read_unlock();
>>+	return !res;
>>+}
>> #endif	/* __KERNEL__ */
>> 
>> /**
>>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>index 2e7783f..89ad6d2 100644
>>--- a/include/linux/netdevice.h
>>+++ b/include/linux/netdevice.h
>>@@ -210,6 +210,13 @@ struct dev_addr_list
>> #define dmi_users	da_users
>> #define dmi_gusers	da_gusers
>> 
>>+struct netdev_hw_addr {
>>+	struct list_head	list;
>>+	unsigned char		addr[MAX_ADDR_LEN];
>>+	int			refcount;
>>+	struct rcu_head		rcu_head;
>>+};
>>+
>> struct hh_cache
>> {
>> 	struct hh_cache *hh_next;	/* Next entry			     */
>>@@ -776,8 +783,11 @@ 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 */
>> 
>> 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
>> 
>>@@ -1778,6 +1788,13 @@ static inline void netif_addr_unlock_bh(struct net_device *dev)
>> 	spin_unlock_bh(&dev->addr_list_lock);
>> }
>> 
>>+/*
>>+ * dev_addr_list walker. Should be used only for read access. Call with
>>+ * rcu_read_lock held.
>>+ */
>>+#define for_each_dev_addr(dev, ha) \
>>+		list_for_each_entry_rcu(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);
>>@@ -1790,6 +1807,17 @@ 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 343883f..2274294 100644
>>--- a/net/core/dev.c
>>+++ b/net/core/dev.c
>>@@ -3438,6 +3438,263 @@ 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 netdev_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 = kmalloc(max(sizeof(*ha), L1_CACHE_BYTES), GFP_ATOMIC);
>>+	if (!ha)
>>+		return -ENOMEM;
>>+	memcpy(ha->addr, addr, addr_len);
>>+	ha->refcount = 1;
>>+	list_add_tail_rcu(&ha->list, list);
>>+	return 0;
>>+}
>>+
>>+static 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 void ha_rcu_free(struct rcu_head *head)
>>+{
>>+	struct netdev_hw_addr *ha;
>>+
>>+	ha = container_of(head, struct netdev_hw_addr, rcu_head);
>>+	kfree(ha);
>>+}
>>+
>>+static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
>>+			    int addr_len, int ignore_index)
>>+{
>>+	struct netdev_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_rcu(&ha->list);
>>+			call_rcu(&ha->rcu_head, ha_rcu_free);
>>+			return 0;
>>+		}
>>+	}
>>+	return -ENOENT;
>>+}
>>+
>>+static 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 netdev_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 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 netdev_hw_addr *ha;
>>+
>>+	list_for_each_entry(ha, from_list, list) {
>>+		__hw_addr_del_ii(to_list, ha->addr, addr_len, 0);
>>+	}
>>+}
>>+
>>+static 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 netdev_hw_addr *ha, *tmp;
>>+
>>+	list_for_each_entry_safe(ha, tmp, list, list) {
>>+		list_del_rcu(&ha->list);
>>+		call_rcu(&ha->rcu_head, ha_rcu_free);
>>+	}
>>+}
>>+
>>+/* Device addresses handling functions */
>>+
>>+static void dev_addr_flush(struct net_device *dev)
>>+{
>>+	/* rtnl_mutex must be held here */
>>+
>>+	__hw_addr_flush(&dev->dev_addr_list);
>>+	dev->dev_addr = NULL;
>>+}
>>+
>>+static int dev_addr_init(struct net_device *dev)
>>+{
>>+	unsigned char addr[MAX_ADDR_LEN];
>>+	struct netdev_hw_addr *ha;
>>+	int err;
>>+
>>+	/* rtnl_mutex must be held here */
>>+
>>+	INIT_LIST_HEAD(&dev->dev_addr_list);
>>+	memset(addr, 0, sizeof(*addr));
>>+	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 netdev_hw_addr, list);
>>+		dev->dev_addr = ha->addr;
>>+	}
>>+	return err;
>>+}
>>+
>>+/**
>>+ *	dev_addr_add	- Add a device address
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_add_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add);
>>+
>>+/**
>>+ *	dev_addr_del	- Release a device address.
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_del);
>>+
>>+/**
>>+ *	dev_addr_add_multiple	- Add device addresses from another device
>>+ *	@to_dev: device to which addresses will be added
>>+ *	@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;
>>+	err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+					&from_dev->dev_addr_list,
>>+					to_dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add_multiple);
>>+
>>+/**
>>+ *	dev_addr_del_multiple	- Delete device addresses by another device
>>+ *	@to_dev: device where the addresses will be deleted
>>+ *	@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;
>>+	__hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+				  &from_dev->dev_addr_list,
>>+				  to_dev->addr_len, 0);
>>+	call_netdevice_notifiers(NETDEV_CHANGEADDR, to_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)
>> {
>>@@ -4780,6 +5037,7 @@ 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);
>>@@ -4805,6 +5063,9 @@ void free_netdev(struct net_device *dev)
>> 
>> 	kfree(dev->_tx);
>> 
>>+	/* Flush device addresses */
>>+	dev_addr_flush(dev);
>>+
>> 	list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
>> 		netif_napi_del(p);
>> 
>>-- 
>>1.6.0.6
>>

WARNING: multiple messages have this Message-ID (diff)
From: Jiri Pirko <jpirko@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: ivecera@redhat.com, fubar@us.ibm.com, netdev@vger.kernel.org,
	bridge@lists.linux-foundation.org, mschmidt@redhat.com,
	bonding-devel@lists.sourceforge.net, jgarzik@pobox.com,
	dada1@cosmosbay.com, davem@davemloft.net
Subject: Re: [PATCH 1/3] net: introduce a list of device addresses	dev_addr_list (v4)
Date: Thu, 23 Apr 2009 10:09:55 +0200	[thread overview]
Message-ID: <20090423080954.GC29268@psychotron.englab.brq.redhat.com> (raw)
In-Reply-To: <20090420161156.GC24584@psychotron.englab.brq.redhat.com>

Mon, Apr 20, 2009 at 06:11:56PM CEST, jpirko@redhat.com wrote:
>How about this (and another 2 patches in patchset)? What's your opinion guys?

Eric, Stephen, Patrick? Can you please look at this? Any objections?
>
>Thanks,
>
>Jirka
>
>Sat, Apr 18, 2009 at 10:58:49AM CEST, jpirko@redhat.com wrote:
>>v3 -> v4 (current):
>>-changed kzalloc to kmalloc in __hw_addr_add_ii()
>>-ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init()
>>
>>v2 -> v3:
>>-removed unnecessary rcu read locking
>>-moved dev_addr_flush() calling to ensure no null dereference of dev_addr
>>
>>v1 -> v2:
>>-added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush
>>-removed unnecessary rcu_read locking in dev_addr_init
>>-use compare_ether_addr_64bits instead of compare_ether_addr
>>-use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr
>>-use call_rcu instead of rcu_synchronize
>>-moved is_etherdev_addr into __KERNEL__ ifdef
>>
>>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@redhat.com>
>>---
>> include/linux/etherdevice.h |   27 +++++
>> include/linux/netdevice.h   |   32 +++++-
>> net/core/dev.c              |  261 +++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 318 insertions(+), 2 deletions(-)
>>
>>diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
>>index a1f17ab..3d7a668 100644
>>--- a/include/linux/etherdevice.h
>>+++ b/include/linux/etherdevice.h
>>@@ -182,6 +182,33 @@ static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2],
>> 	return compare_ether_addr(addr1, addr2);
>> #endif
>> }
>>+
>>+/**
>>+ * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
>>+ * @dev: Pointer to a device structure
>>+ * @addr: Pointer to a six-byte array containing the Ethernet address
>>+ *
>>+ * Compare passed address with all addresses of the device. Return true if the
>>+ * address if one of the device addresses.
>>+ *
>>+ * Note that this function calls compare_ether_addr_64bits() so take care of
>>+ * the right padding.
>>+ */
>>+static inline bool is_etherdev_addr(const struct net_device *dev,
>>+				    const u8 addr[6 + 2])
>>+{
>>+	struct netdev_hw_addr *ha;
>>+	int res = 1;
>>+
>>+	rcu_read_lock();
>>+	for_each_dev_addr(dev, ha) {
>>+		res = compare_ether_addr_64bits(addr, ha->addr);
>>+		if (!res)
>>+			break;
>>+	}
>>+	rcu_read_unlock();
>>+	return !res;
>>+}
>> #endif	/* __KERNEL__ */
>> 
>> /**
>>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>index 2e7783f..89ad6d2 100644
>>--- a/include/linux/netdevice.h
>>+++ b/include/linux/netdevice.h
>>@@ -210,6 +210,13 @@ struct dev_addr_list
>> #define dmi_users	da_users
>> #define dmi_gusers	da_gusers
>> 
>>+struct netdev_hw_addr {
>>+	struct list_head	list;
>>+	unsigned char		addr[MAX_ADDR_LEN];
>>+	int			refcount;
>>+	struct rcu_head		rcu_head;
>>+};
>>+
>> struct hh_cache
>> {
>> 	struct hh_cache *hh_next;	/* Next entry			     */
>>@@ -776,8 +783,11 @@ 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 */
>> 
>> 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
>> 
>>@@ -1778,6 +1788,13 @@ static inline void netif_addr_unlock_bh(struct net_device *dev)
>> 	spin_unlock_bh(&dev->addr_list_lock);
>> }
>> 
>>+/*
>>+ * dev_addr_list walker. Should be used only for read access. Call with
>>+ * rcu_read_lock held.
>>+ */
>>+#define for_each_dev_addr(dev, ha) \
>>+		list_for_each_entry_rcu(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);
>>@@ -1790,6 +1807,17 @@ 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 343883f..2274294 100644
>>--- a/net/core/dev.c
>>+++ b/net/core/dev.c
>>@@ -3438,6 +3438,263 @@ 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 netdev_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 = kmalloc(max(sizeof(*ha), L1_CACHE_BYTES), GFP_ATOMIC);
>>+	if (!ha)
>>+		return -ENOMEM;
>>+	memcpy(ha->addr, addr, addr_len);
>>+	ha->refcount = 1;
>>+	list_add_tail_rcu(&ha->list, list);
>>+	return 0;
>>+}
>>+
>>+static 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 void ha_rcu_free(struct rcu_head *head)
>>+{
>>+	struct netdev_hw_addr *ha;
>>+
>>+	ha = container_of(head, struct netdev_hw_addr, rcu_head);
>>+	kfree(ha);
>>+}
>>+
>>+static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
>>+			    int addr_len, int ignore_index)
>>+{
>>+	struct netdev_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_rcu(&ha->list);
>>+			call_rcu(&ha->rcu_head, ha_rcu_free);
>>+			return 0;
>>+		}
>>+	}
>>+	return -ENOENT;
>>+}
>>+
>>+static 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 netdev_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 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 netdev_hw_addr *ha;
>>+
>>+	list_for_each_entry(ha, from_list, list) {
>>+		__hw_addr_del_ii(to_list, ha->addr, addr_len, 0);
>>+	}
>>+}
>>+
>>+static 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 netdev_hw_addr *ha, *tmp;
>>+
>>+	list_for_each_entry_safe(ha, tmp, list, list) {
>>+		list_del_rcu(&ha->list);
>>+		call_rcu(&ha->rcu_head, ha_rcu_free);
>>+	}
>>+}
>>+
>>+/* Device addresses handling functions */
>>+
>>+static void dev_addr_flush(struct net_device *dev)
>>+{
>>+	/* rtnl_mutex must be held here */
>>+
>>+	__hw_addr_flush(&dev->dev_addr_list);
>>+	dev->dev_addr = NULL;
>>+}
>>+
>>+static int dev_addr_init(struct net_device *dev)
>>+{
>>+	unsigned char addr[MAX_ADDR_LEN];
>>+	struct netdev_hw_addr *ha;
>>+	int err;
>>+
>>+	/* rtnl_mutex must be held here */
>>+
>>+	INIT_LIST_HEAD(&dev->dev_addr_list);
>>+	memset(addr, 0, sizeof(*addr));
>>+	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 netdev_hw_addr, list);
>>+		dev->dev_addr = ha->addr;
>>+	}
>>+	return err;
>>+}
>>+
>>+/**
>>+ *	dev_addr_add	- Add a device address
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_add_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add);
>>+
>>+/**
>>+ *	dev_addr_del	- Release a device address.
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_del);
>>+
>>+/**
>>+ *	dev_addr_add_multiple	- Add device addresses from another device
>>+ *	@to_dev: device to which addresses will be added
>>+ *	@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;
>>+	err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+					&from_dev->dev_addr_list,
>>+					to_dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add_multiple);
>>+
>>+/**
>>+ *	dev_addr_del_multiple	- Delete device addresses by another device
>>+ *	@to_dev: device where the addresses will be deleted
>>+ *	@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;
>>+	__hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+				  &from_dev->dev_addr_list,
>>+				  to_dev->addr_len, 0);
>>+	call_netdevice_notifiers(NETDEV_CHANGEADDR, to_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)
>> {
>>@@ -4780,6 +5037,7 @@ 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);
>>@@ -4805,6 +5063,9 @@ void free_netdev(struct net_device *dev)
>> 
>> 	kfree(dev->_tx);
>> 
>>+	/* Flush device addresses */
>>+	dev_addr_flush(dev);
>>+
>> 	list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
>> 		netif_napi_del(p);
>> 
>>-- 
>>1.6.0.6
>>

WARNING: multiple messages have this Message-ID (diff)
From: Jiri Pirko <jpirko@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: ivecera@redhat.com, fubar@us.ibm.com, netdev@vger.kernel.org,
	bridge@lists.linux-foundation.org, mschmidt@redhat.com,
	bonding-devel@lists.sourceforge.net, jgarzik@pobox.com,
	dada1@cosmosbay.com, davem@davemloft.net
Subject: Re: [Bridge] [PATCH 1/3] net: introduce a list of device addresses	dev_addr_list (v4)
Date: Thu, 23 Apr 2009 10:09:55 +0200	[thread overview]
Message-ID: <20090423080954.GC29268@psychotron.englab.brq.redhat.com> (raw)
In-Reply-To: <20090420161156.GC24584@psychotron.englab.brq.redhat.com>

Mon, Apr 20, 2009 at 06:11:56PM CEST, jpirko@redhat.com wrote:
>How about this (and another 2 patches in patchset)? What's your opinion guys?

Eric, Stephen, Patrick? Can you please look at this? Any objections?
>
>Thanks,
>
>Jirka
>
>Sat, Apr 18, 2009 at 10:58:49AM CEST, jpirko@redhat.com wrote:
>>v3 -> v4 (current):
>>-changed kzalloc to kmalloc in __hw_addr_add_ii()
>>-ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init()
>>
>>v2 -> v3:
>>-removed unnecessary rcu read locking
>>-moved dev_addr_flush() calling to ensure no null dereference of dev_addr
>>
>>v1 -> v2:
>>-added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush
>>-removed unnecessary rcu_read locking in dev_addr_init
>>-use compare_ether_addr_64bits instead of compare_ether_addr
>>-use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr
>>-use call_rcu instead of rcu_synchronize
>>-moved is_etherdev_addr into __KERNEL__ ifdef
>>
>>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@redhat.com>
>>---
>> include/linux/etherdevice.h |   27 +++++
>> include/linux/netdevice.h   |   32 +++++-
>> net/core/dev.c              |  261 +++++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 318 insertions(+), 2 deletions(-)
>>
>>diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
>>index a1f17ab..3d7a668 100644
>>--- a/include/linux/etherdevice.h
>>+++ b/include/linux/etherdevice.h
>>@@ -182,6 +182,33 @@ static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2],
>> 	return compare_ether_addr(addr1, addr2);
>> #endif
>> }
>>+
>>+/**
>>+ * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
>>+ * @dev: Pointer to a device structure
>>+ * @addr: Pointer to a six-byte array containing the Ethernet address
>>+ *
>>+ * Compare passed address with all addresses of the device. Return true if the
>>+ * address if one of the device addresses.
>>+ *
>>+ * Note that this function calls compare_ether_addr_64bits() so take care of
>>+ * the right padding.
>>+ */
>>+static inline bool is_etherdev_addr(const struct net_device *dev,
>>+				    const u8 addr[6 + 2])
>>+{
>>+	struct netdev_hw_addr *ha;
>>+	int res = 1;
>>+
>>+	rcu_read_lock();
>>+	for_each_dev_addr(dev, ha) {
>>+		res = compare_ether_addr_64bits(addr, ha->addr);
>>+		if (!res)
>>+			break;
>>+	}
>>+	rcu_read_unlock();
>>+	return !res;
>>+}
>> #endif	/* __KERNEL__ */
>> 
>> /**
>>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>index 2e7783f..89ad6d2 100644
>>--- a/include/linux/netdevice.h
>>+++ b/include/linux/netdevice.h
>>@@ -210,6 +210,13 @@ struct dev_addr_list
>> #define dmi_users	da_users
>> #define dmi_gusers	da_gusers
>> 
>>+struct netdev_hw_addr {
>>+	struct list_head	list;
>>+	unsigned char		addr[MAX_ADDR_LEN];
>>+	int			refcount;
>>+	struct rcu_head		rcu_head;
>>+};
>>+
>> struct hh_cache
>> {
>> 	struct hh_cache *hh_next;	/* Next entry			     */
>>@@ -776,8 +783,11 @@ 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 */
>> 
>> 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
>> 
>>@@ -1778,6 +1788,13 @@ static inline void netif_addr_unlock_bh(struct net_device *dev)
>> 	spin_unlock_bh(&dev->addr_list_lock);
>> }
>> 
>>+/*
>>+ * dev_addr_list walker. Should be used only for read access. Call with
>>+ * rcu_read_lock held.
>>+ */
>>+#define for_each_dev_addr(dev, ha) \
>>+		list_for_each_entry_rcu(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);
>>@@ -1790,6 +1807,17 @@ 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 343883f..2274294 100644
>>--- a/net/core/dev.c
>>+++ b/net/core/dev.c
>>@@ -3438,6 +3438,263 @@ 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 netdev_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 = kmalloc(max(sizeof(*ha), L1_CACHE_BYTES), GFP_ATOMIC);
>>+	if (!ha)
>>+		return -ENOMEM;
>>+	memcpy(ha->addr, addr, addr_len);
>>+	ha->refcount = 1;
>>+	list_add_tail_rcu(&ha->list, list);
>>+	return 0;
>>+}
>>+
>>+static 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 void ha_rcu_free(struct rcu_head *head)
>>+{
>>+	struct netdev_hw_addr *ha;
>>+
>>+	ha = container_of(head, struct netdev_hw_addr, rcu_head);
>>+	kfree(ha);
>>+}
>>+
>>+static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
>>+			    int addr_len, int ignore_index)
>>+{
>>+	struct netdev_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_rcu(&ha->list);
>>+			call_rcu(&ha->rcu_head, ha_rcu_free);
>>+			return 0;
>>+		}
>>+	}
>>+	return -ENOENT;
>>+}
>>+
>>+static 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 netdev_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 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 netdev_hw_addr *ha;
>>+
>>+	list_for_each_entry(ha, from_list, list) {
>>+		__hw_addr_del_ii(to_list, ha->addr, addr_len, 0);
>>+	}
>>+}
>>+
>>+static 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 netdev_hw_addr *ha, *tmp;
>>+
>>+	list_for_each_entry_safe(ha, tmp, list, list) {
>>+		list_del_rcu(&ha->list);
>>+		call_rcu(&ha->rcu_head, ha_rcu_free);
>>+	}
>>+}
>>+
>>+/* Device addresses handling functions */
>>+
>>+static void dev_addr_flush(struct net_device *dev)
>>+{
>>+	/* rtnl_mutex must be held here */
>>+
>>+	__hw_addr_flush(&dev->dev_addr_list);
>>+	dev->dev_addr = NULL;
>>+}
>>+
>>+static int dev_addr_init(struct net_device *dev)
>>+{
>>+	unsigned char addr[MAX_ADDR_LEN];
>>+	struct netdev_hw_addr *ha;
>>+	int err;
>>+
>>+	/* rtnl_mutex must be held here */
>>+
>>+	INIT_LIST_HEAD(&dev->dev_addr_list);
>>+	memset(addr, 0, sizeof(*addr));
>>+	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 netdev_hw_addr, list);
>>+		dev->dev_addr = ha->addr;
>>+	}
>>+	return err;
>>+}
>>+
>>+/**
>>+ *	dev_addr_add	- Add a device address
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_add_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add);
>>+
>>+/**
>>+ *	dev_addr_del	- Release a device address.
>>+ *	@dev: device
>>+ *	@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();
>>+
>>+	err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_del);
>>+
>>+/**
>>+ *	dev_addr_add_multiple	- Add device addresses from another device
>>+ *	@to_dev: device to which addresses will be added
>>+ *	@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;
>>+	err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+					&from_dev->dev_addr_list,
>>+					to_dev->addr_len, 0);
>>+	if (!err)
>>+		call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
>>+	return err;
>>+}
>>+EXPORT_SYMBOL(dev_addr_add_multiple);
>>+
>>+/**
>>+ *	dev_addr_del_multiple	- Delete device addresses by another device
>>+ *	@to_dev: device where the addresses will be deleted
>>+ *	@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;
>>+	__hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
>>+				  &from_dev->dev_addr_list,
>>+				  to_dev->addr_len, 0);
>>+	call_netdevice_notifiers(NETDEV_CHANGEADDR, to_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)
>> {
>>@@ -4780,6 +5037,7 @@ 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);
>>@@ -4805,6 +5063,9 @@ void free_netdev(struct net_device *dev)
>> 
>> 	kfree(dev->_tx);
>> 
>>+	/* Flush device addresses */
>>+	dev_addr_flush(dev);
>>+
>> 	list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
>> 		netif_napi_del(p);
>> 
>>-- 
>>1.6.0.6
>>

  reply	other threads:[~2009-04-23  8:16 UTC|newest]

Thread overview: 213+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-03-13 18:33 [PATCH] bonding: allow bond in mode balance-alb to work properly in bridge Jiri Pirko
2009-03-13 18:33 ` [Bridge] " Jiri Pirko
2009-03-14  5:39 ` Stephen Hemminger
2009-03-14  5:39   ` [Bridge] " Stephen Hemminger
2009-03-14  9:49   ` Jiri Pirko
2009-03-14  9:49     ` [Bridge] " Jiri Pirko
2009-03-15 23:12     ` Stephen Hemminger
2009-03-15 23:12       ` [Bridge] " Stephen Hemminger
2009-03-16 11:11       ` Jiri Pirko
2009-03-16 11:11         ` [Bridge] " Jiri Pirko
2009-03-19  6:20         ` David Miller
2009-03-19  6:20           ` [Bridge] " David Miller
2009-03-19  8:44           ` Jiri Pirko
2009-03-19  8:44             ` [Bridge] " Jiri Pirko
2009-03-19 10:21             ` David Miller
2009-03-19 10:21               ` [Bridge] " David Miller
2009-03-19 11:19               ` Jiri Pirko
2009-03-19 11:19                 ` [Bridge] " Jiri Pirko
2009-03-19  8:50           ` Patrick McHardy
2009-03-19  8:50             ` [Bridge] " Patrick McHardy
2009-03-19 16:31             ` Jiri Pirko
2009-03-19 16:31               ` [Bridge] " Jiri Pirko
2009-03-25 13:04 ` [PATCH] bonding: allow bond in mode balance-alb to work properly in bridge -try2 Jiri Pirko
2009-03-25 13:04   ` [Bridge] " Jiri Pirko
2009-03-25 13:40   ` Eric Dumazet
2009-03-25 13:40     ` [Bridge] " Eric Dumazet
2009-03-25 14:39     ` Jiri Pirko
2009-03-25 14:39       ` [Bridge] " Jiri Pirko
2009-03-25 15:19 ` [PATCH] bonding: allow bond in mode balance-alb to work properly in bridge -try3 Jiri Pirko
2009-03-25 15:19   ` [Bridge] " Jiri Pirko
2009-03-25 16:31   ` Jay Vosburgh
2009-03-25 16:31     ` [Bridge] " Jay Vosburgh
2009-03-25 17:44     ` Jiri Pirko
2009-03-25 17:44       ` [Bridge] " Jiri Pirko
2009-03-26  0:24       ` David Miller
2009-03-26  0:24         ` [Bridge] " David Miller
2009-03-26  0:34       ` Jay Vosburgh
2009-03-26  0:34         ` [Bridge] " Jay Vosburgh
2009-03-26 11:12     ` Jiri Pirko
2009-03-26 11:12       ` [Bridge] " Jiri Pirko
2009-03-26 15:52 ` [PATCH] bonding: allow bond in mode balance-alb to work properly in bridge -try4 Jiri Pirko
2009-03-26 15:52   ` [Bridge] " Jiri Pirko
2009-03-27  7:38   ` David Miller
2009-03-27  7:38     ` [Bridge] " David Miller
2009-03-27  7:46     ` Jiri Pirko
2009-03-27  7:46       ` [Bridge] " Jiri Pirko
2009-03-27  7:53     ` Patrick McHardy
2009-03-27  7:53       ` [Bridge] " Patrick McHardy
2009-03-27  8:41       ` Jiri Pirko
2009-03-27  8:41         ` [Bridge] " Jiri Pirko
2009-03-27  8:55         ` Patrick McHardy
2009-03-27  8:55           ` [Bridge] " Patrick McHardy
2009-03-27  9:47           ` Jiri Pirko
2009-03-27  9:47             ` [Bridge] " Jiri Pirko
2009-03-29 20:53       ` David Miller
2009-03-29 20:53         ` [Bridge] " David Miller
2009-03-30 12:04         ` Patrick McHardy
2009-03-30 12:04           ` [Bridge] " Patrick McHardy
2009-03-30 12:40           ` Jiri Pirko
2009-03-30 12:40             ` [Bridge] " Jiri Pirko
2009-03-30 12:47             ` Patrick McHardy
2009-03-30 12:47               ` [Bridge] " Patrick McHardy
2009-03-30 12:52               ` Jiri Pirko
2009-03-30 12:52                 ` [Bridge] " Jiri Pirko
2009-03-30 12:58                 ` Patrick McHardy
2009-03-30 12:58                   ` [Bridge] " Patrick McHardy
2009-05-26 15:17   ` [PATCH net-next] bonding: allow bond in mode balance-alb to work properly in bridge -try4.1 Jiri Pirko
2009-05-26 15:17     ` [Bridge] " Jiri Pirko
2009-05-26 16:32     ` Andy Gospodarek
2009-05-26 16:32       ` [Bridge] " Andy Gospodarek
2009-05-27  8:25       ` Jiri Pirko
2009-05-27  8:25         ` [Bridge] " Jiri Pirko
2009-05-26 16:59     ` Eric Dumazet
2009-05-26 16:59       ` [Bridge] " Eric Dumazet
2009-05-27  8:42       ` Jiri Pirko
2009-05-27  8:42         ` [Bridge] " Jiri Pirko
2009-05-27 13:53     ` [PATCH net-next] bonding: allow bond in mode balance-alb to work properly in bridge -try4.2 Jiri Pirko
2009-05-27 13:53       ` [Bridge] " Jiri Pirko
2009-05-27 14:39       ` Eric Dumazet
2009-05-27 14:39         ` [Bridge] " Eric Dumazet
2009-05-28  9:57         ` Jiri Pirko
2009-05-28  9:57           ` [Bridge] " Jiri Pirko
2009-05-28 11:05       ` [PATCH net-next] bonding: allow bond in mode balance-alb to work properly in bridge -try4.3 Jiri Pirko
2009-05-28 11:05         ` [Bridge] " Jiri Pirko
2009-05-28 11:41         ` Eric Dumazet
2009-05-28 11:41           ` [Bridge] " Eric Dumazet
2009-05-29  8:52           ` David Miller
2009-05-29  8:52             ` [Bridge] " David Miller
2009-05-28 12:11         ` Andy Gospodarek
2009-05-28 12:11           ` [Bridge] " Andy Gospodarek
2009-04-13  8:37 ` [PATCH 0/4] bonding: allow bond in mode balance-alb to work properly in bridge -try5 Jiri Pirko
2009-04-13  8:37   ` [Bridge] " Jiri Pirko
2009-04-13  8:38   ` [PATCH 1/4] net: introduce dev_mac_address_changed Jiri Pirko
2009-04-13  8:38     ` [Bridge] " Jiri Pirko
2009-04-13 14:58     ` Stephen Hemminger
2009-04-13 14:58       ` [Bridge] " Stephen Hemminger
2009-04-13  8:42   ` [PATCH 2/4] net: introduce a list of device addresses dev_addr_list Jiri Pirko
2009-04-13  8:42     ` [Bridge] " Jiri Pirko
2009-04-13 14:49     ` Stephen Hemminger
2009-04-13 14:49       ` [Bridge] " Stephen Hemminger
2009-04-13 22:54       ` David Miller
2009-04-13 22:54         ` [Bridge] " David Miller
2009-04-13 22:53     ` David Miller
2009-04-13 22:53       ` [Bridge] " David Miller
2009-04-13  8:44   ` [PATCH 3/4] net: bridge: use device address list instead of dev_addr Jiri Pirko
2009-04-13  8:44     ` [Bridge] " Jiri Pirko
2009-04-13 14:54     ` Stephen Hemminger
2009-04-13 14:54       ` [Bridge] " Stephen Hemminger
2009-04-14 10:15       ` Jiri Pirko
2009-04-14 10:15         ` [Bridge] " Jiri Pirko
2009-04-13 22:54     ` David Miller
2009-04-13 22:54       ` [Bridge] " David Miller
2009-04-13  8:46   ` [PATCH 4/4] net: bonding: add slave device addresses in mode alb Jiri Pirko
2009-04-13  8:46     ` [Bridge] " Jiri Pirko
2009-04-13 14:56     ` Stephen Hemminger
2009-04-13 14:56       ` [Bridge] " Stephen Hemminger
2009-04-15  8:17 ` [PATCH 0/3] bonding: allow bond in mode balance-alb to work properly in bridge -try6 Jiri Pirko
2009-04-15  8:17   ` [Bridge] " Jiri Pirko
2009-04-15  8:18   ` [PATCH 1/3] net: introduce a list of device addresses dev_addr_list Jiri Pirko
2009-04-15  8:18     ` [Bridge] " Jiri Pirko
2009-04-15  8:26     ` Li Zefan
2009-04-15  8:26       ` [Bridge] " Li Zefan
2009-04-15  8:29       ` Jiri Pirko
2009-04-15  8:29         ` [Bridge] " Jiri Pirko
2009-04-15  8:32       ` Jiri Pirko
2009-04-15  8:32         ` [Bridge] " Jiri Pirko
2009-04-15  9:21         ` David Miller
2009-04-15  9:21           ` [Bridge] " David Miller
2009-04-15  9:27         ` Eric Dumazet
2009-04-15  9:27           ` [Bridge] " Eric Dumazet
2009-04-15  9:31           ` David Miller
2009-04-15  9:31             ` [Bridge] " David Miller
2009-04-15 10:13             ` Patrick McHardy
2009-04-15 10:13               ` [Bridge] " Patrick McHardy
2009-04-15 10:15               ` David Miller
2009-04-15 10:15                 ` [Bridge] " David Miller
2009-04-15 10:41                 ` Patrick McHardy
2009-04-15 10:41                   ` [Bridge] " Patrick McHardy
2009-04-15 10:45                   ` David Miller
2009-04-15 10:45                     ` [Bridge] " David Miller
2009-04-15 10:47                     ` Patrick McHardy
2009-04-15 10:47                       ` [Bridge] " Patrick McHardy
2009-04-15 14:42               ` Jiri Pirko
2009-04-15 14:42                 ` [Bridge] " Jiri Pirko
2009-04-15 11:17           ` Jiri Pirko
2009-04-15 11:17             ` [Bridge] " Jiri Pirko
2009-04-15 11:22             ` Patrick McHardy
2009-04-15 11:22               ` [Bridge] " Patrick McHardy
2009-04-15 11:28               ` Jiri Pirko
2009-04-15 11:28                 ` [Bridge] " Jiri Pirko
2009-04-15 12:28             ` Eric Dumazet
2009-04-15 12:28               ` [Bridge] " Eric Dumazet
2009-04-15 18:02     ` [PATCH 1/3] net: introduce a list of device addresses dev_addr_list (v2) Jiri Pirko
2009-04-15 18:02       ` [Bridge] " Jiri Pirko
2009-04-15 18:54       ` Eric Dumazet
2009-04-15 18:54         ` [Bridge] " Eric Dumazet
2009-04-16  8:46         ` Jiri Pirko
2009-04-16  8:46           ` [Bridge] " Jiri Pirko
2009-04-17 11:57       ` [PATCH 1/3] net: introduce a list of device addresses dev_addr_list (v3) Jiri Pirko
2009-04-17 11:57         ` [Bridge] " Jiri Pirko
2009-04-17 15:33         ` Stephen Hemminger
2009-04-17 15:33           ` [Bridge] " Stephen Hemminger
2009-04-18  7:01           ` Jiri Pirko
2009-04-18  7:01             ` [Bridge] " Jiri Pirko
2009-04-18  7:35             ` Eric Dumazet
2009-04-18  7:35               ` [Bridge] " Eric Dumazet
2009-04-18  7:44               ` Jiri Pirko
2009-04-18  7:44                 ` [Bridge] " Jiri Pirko
2009-04-18  8:06                 ` Eric Dumazet
2009-04-18  8:06                   ` [Bridge] " Eric Dumazet
2009-04-18  8:58         ` [PATCH 1/3] net: introduce a list of device addresses dev_addr_list (v4) Jiri Pirko
2009-04-18  8:58           ` [Bridge] " Jiri Pirko
2009-04-20 16:11           ` Jiri Pirko
2009-04-20 16:11             ` [Bridge] " Jiri Pirko
2009-04-23  8:09             ` Jiri Pirko [this message]
2009-04-23  8:09               ` Jiri Pirko
2009-04-23  8:09               ` Jiri Pirko
2009-04-23 15:58           ` [Bonding-devel] " Stephen Hemminger
2009-04-23 15:58             ` [Bridge] " Stephen Hemminger
2009-04-24 21:26             ` Jiri Pirko
2009-04-24 21:26               ` [Bridge] " Jiri Pirko
2009-05-04 11:14           ` [PATCH] net: introduce a list of device addresses dev_addr_list (v5) Jiri Pirko
2009-05-04 11:14             ` [Bridge] " Jiri Pirko
2009-05-05  4:37             ` David Miller
2009-05-05  4:37               ` [Bridge] " David Miller
2009-05-05  6:37               ` Jiri Pirko
2009-05-05  6:37                 ` [Bridge] " Jiri Pirko
2009-05-05 12:48             ` [PATCH] net: introduce a list of device addresses dev_addr_list (v6) Jiri Pirko
2009-05-05 12:48               ` [Bridge] " Jiri Pirko
2009-05-05 19:27               ` David Miller
2009-05-05 19:27                 ` [Bridge] " David Miller
2009-05-08 22:38                 ` Stephen Hemminger
2009-05-08 22:38                   ` [Bridge] " Stephen Hemminger
2009-05-08 23:00                   ` David Miller
2009-05-08 23:00                     ` [Bridge] " David Miller
2009-05-08 23:12                     ` Stephen Hemminger
2009-05-08 23:12                       ` [Bridge] " Stephen Hemminger
2009-05-08 23:25                       ` David Miller
2009-05-08 23:25                         ` [Bridge] " David Miller
2009-05-08 23:29                         ` Stephen Hemminger
2009-05-08 23:29                           ` [Bridge] " Stephen Hemminger
2009-04-15  8:21   ` [PATCH 2/3] net: bridge: use device address list instead of dev_addr Jiri Pirko
2009-04-15  8:21     ` [Bridge] " Jiri Pirko
2009-05-06 14:46     ` [PATCH net-next] net: bridge: use device address list instead of dev_addr (repost) Jiri Pirko
2009-05-06 14:46       ` [Bridge] " Jiri Pirko
2009-05-06 15:08       ` Eric Dumazet
2009-05-06 15:08         ` [Bridge] " Eric Dumazet
2009-05-06 19:26       ` Stephen Hemminger
2009-05-06 19:26         ` [Bridge] " Stephen Hemminger
2009-05-07 22:03         ` David Miller
2009-05-07 22:03           ` [Bridge] " David Miller
2009-04-15  8:22   ` [PATCH 3/3] net: bonding: add slave device addresses in mode alb Jiri Pirko
2009-04-15  8:22     ` [Bridge] " Jiri Pirko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090423080954.GC29268@psychotron.englab.brq.redhat.com \
    --to=jpirko@redhat.com \
    --cc=bonding-devel@lists.sourceforge.net \
    --cc=bridge@lists.linux-foundation.org \
    --cc=dada1@cosmosbay.com \
    --cc=davem@davemloft.net \
    --cc=fubar@us.ibm.com \
    --cc=ivecera@redhat.com \
    --cc=jgarzik@pobox.com \
    --cc=kaber@trash.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mschmidt@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=shemminger@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.