netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/7] net: constify netdev->dev_addr
@ 2021-11-19 14:21 Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 1/7] 82596: use eth_hw_addr_set() Jakub Kicinski
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

Take care of a few stragglers and make netdev->dev_addr const.

netdev->dev_addr can be held on the address tree like any other
address now.

Jakub Kicinski (7):
  82596: use eth_hw_addr_set()
  bnx2x: constify static inline stub for dev_addr
  net: constify netdev->dev_addr
  net: unexport dev_addr_init() & dev_addr_flush()
  dev_addr: add a modification check
  dev_addr_list: put the first addr on the tree
  net: kunit: add a test for dev_addr_lists

 .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.h |   2 +-
 drivers/net/ethernet/i825xx/82596.c           |   3 +-
 include/linux/netdevice.h                     |  19 +-
 net/Kconfig                                   |   5 +
 net/core/Makefile                             |   2 +
 net/core/dev.c                                |   1 +
 net/core/dev_addr_lists.c                     |  93 ++++---
 net/core/dev_addr_lists_test.c                | 236 ++++++++++++++++++
 8 files changed, 320 insertions(+), 41 deletions(-)
 create mode 100644 net/core/dev_addr_lists_test.c

-- 
2.31.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 1/7] 82596: use eth_hw_addr_set()
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 2/7] bnx2x: constify static inline stub for dev_addr Jakub Kicinski
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

Byte by byte assignments.

Fixes build on m68k.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/net/ethernet/i825xx/82596.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/i825xx/82596.c b/drivers/net/ethernet/i825xx/82596.c
index b482f6f633bd..3ee89ae496d0 100644
--- a/drivers/net/ethernet/i825xx/82596.c
+++ b/drivers/net/ethernet/i825xx/82596.c
@@ -1178,7 +1178,8 @@ static struct net_device * __init i82596_probe(void)
 	DEB(DEB_PROBE,printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
 
 	for (i = 0; i < 6; i++)
-		DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));
+		DEB(DEB_PROBE,printk(" %2.2X", eth_addr[i]));
+	eth_hw_addr_set(dev, eth_addr);
 
 	DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 2/7] bnx2x: constify static inline stub for dev_addr
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 1/7] 82596: use eth_hw_addr_set() Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 3/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski, kernel test robot

bnx2x_vfpf_config_mac() was constified by not its stub.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index 8c2cf5519787..2dac704dc346 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -586,7 +586,7 @@ static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
 static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
 static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
 static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp, bool is_leading) {return 0; }
-static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr,
+static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, const u8 *addr,
 					u8 vf_qid, bool set) {return 0; }
 static inline int bnx2x_vfpf_config_rss(struct bnx2x *bp,
 					struct bnx2x_config_rss_params *params) {return 0; }
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 3/7] net: constify netdev->dev_addr
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 1/7] 82596: use eth_hw_addr_set() Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 2/7] bnx2x: constify static inline stub for dev_addr Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 4/7] net: unexport dev_addr_init() & dev_addr_flush() Jakub Kicinski
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

Commit 406f42fa0d3c ("net-next: When a bond have a massive amount
of VLANs...") introduced a rbtree for faster Ethernet address look
up. We converted all users to make modifications via appropriate
helpers, make netdev->dev_addr const.

The update helpers need to upcast from the buffer to
struct netdev_hw_addr.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/linux/netdevice.h | 14 +++++---------
 net/core/dev_addr_lists.c | 10 ++++++++++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4f4a299e92de..2462195784a9 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2117,7 +2117,7 @@ struct net_device {
  * Cache lines mostly used on receive path (including eth_type_trans())
  */
 	/* Interface address info used in eth_type_trans() */
-	unsigned char		*dev_addr;
+	const unsigned char	*dev_addr;
 
 	struct netdev_rx_queue	*_rx;
 	unsigned int		num_rx_queues;
@@ -4268,10 +4268,13 @@ void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list,
 void __hw_addr_init(struct netdev_hw_addr_list *list);
 
 /* Functions used for device addresses handling */
+void dev_addr_mod(struct net_device *dev, unsigned int offset,
+		  const void *addr, size_t len);
+
 static inline void
 __dev_addr_set(struct net_device *dev, const void *addr, size_t len)
 {
-	memcpy(dev->dev_addr, addr, len);
+	dev_addr_mod(dev, 0, addr, len);
 }
 
 static inline void dev_addr_set(struct net_device *dev, const u8 *addr)
@@ -4279,13 +4282,6 @@ static inline void dev_addr_set(struct net_device *dev, const u8 *addr)
 	__dev_addr_set(dev, addr, dev->addr_len);
 }
 
-static inline void
-dev_addr_mod(struct net_device *dev, unsigned int offset,
-	     const void *addr, size_t len)
-{
-	memcpy(&dev->dev_addr[offset], addr, len);
-}
-
 int dev_addr_add(struct net_device *dev, const unsigned char *addr,
 		 unsigned char addr_type);
 int dev_addr_del(struct net_device *dev, const unsigned char *addr,
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index f0cb38344126..ae8b1ef00fec 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -549,6 +549,16 @@ int dev_addr_init(struct net_device *dev)
 }
 EXPORT_SYMBOL(dev_addr_init);
 
+void dev_addr_mod(struct net_device *dev, unsigned int offset,
+		  const void *addr, size_t len)
+{
+	struct netdev_hw_addr *ha;
+
+	ha = container_of(dev->dev_addr, struct netdev_hw_addr, addr[0]);
+	memcpy(&ha->addr[offset], addr, len);
+}
+EXPORT_SYMBOL(dev_addr_mod);
+
 /**
  *	dev_addr_add - Add a device address
  *	@dev: device
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 4/7] net: unexport dev_addr_init() & dev_addr_flush()
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (2 preceding siblings ...)
  2021-11-19 14:21 ` [PATCH net-next v2 3/7] net: constify netdev->dev_addr Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 5/7] dev_addr: add a modification check Jakub Kicinski
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

There are no module callers in-tree and it's hard to justify
why anyone would init or flush addresses of a netdev (note
the flush is more of a destructor, it frees netdev->dev_addr).

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/core/dev_addr_lists.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index ae8b1ef00fec..a23a83ac18e5 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -513,7 +513,6 @@ void dev_addr_flush(struct net_device *dev)
 	__hw_addr_flush(&dev->dev_addrs);
 	dev->dev_addr = NULL;
 }
-EXPORT_SYMBOL(dev_addr_flush);
 
 /**
  *	dev_addr_init - Init device address list
@@ -547,7 +546,6 @@ int dev_addr_init(struct net_device *dev)
 	}
 	return err;
 }
-EXPORT_SYMBOL(dev_addr_init);
 
 void dev_addr_mod(struct net_device *dev, unsigned int offset,
 		  const void *addr, size_t len)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 5/7] dev_addr: add a modification check
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (3 preceding siblings ...)
  2021-11-19 14:21 ` [PATCH net-next v2 4/7] net: unexport dev_addr_init() & dev_addr_flush() Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 6/7] dev_addr_list: put the first addr on the tree Jakub Kicinski
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

netdev->dev_addr should only be modified via helpers,
but someone may be casting off the const. Add a runtime
check to catch abuses.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 include/linux/netdevice.h |  5 +++++
 net/core/dev.c            |  1 +
 net/core/dev_addr_lists.c | 19 +++++++++++++++++++
 3 files changed, 25 insertions(+)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2462195784a9..cb7f2661d187 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1942,6 +1942,8 @@ enum netdev_ml_priv_type {
  *	@unlink_list:	As netif_addr_lock() can be called recursively,
  *			keep a list of interfaces to be deleted.
  *
+ *	@dev_addr_shadow:	Copy of @dev_addr to catch direct writes.
+ *
  *	FIXME: cleanup struct net_device such that network protocol info
  *	moves out.
  */
@@ -2268,6 +2270,8 @@ struct net_device {
 
 	/* protected by rtnl_lock */
 	struct bpf_xdp_entity	xdp_state[__MAX_XDP_MODE];
+
+	u8 dev_addr_shadow[MAX_ADDR_LEN];
 };
 #define to_net_dev(d) container_of(d, struct net_device, dev)
 
@@ -4288,6 +4292,7 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr,
 		 unsigned char addr_type);
 void dev_addr_flush(struct net_device *dev);
 int dev_addr_init(struct net_device *dev);
+void dev_addr_check(struct net_device *dev);
 
 /* Functions used for unicast addresses handling */
 int dev_uc_add(struct net_device *dev, const unsigned char *addr);
diff --git a/net/core/dev.c b/net/core/dev.c
index 92c9258cbf28..9219e319e901 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1377,6 +1377,7 @@ static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
 	int ret;
 
 	ASSERT_RTNL();
+	dev_addr_check(dev);
 
 	if (!netif_device_present(dev)) {
 		/* may be detached because parent is runtime-suspended */
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index a23a83ac18e5..969942734951 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -498,6 +498,21 @@ EXPORT_SYMBOL(__hw_addr_init);
  * Device addresses handling functions
  */
 
+/* Check that netdev->dev_addr is not written to directly as this would
+ * break the rbtree layout. All changes should go thru dev_addr_set() and co.
+ * Remove this check in mid-2024.
+ */
+void dev_addr_check(struct net_device *dev)
+{
+	if (!memcmp(dev->dev_addr, dev->dev_addr_shadow, MAX_ADDR_LEN))
+		return;
+
+	netdev_warn(dev, "Current addr:  %*ph\n", MAX_ADDR_LEN, dev->dev_addr);
+	netdev_warn(dev, "Expected addr: %*ph\n",
+		    MAX_ADDR_LEN, dev->dev_addr_shadow);
+	netdev_WARN(dev, "Incorrect netdev->dev_addr\n");
+}
+
 /**
  *	dev_addr_flush - Flush device address list
  *	@dev: device
@@ -509,6 +524,7 @@ EXPORT_SYMBOL(__hw_addr_init);
 void dev_addr_flush(struct net_device *dev)
 {
 	/* rtnl_mutex must be held here */
+	dev_addr_check(dev);
 
 	__hw_addr_flush(&dev->dev_addrs);
 	dev->dev_addr = NULL;
@@ -552,8 +568,11 @@ void dev_addr_mod(struct net_device *dev, unsigned int offset,
 {
 	struct netdev_hw_addr *ha;
 
+	dev_addr_check(dev);
+
 	ha = container_of(dev->dev_addr, struct netdev_hw_addr, addr[0]);
 	memcpy(&ha->addr[offset], addr, len);
+	memcpy(&dev->dev_addr_shadow[offset], addr, len);
 }
 EXPORT_SYMBOL(dev_addr_mod);
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 6/7] dev_addr_list: put the first addr on the tree
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (4 preceding siblings ...)
  2021-11-19 14:21 ` [PATCH net-next v2 5/7] dev_addr: add a modification check Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 14:21 ` [PATCH net-next v2 7/7] net: kunit: add a test for dev_addr_lists Jakub Kicinski
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

Since all netdev->dev_addr modifications go via dev_addr_mod()
we can put it on the list. When address is change remove it
and add it back.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/core/dev_addr_lists.c | 62 +++++++++++++++++++++------------------
 1 file changed, 34 insertions(+), 28 deletions(-)

diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 969942734951..bead38ca50bd 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -16,6 +16,35 @@
  * General list handling functions
  */
 
+static int __hw_addr_insert(struct netdev_hw_addr_list *list,
+			    struct netdev_hw_addr *new, int addr_len)
+{
+	struct rb_node **ins_point = &list->tree.rb_node, *parent = NULL;
+	struct netdev_hw_addr *ha;
+
+	while (*ins_point) {
+		int diff;
+
+		ha = rb_entry(*ins_point, struct netdev_hw_addr, node);
+		diff = memcmp(new->addr, ha->addr, addr_len);
+		if (diff == 0)
+			diff = memcmp(&new->type, &ha->type, sizeof(new->type));
+
+		parent = *ins_point;
+		if (diff < 0)
+			ins_point = &parent->rb_left;
+		else if (diff > 0)
+			ins_point = &parent->rb_right;
+		else
+			return -EEXIST;
+	}
+
+	rb_link_node_rcu(&new->node, parent, ins_point);
+	rb_insert_color(&new->node, &list->tree);
+
+	return 0;
+}
+
 static struct netdev_hw_addr*
 __hw_addr_create(const unsigned char *addr, int addr_len,
 		 unsigned char addr_type, bool global, bool sync)
@@ -50,11 +79,6 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
 	if (addr_len > MAX_ADDR_LEN)
 		return -EINVAL;
 
-	ha = list_first_entry(&list->list, struct netdev_hw_addr, list);
-	if (ha && !memcmp(addr, ha->addr, addr_len) &&
-	    (!addr_type || addr_type == ha->type))
-		goto found_it;
-
 	while (*ins_point) {
 		int diff;
 
@@ -69,7 +93,6 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
 		} else if (diff > 0) {
 			ins_point = &parent->rb_right;
 		} else {
-found_it:
 			if (exclusive)
 				return -EEXIST;
 			if (global) {
@@ -94,16 +117,8 @@ static int __hw_addr_add_ex(struct netdev_hw_addr_list *list,
 	if (!ha)
 		return -ENOMEM;
 
-	/* The first address in dev->dev_addrs is pointed to by dev->dev_addr
-	 * and mutated freely by device drivers and netdev ops, so if we insert
-	 * it into the tree we'll end up with an invalid rbtree.
-	 */
-	if (list->count > 0) {
-		rb_link_node(&ha->node, parent, ins_point);
-		rb_insert_color(&ha->node, &list->tree);
-	} else {
-		RB_CLEAR_NODE(&ha->node);
-	}
+	rb_link_node(&ha->node, parent, ins_point);
+	rb_insert_color(&ha->node, &list->tree);
 
 	list_add_tail_rcu(&ha->list, &list->list);
 	list->count++;
@@ -138,8 +153,7 @@ static int __hw_addr_del_entry(struct netdev_hw_addr_list *list,
 	if (--ha->refcount)
 		return 0;
 
-	if (!RB_EMPTY_NODE(&ha->node))
-		rb_erase(&ha->node, &list->tree);
+	rb_erase(&ha->node, &list->tree);
 
 	list_del_rcu(&ha->list);
 	kfree_rcu(ha, rcu_head);
@@ -151,18 +165,8 @@ static struct netdev_hw_addr *__hw_addr_lookup(struct netdev_hw_addr_list *list,
 					       const unsigned char *addr, int addr_len,
 					       unsigned char addr_type)
 {
-	struct netdev_hw_addr *ha;
 	struct rb_node *node;
 
-	/* The first address isn't inserted into the tree because in the dev->dev_addrs
-	 * list it's the address pointed to by dev->dev_addr which is freely mutated
-	 * in place, so we need to check it separately.
-	 */
-	ha = list_first_entry(&list->list, struct netdev_hw_addr, list);
-	if (ha && !memcmp(addr, ha->addr, addr_len) &&
-	    (!addr_type || addr_type == ha->type))
-		return ha;
-
 	node = list->tree.rb_node;
 
 	while (node) {
@@ -571,8 +575,10 @@ void dev_addr_mod(struct net_device *dev, unsigned int offset,
 	dev_addr_check(dev);
 
 	ha = container_of(dev->dev_addr, struct netdev_hw_addr, addr[0]);
+	rb_erase(&ha->node, &dev->dev_addrs.tree);
 	memcpy(&ha->addr[offset], addr, len);
 	memcpy(&dev->dev_addr_shadow[offset], addr, len);
+	WARN_ON(__hw_addr_insert(&dev->dev_addrs, ha, dev->addr_len));
 }
 EXPORT_SYMBOL(dev_addr_mod);
 
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 7/7] net: kunit: add a test for dev_addr_lists
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (5 preceding siblings ...)
  2021-11-19 14:21 ` [PATCH net-next v2 6/7] dev_addr_list: put the first addr on the tree Jakub Kicinski
@ 2021-11-19 14:21 ` Jakub Kicinski
  2021-11-19 15:46 ` [PATCH net-next v2 0/7] net: constify netdev->dev_addr David Miller
  2021-11-20 12:30 ` patchwork-bot+netdevbpf
  8 siblings, 0 replies; 10+ messages in thread
From: Jakub Kicinski @ 2021-11-19 14:21 UTC (permalink / raw)
  To: davem; +Cc: netdev, Jakub Kicinski

Add a KUnit test for the dev_addr API.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 net/Kconfig                    |   5 +
 net/core/Makefile              |   2 +
 net/core/dev_addr_lists_test.c | 236 +++++++++++++++++++++++++++++++++
 3 files changed, 243 insertions(+)
 create mode 100644 net/core/dev_addr_lists_test.c

diff --git a/net/Kconfig b/net/Kconfig
index 074472dfa94a..8a1f9d0287de 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -455,4 +455,9 @@ config ETHTOOL_NETLINK
 	  netlink. It provides better extensibility and some new features,
 	  e.g. notification messages.
 
+config NETDEV_ADDR_LIST_TEST
+	tristate "Unit tests for device address list"
+	default KUNIT_ALL_TESTS
+	depends on KUNIT
+
 endif   # if NET
diff --git a/net/core/Makefile b/net/core/Makefile
index 6bdcb2cafed8..a8e4f737692b 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -13,6 +13,8 @@ obj-y		     += dev.o dev_addr_lists.o dst.o netevent.o \
 			sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
 			fib_notifier.o xdp.o flow_offload.o gro.o
 
+obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
+
 obj-y += net-sysfs.o
 obj-$(CONFIG_PAGE_POOL) += page_pool.o
 obj-$(CONFIG_PROC_FS) += net-procfs.o
diff --git a/net/core/dev_addr_lists_test.c b/net/core/dev_addr_lists_test.c
new file mode 100644
index 000000000000..049cfbc58aa9
--- /dev/null
+++ b/net/core/dev_addr_lists_test.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <kunit/test.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+
+static const struct net_device_ops dummy_netdev_ops = {
+};
+
+struct dev_addr_test_priv {
+	u32 addr_seen;
+};
+
+static int dev_addr_test_sync(struct net_device *netdev, const unsigned char *a)
+{
+	struct dev_addr_test_priv *datp = netdev_priv(netdev);
+
+	if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
+		datp->addr_seen |= 1 << a[0];
+	return 0;
+}
+
+static int dev_addr_test_unsync(struct net_device *netdev,
+				const unsigned char *a)
+{
+	struct dev_addr_test_priv *datp = netdev_priv(netdev);
+
+	if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
+		datp->addr_seen &= ~(1 << a[0]);
+	return 0;
+}
+
+static int dev_addr_test_init(struct kunit *test)
+{
+	struct dev_addr_test_priv *datp;
+	struct net_device *netdev;
+	int err;
+
+	netdev = alloc_etherdev(sizeof(*datp));
+	KUNIT_ASSERT_TRUE(test, !!netdev);
+
+	test->priv = netdev;
+	netdev->netdev_ops = &dummy_netdev_ops;
+
+	err = register_netdev(netdev);
+	if (err) {
+		free_netdev(netdev);
+		KUNIT_FAIL(test, "Can't register netdev %d", err);
+	}
+
+	rtnl_lock();
+	return 0;
+}
+
+static void dev_addr_test_exit(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+
+	rtnl_unlock();
+	unregister_netdev(netdev);
+	free_netdev(netdev);
+}
+
+static void dev_addr_test_basic(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	u8 addr[ETH_ALEN];
+
+	KUNIT_EXPECT_TRUE(test, !!netdev->dev_addr);
+
+	memset(addr, 2, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+	KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
+
+	memset(addr, 3, sizeof(addr));
+	dev_addr_set(netdev, addr);
+	KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
+}
+
+static void dev_addr_test_sync_one(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	struct dev_addr_test_priv *datp;
+	u8 addr[ETH_ALEN];
+
+	datp = netdev_priv(netdev);
+
+	memset(addr, 1, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	KUNIT_EXPECT_EQ(test, 2, datp->addr_seen);
+
+	memset(addr, 2, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+
+	datp->addr_seen = 0;
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	/* It's not going to sync anything because the main address is
+	 * considered synced and we overwrite in place.
+	 */
+	KUNIT_EXPECT_EQ(test, 0, datp->addr_seen);
+}
+
+static void dev_addr_test_add_del(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	struct dev_addr_test_priv *datp;
+	u8 addr[ETH_ALEN];
+	int i;
+
+	datp = netdev_priv(netdev);
+
+	for (i = 1; i < 4; i++) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
+						      NETDEV_HW_ADDR_T_LAN));
+	}
+	/* Add 3 again */
+	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
+					      NETDEV_HW_ADDR_T_LAN));
+
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
+
+	KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
+					      NETDEV_HW_ADDR_T_LAN));
+
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
+
+	for (i = 1; i < 4; i++) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
+						      NETDEV_HW_ADDR_T_LAN));
+	}
+
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	KUNIT_EXPECT_EQ(test, 1, datp->addr_seen);
+}
+
+static void dev_addr_test_del_main(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	u8 addr[ETH_ALEN];
+
+	memset(addr, 1, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+
+	KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
+						    NETDEV_HW_ADDR_T_LAN));
+	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
+					      NETDEV_HW_ADDR_T_LAN));
+	KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
+					      NETDEV_HW_ADDR_T_LAN));
+	KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
+						    NETDEV_HW_ADDR_T_LAN));
+}
+
+static void dev_addr_test_add_set(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	struct dev_addr_test_priv *datp;
+	u8 addr[ETH_ALEN];
+	int i;
+
+	datp = netdev_priv(netdev);
+
+	/* There is no external API like dev_addr_add_excl(),
+	 * so shuffle the tree a little bit and exploit aliasing.
+	 */
+	for (i = 1; i < 16; i++) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
+						      NETDEV_HW_ADDR_T_LAN));
+	}
+
+	memset(addr, i, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
+					      NETDEV_HW_ADDR_T_LAN));
+	memset(addr, 0, sizeof(addr));
+	eth_hw_addr_set(netdev, addr);
+
+	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
+			   dev_addr_test_unsync);
+	KUNIT_EXPECT_EQ(test, 0xffff, datp->addr_seen);
+}
+
+static void dev_addr_test_add_excl(struct kunit *test)
+{
+	struct net_device *netdev = test->priv;
+	u8 addr[ETH_ALEN];
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, 0, dev_uc_add_excl(netdev, addr));
+	}
+	KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
+
+	for (i = 0; i < 10; i += 2) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
+	}
+	for (i = 1; i < 10; i += 2) {
+		memset(addr, i, sizeof(addr));
+		KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
+	}
+}
+
+static struct kunit_case dev_addr_test_cases[] = {
+	KUNIT_CASE(dev_addr_test_basic),
+	KUNIT_CASE(dev_addr_test_sync_one),
+	KUNIT_CASE(dev_addr_test_add_del),
+	KUNIT_CASE(dev_addr_test_del_main),
+	KUNIT_CASE(dev_addr_test_add_set),
+	KUNIT_CASE(dev_addr_test_add_excl),
+	{}
+};
+
+static struct kunit_suite dev_addr_test_suite = {
+	.name = "dev-addr-list-test",
+	.test_cases = dev_addr_test_cases,
+	.init = dev_addr_test_init,
+	.exit = dev_addr_test_exit,
+};
+kunit_test_suite(dev_addr_test_suite);
+
+MODULE_LICENSE("GPL");
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 0/7] net: constify netdev->dev_addr
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (6 preceding siblings ...)
  2021-11-19 14:21 ` [PATCH net-next v2 7/7] net: kunit: add a test for dev_addr_lists Jakub Kicinski
@ 2021-11-19 15:46 ` David Miller
  2021-11-20 12:30 ` patchwork-bot+netdevbpf
  8 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2021-11-19 15:46 UTC (permalink / raw)
  To: kuba; +Cc: netdev

From: Jakub Kicinski <kuba@kernel.org>
Date: Fri, 19 Nov 2021 06:21:48 -0800

> Take care of a few stragglers and make netdev->dev_addr const.
> 
> netdev->dev_addr can be held on the address tree like any other
> address now.

Acked-by: David S. Miller <davem@davemloft.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 0/7] net: constify netdev->dev_addr
  2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
                   ` (7 preceding siblings ...)
  2021-11-19 15:46 ` [PATCH net-next v2 0/7] net: constify netdev->dev_addr David Miller
@ 2021-11-20 12:30 ` patchwork-bot+netdevbpf
  8 siblings, 0 replies; 10+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-11-20 12:30 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev

Hello:

This series was applied to netdev/net-next.git (master)
by David S. Miller <davem@davemloft.net>:

On Fri, 19 Nov 2021 06:21:48 -0800 you wrote:
> Take care of a few stragglers and make netdev->dev_addr const.
> 
> netdev->dev_addr can be held on the address tree like any other
> address now.
> 
> Jakub Kicinski (7):
>   82596: use eth_hw_addr_set()
>   bnx2x: constify static inline stub for dev_addr
>   net: constify netdev->dev_addr
>   net: unexport dev_addr_init() & dev_addr_flush()
>   dev_addr: add a modification check
>   dev_addr_list: put the first addr on the tree
>   net: kunit: add a test for dev_addr_lists
> 
> [...]

Here is the summary with links:
  - [net-next,v2,1/7] 82596: use eth_hw_addr_set()
    https://git.kernel.org/netdev/net-next/c/0f98d7e47843
  - [net-next,v2,2/7] bnx2x: constify static inline stub for dev_addr
    https://git.kernel.org/netdev/net-next/c/c9646a18033e
  - [net-next,v2,3/7] net: constify netdev->dev_addr
    https://git.kernel.org/netdev/net-next/c/adeef3e32146
  - [net-next,v2,4/7] net: unexport dev_addr_init() & dev_addr_flush()
    https://git.kernel.org/netdev/net-next/c/5f0b69238427
  - [net-next,v2,5/7] dev_addr: add a modification check
    https://git.kernel.org/netdev/net-next/c/d07b26f5bbea
  - [net-next,v2,6/7] dev_addr_list: put the first addr on the tree
    https://git.kernel.org/netdev/net-next/c/a387ff8e5dda
  - [net-next,v2,7/7] net: kunit: add a test for dev_addr_lists
    https://git.kernel.org/netdev/net-next/c/2c193f2cb110

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2021-11-20 12:30 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-11-19 14:21 [PATCH net-next v2 0/7] net: constify netdev->dev_addr Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 1/7] 82596: use eth_hw_addr_set() Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 2/7] bnx2x: constify static inline stub for dev_addr Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 3/7] net: constify netdev->dev_addr Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 4/7] net: unexport dev_addr_init() & dev_addr_flush() Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 5/7] dev_addr: add a modification check Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 6/7] dev_addr_list: put the first addr on the tree Jakub Kicinski
2021-11-19 14:21 ` [PATCH net-next v2 7/7] net: kunit: add a test for dev_addr_lists Jakub Kicinski
2021-11-19 15:46 ` [PATCH net-next v2 0/7] net: constify netdev->dev_addr David Miller
2021-11-20 12:30 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).