Skip to content

Commit

Permalink
Merge branch 'dev_addr-const'
Browse files Browse the repository at this point in the history
Jakub Kicinski says:

====================
net: constify netdev->dev_addr

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.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Nov 20, 2021
2 parents 1388d4a + 2c193f2 commit 979594c
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 41 deletions.
2 changes: 1 addition & 1 deletion drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/i825xx/82596.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));

Expand Down
19 changes: 10 additions & 9 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -2117,7 +2119,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;
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -4268,30 +4272,27 @@ 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)
{
__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,
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);
Expand Down
5 changes: 5 additions & 0 deletions net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions net/core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
93 changes: 63 additions & 30 deletions net/core/dev_addr_lists.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand All @@ -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++;
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -498,6 +502,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
Expand All @@ -509,11 +528,11 @@ 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;
}
EXPORT_SYMBOL(dev_addr_flush);

/**
* dev_addr_init - Init device address list
Expand Down Expand Up @@ -547,7 +566,21 @@ 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)
{
struct netdev_hw_addr *ha;

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);

/**
* dev_addr_add - Add a device address
Expand Down
Loading

0 comments on commit 979594c

Please sign in to comment.