Skip to content

Commit 522185d

Browse files
committed
Merge branch 'Introduce-NETDEV_PRE_CHANGEADDR'
Petr Machata says: ==================== Introduce NETDEV_PRE_CHANGEADDR Spectrum devices have a limitation that all router interfaces need to have the same address prefix. In Spectrum-1, the requirement is for the initial 38 bits of all RIFs to be the same, in Spectrum-2 the limit is 36 bits. Currently violations of this requirement are not diagnosed. At the same time, if the condition is not upheld, the mismatched MAC address ends up overwriting the common prefix, and all RIF MAC addresses silently change to the new prefix. It is therefore desirable to be able at least to diagnose the issue, and better to reject attempts to change MAC addresses in ways that is incompatible with the device. Currently MAC address changes are notified through emission of NETDEV_CHANGEADDR, which is done after the change. Extending this message to allow vetoing is certainly possible, but several other notification types have instead adopted a simple two-stage approach: first a "pre" notification is sent to make sure all interested parties are OK with the change that's about to be done. Then the change is done, and afterwards a "post" notification is sent. This dual approach is easier to use: when the change is vetoed, nothing has changed yet, and it's therefore unnecessary to roll anything back. Therefore this patchset introduces it for NETDEV_CHANGEADDR as well. One prominent path to emitting NETDEV_CHANGEADDR is through dev_set_mac_address(). Therefore in patch #1, give this function an extack argument, so that a textual reason for rejection (or a warning) can be communicated back to the user. In patch #2, add the new notification type. In patch #3, have dev.c emit the notification for instances of dev_addr change, or addition of an address to dev_addrs list. In patches #4 and #5, extend the bridge driver to handle and emit the new notifier. In patch #6, change IPVLAN to emit the new notifier. Likewise for bonding driver in patches #7 and #8. Note that the team driver doesn't need this treatment, as it goes through dev_set_mac_address(). In patches #9, #10 and #11 adapt mlxsw to veto MAC addresses on router interfaces, if they violate the requirement that all RIF MAC addresses have the same prefix. Finally in patches #12 and #13, add a test for vetoing of a direct change of a port device MAC, and indirect change of a bridge MAC. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 95302c3 + 9651ee1 commit 522185d

File tree

21 files changed

+385
-46
lines changed

21 files changed

+385
-46
lines changed

drivers/net/bonding/bond_alb.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[],
10311031
*/
10321032
memcpy(ss.__data, addr, len);
10331033
ss.ss_family = dev->type;
1034-
if (dev_set_mac_address(dev, (struct sockaddr *)&ss)) {
1034+
if (dev_set_mac_address(dev, (struct sockaddr *)&ss, NULL)) {
10351035
netdev_err(slave->bond->dev, "dev_set_mac_address of dev %s failed! ALB mode requires that the base driver support setting the hw address also when the network device's interface is open\n",
10361036
dev->name);
10371037
return -EOPNOTSUPP;
@@ -1250,7 +1250,7 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
12501250
bond_hw_addr_copy(tmp_addr, slave->dev->dev_addr,
12511251
slave->dev->addr_len);
12521252

1253-
res = dev_set_mac_address(slave->dev, addr);
1253+
res = dev_set_mac_address(slave->dev, addr, NULL);
12541254

12551255
/* restore net_device's hw address */
12561256
bond_hw_addr_copy(slave->dev->dev_addr, tmp_addr,
@@ -1273,7 +1273,7 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
12731273
bond_hw_addr_copy(tmp_addr, rollback_slave->dev->dev_addr,
12741274
rollback_slave->dev->addr_len);
12751275
dev_set_mac_address(rollback_slave->dev,
1276-
(struct sockaddr *)&ss);
1276+
(struct sockaddr *)&ss, NULL);
12771277
bond_hw_addr_copy(rollback_slave->dev->dev_addr, tmp_addr,
12781278
rollback_slave->dev->addr_len);
12791279
}
@@ -1732,7 +1732,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
17321732
bond->dev->addr_len);
17331733
ss.ss_family = bond->dev->type;
17341734
/* we don't care if it can't change its mac, best effort */
1735-
dev_set_mac_address(new_slave->dev, (struct sockaddr *)&ss);
1735+
dev_set_mac_address(new_slave->dev, (struct sockaddr *)&ss,
1736+
NULL);
17361737

17371738
bond_hw_addr_copy(new_slave->dev->dev_addr, tmp_addr,
17381739
new_slave->dev->addr_len);

drivers/net/bonding/bond_main.c

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,21 @@ static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
609609
*
610610
* Should be called with RTNL held.
611611
*/
612-
static void bond_set_dev_addr(struct net_device *bond_dev,
613-
struct net_device *slave_dev)
612+
static int bond_set_dev_addr(struct net_device *bond_dev,
613+
struct net_device *slave_dev)
614614
{
615+
int err;
616+
615617
netdev_dbg(bond_dev, "bond_dev=%p slave_dev=%p slave_dev->name=%s slave_dev->addr_len=%d\n",
616618
bond_dev, slave_dev, slave_dev->name, slave_dev->addr_len);
619+
err = dev_pre_changeaddr_notify(bond_dev, slave_dev->dev_addr, NULL);
620+
if (err)
621+
return err;
622+
617623
memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len);
618624
bond_dev->addr_assign_type = NET_ADDR_STOLEN;
619625
call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
626+
return 0;
620627
}
621628

622629
static struct slave *bond_get_old_active(struct bonding *bond,
@@ -652,8 +659,12 @@ static void bond_do_fail_over_mac(struct bonding *bond,
652659

653660
switch (bond->params.fail_over_mac) {
654661
case BOND_FOM_ACTIVE:
655-
if (new_active)
656-
bond_set_dev_addr(bond->dev, new_active->dev);
662+
if (new_active) {
663+
rv = bond_set_dev_addr(bond->dev, new_active->dev);
664+
if (rv)
665+
netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
666+
-rv, bond->dev->name);
667+
}
657668
break;
658669
case BOND_FOM_FOLLOW:
659670
/* if new_active && old_active, swap them
@@ -680,7 +691,7 @@ static void bond_do_fail_over_mac(struct bonding *bond,
680691
}
681692

682693
rv = dev_set_mac_address(new_active->dev,
683-
(struct sockaddr *)&ss);
694+
(struct sockaddr *)&ss, NULL);
684695
if (rv) {
685696
netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
686697
-rv, new_active->dev->name);
@@ -695,7 +706,7 @@ static void bond_do_fail_over_mac(struct bonding *bond,
695706
ss.ss_family = old_active->dev->type;
696707

697708
rv = dev_set_mac_address(old_active->dev,
698-
(struct sockaddr *)&ss);
709+
(struct sockaddr *)&ss, NULL);
699710
if (rv)
700711
netdev_err(bond->dev, "Error %d setting MAC of slave %s\n",
701712
-rv, new_active->dev->name);
@@ -1489,8 +1500,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
14891500
* address to be the same as the slave's.
14901501
*/
14911502
if (!bond_has_slaves(bond) &&
1492-
bond->dev->addr_assign_type == NET_ADDR_RANDOM)
1493-
bond_set_dev_addr(bond->dev, slave_dev);
1503+
bond->dev->addr_assign_type == NET_ADDR_RANDOM) {
1504+
res = bond_set_dev_addr(bond->dev, slave_dev);
1505+
if (res)
1506+
goto err_undo_flags;
1507+
}
14941508

14951509
new_slave = bond_alloc_slave(bond);
14961510
if (!new_slave) {
@@ -1527,7 +1541,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
15271541
*/
15281542
memcpy(ss.__data, bond_dev->dev_addr, bond_dev->addr_len);
15291543
ss.ss_family = slave_dev->type;
1530-
res = dev_set_mac_address(slave_dev, (struct sockaddr *)&ss);
1544+
res = dev_set_mac_address(slave_dev, (struct sockaddr *)&ss,
1545+
extack);
15311546
if (res) {
15321547
netdev_dbg(bond_dev, "Error %d calling set_mac_address\n", res);
15331548
goto err_restore_mtu;
@@ -1818,7 +1833,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
18181833
bond_hw_addr_copy(ss.__data, new_slave->perm_hwaddr,
18191834
new_slave->dev->addr_len);
18201835
ss.ss_family = slave_dev->type;
1821-
dev_set_mac_address(slave_dev, (struct sockaddr *)&ss);
1836+
dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, NULL);
18221837
}
18231838

18241839
err_restore_mtu:
@@ -1999,7 +2014,7 @@ static int __bond_release_one(struct net_device *bond_dev,
19992014
bond_hw_addr_copy(ss.__data, slave->perm_hwaddr,
20002015
slave->dev->addr_len);
20012016
ss.ss_family = slave_dev->type;
2002-
dev_set_mac_address(slave_dev, (struct sockaddr *)&ss);
2017+
dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, NULL);
20032018
}
20042019

20052020
if (unregister)
@@ -3544,8 +3559,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
35443559
break;
35453560
case BOND_SETHWADDR_OLD:
35463561
case SIOCBONDSETHWADDR:
3547-
bond_set_dev_addr(bond_dev, slave_dev);
3548-
res = 0;
3562+
res = bond_set_dev_addr(bond_dev, slave_dev);
35493563
break;
35503564
case BOND_CHANGE_ACTIVE_OLD:
35513565
case SIOCBONDCHANGEACTIVE:
@@ -3732,7 +3746,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
37323746

37333747
bond_for_each_slave(bond, slave, iter) {
37343748
netdev_dbg(bond_dev, "slave %p %s\n", slave, slave->dev->name);
3735-
res = dev_set_mac_address(slave->dev, addr);
3749+
res = dev_set_mac_address(slave->dev, addr, NULL);
37363750
if (res) {
37373751
/* TODO: consider downing the slave
37383752
* and retry ?
@@ -3761,7 +3775,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
37613775
break;
37623776

37633777
tmp_res = dev_set_mac_address(rollback_slave->dev,
3764-
(struct sockaddr *)&tmp_ss);
3778+
(struct sockaddr *)&tmp_ss, NULL);
37653779
if (tmp_res) {
37663780
netdev_dbg(bond_dev, "unwind err %d dev %s\n",
37673781
tmp_res, rollback_slave->dev->name);

drivers/net/ethernet/mellanox/mlxsw/spectrum.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ static const char mlxsw_sp1_driver_name[] = "mlxsw_spectrum";
6565
static const char mlxsw_sp2_driver_name[] = "mlxsw_spectrum2";
6666
static const char mlxsw_sp_driver_version[] = "1.0";
6767

68+
static const unsigned char mlxsw_sp1_mac_mask[ETH_ALEN] = {
69+
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00
70+
};
71+
static const unsigned char mlxsw_sp2_mac_mask[ETH_ALEN] = {
72+
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00
73+
};
74+
6875
/* tx_hdr_version
6976
* Tx header version.
7077
* Must be set to 1.
@@ -4083,6 +4090,7 @@ static int mlxsw_sp1_init(struct mlxsw_core *mlxsw_core,
40834090
mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
40844091
mlxsw_sp->acl_tcam_ops = &mlxsw_sp1_acl_tcam_ops;
40854092
mlxsw_sp->nve_ops_arr = mlxsw_sp1_nve_ops_arr;
4093+
mlxsw_sp->mac_mask = mlxsw_sp1_mac_mask;
40864094

40874095
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
40884096
}
@@ -4098,6 +4106,7 @@ static int mlxsw_sp2_init(struct mlxsw_core *mlxsw_core,
40984106
mlxsw_sp->mr_tcam_ops = &mlxsw_sp2_mr_tcam_ops;
40994107
mlxsw_sp->acl_tcam_ops = &mlxsw_sp2_acl_tcam_ops;
41004108
mlxsw_sp->nve_ops_arr = mlxsw_sp2_nve_ops_arr;
4109+
mlxsw_sp->mac_mask = mlxsw_sp2_mac_mask;
41014110

41024111
return mlxsw_sp_init(mlxsw_core, mlxsw_bus_info);
41034112
}
@@ -5325,8 +5334,10 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
53255334
else if (mlxsw_sp_netdev_is_ipip_ul(mlxsw_sp, dev))
53265335
err = mlxsw_sp_netdevice_ipip_ul_event(mlxsw_sp, dev,
53275336
event, ptr);
5328-
else if (event == NETDEV_CHANGEADDR || event == NETDEV_CHANGEMTU)
5329-
err = mlxsw_sp_netdevice_router_port_event(dev);
5337+
else if (event == NETDEV_PRE_CHANGEADDR ||
5338+
event == NETDEV_CHANGEADDR ||
5339+
event == NETDEV_CHANGEMTU)
5340+
err = mlxsw_sp_netdevice_router_port_event(dev, event, ptr);
53305341
else if (mlxsw_sp_is_vrf_event(event, ptr))
53315342
err = mlxsw_sp_netdevice_vrf_event(dev, event, ptr);
53325343
else if (mlxsw_sp_port_dev_check(dev))

drivers/net/ethernet/mellanox/mlxsw/spectrum.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ struct mlxsw_sp {
132132
struct mlxsw_core *core;
133133
const struct mlxsw_bus_info *bus_info;
134134
unsigned char base_mac[ETH_ALEN];
135+
const unsigned char *mac_mask;
135136
struct mlxsw_sp_upper *lags;
136137
int *port_to_module;
137138
struct mlxsw_sp_sb *sb;
@@ -454,7 +455,8 @@ union mlxsw_sp_l3addr {
454455

455456
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp);
456457
void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp);
457-
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev);
458+
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
459+
unsigned long event, void *ptr);
458460
void mlxsw_sp_rif_macvlan_del(struct mlxsw_sp *mlxsw_sp,
459461
const struct net_device *macvlan_dev);
460462
int mlxsw_sp_inetaddr_event(struct notifier_block *unused,

drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6699,6 +6699,33 @@ static int mlxsw_sp_inetaddr_macvlan_event(struct net_device *macvlan_dev,
66996699
return 0;
67006700
}
67016701

6702+
static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
6703+
struct net_device *dev,
6704+
const unsigned char *dev_addr,
6705+
struct netlink_ext_ack *extack)
6706+
{
6707+
struct mlxsw_sp_rif *rif;
6708+
int i;
6709+
6710+
/* A RIF is not created for macvlan netdevs. Their MAC is used to
6711+
* populate the FDB
6712+
*/
6713+
if (netif_is_macvlan(dev))
6714+
return 0;
6715+
6716+
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
6717+
rif = mlxsw_sp->router->rifs[i];
6718+
if (rif && rif->dev != dev &&
6719+
!ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
6720+
mlxsw_sp->mac_mask)) {
6721+
NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix");
6722+
return -EINVAL;
6723+
}
6724+
}
6725+
6726+
return 0;
6727+
}
6728+
67026729
static int __mlxsw_sp_inetaddr_event(struct net_device *dev,
67036730
unsigned long event,
67046731
struct netlink_ext_ack *extack)
@@ -6760,6 +6787,11 @@ int mlxsw_sp_inetaddr_valid_event(struct notifier_block *unused,
67606787
if (!mlxsw_sp_rif_should_config(rif, dev, event))
67616788
goto out;
67626789

6790+
err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
6791+
ivi->extack);
6792+
if (err)
6793+
goto out;
6794+
67636795
err = __mlxsw_sp_inetaddr_event(dev, event, ivi->extack);
67646796
out:
67656797
return notifier_from_errno(err);
@@ -6841,6 +6873,11 @@ int mlxsw_sp_inet6addr_valid_event(struct notifier_block *unused,
68416873
if (!mlxsw_sp_rif_should_config(rif, dev, event))
68426874
goto out;
68436875

6876+
err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
6877+
i6vi->extack);
6878+
if (err)
6879+
goto out;
6880+
68446881
err = __mlxsw_sp_inetaddr_event(dev, event, i6vi->extack);
68456882
out:
68466883
return notifier_from_errno(err);
@@ -6863,20 +6900,14 @@ static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
68636900
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
68646901
}
68656902

6866-
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
6903+
static int
6904+
mlxsw_sp_router_port_change_event(struct mlxsw_sp *mlxsw_sp,
6905+
struct mlxsw_sp_rif *rif)
68676906
{
6868-
struct mlxsw_sp *mlxsw_sp;
6869-
struct mlxsw_sp_rif *rif;
6907+
struct net_device *dev = rif->dev;
68706908
u16 fid_index;
68716909
int err;
68726910

6873-
mlxsw_sp = mlxsw_sp_lower_get(dev);
6874-
if (!mlxsw_sp)
6875-
return 0;
6876-
6877-
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6878-
if (!rif)
6879-
return 0;
68806911
fid_index = mlxsw_sp_fid_index(rif->fid);
68816912

68826913
err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false);
@@ -6920,6 +6951,41 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev)
69206951
return err;
69216952
}
69226953

6954+
static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
6955+
struct netdev_notifier_pre_changeaddr_info *info)
6956+
{
6957+
struct netlink_ext_ack *extack;
6958+
6959+
extack = netdev_notifier_info_to_extack(&info->info);
6960+
return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev,
6961+
info->dev_addr, extack);
6962+
}
6963+
6964+
int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
6965+
unsigned long event, void *ptr)
6966+
{
6967+
struct mlxsw_sp *mlxsw_sp;
6968+
struct mlxsw_sp_rif *rif;
6969+
6970+
mlxsw_sp = mlxsw_sp_lower_get(dev);
6971+
if (!mlxsw_sp)
6972+
return 0;
6973+
6974+
rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev);
6975+
if (!rif)
6976+
return 0;
6977+
6978+
switch (event) {
6979+
case NETDEV_CHANGEMTU: /* fall through */
6980+
case NETDEV_CHANGEADDR:
6981+
return mlxsw_sp_router_port_change_event(mlxsw_sp, rif);
6982+
case NETDEV_PRE_CHANGEADDR:
6983+
return mlxsw_sp_router_port_pre_changeaddr_event(rif, ptr);
6984+
}
6985+
6986+
return 0;
6987+
}
6988+
69236989
static int mlxsw_sp_port_vrf_join(struct mlxsw_sp *mlxsw_sp,
69246990
struct net_device *l3_dev,
69256991
struct netlink_ext_ack *extack)

drivers/net/hyperv/netvsc_drv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,7 +1247,7 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
12471247
return -ENODEV;
12481248

12491249
if (vf_netdev) {
1250-
err = dev_set_mac_address(vf_netdev, addr);
1250+
err = dev_set_mac_address(vf_netdev, addr, NULL);
12511251
if (err)
12521252
return err;
12531253
}
@@ -1258,7 +1258,7 @@ static int netvsc_set_mac_addr(struct net_device *ndev, void *p)
12581258
} else if (vf_netdev) {
12591259
/* rollback change on VF */
12601260
memcpy(addr->sa_data, ndev->dev_addr, ETH_ALEN);
1261-
dev_set_mac_address(vf_netdev, addr);
1261+
dev_set_mac_address(vf_netdev, addr, NULL);
12621262
}
12631263

12641264
return err;

drivers/net/ipvlan/ipvlan_main.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,10 +759,13 @@ EXPORT_SYMBOL_GPL(ipvlan_link_register);
759759
static int ipvlan_device_event(struct notifier_block *unused,
760760
unsigned long event, void *ptr)
761761
{
762+
struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr);
763+
struct netdev_notifier_pre_changeaddr_info *prechaddr_info;
762764
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
763765
struct ipvl_dev *ipvlan, *next;
764766
struct ipvl_port *port;
765767
LIST_HEAD(lst_kill);
768+
int err;
766769

767770
if (!netif_is_ipvlan_port(dev))
768771
return NOTIFY_DONE;
@@ -818,6 +821,17 @@ static int ipvlan_device_event(struct notifier_block *unused,
818821
ipvlan_adjust_mtu(ipvlan, dev);
819822
break;
820823

824+
case NETDEV_PRE_CHANGEADDR:
825+
prechaddr_info = ptr;
826+
list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
827+
err = dev_pre_changeaddr_notify(ipvlan->dev,
828+
prechaddr_info->dev_addr,
829+
extack);
830+
if (err)
831+
return notifier_from_errno(err);
832+
}
833+
break;
834+
821835
case NETDEV_CHANGEADDR:
822836
list_for_each_entry(ipvlan, &port->ipvlans, pnode) {
823837
ether_addr_copy(ipvlan->dev->dev_addr, dev->dev_addr);

0 commit comments

Comments
 (0)