diff options
author | 2017-06-08 14:16:31 -0400 | |
---|---|---|
committer | 2017-06-08 14:16:31 -0400 | |
commit | 4cd31af77582653a8e4b367fdb612e84a2cdd685 (patch) | |
tree | c88e676bbbe2590489392fdad2f69792b29f600e | |
parent | Merge branch 'dsa-add-cross-chip-VLAN-support' (diff) | |
parent | rocker: Remove support bridge bypass FDB (diff) | |
download | linux-dev-4cd31af77582653a8e4b367fdb612e84a2cdd685.tar.xz linux-dev-4cd31af77582653a8e4b367fdb612e84a2cdd685.zip |
Merge branch 'net-Remove-support-from-bridge-bypass-for-mlxsw-rocker-drivers'
Jiri Pirko says:
===================
net: Remove support from bridge bypass for mlxsw/rocker drivers
Currently setting bridge port attributes and adding FDBs are done via
setting the SELF flag which implies unconsistent offloading model. This
patch-set fixes this behavior by making the bridge and drivers which are
using it to be totally in sync.
This implies several changes:
- Offloading bridge flags from the bridge code.
- Sending notification about FDB add/del to the software bridge in a
similiar way it is done for the hardware externally learned FDBs.
By making the offloading model more consistent a cleanup is done in
the drivers supporting it. This is done in order to remove un-needed
logic related to dump operation which is redundant.
First add missing functionality to bridge, then clean up the mlxsw/rocker
drivers.
v1->v2
- Move bridge-switchdev related stuff to br_switchdev.c as suggested by Nik
===================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_main.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 360 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker_main.c | 235 | ||||
-rw-r--r-- | drivers/net/ethernet/rocker/rocker_ofdpa.c | 610 | ||||
-rw-r--r-- | drivers/net/team/team.c | 6 | ||||
-rw-r--r-- | include/net/switchdev.h | 9 | ||||
-rw-r--r-- | include/uapi/linux/neighbour.h | 1 | ||||
-rw-r--r-- | net/8021q/vlan_dev.c | 6 | ||||
-rw-r--r-- | net/bridge/br.c | 19 | ||||
-rw-r--r-- | net/bridge/br_fdb.c | 26 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 87 | ||||
-rw-r--r-- | net/bridge/br_private.h | 28 | ||||
-rw-r--r-- | net/bridge/br_switchdev.c | 76 | ||||
-rw-r--r-- | net/switchdev/switchdev.c | 30 |
17 files changed, 736 insertions, 793 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d4484d1a8164..7d9474352c36 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4175,12 +4175,6 @@ static const struct net_device_ops bond_netdev_ops = { .ndo_add_slave = bond_enslave, .ndo_del_slave = bond_release, .ndo_fix_features = bond_fix_features, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index a2316d038810..ecc73525529d 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1756,12 +1756,6 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = { .ndo_get_offload_stats = mlxsw_sp_port_get_offload_stats, .ndo_vlan_rx_add_vid = mlxsw_sp_port_add_vid, .ndo_vlan_rx_kill_vid = mlxsw_sp_port_kill_vid, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, .ndo_get_phys_port_name = mlxsw_sp_port_get_phys_port_name, }; @@ -3709,7 +3703,7 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev) return mlxsw_sp_port ? mlxsw_sp_port->mlxsw_sp : NULL; } -static struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev) { struct mlxsw_sp_port *mlxsw_sp_port; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 4a7a39a9f1a1..5ef98d4d0ab6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -361,6 +361,7 @@ struct mlxsw_sp *mlxsw_sp_lower_get(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find(struct net_device *dev); struct mlxsw_sp_port *mlxsw_sp_port_lower_dev_hold(struct net_device *dev); void mlxsw_sp_port_dev_put(struct mlxsw_sp_port *mlxsw_sp_port); +struct mlxsw_sp_port *mlxsw_sp_port_dev_lower_find_rcu(struct net_device *dev); /* spectrum_dcb.c */ #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index edcc273d7597..cd89a3e6cd81 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -102,8 +102,6 @@ struct mlxsw_sp_bridge_vlan { struct list_head list; struct list_head port_vlan_list; u16 vid; - u8 egress_untagged:1, - pvid:1; }; struct mlxsw_sp_bridge_ops { @@ -456,6 +454,9 @@ static int mlxsw_sp_port_attr_get(struct net_device *dev, mlxsw_sp_port_bridge_flags_get(mlxsw_sp->bridge, attr->orig_dev, &attr->u.brport_flags); break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + attr->u.brport_flags_support = BR_LEARNING | BR_FLOOD; + break; default: return -EOPNOTSUPP; } @@ -1000,8 +1001,6 @@ mlxsw_sp_bridge_port_vlan_add(struct mlxsw_sp_port *mlxsw_sp_port, goto err_port_vlan_bridge_join; bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); - bridge_vlan->egress_untagged = is_untagged; - bridge_vlan->pvid = is_pvid; return 0; @@ -1142,44 +1141,40 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, } static int -mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) +mlxsw_sp_port_fdb_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_notifier_fdb_info *fdb_info, bool adding) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; + struct net_device *orig_dev = fdb_info->info.dev; struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_port *bridge_port; u16 fid_index, vid; - if (switchdev_trans_ph_prepare(trans)) - return 0; - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) + if (!bridge_port) return -EINVAL; bridge_device = bridge_port->bridge_device; mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, bridge_device, - fdb->vid); + fdb_info->vid); if (!mlxsw_sp_port_vlan) return 0; fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); vid = mlxsw_sp_port_vlan->vid; - if (!mlxsw_sp_port->lagged) + if (!bridge_port->lagged) return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, - mlxsw_sp_port->local_port, - fdb->addr, fid_index, true, - false); + bridge_port->system_port, + fdb_info->addr, fid_index, + adding, false); else return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, - mlxsw_sp_port->lag_id, - fdb->addr, fid_index, vid, - true, false); + bridge_port->lag_id, + fdb_info->addr, fid_index, + vid, adding, false); } static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, @@ -1349,11 +1344,6 @@ static int mlxsw_sp_port_obj_add(struct net_device *dev, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_static_add(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - trans); - break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = mlxsw_sp_port_mdb_add(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_MDB(obj), @@ -1405,43 +1395,6 @@ static int mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port, return 0; } -static int -mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, - const struct switchdev_obj_port_fdb *fdb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_bridge_device *bridge_device; - struct mlxsw_sp_bridge_port *bridge_port; - u16 fid_index, vid; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) - return -EINVAL; - - bridge_device = bridge_port->bridge_device; - mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_bridge(mlxsw_sp_port, - bridge_device, - fdb->vid); - if (!mlxsw_sp_port_vlan) - return 0; - - fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); - vid = mlxsw_sp_port_vlan->vid; - - if (!mlxsw_sp_port->lagged) - return mlxsw_sp_port_fdb_uc_op(mlxsw_sp, - mlxsw_sp_port->local_port, - fdb->addr, fid_index, false, - false); - else - return mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, - mlxsw_sp_port->lag_id, - fdb->addr, fid_index, vid, - false, false); -} - static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, const struct switchdev_obj_port_mdb *mdb) { @@ -1501,10 +1454,6 @@ static int mlxsw_sp_port_obj_del(struct net_device *dev, err = mlxsw_sp_port_vlans_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_static_del(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj)); - break; case SWITCHDEV_OBJ_ID_PORT_MDB: err = mlxsw_sp_port_mdb_del(mlxsw_sp_port, SWITCHDEV_OBJ_PORT_MDB(obj)); @@ -1534,161 +1483,11 @@ static struct mlxsw_sp_port *mlxsw_sp_lag_rep_port(struct mlxsw_sp *mlxsw_sp, return NULL; } -static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = fdb->obj.orig_dev; - struct mlxsw_sp_bridge_port *bridge_port; - u16 lag_id, fid_index; - char mac[ETH_ALEN]; - int stored_err = 0; - char *sfd_pl; - u8 num_rec; - int err; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (!bridge_port) - return 0; - - sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); - if (!sfd_pl) - return -ENOMEM; - - mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); - do { - struct mlxsw_sp_port *tmp; - u8 local_port; - int i; - - mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT); - err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - if (err) - goto out; - - num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); - - /* Even in case of error, we have to run the dump to the end - * so the session in firmware is finished. - */ - if (stored_err) - continue; - - for (i = 0; i < num_rec; i++) { - switch (mlxsw_reg_sfd_rec_type_get(sfd_pl, i)) { - case MLXSW_REG_SFD_REC_TYPE_UNICAST: - mlxsw_reg_sfd_uc_unpack(sfd_pl, i, mac, - &fid_index, - &local_port); - if (bridge_port->lagged) - continue; - if (bridge_port->system_port != local_port) - continue; - if (bridge_port->bridge_device->vlan_enabled) - fdb->vid = fid_index; - else - fdb->vid = 0; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - break; - case MLXSW_REG_SFD_REC_TYPE_UNICAST_LAG: - mlxsw_reg_sfd_uc_lag_unpack(sfd_pl, i, - mac, &fid_index, - &lag_id); - if (!bridge_port->lagged) - continue; - if (bridge_port->lag_id != lag_id) - continue; - tmp = mlxsw_sp_lag_rep_port(mlxsw_sp, lag_id); - if (tmp->local_port != - mlxsw_sp_port->local_port) - continue; - if (bridge_port->bridge_device->vlan_enabled) - fdb->vid = fid_index; - else - fdb->vid = 0; - ether_addr_copy(fdb->addr, mac); - fdb->ndm_state = NUD_REACHABLE; - err = cb(&fdb->obj); - if (err) - stored_err = err; - break; - } - } - } while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT); - -out: - kfree(sfd_pl); - return stored_err ? stored_err : err; -} - -static int mlxsw_sp_port_vlan_dump(struct mlxsw_sp_port *mlxsw_sp_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct net_device *orig_dev = vlan->obj.orig_dev; - struct mlxsw_sp_bridge_port *bridge_port; - struct mlxsw_sp_bridge_vlan *bridge_vlan; - int err = 0; - - bridge_port = mlxsw_sp_bridge_port_find(mlxsw_sp->bridge, orig_dev); - if (WARN_ON(!bridge_port)) - return -EINVAL; - - if (!bridge_port->bridge_device->vlan_enabled) - return 0; - - list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { - vlan->flags = 0; - if (bridge_vlan->pvid) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - if (bridge_vlan->egress_untagged) - vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED; - vlan->vid_begin = bridge_vlan->vid; - vlan->vid_end = bridge_vlan->vid; - err = cb(&vlan->obj); - if (err) - break; - } - - return err; -} - -static int mlxsw_sp_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb) -{ - struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); - int err = 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = mlxsw_sp_port_vlan_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_VLAN(obj), cb); - break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = mlxsw_sp_port_fdb_dump(mlxsw_sp_port, - SWITCHDEV_OBJ_PORT_FDB(obj), cb); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - static const struct switchdev_ops mlxsw_sp_port_switchdev_ops = { .switchdev_port_attr_get = mlxsw_sp_port_attr_get, .switchdev_port_attr_set = mlxsw_sp_port_attr_set, .switchdev_port_obj_add = mlxsw_sp_port_obj_add, .switchdev_port_obj_del = mlxsw_sp_port_obj_del, - .switchdev_port_obj_dump = mlxsw_sp_port_obj_dump, }; static int @@ -1857,19 +1656,16 @@ void mlxsw_sp_port_bridge_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_bridge_port_put(mlxsw_sp->bridge, bridge_port); } -static void mlxsw_sp_fdb_call_notifiers(bool learning_sync, bool adding, - char *mac, u16 vid, - struct net_device *dev) +static void +mlxsw_sp_fdb_call_notifiers(enum switchdev_notifier_type type, + const char *mac, u16 vid, + struct net_device *dev) { struct switchdev_notifier_fdb_info info; - unsigned long notifier_type; - if (learning_sync) { - info.addr = mac; - info.vid = vid; - notifier_type = adding ? SWITCHDEV_FDB_ADD : SWITCHDEV_FDB_DEL; - call_switchdev_notifiers(notifier_type, dev, &info.info); - } + info.addr = mac; + info.vid = vid; + call_switchdev_notifiers(type, dev, &info.info); } static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, @@ -1880,6 +1676,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; + enum switchdev_notifier_type type; char mac[ETH_ALEN]; u8 local_port; u16 vid, fid; @@ -1918,8 +1715,9 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, - adding, mac, vid, bridge_port->dev); + type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); + return; just_remove: @@ -1936,6 +1734,7 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_bridge_device *bridge_device; struct mlxsw_sp_bridge_port *bridge_port; struct mlxsw_sp_port *mlxsw_sp_port; + enum switchdev_notifier_type type; char mac[ETH_ALEN]; u16 lag_vid = 0; u16 lag_id; @@ -1976,8 +1775,9 @@ do_fdb_op: if (!do_notification) return; - mlxsw_sp_fdb_call_notifiers(bridge_port->flags & BR_LEARNING_SYNC, - adding, mac, vid, bridge_port->dev); + type = adding ? SWITCHDEV_FDB_ADD_TO_BRIDGE : SWITCHDEV_FDB_DEL_TO_BRIDGE; + mlxsw_sp_fdb_call_notifiers(type, mac, vid, bridge_port->dev); + return; just_remove: @@ -2050,6 +1850,97 @@ out: mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); } +struct mlxsw_sp_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct net_device *dev; + unsigned long event; +}; + +static void mlxsw_sp_switchdev_event_work(struct work_struct *work) +{ + struct mlxsw_sp_switchdev_event_work *switchdev_work = + container_of(work, struct mlxsw_sp_switchdev_event_work, work); + struct net_device *dev = switchdev_work->dev; + struct switchdev_notifier_fdb_info *fdb_info; + struct mlxsw_sp_port *mlxsw_sp_port; + int err; + + rtnl_lock(); + mlxsw_sp_port = mlxsw_sp_port_dev_lower_find(dev); + if (!mlxsw_sp_port) + goto out; + + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, true); + if (err) + break; + mlxsw_sp_fdb_call_notifiers(SWITCHDEV_FDB_OFFLOADED, + fdb_info->addr, + fdb_info->vid, dev); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + mlxsw_sp_port_fdb_set(mlxsw_sp_port, fdb_info, false); + break; + } + +out: + rtnl_unlock(); + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(dev); +} + +/* Called under rcu_read_lock() */ +static int mlxsw_sp_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct mlxsw_sp_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + + if (!mlxsw_sp_port_dev_lower_find_rcu(dev)) + return NOTIFY_DONE; + + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (!switchdev_work) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, mlxsw_sp_switchdev_event_work); + switchdev_work->dev = dev; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + /* Take a reference on the device. This can be either + * upper device containig mlxsw_sp_port or just a + * mlxsw_sp_port + */ + dev_hold(dev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + mlxsw_core_schedule_work(&switchdev_work->work); + + return NOTIFY_DONE; +} + +static struct notifier_block mlxsw_sp_switchdev_notifier = { + .notifier_call = mlxsw_sp_switchdev_event, +}; + static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) { struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; @@ -2060,6 +1951,13 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n"); return err; } + + err = register_switchdev_notifier(&mlxsw_sp_switchdev_notifier); + if (err) { + dev_err(mlxsw_sp->bus_info->dev, "Failed to register switchdev notifier\n"); + return err; + } + INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); @@ -2069,6 +1967,8 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp) { cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw); + unregister_switchdev_notifier(&mlxsw_sp_switchdev_notifier); + } int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp) diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index ee9675db5bf9..748fb12260a6 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -105,32 +105,27 @@ struct rocker_world_ops { int (*port_open)(struct rocker_port *rocker_port); void (*port_stop)(struct rocker_port *rocker_port); int (*port_attr_stp_state_set)(struct rocker_port *rocker_port, - u8 state, - struct switchdev_trans *trans); + u8 state); int (*port_attr_bridge_flags_set)(struct rocker_port *rocker_port, unsigned long brport_flags, struct switchdev_trans *trans); int (*port_attr_bridge_flags_get)(const struct rocker_port *rocker_port, unsigned long *p_brport_flags); + int (*port_attr_bridge_flags_support_get)(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags); int (*port_attr_bridge_ageing_time_set)(struct rocker_port *rocker_port, u32 ageing_time, struct switchdev_trans *trans); int (*port_obj_vlan_add)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans); + const struct switchdev_obj_port_vlan *vlan); int (*port_obj_vlan_del)(struct rocker_port *rocker_port, const struct switchdev_obj_port_vlan *vlan); - int (*port_obj_vlan_dump)(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb); int (*port_obj_fdb_add)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans); + u16 vid, const unsigned char *addr); int (*port_obj_fdb_del)(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb); - int (*port_obj_fdb_dump)(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb); + u16 vid, const unsigned char *addr); int (*port_master_linked)(struct rocker_port *rocker_port, struct net_device *master); int (*port_master_unlinked)(struct rocker_port *rocker_port, diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index bab13613b138..b1e5c07099fa 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1557,7 +1557,11 @@ static int rocker_world_port_attr_stp_state_set(struct rocker_port *rocker_port, if (!wops->port_attr_stp_state_set) return -EOPNOTSUPP; - return wops->port_attr_stp_state_set(rocker_port, state, trans); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return wops->port_attr_stp_state_set(rocker_port, state); } static int @@ -1569,6 +1573,10 @@ rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port, if (!wops->port_attr_bridge_flags_set) return -EOPNOTSUPP; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + return wops->port_attr_bridge_flags_set(rocker_port, brport_flags, trans); } @@ -1585,6 +1593,20 @@ rocker_world_port_attr_bridge_flags_get(const struct rocker_port *rocker_port, } static int +rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags_support) +{ + struct rocker_world_ops *wops = rocker_port->rocker->wops; + + if (!wops->port_attr_bridge_flags_support_get) + return -EOPNOTSUPP; + return wops->port_attr_bridge_flags_support_get(rocker_port, + p_brport_flags_support); +} + +static int rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, u32 ageing_time, struct switchdev_trans *trans) @@ -1594,6 +1616,10 @@ rocker_world_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, if (!wops->port_attr_bridge_ageing_time_set) return -EOPNOTSUPP; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + return wops->port_attr_bridge_ageing_time_set(rocker_port, ageing_time, trans); } @@ -1607,7 +1633,11 @@ rocker_world_port_obj_vlan_add(struct rocker_port *rocker_port, if (!wops->port_obj_vlan_add) return -EOPNOTSUPP; - return wops->port_obj_vlan_add(rocker_port, vlan, trans); + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + return wops->port_obj_vlan_add(rocker_port, vlan); } static int @@ -1622,50 +1652,26 @@ rocker_world_port_obj_vlan_del(struct rocker_port *rocker_port, } static int -rocker_world_port_obj_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - - if (!wops->port_obj_vlan_dump) - return -EOPNOTSUPP; - return wops->port_obj_vlan_dump(rocker_port, vlan, cb); -} - -static int -rocker_world_port_obj_fdb_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) +rocker_world_port_fdb_add(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *info) { struct rocker_world_ops *wops = rocker_port->rocker->wops; if (!wops->port_obj_fdb_add) return -EOPNOTSUPP; - return wops->port_obj_fdb_add(rocker_port, fdb, trans); -} - -static int -rocker_world_port_obj_fdb_del(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb) -{ - struct rocker_world_ops *wops = rocker_port->rocker->wops; - if (!wops->port_obj_fdb_del) - return -EOPNOTSUPP; - return wops->port_obj_fdb_del(rocker_port, fdb); + return wops->port_obj_fdb_add(rocker_port, info->vid, info->addr); } static int -rocker_world_port_obj_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) +rocker_world_port_fdb_del(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *info) { struct rocker_world_ops *wops = rocker_port->rocker->wops; - if (!wops->port_obj_fdb_dump) + if (!wops->port_obj_fdb_del) return -EOPNOTSUPP; - return wops->port_obj_fdb_dump(rocker_port, fdb, cb); + return wops->port_obj_fdb_del(rocker_port, info->vid, info->addr); } static int rocker_world_port_master_linked(struct rocker_port *rocker_port, @@ -2022,12 +2028,6 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, .ndo_change_mtu = rocker_port_change_mtu, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = rocker_port_get_phys_port_name, .ndo_change_proto_down = rocker_port_change_proto_down, .ndo_neigh_destroy = rocker_port_neigh_destroy, @@ -2053,6 +2053,10 @@ static int rocker_port_attr_get(struct net_device *dev, err = rocker_world_port_attr_bridge_flags_get(rocker_port, &attr->u.brport_flags); break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: + err = rocker_world_port_attr_bridge_flags_support_get(rocker_port, + &attr->u.brport_flags_support); + break; default: return -EOPNOTSUPP; } @@ -2104,11 +2108,6 @@ static int rocker_port_obj_add(struct net_device *dev, SWITCHDEV_OBJ_PORT_VLAN(obj), trans); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_add(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - trans); - break; default: err = -EOPNOTSUPP; break; @@ -2128,36 +2127,6 @@ static int rocker_port_obj_del(struct net_device *dev, err = rocker_world_port_obj_vlan_del(rocker_port, SWITCHDEV_OBJ_PORT_VLAN(obj)); break; - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_del(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj)); - break; - default: - err = -EOPNOTSUPP; - break; - } - - return err; -} - -static int rocker_port_obj_dump(struct net_device *dev, - struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb) -{ - const struct rocker_port *rocker_port = netdev_priv(dev); - int err = 0; - - switch (obj->id) { - case SWITCHDEV_OBJ_ID_PORT_FDB: - err = rocker_world_port_obj_fdb_dump(rocker_port, - SWITCHDEV_OBJ_PORT_FDB(obj), - cb); - break; - case SWITCHDEV_OBJ_ID_PORT_VLAN: - err = rocker_world_port_obj_vlan_dump(rocker_port, - SWITCHDEV_OBJ_PORT_VLAN(obj), - cb); - break; default: err = -EOPNOTSUPP; break; @@ -2171,7 +2140,6 @@ static const struct switchdev_ops rocker_port_switchdev_ops = { .switchdev_port_attr_set = rocker_port_attr_set, .switchdev_port_obj_add = rocker_port_obj_add, .switchdev_port_obj_del = rocker_port_obj_del, - .switchdev_port_obj_dump = rocker_port_obj_dump, }; struct rocker_fib_event_work { @@ -2729,6 +2697,109 @@ static void rocker_msix_fini(const struct rocker *rocker) kfree(rocker->msix_entries); } +static bool rocker_port_dev_check(const struct net_device *dev) +{ + return dev->netdev_ops == &rocker_port_netdev_ops; +} + +struct rocker_switchdev_event_work { + struct work_struct work; + struct switchdev_notifier_fdb_info fdb_info; + struct rocker_port *rocker_port; + unsigned long event; +}; + +static void +rocker_fdb_offload_notify(struct rocker_port *rocker_port, + struct switchdev_notifier_fdb_info *recv_info) +{ + struct switchdev_notifier_fdb_info info; + + info.addr = recv_info->addr; + info.vid = recv_info->vid; + call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED, + rocker_port->dev, &info.info); +} + +static void rocker_switchdev_event_work(struct work_struct *work) +{ + struct rocker_switchdev_event_work *switchdev_work = + container_of(work, struct rocker_switchdev_event_work, work); + struct rocker_port *rocker_port = switchdev_work->rocker_port; + struct switchdev_notifier_fdb_info *fdb_info; + int err; + + rtnl_lock(); + switch (switchdev_work->event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = rocker_world_port_fdb_add(rocker_port, fdb_info); + if (err) { + netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err); + break; + } + rocker_fdb_offload_notify(rocker_port, fdb_info); + break; + case SWITCHDEV_FDB_DEL_TO_DEVICE: + fdb_info = &switchdev_work->fdb_info; + err = rocker_world_port_fdb_del(rocker_port, fdb_info); + if (err) + netdev_dbg(rocker_port->dev, "fdb add failed err=%d\n", err); + break; + } + rtnl_unlock(); + + kfree(switchdev_work->fdb_info.addr); + kfree(switchdev_work); + dev_put(rocker_port->dev); +} + +/* called under rcu_read_lock() */ +static int rocker_switchdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = switchdev_notifier_info_to_dev(ptr); + struct rocker_switchdev_event_work *switchdev_work; + struct switchdev_notifier_fdb_info *fdb_info = ptr; + struct rocker_port *rocker_port; + + if (!rocker_port_dev_check(dev)) + return NOTIFY_DONE; + + rocker_port = netdev_priv(dev); + switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC); + if (WARN_ON(!switchdev_work)) + return NOTIFY_BAD; + + INIT_WORK(&switchdev_work->work, rocker_switchdev_event_work); + switchdev_work->rocker_port = rocker_port; + switchdev_work->event = event; + + switch (event) { + case SWITCHDEV_FDB_ADD_TO_DEVICE: /* fall through */ + case SWITCHDEV_FDB_DEL_TO_DEVICE: + memcpy(&switchdev_work->fdb_info, ptr, + sizeof(switchdev_work->fdb_info)); + switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC); + ether_addr_copy((u8 *)switchdev_work->fdb_info.addr, + fdb_info->addr); + /* Take a reference on the rocker device */ + dev_hold(dev); + break; + default: + kfree(switchdev_work); + return NOTIFY_DONE; + } + + queue_work(rocker_port->rocker->rocker_owq, + &switchdev_work->work); + return NOTIFY_DONE; +} + +static struct notifier_block rocker_switchdev_notifier = { + .notifier_call = rocker_switchdev_event, +}; + static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct rocker *rocker; @@ -2834,6 +2905,12 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_register_fib_notifier; + err = register_switchdev_notifier(&rocker_switchdev_notifier); + if (err) { + dev_err(&pdev->dev, "Failed to register switchdev notifier\n"); + goto err_register_switchdev_notifier; + } + rocker->hw.id = rocker_read64(rocker, SWITCH_ID); err = rocker_probe_ports(rocker); @@ -2848,6 +2925,8 @@ static int rocker_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_probe_ports: + unregister_switchdev_notifier(&rocker_switchdev_notifier); +err_register_switchdev_notifier: unregister_fib_notifier(&rocker->fib_nb); err_register_fib_notifier: destroy_workqueue(rocker->rocker_owq); @@ -2878,6 +2957,7 @@ static void rocker_remove(struct pci_dev *pdev) struct rocker *rocker = pci_get_drvdata(pdev); rocker_remove_ports(rocker); + unregister_switchdev_notifier(&rocker_switchdev_notifier); unregister_fib_notifier(&rocker->fib_nb); rocker_write32(rocker, CONTROL, ROCKER_CONTROL_RESET); destroy_workqueue(rocker->rocker_owq); @@ -2902,11 +2982,6 @@ static struct pci_driver rocker_pci_driver = { * Net device notifier event handler ************************************/ -static bool rocker_port_dev_check(const struct net_device *dev) -{ - return dev->netdev_ops == &rocker_port_netdev_ops; -} - static bool rocker_port_dev_check_under(const struct net_device *dev, struct rocker *rocker) { diff --git a/drivers/net/ethernet/rocker/rocker_ofdpa.c b/drivers/net/ethernet/rocker/rocker_ofdpa.c index 2ae852454780..bd0e3f157e9e 100644 --- a/drivers/net/ethernet/rocker/rocker_ofdpa.c +++ b/drivers/net/ethernet/rocker/rocker_ofdpa.c @@ -300,64 +300,6 @@ static bool ofdpa_flags_nowait(int flags) return flags & OFDPA_OP_FLAG_NOWAIT; } -static void *__ofdpa_mem_alloc(struct switchdev_trans *trans, int flags, - size_t size) -{ - struct switchdev_trans_item *elem = NULL; - gfp_t gfp_flags = (flags & OFDPA_OP_FLAG_NOWAIT) ? - GFP_ATOMIC : GFP_KERNEL; - - /* If in transaction prepare phase, allocate the memory - * and enqueue it on a transaction. If in transaction - * commit phase, dequeue the memory from the transaction - * rather than re-allocating the memory. The idea is the - * driver code paths for prepare and commit are identical - * so the memory allocated in the prepare phase is the - * memory used in the commit phase. - */ - - if (!trans) { - elem = kzalloc(size + sizeof(*elem), gfp_flags); - } else if (switchdev_trans_ph_prepare(trans)) { - elem = kzalloc(size + sizeof(*elem), gfp_flags); - if (!elem) - return NULL; - switchdev_trans_item_enqueue(trans, elem, kfree, elem); - } else { - elem = switchdev_trans_item_dequeue(trans); - } - - return elem ? elem + 1 : NULL; -} - -static void *ofdpa_kzalloc(struct switchdev_trans *trans, int flags, - size_t size) -{ - return __ofdpa_mem_alloc(trans, flags, size); -} - -static void *ofdpa_kcalloc(struct switchdev_trans *trans, int flags, - size_t n, size_t size) -{ - return __ofdpa_mem_alloc(trans, flags, n * size); -} - -static void ofdpa_kfree(struct switchdev_trans *trans, const void *mem) -{ - struct switchdev_trans_item *elem; - - /* Frees are ignored if in transaction prepare phase. The - * memory remains on the per-port list until freed in the - * commit phase. - */ - - if (switchdev_trans_ph_prepare(trans)) - return; - - elem = (struct switchdev_trans_item *) mem - 1; - kfree(elem); -} - /************************************************************* * Flow, group, FDB, internal VLAN and neigh command prepares *************************************************************/ @@ -815,8 +757,7 @@ ofdpa_flow_tbl_find(const struct ofdpa *ofdpa, } static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - struct ofdpa_flow_tbl_entry *match) + int flags, struct ofdpa_flow_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_flow_tbl_entry *found; @@ -831,9 +772,8 @@ static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, if (found) { match->cookie = found->cookie; - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); - ofdpa_kfree(trans, found); + hash_del(&found->entry); + kfree(found); found = match; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_MOD; } else { @@ -842,22 +782,18 @@ static int ofdpa_flow_tbl_add(struct ofdpa_port *ofdpa_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_ADD; } - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32); - + hash_add(ofdpa->flow_tbl, &found->entry, found->key_crc32); spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags); - if (!switchdev_trans_ph_prepare(trans)) - return rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_flow_tbl_add, - found, NULL, NULL); + return rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_flow_tbl_add, + found, NULL, NULL); return 0; } static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - struct ofdpa_flow_tbl_entry *match) + int flags, struct ofdpa_flow_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_flow_tbl_entry *found; @@ -872,45 +808,41 @@ static int ofdpa_flow_tbl_del(struct ofdpa_port *ofdpa_port, found = ofdpa_flow_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_FLOW_DEL; } spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, lock_flags); - ofdpa_kfree(trans, match); + kfree(match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - err = rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_flow_tbl_del, - found, NULL, NULL); - ofdpa_kfree(trans, found); + err = rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_flow_tbl_del, + found, NULL, NULL); + kfree(found); } return err; } -static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_do(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_flow_tbl_entry *entry) { if (flags & OFDPA_OP_FLAG_REMOVE) - return ofdpa_flow_tbl_del(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_del(ofdpa_port, flags, entry); else - return ofdpa_flow_tbl_add(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_add(ofdpa_port, flags, entry); } -static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, int flags, u32 in_pport, u32 in_pport_mask, enum rocker_of_dpa_table_id goto_tbl) { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -920,11 +852,11 @@ static int ofdpa_flow_tbl_ig_port(struct ofdpa_port *ofdpa_port, entry->key.ig_port.in_pport_mask = in_pport_mask; entry->key.ig_port.goto_tbl = goto_tbl; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, + int flags, u32 in_pport, __be16 vlan_id, __be16 vlan_id_mask, enum rocker_of_dpa_table_id goto_tbl, @@ -932,7 +864,7 @@ static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -946,11 +878,10 @@ static int ofdpa_flow_tbl_vlan(struct ofdpa_port *ofdpa_port, entry->key.vlan.untagged = untagged; entry->key.vlan.new_vlan_id = new_vlan_id; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, u32 in_pport, u32 in_pport_mask, __be16 eth_type, const u8 *eth_dst, const u8 *eth_dst_mask, __be16 vlan_id, @@ -959,7 +890,7 @@ static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -983,13 +914,13 @@ static int ofdpa_flow_tbl_term_mac(struct ofdpa_port *ofdpa_port, entry->key.term_mac.vlan_id_mask = vlan_id_mask; entry->key.term_mac.copy_to_cpu = copy_to_cpu; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - const u8 *eth_dst, const u8 *eth_dst_mask, - __be16 vlan_id, u32 tunnel_id, + int flags, const u8 *eth_dst, + const u8 *eth_dst_mask, __be16 vlan_id, + u32 tunnel_id, enum rocker_of_dpa_table_id goto_tbl, u32 group_id, bool copy_to_cpu) { @@ -999,7 +930,7 @@ static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, bool dflt = !eth_dst || (eth_dst && eth_dst_mask); bool wild = false; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) return -ENOMEM; @@ -1037,11 +968,10 @@ static int ofdpa_flow_tbl_bridge(struct ofdpa_port *ofdpa_port, entry->key.bridge.group_id = group_id; entry->key.bridge.copy_to_cpu = copy_to_cpu; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be16 eth_type, __be32 dst, __be32 dst_mask, u32 priority, enum rocker_of_dpa_table_id goto_tbl, @@ -1050,7 +980,7 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, { struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1065,11 +995,10 @@ static int ofdpa_flow_tbl_ucast4_routing(struct ofdpa_port *ofdpa_port, ucast_routing.group_id); entry->fi = fi; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } -static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, int flags, u32 in_pport, u32 in_pport_mask, const u8 *eth_src, const u8 *eth_src_mask, const u8 *eth_dst, const u8 *eth_dst_mask, @@ -1081,7 +1010,7 @@ static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, u32 priority; struct ofdpa_flow_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1116,7 +1045,7 @@ static int ofdpa_flow_tbl_acl(struct ofdpa_port *ofdpa_port, entry->key.acl.ip_tos_mask = ip_tos_mask; entry->key.acl.group_id = group_id; - return ofdpa_flow_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_flow_tbl_do(ofdpa_port, flags, entry); } static struct ofdpa_group_tbl_entry * @@ -1134,22 +1063,20 @@ ofdpa_group_tbl_find(const struct ofdpa *ofdpa, return NULL; } -static void ofdpa_group_tbl_entry_free(struct switchdev_trans *trans, - struct ofdpa_group_tbl_entry *entry) +static void ofdpa_group_tbl_entry_free(struct ofdpa_group_tbl_entry *entry) { switch (ROCKER_GROUP_TYPE_GET(entry->group_id)) { case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: - ofdpa_kfree(trans, entry->group_ids); + kfree(entry->group_ids); break; default: break; } - ofdpa_kfree(trans, entry); + kfree(entry); } -static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1161,9 +1088,8 @@ static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, found = ofdpa_group_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); - ofdpa_group_tbl_entry_free(trans, found); + hash_del(&found->entry); + ofdpa_group_tbl_entry_free(found); found = match; found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_MOD; } else { @@ -1171,21 +1097,17 @@ static int ofdpa_group_tbl_add(struct ofdpa_port *ofdpa_port, found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_ADD; } - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->group_tbl, &found->entry, found->group_id); + hash_add(ofdpa->group_tbl, &found->entry, found->group_id); spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags); - if (!switchdev_trans_ph_prepare(trans)) - return rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_group_tbl_add, - found, NULL, NULL); - return 0; + return rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_group_tbl_add, + found, NULL, NULL); } -static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *match) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1198,97 +1120,90 @@ static int ofdpa_group_tbl_del(struct ofdpa_port *ofdpa_port, found = ofdpa_group_tbl_find(ofdpa, match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); found->cmd = ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL; } spin_unlock_irqrestore(&ofdpa->group_tbl_lock, lock_flags); - ofdpa_group_tbl_entry_free(trans, match); + ofdpa_group_tbl_entry_free(match); if (found) { - if (!switchdev_trans_ph_prepare(trans)) - err = rocker_cmd_exec(ofdpa_port->rocker_port, - ofdpa_flags_nowait(flags), - ofdpa_cmd_group_tbl_del, - found, NULL, NULL); - ofdpa_group_tbl_entry_free(trans, found); + err = rocker_cmd_exec(ofdpa_port->rocker_port, + ofdpa_flags_nowait(flags), + ofdpa_cmd_group_tbl_del, + found, NULL, NULL); + ofdpa_group_tbl_entry_free(found); } return err; } -static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_tbl_do(struct ofdpa_port *ofdpa_port, int flags, struct ofdpa_group_tbl_entry *entry) { if (flags & OFDPA_OP_FLAG_REMOVE) - return ofdpa_group_tbl_del(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_del(ofdpa_port, flags, entry); else - return ofdpa_group_tbl_add(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_add(ofdpa_port, flags, entry); } static int ofdpa_group_l2_interface(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id, u32 out_pport, - int pop_vlan) + int flags, __be16 vlan_id, + u32 out_pport, int pop_vlan) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); entry->l2_interface.pop_vlan = pop_vlan; - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_group_l2_fan_out(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u8 group_count, const u32 *group_ids, u32 group_id) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->group_id = group_id; entry->group_count = group_count; - entry->group_ids = ofdpa_kcalloc(trans, flags, - group_count, sizeof(u32)); + entry->group_ids = kcalloc(flags, group_count, sizeof(u32)); if (!entry->group_ids) { - ofdpa_kfree(trans, entry); + kfree(entry); return -ENOMEM; } memcpy(entry->group_ids, group_ids, group_count * sizeof(u32)); - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static int ofdpa_group_l2_flood(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id, u8 group_count, - const u32 *group_ids, u32 group_id) + int flags, __be16 vlan_id, + u8 group_count, const u32 *group_ids, + u32 group_id) { - return ofdpa_group_l2_fan_out(ofdpa_port, trans, flags, + return ofdpa_group_l2_fan_out(ofdpa_port, flags, group_count, group_ids, group_id); } -static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, int flags, u32 index, const u8 *src_mac, const u8 *dst_mac, __be16 vlan_id, bool ttl_check, u32 pport) { struct ofdpa_group_tbl_entry *entry; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1301,7 +1216,7 @@ static int ofdpa_group_l3_unicast(struct ofdpa_port *ofdpa_port, entry->l3_unicast.ttl_check = ttl_check; entry->l3_unicast.group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, pport); - return ofdpa_group_tbl_do(ofdpa_port, trans, flags, entry); + return ofdpa_group_tbl_do(ofdpa_port, flags, entry); } static struct ofdpa_neigh_tbl_entry * @@ -1318,43 +1233,34 @@ ofdpa_neigh_tbl_find(const struct ofdpa *ofdpa, __be32 ip_addr) } static void ofdpa_neigh_add(struct ofdpa *ofdpa, - struct switchdev_trans *trans, struct ofdpa_neigh_tbl_entry *entry) { - if (!switchdev_trans_ph_commit(trans)) - entry->index = ofdpa->neigh_tbl_next_index++; - if (switchdev_trans_ph_prepare(trans)) - return; + entry->index = ofdpa->neigh_tbl_next_index++; entry->ref_count++; hash_add(ofdpa->neigh_tbl, &entry->entry, be32_to_cpu(entry->ip_addr)); } -static void ofdpa_neigh_del(struct switchdev_trans *trans, - struct ofdpa_neigh_tbl_entry *entry) +static void ofdpa_neigh_del(struct ofdpa_neigh_tbl_entry *entry) { - if (switchdev_trans_ph_prepare(trans)) - return; if (--entry->ref_count == 0) { hash_del(&entry->entry); - ofdpa_kfree(trans, entry); + kfree(entry); } } static void ofdpa_neigh_update(struct ofdpa_neigh_tbl_entry *entry, - struct switchdev_trans *trans, const u8 *eth_dst, bool ttl_check) { if (eth_dst) { ether_addr_copy(entry->eth_dst, eth_dst); entry->ttl_check = ttl_check; - } else if (!switchdev_trans_ph_prepare(trans)) { + } else { entry->ref_count++; } } static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, __be32 ip_addr, const u8 *eth_dst) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1371,7 +1277,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, bool removing; int err = 0; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1388,12 +1294,12 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, entry->dev = ofdpa_port->dev; ether_addr_copy(entry->eth_dst, eth_dst); entry->ttl_check = true; - ofdpa_neigh_add(ofdpa, trans, entry); + ofdpa_neigh_add(ofdpa, entry); } else if (removing) { memcpy(entry, found, sizeof(*entry)); - ofdpa_neigh_del(trans, found); + ofdpa_neigh_del(found); } else if (updating) { - ofdpa_neigh_update(found, trans, eth_dst, true); + ofdpa_neigh_update(found, eth_dst, true); memcpy(entry, found, sizeof(*entry)); } else { err = -ENOENT; @@ -1410,7 +1316,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, * other routes' nexthops. */ - err = ofdpa_group_l3_unicast(ofdpa_port, trans, flags, + err = ofdpa_group_l3_unicast(ofdpa_port, flags, entry->index, ofdpa_port->dev->dev_addr, entry->eth_dst, @@ -1425,7 +1331,7 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, if (adding || removing) { group_id = ROCKER_GROUP_L3_UNICAST(entry->index); - err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, + err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, ip_addr, inet_make_mask(32), priority, goto_tbl, @@ -1438,13 +1344,12 @@ static int ofdpa_port_ipv4_neigh(struct ofdpa_port *ofdpa_port, err_out: if (!adding) - ofdpa_kfree(trans, entry); + kfree(entry); return err; } static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be32 ip_addr) { struct net_device *dev = ofdpa_port->dev; @@ -1463,7 +1368,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, */ if (n->nud_state & NUD_VALID) - err = ofdpa_port_ipv4_neigh(ofdpa_port, trans, 0, + err = ofdpa_port_ipv4_neigh(ofdpa_port, 0, ip_addr, n->ha); else neigh_event_send(n, NULL); @@ -1473,8 +1378,7 @@ static int ofdpa_port_ipv4_resolve(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be32 ip_addr, u32 *index) + int flags, __be32 ip_addr, u32 *index) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_neigh_tbl_entry *entry; @@ -1486,7 +1390,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, bool resolved = true; int err = 0; - entry = ofdpa_kzalloc(trans, flags, sizeof(*entry)); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -1501,14 +1405,14 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, if (adding) { entry->ip_addr = ip_addr; entry->dev = ofdpa_port->dev; - ofdpa_neigh_add(ofdpa, trans, entry); + ofdpa_neigh_add(ofdpa, entry); *index = entry->index; resolved = false; } else if (removing) { - ofdpa_neigh_del(trans, found); + ofdpa_neigh_del(found); *index = found->index; } else if (updating) { - ofdpa_neigh_update(found, trans, NULL, false); + ofdpa_neigh_update(found, NULL, false); resolved = !is_zero_ether_addr(found->eth_dst); *index = found->index; } else { @@ -1518,7 +1422,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, spin_unlock_irqrestore(&ofdpa->neigh_tbl_lock, lock_flags); if (!adding) - ofdpa_kfree(trans, entry); + kfree(entry); if (err) return err; @@ -1526,7 +1430,7 @@ static int ofdpa_port_ipv4_nh(struct ofdpa_port *ofdpa_port, /* Resolved means neigh ip_addr is resolved to neigh mac. */ if (!resolved) - err = ofdpa_port_ipv4_resolve(ofdpa_port, trans, ip_addr); + err = ofdpa_port_ipv4_resolve(ofdpa_port, ip_addr); return err; } @@ -1541,7 +1445,6 @@ static struct ofdpa_port *ofdpa_port_get(const struct ofdpa *ofdpa, } static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, __be16 vlan_id) { struct ofdpa_port *p; @@ -1553,7 +1456,7 @@ static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, int err = 0; int i; - group_ids = ofdpa_kcalloc(trans, flags, port_count, sizeof(u32)); + group_ids = kcalloc(flags, port_count, sizeof(u32)); if (!group_ids) return -ENOMEM; @@ -1578,18 +1481,17 @@ static int ofdpa_port_vlan_flood_group(struct ofdpa_port *ofdpa_port, if (group_count == 0) goto no_ports_in_vlan; - err = ofdpa_group_l2_flood(ofdpa_port, trans, flags, vlan_id, + err = ofdpa_group_l2_flood(ofdpa_port, flags, vlan_id, group_count, group_ids, group_id); if (err) netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err); no_ports_in_vlan: - ofdpa_kfree(trans, group_ids); + kfree(group_ids); return err; } -static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, int flags, __be16 vlan_id, bool pop_vlan) { const struct ofdpa *ofdpa = ofdpa_port->ofdpa; @@ -1608,7 +1510,7 @@ static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, if (ofdpa_port->stp_state == BR_STATE_LEARNING || ofdpa_port->stp_state == BR_STATE_FORWARDING) { out_pport = ofdpa_port->pport; - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n", @@ -1632,7 +1534,7 @@ static int ofdpa_port_vlan_l2_groups(struct ofdpa_port *ofdpa_port, return 0; out_pport = 0; - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for CPU port\n", err); @@ -1693,8 +1595,7 @@ static struct ofdpa_ctrl { }, }; -static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { u32 in_pport = ofdpa_port->pport; @@ -1710,7 +1611,7 @@ static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, u32 group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); int err; - err = ofdpa_flow_tbl_acl(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_acl(ofdpa_port, flags, in_pport, in_pport_mask, eth_src, eth_src_mask, ctrl->eth_dst, ctrl->eth_dst_mask, @@ -1727,9 +1628,7 @@ static int ofdpa_port_ctrl_vlan_acl(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, - int flags, - const struct ofdpa_ctrl *ctrl, + int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { enum rocker_of_dpa_table_id goto_tbl = @@ -1741,7 +1640,7 @@ static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, if (!ofdpa_port_is_bridged(ofdpa_port)) return 0; - err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, ctrl->eth_dst, ctrl->eth_dst_mask, vlan_id, tunnel_id, goto_tbl, group_id, ctrl->copy_to_cpu); @@ -1752,8 +1651,7 @@ static int ofdpa_port_ctrl_vlan_bridge(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { u32 in_pport_mask = 0xffffffff; @@ -1763,8 +1661,7 @@ static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, if (ntohs(vlan_id) == 0) vlan_id = ofdpa_port->internal_vlan_id; - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, in_pport_mask, ctrl->eth_type, ctrl->eth_dst, ctrl->eth_dst_mask, vlan_id, vlan_id_mask, ctrl->copy_to_cpu, @@ -1776,26 +1673,24 @@ static int ofdpa_port_ctrl_vlan_term(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl, __be16 vlan_id) { if (ctrl->acl) - return ofdpa_port_ctrl_vlan_acl(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_acl(ofdpa_port, flags, ctrl, vlan_id); if (ctrl->bridge) - return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_bridge(ofdpa_port, flags, ctrl, vlan_id); if (ctrl->term) - return ofdpa_port_ctrl_vlan_term(ofdpa_port, trans, flags, + return ofdpa_port_ctrl_vlan_term(ofdpa_port, flags, ctrl, vlan_id); return -EOPNOTSUPP; } -static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, int flags, __be16 vlan_id) { int err = 0; @@ -1803,7 +1698,7 @@ static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, for (i = 0; i < OFDPA_CTRL_MAX; i++) { if (ofdpa_port->ctrls[i]) { - err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan(ofdpa_port, flags, &ofdpa_ctrls[i], vlan_id); if (err) return err; @@ -1813,8 +1708,7 @@ static int ofdpa_port_ctrl_vlan_add(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, +static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, int flags, const struct ofdpa_ctrl *ctrl) { u16 vid; @@ -1823,7 +1717,7 @@ static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, for (vid = 1; vid < VLAN_N_VID; vid++) { if (!test_bit(vid, ofdpa_port->vlan_bitmap)) continue; - err = ofdpa_port_ctrl_vlan(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan(ofdpa_port, flags, ctrl, htons(vid)); if (err) break; @@ -1832,8 +1726,8 @@ static int ofdpa_port_ctrl(struct ofdpa_port *ofdpa_port, return err; } -static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u16 vid) +static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, int flags, + u16 vid) { enum rocker_of_dpa_table_id goto_tbl = ROCKER_OF_DPA_TABLE_ID_TERMINATION_MAC; @@ -1857,43 +1751,44 @@ static int ofdpa_port_vlan(struct ofdpa_port *ofdpa_port, change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); if (adding) { - err = ofdpa_port_ctrl_vlan_add(ofdpa_port, trans, flags, + err = ofdpa_port_ctrl_vlan_add(ofdpa_port, flags, internal_vlan_id); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port ctrl vlan add\n", err); - goto err_out; + goto err_vlan_add; } } - err = ofdpa_port_vlan_l2_groups(ofdpa_port, trans, flags, + err = ofdpa_port_vlan_l2_groups(ofdpa_port, flags, internal_vlan_id, untagged); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 groups\n", err); - goto err_out; + goto err_vlan_l2_groups; } - err = ofdpa_port_vlan_flood_group(ofdpa_port, trans, flags, + err = ofdpa_port_vlan_flood_group(ofdpa_port, flags, internal_vlan_id); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 flood group\n", err); - goto err_out; + goto err_flood_group; } - err = ofdpa_flow_tbl_vlan(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_vlan(ofdpa_port, flags, in_pport, vlan_id, vlan_id_mask, goto_tbl, untagged, internal_vlan_id); if (err) netdev_err(ofdpa_port->dev, "Error (%d) port VLAN table\n", err); -err_out: - if (switchdev_trans_ph_prepare(trans)) - change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); + return 0; +err_vlan_add: +err_vlan_l2_groups: +err_flood_group: + change_bit(ntohs(internal_vlan_id), ofdpa_port->vlan_bitmap); return err; } -static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, int flags) { enum rocker_of_dpa_table_id goto_tbl; u32 in_pport; @@ -1908,7 +1803,7 @@ static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, in_pport_mask = 0xffff0000; goto_tbl = ROCKER_OF_DPA_TABLE_ID_VLAN; - err = ofdpa_flow_tbl_ig_port(ofdpa_port, trans, flags, + err = ofdpa_flow_tbl_ig_port(ofdpa_port, flags, in_pport, in_pport_mask, goto_tbl); if (err) @@ -1920,7 +1815,6 @@ static int ofdpa_port_ig_tbl(struct ofdpa_port *ofdpa_port, struct ofdpa_fdb_learn_work { struct work_struct work; struct ofdpa_port *ofdpa_port; - struct switchdev_trans *trans; int flags; u8 addr[ETH_ALEN]; u16 vid; @@ -1939,19 +1833,18 @@ static void ofdpa_port_fdb_learn_work(struct work_struct *work) rtnl_lock(); if (learned && removing) - call_switchdev_notifiers(SWITCHDEV_FDB_DEL, + call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_BRIDGE, lw->ofdpa_port->dev, &info.info); else if (learned && !removing) - call_switchdev_notifiers(SWITCHDEV_FDB_ADD, + call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_BRIDGE, lw->ofdpa_port->dev, &info.info); rtnl_unlock(); - ofdpa_kfree(lw->trans, work); + kfree(work); } static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - const u8 *addr, __be16 vlan_id) + int flags, const u8 *addr, __be16 vlan_id) { struct ofdpa_fdb_learn_work *lw; enum rocker_of_dpa_table_id goto_tbl = @@ -1959,7 +1852,6 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, u32 out_pport = ofdpa_port->pport; u32 tunnel_id = 0; u32 group_id = ROCKER_GROUP_NONE; - bool syncing = !!(ofdpa_port->brport_flags & BR_LEARNING_SYNC); bool copy_to_cpu = false; int err; @@ -1967,36 +1859,28 @@ static int ofdpa_port_fdb_learn(struct ofdpa_port *ofdpa_port, group_id = ROCKER_GROUP_L2_INTERFACE(vlan_id, out_pport); if (!(flags & OFDPA_OP_FLAG_REFRESH)) { - err = ofdpa_flow_tbl_bridge(ofdpa_port, trans, flags, addr, + err = ofdpa_flow_tbl_bridge(ofdpa_port, flags, addr, NULL, vlan_id, tunnel_id, goto_tbl, group_id, copy_to_cpu); if (err) return err; } - if (!syncing) - return 0; - if (!ofdpa_port_is_bridged(ofdpa_port)) return 0; - lw = ofdpa_kzalloc(trans, flags, sizeof(*lw)); + lw = kzalloc(sizeof(*lw), GFP_ATOMIC); if (!lw) return -ENOMEM; INIT_WORK(&lw->work, ofdpa_port_fdb_learn_work); lw->ofdpa_port = ofdpa_port; - lw->trans = trans; lw->flags = flags; ether_addr_copy(lw->addr, addr); lw->vid = ofdpa_port_vlan_to_vid(ofdpa_port, vlan_id); - if (switchdev_trans_ph_prepare(trans)) - ofdpa_kfree(trans, lw); - else - schedule_work(&lw->work); - + schedule_work(&lw->work); return 0; } @@ -2014,7 +1898,6 @@ ofdpa_fdb_tbl_find(const struct ofdpa *ofdpa, } static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, const unsigned char *addr, __be16 vlan_id, int flags) { @@ -2024,7 +1907,7 @@ static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, bool removing = (flags & OFDPA_OP_FLAG_REMOVE); unsigned long lock_flags; - fdb = ofdpa_kzalloc(trans, flags, sizeof(*fdb)); + fdb = kzalloc(sizeof(*fdb), GFP_KERNEL); if (!fdb) return -ENOMEM; @@ -2042,32 +1925,29 @@ static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, if (found) { found->touched = jiffies; if (removing) { - ofdpa_kfree(trans, fdb); - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + kfree(fdb); + hash_del(&found->entry); } } else if (!removing) { - if (!switchdev_trans_ph_prepare(trans)) - hash_add(ofdpa->fdb_tbl, &fdb->entry, - fdb->key_crc32); + hash_add(ofdpa->fdb_tbl, &fdb->entry, + fdb->key_crc32); } spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags); /* Check if adding and already exists, or removing and can't find */ if (!found != !removing) { - ofdpa_kfree(trans, fdb); + kfree(fdb); if (!found && removing) return 0; /* Refreshing existing to update aging timers */ flags |= OFDPA_OP_FLAG_REFRESH; } - return ofdpa_port_fdb_learn(ofdpa_port, trans, flags, addr, vlan_id); + return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id); } -static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, int flags) { struct ofdpa *ofdpa = ofdpa_port->ofdpa; struct ofdpa_fdb_tbl_entry *found; @@ -2089,13 +1969,12 @@ static int ofdpa_port_fdb_flush(struct ofdpa_port *ofdpa_port, continue; if (!found->learned) continue; - err = ofdpa_port_fdb_learn(ofdpa_port, trans, flags, + err = ofdpa_port_fdb_learn(ofdpa_port, flags, found->key.addr, found->key.vlan_id); if (err) goto err_out; - if (!switchdev_trans_ph_prepare(trans)) - hash_del(&found->entry); + hash_del(&found->entry); } err_out: @@ -2125,8 +2004,8 @@ static void ofdpa_fdb_cleanup(unsigned long data) ofdpa_port = entry->key.ofdpa_port; expires = entry->touched + ofdpa_port->ageing_time; if (time_before_eq(expires, jiffies)) { - ofdpa_port_fdb_learn(ofdpa_port, NULL, - flags, entry->key.addr, + ofdpa_port_fdb_learn(ofdpa_port, flags, + entry->key.addr, entry->key.vlan_id); hash_del(&entry->entry); } else if (time_before(expires, next_timer)) { @@ -2140,8 +2019,7 @@ static void ofdpa_fdb_cleanup(unsigned long data) } static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, - __be16 vlan_id) + int flags, __be16 vlan_id) { u32 in_pport_mask = 0xffffffff; __be16 eth_type; @@ -2154,26 +2032,25 @@ static int ofdpa_port_router_mac(struct ofdpa_port *ofdpa_port, vlan_id = ofdpa_port->internal_vlan_id; eth_type = htons(ETH_P_IP); - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, - eth_type, ofdpa_port->dev->dev_addr, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, + in_pport_mask, eth_type, + ofdpa_port->dev->dev_addr, dst_mac_mask, vlan_id, vlan_id_mask, copy_to_cpu, flags); if (err) return err; eth_type = htons(ETH_P_IPV6); - err = ofdpa_flow_tbl_term_mac(ofdpa_port, trans, - ofdpa_port->pport, in_pport_mask, - eth_type, ofdpa_port->dev->dev_addr, + err = ofdpa_flow_tbl_term_mac(ofdpa_port, ofdpa_port->pport, + in_pport_mask, eth_type, + ofdpa_port->dev->dev_addr, dst_mac_mask, vlan_id, vlan_id_mask, copy_to_cpu, flags); return err; } -static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags) +static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, int flags) { bool pop_vlan; u32 out_pport; @@ -2198,7 +2075,7 @@ static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, continue; vlan_id = htons(vid); pop_vlan = ofdpa_vlan_id_is_internal(vlan_id); - err = ofdpa_group_l2_interface(ofdpa_port, trans, flags, + err = ofdpa_group_l2_interface(ofdpa_port, flags, vlan_id, out_pport, pop_vlan); if (err) { netdev_err(ofdpa_port->dev, "Error (%d) port VLAN l2 group for pport %d\n", @@ -2211,7 +2088,6 @@ static int ofdpa_port_fwding(struct ofdpa_port *ofdpa_port, } static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, int flags, u8 state) { bool want[OFDPA_CTRL_MAX] = { 0, }; @@ -2220,11 +2096,12 @@ static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, int err; int i; + memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); prev_state = ofdpa_port->stp_state; - if (prev_state == state) + + if (ofdpa_port->stp_state == state) return 0; - memcpy(prev_ctrls, ofdpa_port->ctrls, sizeof(prev_ctrls)); ofdpa_port->stp_state = state; switch (state) { @@ -2254,26 +2131,29 @@ static int ofdpa_port_stp_update(struct ofdpa_port *ofdpa_port, if (want[i] != ofdpa_port->ctrls[i]) { int ctrl_flags = flags | (want[i] ? 0 : OFDPA_OP_FLAG_REMOVE); - err = ofdpa_port_ctrl(ofdpa_port, trans, ctrl_flags, + err = ofdpa_port_ctrl(ofdpa_port, ctrl_flags, &ofdpa_ctrls[i]); if (err) - goto err_out; + goto err_port_ctrl; ofdpa_port->ctrls[i] = want[i]; } } - err = ofdpa_port_fdb_flush(ofdpa_port, trans, flags); + err = ofdpa_port_fdb_flush(ofdpa_port, flags); if (err) - goto err_out; + goto err_fdb_flush; - err = ofdpa_port_fwding(ofdpa_port, trans, flags); + err = ofdpa_port_fwding(ofdpa_port, flags); + if (err) + goto err_port_fwding; -err_out: - if (switchdev_trans_ph_prepare(trans)) { - memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls)); - ofdpa_port->stp_state = prev_state; - } + return 0; +err_port_ctrl: +err_fdb_flush: +err_port_fwding: + memcpy(ofdpa_port->ctrls, prev_ctrls, sizeof(prev_ctrls)); + ofdpa_port->stp_state = prev_state; return err; } @@ -2284,7 +2164,7 @@ static int ofdpa_port_fwd_enable(struct ofdpa_port *ofdpa_port, int flags) return 0; /* port is not bridged, so simulate going to FORWARDING state */ - return ofdpa_port_stp_update(ofdpa_port, NULL, flags, + return ofdpa_port_stp_update(ofdpa_port, flags, BR_STATE_FORWARDING); } @@ -2295,25 +2175,24 @@ static int ofdpa_port_fwd_disable(struct ofdpa_port *ofdpa_port, int flags) return 0; /* port is not bridged, so simulate going to DISABLED state */ - return ofdpa_port_stp_update(ofdpa_port, NULL, flags, + return ofdpa_port_stp_update(ofdpa_port, flags, BR_STATE_DISABLED); } static int ofdpa_port_vlan_add(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, u16 vid, u16 flags) { int err; /* XXX deal with flags for PVID and untagged */ - err = ofdpa_port_vlan(ofdpa_port, trans, 0, vid); + err = ofdpa_port_vlan(ofdpa_port, 0, vid); if (err) return err; - err = ofdpa_port_router_mac(ofdpa_port, trans, 0, htons(vid)); + err = ofdpa_port_router_mac(ofdpa_port, 0, htons(vid)); if (err) - ofdpa_port_vlan(ofdpa_port, trans, + ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE, vid); return err; @@ -2324,13 +2203,13 @@ static int ofdpa_port_vlan_del(struct ofdpa_port *ofdpa_port, { int err; - err = ofdpa_port_router_mac(ofdpa_port, NULL, - OFDPA_OP_FLAG_REMOVE, htons(vid)); + err = ofdpa_port_router_mac(ofdpa_port, OFDPA_OP_FLAG_REMOVE, + htons(vid)); if (err) return err; - return ofdpa_port_vlan(ofdpa_port, NULL, - OFDPA_OP_FLAG_REMOVE, vid); + return ofdpa_port_vlan(ofdpa_port, OFDPA_OP_FLAG_REMOVE, + vid); } static struct ofdpa_internal_vlan_tbl_entry * @@ -2389,10 +2268,9 @@ found: return found->vlan_id; } -static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, - struct switchdev_trans *trans, __be32 dst, - int dst_len, struct fib_info *fi, - u32 tb_id, int flags) +static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, __be32 dst, + int dst_len, struct fib_info *fi, u32 tb_id, + int flags) { const struct fib_nh *nh; __be16 eth_type = htons(ETH_P_IP); @@ -2414,7 +2292,7 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, has_gw = !!nh->nh_gw; if (has_gw && nh_on_port) { - err = ofdpa_port_ipv4_nh(ofdpa_port, trans, flags, + err = ofdpa_port_ipv4_nh(ofdpa_port, flags, nh->nh_gw, &index); if (err) return err; @@ -2425,7 +2303,7 @@ static int ofdpa_port_fib_ipv4(struct ofdpa_port *ofdpa_port, group_id = ROCKER_GROUP_L2_INTERFACE(internal_vlan_id, 0); } - err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, trans, eth_type, dst, + err = ofdpa_flow_tbl_ucast4_routing(ofdpa_port, eth_type, dst, dst_mask, priority, goto_tbl, group_id, fi, flags); if (err) @@ -2550,7 +2428,7 @@ static int ofdpa_port_pre_init(struct rocker_port *rocker_port) ofdpa_port->rocker_port = rocker_port; ofdpa_port->dev = rocker_port->dev; ofdpa_port->pport = rocker_port->pport; - ofdpa_port->brport_flags = BR_LEARNING | BR_LEARNING_SYNC; + ofdpa_port->brport_flags = BR_LEARNING; ofdpa_port->ageing_time = BR_DEFAULT_AGEING_TIME; return 0; } @@ -2563,7 +2441,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) rocker_port_set_learning(rocker_port, !!(ofdpa_port->brport_flags & BR_LEARNING)); - err = ofdpa_port_ig_tbl(ofdpa_port, NULL, 0); + err = ofdpa_port_ig_tbl(ofdpa_port, 0); if (err) { netdev_err(ofdpa_port->dev, "install ig port table failed\n"); return err; @@ -2573,7 +2451,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) ofdpa_port_internal_vlan_id_get(ofdpa_port, ofdpa_port->dev->ifindex); - err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); if (err) { netdev_err(ofdpa_port->dev, "install untagged VLAN failed\n"); goto err_untagged_vlan; @@ -2581,7 +2459,7 @@ static int ofdpa_port_init(struct rocker_port *rocker_port) return 0; err_untagged_vlan: - ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE); + ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE); return err; } @@ -2589,7 +2467,7 @@ static void ofdpa_port_fini(struct rocker_port *rocker_port) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - ofdpa_port_ig_tbl(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE); + ofdpa_port_ig_tbl(ofdpa_port, OFDPA_OP_FLAG_REMOVE); } static int ofdpa_port_open(struct rocker_port *rocker_port) @@ -2607,12 +2485,11 @@ static void ofdpa_port_stop(struct rocker_port *rocker_port) } static int ofdpa_port_attr_stp_state_set(struct rocker_port *rocker_port, - u8 state, - struct switchdev_trans *trans) + u8 state) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - return ofdpa_port_stp_update(ofdpa_port, trans, 0, state); + return ofdpa_port_stp_update(ofdpa_port, 0, state); } static int ofdpa_port_attr_bridge_flags_set(struct rocker_port *rocker_port, @@ -2647,6 +2524,16 @@ ofdpa_port_attr_bridge_flags_get(const struct rocker_port *rocker_port, } static int +ofdpa_port_attr_bridge_flags_support_get(const struct rocker_port * + rocker_port, + unsigned long * + p_brport_flags_support) +{ + *p_brport_flags_support = BR_LEARNING; + return 0; +} + +static int ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, u32 ageing_time, struct switchdev_trans *trans) @@ -2665,15 +2552,14 @@ ofdpa_port_attr_bridge_ageing_time_set(struct rocker_port *rocker_port, } static int ofdpa_port_obj_vlan_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans) + const struct switchdev_obj_port_vlan *vlan) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; u16 vid; int err; for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) { - err = ofdpa_port_vlan_add(ofdpa_port, trans, vid, vlan->flags); + err = ofdpa_port_vlan_add(ofdpa_port, vid, vlan->flags); if (err) return err; } @@ -2697,82 +2583,29 @@ static int ofdpa_port_obj_vlan_del(struct rocker_port *rocker_port, return 0; } -static int ofdpa_port_obj_vlan_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_vlan *vlan, - switchdev_obj_dump_cb_t *cb) -{ - const struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - u16 vid; - int err = 0; - - for (vid = 1; vid < VLAN_N_VID; vid++) { - if (!test_bit(vid, ofdpa_port->vlan_bitmap)) - continue; - vlan->flags = 0; - if (ofdpa_vlan_id_is_internal(htons(vid))) - vlan->flags |= BRIDGE_VLAN_INFO_PVID; - vlan->vid_begin = vlan->vid_end = vid; - err = cb(&vlan->obj); - if (err) - break; - } - - return err; -} - static int ofdpa_port_obj_fdb_add(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans) + u16 vid, const unsigned char *addr) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL); + __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL); if (!ofdpa_port_is_bridged(ofdpa_port)) return -EINVAL; - return ofdpa_port_fdb(ofdpa_port, trans, fdb->addr, vlan_id, 0); + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, 0); } static int ofdpa_port_obj_fdb_del(struct rocker_port *rocker_port, - const struct switchdev_obj_port_fdb *fdb) + u16 vid, const unsigned char *addr) { struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, fdb->vid, NULL); + __be16 vlan_id = ofdpa_port_vid_to_vlan(ofdpa_port, vid, NULL); int flags = OFDPA_OP_FLAG_REMOVE; if (!ofdpa_port_is_bridged(ofdpa_port)) return -EINVAL; - return ofdpa_port_fdb(ofdpa_port, NULL, fdb->addr, vlan_id, flags); -} - -static int ofdpa_port_obj_fdb_dump(const struct rocker_port *rocker_port, - struct switchdev_obj_port_fdb *fdb, - switchdev_obj_dump_cb_t *cb) -{ - const struct ofdpa_port *ofdpa_port = rocker_port->wpriv; - struct ofdpa *ofdpa = ofdpa_port->ofdpa; - struct ofdpa_fdb_tbl_entry *found; - struct hlist_node *tmp; - unsigned long lock_flags; - int bkt; - int err = 0; - - spin_lock_irqsave(&ofdpa->fdb_tbl_lock, lock_flags); - hash_for_each_safe(ofdpa->fdb_tbl, bkt, tmp, found, entry) { - if (found->key.ofdpa_port != ofdpa_port) - continue; - ether_addr_copy(fdb->addr, found->key.addr); - fdb->ndm_state = NUD_REACHABLE; - fdb->vid = ofdpa_port_vlan_to_vid(ofdpa_port, - found->key.vlan_id); - err = cb(&fdb->obj); - if (err) - break; - } - spin_unlock_irqrestore(&ofdpa->fdb_tbl_lock, lock_flags); - - return err; + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags); } static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port, @@ -2797,7 +2630,7 @@ static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port, ofdpa_port->bridge_dev = bridge; - return ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + return ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); } static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port) @@ -2816,7 +2649,7 @@ static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port) ofdpa_port->bridge_dev = NULL; - err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0); + err = ofdpa_port_vlan_add(ofdpa_port, OFDPA_UNTAGGED_VID, 0); if (err) return err; @@ -2875,7 +2708,7 @@ static int ofdpa_port_neigh_update(struct rocker_port *rocker_port, OFDPA_OP_FLAG_NOWAIT; __be32 ip_addr = *(__be32 *) n->primary_key; - return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha); + return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha); } static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port, @@ -2885,7 +2718,7 @@ static int ofdpa_port_neigh_destroy(struct rocker_port *rocker_port, int flags = OFDPA_OP_FLAG_REMOVE | OFDPA_OP_FLAG_NOWAIT; __be32 ip_addr = *(__be32 *) n->primary_key; - return ofdpa_port_ipv4_neigh(ofdpa_port, NULL, flags, ip_addr, n->ha); + return ofdpa_port_ipv4_neigh(ofdpa_port, flags, ip_addr, n->ha); } static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port, @@ -2899,7 +2732,7 @@ static int ofdpa_port_ev_mac_vlan_seen(struct rocker_port *rocker_port, ofdpa_port->stp_state != BR_STATE_FORWARDING) return 0; - return ofdpa_port_fdb(ofdpa_port, NULL, addr, vlan_id, flags); + return ofdpa_port_fdb(ofdpa_port, addr, vlan_id, flags); } static struct ofdpa_port *ofdpa_port_dev_lower_find(struct net_device *dev, @@ -2923,7 +2756,7 @@ static int ofdpa_fib4_add(struct rocker *rocker, ofdpa_port = ofdpa_port_dev_lower_find(fen_info->fi->fib_dev, rocker); if (!ofdpa_port) return 0; - err = ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), + err = ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst), fen_info->dst_len, fen_info->fi, fen_info->tb_id, 0); if (err) @@ -2944,7 +2777,7 @@ static int ofdpa_fib4_del(struct rocker *rocker, if (!ofdpa_port) return 0; fib_info_offload_dec(fen_info->fi); - return ofdpa_port_fib_ipv4(ofdpa_port, NULL, htonl(fen_info->dst), + return ofdpa_port_fib_ipv4(ofdpa_port, htonl(fen_info->dst), fen_info->dst_len, fen_info->fi, fen_info->tb_id, OFDPA_OP_FLAG_REMOVE); } @@ -2971,7 +2804,7 @@ static void ofdpa_fib4_abort(struct rocker *rocker) if (!ofdpa_port) continue; fib_info_offload_dec(flow_entry->fi); - ofdpa_flow_tbl_del(ofdpa_port, NULL, OFDPA_OP_FLAG_REMOVE, + ofdpa_flow_tbl_del(ofdpa_port, OFDPA_OP_FLAG_REMOVE, flow_entry); } spin_unlock_irqrestore(&ofdpa->flow_tbl_lock, flags); @@ -2993,13 +2826,12 @@ struct rocker_world_ops rocker_ofdpa_ops = { .port_attr_stp_state_set = ofdpa_port_attr_stp_state_set, .port_attr_bridge_flags_set = ofdpa_port_attr_bridge_flags_set, .port_attr_bridge_flags_get = ofdpa_port_attr_bridge_flags_get, + .port_attr_bridge_flags_support_get = ofdpa_port_attr_bridge_flags_support_get, .port_attr_bridge_ageing_time_set = ofdpa_port_attr_bridge_ageing_time_set, .port_obj_vlan_add = ofdpa_port_obj_vlan_add, .port_obj_vlan_del = ofdpa_port_obj_vlan_del, - .port_obj_vlan_dump = ofdpa_port_obj_vlan_dump, .port_obj_fdb_add = ofdpa_port_obj_fdb_add, .port_obj_fdb_del = ofdpa_port_obj_fdb_del, - .port_obj_fdb_dump = ofdpa_port_obj_fdb_dump, .port_master_linked = ofdpa_port_master_linked, .port_master_unlinked = ofdpa_port_master_unlinked, .port_neigh_update = ofdpa_port_neigh_update, diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 6c5d5ef46f75..a3ec1892a286 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2005,12 +2005,6 @@ static const struct net_device_ops team_netdev_ops = { .ndo_del_slave = team_del_slave, .ndo_fix_features = team_fix_features, .ndo_change_carrier = team_change_carrier, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_features_check = passthru_features_check, }; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 929d6af321cd..c784a6ac6ef1 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -46,6 +46,7 @@ enum switchdev_attr_id { SWITCHDEV_ATTR_ID_PORT_PARENT_ID, SWITCHDEV_ATTR_ID_PORT_STP_STATE, SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, + SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT, SWITCHDEV_ATTR_ID_PORT_MROUTER, SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, @@ -62,6 +63,7 @@ struct switchdev_attr { struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ u8 stp_state; /* PORT_STP_STATE */ unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ + unsigned long brport_flags_support; /* PORT_BRIDGE_FLAGS_SUPPORT */ bool mrouter; /* PORT_MROUTER */ clock_t ageing_time; /* BRIDGE_AGEING_TIME */ bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ @@ -153,8 +155,11 @@ struct switchdev_ops { }; enum switchdev_notifier_type { - SWITCHDEV_FDB_ADD = 1, - SWITCHDEV_FDB_DEL, + SWITCHDEV_FDB_ADD_TO_BRIDGE = 1, + SWITCHDEV_FDB_DEL_TO_BRIDGE, + SWITCHDEV_FDB_ADD_TO_DEVICE, + SWITCHDEV_FDB_DEL_TO_DEVICE, + SWITCHDEV_FDB_OFFLOADED, }; struct switchdev_notifier_info { diff --git a/include/uapi/linux/neighbour.h b/include/uapi/linux/neighbour.h index f3d16dbe09d6..3199d28980b3 100644 --- a/include/uapi/linux/neighbour.h +++ b/include/uapi/linux/neighbour.h @@ -41,6 +41,7 @@ enum { #define NTF_MASTER 0x04 #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_EXT_LEARNED 0x10 +#define NTF_OFFLOADED 0x20 #define NTF_ROUTER 0x80 /* diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 953b6728bd00..56d4b6977d03 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -797,12 +797,6 @@ static const struct net_device_ops vlan_netdev_ops = { .ndo_netpoll_cleanup = vlan_dev_netpoll_cleanup, #endif .ndo_fix_features = vlan_dev_fix_features, - .ndo_fdb_add = switchdev_port_fdb_add, - .ndo_fdb_del = switchdev_port_fdb_del, - .ndo_fdb_dump = switchdev_port_fdb_dump, - .ndo_bridge_setlink = switchdev_port_bridge_setlink, - .ndo_bridge_getlink = switchdev_port_bridge_getlink, - .ndo_bridge_dellink = switchdev_port_bridge_dellink, .ndo_get_lock_subclass = vlan_dev_get_lock_subclass, .ndo_get_iflink = vlan_dev_get_iflink, }; diff --git a/net/bridge/br.c b/net/bridge/br.c index 889e5640455f..1407d1ba7577 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -121,7 +121,7 @@ static struct notifier_block br_device_notifier = { .notifier_call = br_device_event }; -/* called with RTNL */ +/* called with RTNL or RCU */ static int br_switchdev_event(struct notifier_block *unused, unsigned long event, void *ptr) { @@ -131,27 +131,36 @@ static int br_switchdev_event(struct notifier_block *unused, struct switchdev_notifier_fdb_info *fdb_info; int err = NOTIFY_DONE; - p = br_port_get_rtnl(dev); + p = br_port_get_rtnl_rcu(dev); if (!p) goto out; br = p->br; switch (event) { - case SWITCHDEV_FDB_ADD: + case SWITCHDEV_FDB_ADD_TO_BRIDGE: fdb_info = ptr; err = br_fdb_external_learn_add(br, p, fdb_info->addr, fdb_info->vid); - if (err) + if (err) { err = notifier_from_errno(err); + break; + } + br_fdb_offloaded_set(br, p, fdb_info->addr, + fdb_info->vid); break; - case SWITCHDEV_FDB_DEL: + case SWITCHDEV_FDB_DEL_TO_BRIDGE: fdb_info = ptr; err = br_fdb_external_learn_del(br, p, fdb_info->addr, fdb_info->vid); if (err) err = notifier_from_errno(err); break; + case SWITCHDEV_FDB_OFFLOADED: + fdb_info = ptr; + br_fdb_offloaded_set(br, p, fdb_info->addr, + fdb_info->vid); + break; } out: diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index ab0c7cc8448f..fef7872a320b 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -511,6 +511,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head, fdb->is_static = is_static; fdb->added_by_user = 0; fdb->added_by_external_learn = 0; + fdb->offloaded = 0; fdb->updated = fdb->used = jiffies; hlist_add_head_rcu(&fdb->hlist, head); } @@ -647,11 +648,16 @@ static int fdb_fill_info(struct sk_buff *skb, const struct net_bridge *br, ndm->ndm_family = AF_BRIDGE; ndm->ndm_pad1 = 0; ndm->ndm_pad2 = 0; - ndm->ndm_flags = fdb->added_by_external_learn ? NTF_EXT_LEARNED : 0; + ndm->ndm_flags = 0; ndm->ndm_type = 0; ndm->ndm_ifindex = fdb->dst ? fdb->dst->dev->ifindex : br->dev->ifindex; ndm->ndm_state = fdb_to_nud(br, fdb); + if (fdb->offloaded) + ndm->ndm_flags |= NTF_OFFLOADED; + if (fdb->added_by_external_learn) + ndm->ndm_flags |= NTF_EXT_LEARNED; + if (nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->addr)) goto nla_put_failure; if (nla_put_u32(skb, NDA_MASTER, br->dev->ifindex)) @@ -690,6 +696,8 @@ static void fdb_notify(struct net_bridge *br, struct sk_buff *skb; int err = -ENOBUFS; + br_switchdev_fdb_notify(fdb, type); + skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC); if (skb == NULL) goto errout; @@ -1075,7 +1083,6 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, struct net_bridge_fdb_entry *fdb; int err = 0; - ASSERT_RTNL(); spin_lock_bh(&br->hash_lock); head = &br->hash[br_mac_hash(addr, vid)]; @@ -1110,7 +1117,6 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, struct net_bridge_fdb_entry *fdb; int err = 0; - ASSERT_RTNL(); spin_lock_bh(&br->hash_lock); fdb = br_fdb_find(br, addr, vid); @@ -1123,3 +1129,17 @@ int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, return err; } + +void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, + const unsigned char *addr, u16 vid) +{ + struct net_bridge_fdb_entry *fdb; + + spin_lock_bh(&br->hash_lock); + + fdb = br_fdb_find(br, addr, vid); + if (fdb) + fdb->offloaded = 1; + + spin_unlock_bh(&br->hash_lock); +} diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 3bcda556971e..63dca347b73b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -662,16 +662,26 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state) } /* Set/clear or port flags based on attribute */ -static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], - int attrtype, unsigned long mask) +static int br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], + int attrtype, unsigned long mask) { - if (tb[attrtype]) { - u8 flag = nla_get_u8(tb[attrtype]); - if (flag) - p->flags |= mask; - else - p->flags &= ~mask; - } + unsigned long flags; + int err; + + if (!tb[attrtype]) + return 0; + + if (nla_get_u8(tb[attrtype])) + flags = p->flags | mask; + else + flags = p->flags & ~mask; + + err = br_switchdev_set_port_flag(p, flags, mask); + if (err) + return err; + + p->flags = flags; + return 0; } /* Process bridge protocol info on port */ @@ -681,20 +691,55 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) bool br_vlan_tunnel_old = false; int err; - br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); - br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); - br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); - br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); - br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); - br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); - br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); - br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST); - br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD); - br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); - br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); + err = br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); + if (err) + return err; + + err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); + if (err) + return err; br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false; - br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); + err = br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); + if (err) + return err; + if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL)) nbp_vlan_tunnel_info_flush(p); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 20626927f433..c18682f804a0 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -169,7 +169,8 @@ struct net_bridge_fdb_entry { unsigned char is_local:1, is_static:1, added_by_user:1, - added_by_external_learn:1; + added_by_external_learn:1, + offloaded:1; /* write-heavy members should not affect lookups */ unsigned long updated ____cacheline_aligned_in_smp; @@ -284,6 +285,12 @@ static inline struct net_bridge_port *br_port_get_rtnl(const struct net_device * rtnl_dereference(dev->rx_handler_data) : NULL; } +static inline struct net_bridge_port *br_port_get_rtnl_rcu(const struct net_device *dev) +{ + return br_port_exists(dev) ? + rcu_dereference_rtnl(dev->rx_handler_data) : NULL; +} + struct net_bridge { spinlock_t lock; spinlock_t hash_lock; @@ -530,6 +537,8 @@ int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, const unsigned char *addr, u16 vid); int br_fdb_external_learn_del(struct net_bridge *br, struct net_bridge_port *p, const unsigned char *addr, u16 vid); +void br_fdb_offloaded_set(struct net_bridge *br, struct net_bridge_port *p, + const unsigned char *addr, u16 vid); /* br_forward.c */ enum br_pkt_type { @@ -1076,6 +1085,11 @@ void nbp_switchdev_frame_mark(const struct net_bridge_port *p, struct sk_buff *skb); bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, const struct sk_buff *skb); +int br_switchdev_set_port_flag(struct net_bridge_port *p, + unsigned long flags, + unsigned long mask); +void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, + int type); #else static inline int nbp_switchdev_mark_set(struct net_bridge_port *p) { @@ -1092,6 +1106,18 @@ static inline bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, { return true; } + +static inline int br_switchdev_set_port_flag(struct net_bridge_port *p, + unsigned long flags, + unsigned long mask) +{ + return 0; +} + +static inline void +br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) +{ +} #endif /* CONFIG_NET_SWITCHDEV */ #endif diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index f4097b900de1..181a44d0f1da 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -55,3 +55,79 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, return !skb->offload_fwd_mark || BR_INPUT_SKB_CB(skb)->offload_fwd_mark != p->offload_fwd_mark; } + +/* Flags that can be offloaded to hardware */ +#define BR_PORT_FLAGS_HW_OFFLOAD (BR_LEARNING | BR_FLOOD | \ + BR_MCAST_FLOOD | BR_BCAST_FLOOD) + +int br_switchdev_set_port_flag(struct net_bridge_port *p, + unsigned long flags, + unsigned long mask) +{ + struct switchdev_attr attr = { + .orig_dev = p->dev, + .id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT, + }; + int err; + + if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD) + return 0; + + err = switchdev_port_attr_get(p->dev, &attr); + if (err == -EOPNOTSUPP) + return 0; + if (err) + return err; + + /* Check if specific bridge flag attribute offload is supported */ + if (!(attr.u.brport_flags_support & mask)) { + br_warn(p->br, "bridge flag offload is not supported %u(%s)\n", + (unsigned int)p->port_no, p->dev->name); + return -EOPNOTSUPP; + } + + attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS; + attr.flags = SWITCHDEV_F_DEFER; + attr.u.brport_flags = flags; + err = switchdev_port_attr_set(p->dev, &attr); + if (err) { + br_warn(p->br, "error setting offload flag on port %u(%s)\n", + (unsigned int)p->port_no, p->dev->name); + return err; + } + + return 0; +} + +static void +br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac, + u16 vid, struct net_device *dev) +{ + struct switchdev_notifier_fdb_info info; + unsigned long notifier_type; + + info.addr = mac; + info.vid = vid; + notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE; + call_switchdev_notifiers(notifier_type, dev, &info.info); +} + +void +br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type) +{ + if (!fdb->added_by_user) + return; + + switch (type) { + case RTM_DELNEIGH: + br_switchdev_fdb_call_notifiers(false, fdb->addr.addr, + fdb->vlan_id, + fdb->dst->dev); + break; + case RTM_NEWNEIGH: + br_switchdev_fdb_call_notifiers(true, fdb->addr.addr, + fdb->vlan_id, + fdb->dst->dev); + break; + } +} diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 8d40a7d31c99..25dc67ef9d37 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -571,24 +571,17 @@ int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, } EXPORT_SYMBOL_GPL(switchdev_port_obj_dump); -static RAW_NOTIFIER_HEAD(switchdev_notif_chain); +static ATOMIC_NOTIFIER_HEAD(switchdev_notif_chain); /** * register_switchdev_notifier - Register notifier * @nb: notifier_block * - * Register switch device notifier. This should be used by code - * which needs to monitor events happening in particular device. - * Return values are same as for atomic_notifier_chain_register(). + * Register switch device notifier. */ int register_switchdev_notifier(struct notifier_block *nb) { - int err; - - rtnl_lock(); - err = raw_notifier_chain_register(&switchdev_notif_chain, nb); - rtnl_unlock(); - return err; + return atomic_notifier_chain_register(&switchdev_notif_chain, nb); } EXPORT_SYMBOL_GPL(register_switchdev_notifier); @@ -597,16 +590,10 @@ EXPORT_SYMBOL_GPL(register_switchdev_notifier); * @nb: notifier_block * * Unregister switch device notifier. - * Return values are same as for atomic_notifier_chain_unregister(). */ int unregister_switchdev_notifier(struct notifier_block *nb) { - int err; - - rtnl_lock(); - err = raw_notifier_chain_unregister(&switchdev_notif_chain, nb); - rtnl_unlock(); - return err; + return atomic_notifier_chain_unregister(&switchdev_notif_chain, nb); } EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); @@ -616,18 +603,13 @@ EXPORT_SYMBOL_GPL(unregister_switchdev_notifier); * @dev: port device * @info: notifier information data * - * Call all network notifier blocks. This should be called by driver - * when it needs to propagate hardware event. - * Return values are same as for atomic_notifier_call_chain(). - * rtnl_lock must be held. + * Call all network notifier blocks. */ int call_switchdev_notifiers(unsigned long val, struct net_device *dev, struct switchdev_notifier_info *info) { - ASSERT_RTNL(); - info->dev = dev; - return raw_notifier_call_chain(&switchdev_notif_chain, val, info); + return atomic_notifier_call_chain(&switchdev_notif_chain, val, info); } EXPORT_SYMBOL_GPL(call_switchdev_notifiers); |