aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-06-08 14:16:31 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-08 14:16:31 -0400
commit4cd31af77582653a8e4b367fdb612e84a2cdd685 (patch)
treec88e676bbbe2590489392fdad2f69792b29f600e
parentMerge branch 'dsa-add-cross-chip-VLAN-support' (diff)
parentrocker: Remove support bridge bypass FDB (diff)
downloadlinux-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.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c360
-rw-r--r--drivers/net/ethernet/rocker/rocker.h21
-rw-r--r--drivers/net/ethernet/rocker/rocker_main.c235
-rw-r--r--drivers/net/ethernet/rocker/rocker_ofdpa.c610
-rw-r--r--drivers/net/team/team.c6
-rw-r--r--include/net/switchdev.h9
-rw-r--r--include/uapi/linux/neighbour.h1
-rw-r--r--net/8021q/vlan_dev.c6
-rw-r--r--net/bridge/br.c19
-rw-r--r--net/bridge/br_fdb.c26
-rw-r--r--net/bridge/br_netlink.c87
-rw-r--r--net/bridge/br_private.h28
-rw-r--r--net/bridge/br_switchdev.c76
-rw-r--r--net/switchdev/switchdev.c30
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);