Commit 195bb48f authored by Michal Swiatkowski's avatar Michal Swiatkowski Committed by Tony Nguyen

ice: support for indirect notification

Implement indirect notification mechanism to support offloading TC rules
on tunnel devices.

Keep indirect block list in netdev priv. Notification will call setting
tc cls flower function. For now we can offload only ingress type. Return
not supported for other flow block binder.
Signed-off-by: default avatarMichal Swiatkowski <michal.swiatkowski@linux.intel.com>
Acked-by: default avatarPaul Menzel <pmenzel@molgen.mpg.de>
Tested-by: default avatarSandeep Penigalapati <sandeep.penigalapati@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent f2edaa4a
......@@ -34,6 +34,7 @@
#include <linux/if_bridge.h>
#include <linux/ctype.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/auxiliary_bus.h>
#include <linux/avf/virtchnl.h>
#include <linux/cpu_rmap.h>
......@@ -610,6 +611,13 @@ struct ice_pf {
struct ice_netdev_priv {
struct ice_vsi *vsi;
struct ice_repr *repr;
/* indirect block callbacks on registered higher level devices
* (e.g. tunnel devices)
*
* tc_indr_block_cb_priv_list is used to look up indirect callback
* private data
*/
struct list_head tc_indr_block_priv_list;
};
/**
......
......@@ -58,6 +58,12 @@ static void ice_vsi_release_all(struct ice_pf *pf);
static int ice_rebuild_channels(struct ice_pf *pf);
static void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_adv_fltr);
static int
ice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch,
void *cb_priv, enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb));
bool netif_is_ice(struct net_device *dev)
{
return dev && (dev->netdev_ops == &ice_netdev_ops);
......@@ -3393,6 +3399,63 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
return ret;
}
/**
* ice_rep_indr_tc_block_unbind
* @cb_priv: indirection block private data
*/
static void ice_rep_indr_tc_block_unbind(void *cb_priv)
{
struct ice_indr_block_priv *indr_priv = cb_priv;
list_del(&indr_priv->list);
kfree(indr_priv);
}
/**
* ice_tc_indir_block_unregister - Unregister TC indirect block notifications
* @vsi: VSI struct which has the netdev
*/
static void ice_tc_indir_block_unregister(struct ice_vsi *vsi)
{
struct ice_netdev_priv *np = netdev_priv(vsi->netdev);
flow_indr_dev_unregister(ice_indr_setup_tc_cb, np,
ice_rep_indr_tc_block_unbind);
}
/**
* ice_tc_indir_block_remove - clean indirect TC block notifications
* @pf: PF structure
*/
static void ice_tc_indir_block_remove(struct ice_pf *pf)
{
struct ice_vsi *pf_vsi = ice_get_main_vsi(pf);
if (!pf_vsi)
return;
ice_tc_indir_block_unregister(pf_vsi);
}
/**
* ice_tc_indir_block_register - Register TC indirect block notifications
* @vsi: VSI struct which has the netdev
*
* Returns 0 on success, negative value on failure
*/
static int ice_tc_indir_block_register(struct ice_vsi *vsi)
{
struct ice_netdev_priv *np;
if (!vsi || !vsi->netdev)
return -EINVAL;
np = netdev_priv(vsi->netdev);
INIT_LIST_HEAD(&np->tc_indr_block_priv_list);
return flow_indr_dev_register(ice_indr_setup_tc_cb, np);
}
/**
* ice_setup_pf_sw - Setup the HW switch on startup or after reset
* @pf: board private structure
......@@ -3401,6 +3464,7 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto,
*/
static int ice_setup_pf_sw(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_vsi *vsi;
int status = 0;
......@@ -3422,6 +3486,13 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
/* netdev has to be configured before setting frame size */
ice_vsi_cfg_frame_size(vsi);
/* init indirect block notifications */
status = ice_tc_indir_block_register(vsi);
if (status) {
dev_err(dev, "Failed to register netdev notifier\n");
goto unroll_cfg_netdev;
}
/* Setup DCB netlink interface */
ice_dcbnl_setup(vsi);
......@@ -3433,7 +3504,7 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
status = ice_set_cpu_rx_rmap(vsi);
if (status) {
dev_err(ice_pf_to_dev(pf), "Failed to set CPU Rx map VSI %d error %d\n",
dev_err(dev, "Failed to set CPU Rx map VSI %d error %d\n",
vsi->vsi_num, status);
status = -EINVAL;
goto unroll_napi_add;
......@@ -3446,8 +3517,9 @@ static int ice_setup_pf_sw(struct ice_pf *pf)
free_cpu_rx_map:
ice_free_cpu_rx_rmap(vsi);
unroll_napi_add:
ice_tc_indir_block_unregister(vsi);
unroll_cfg_netdev:
if (vsi) {
ice_napi_del(vsi);
if (vsi->netdev) {
......@@ -4721,6 +4793,8 @@ static void ice_remove(struct pci_dev *pdev)
msleep(100);
}
ice_tc_indir_block_remove(pf);
if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
set_bit(ICE_VF_RESETS_DISABLED, pf->state);
ice_free_vfs(pf);
......@@ -8155,6 +8229,116 @@ ice_setup_tc(struct net_device *netdev, enum tc_setup_type type,
return -EOPNOTSUPP;
}
static struct ice_indr_block_priv *
ice_indr_block_priv_lookup(struct ice_netdev_priv *np,
struct net_device *netdev)
{
struct ice_indr_block_priv *cb_priv;
list_for_each_entry(cb_priv, &np->tc_indr_block_priv_list, list) {
if (!cb_priv->netdev)
return NULL;
if (cb_priv->netdev == netdev)
return cb_priv;
}
return NULL;
}
static int
ice_indr_setup_block_cb(enum tc_setup_type type, void *type_data,
void *indr_priv)
{
struct ice_indr_block_priv *priv = indr_priv;
struct ice_netdev_priv *np = priv->np;
switch (type) {
case TC_SETUP_CLSFLOWER:
return ice_setup_tc_cls_flower(np, priv->netdev,
(struct flow_cls_offload *)
type_data);
default:
return -EOPNOTSUPP;
}
}
static int
ice_indr_setup_tc_block(struct net_device *netdev, struct Qdisc *sch,
struct ice_netdev_priv *np,
struct flow_block_offload *f, void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{
struct ice_indr_block_priv *indr_priv;
struct flow_block_cb *block_cb;
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
case FLOW_BLOCK_BIND:
indr_priv = ice_indr_block_priv_lookup(np, netdev);
if (indr_priv)
return -EEXIST;
indr_priv = kzalloc(sizeof(*indr_priv), GFP_KERNEL);
if (!indr_priv)
return -ENOMEM;
indr_priv->netdev = netdev;
indr_priv->np = np;
list_add(&indr_priv->list, &np->tc_indr_block_priv_list);
block_cb =
flow_indr_block_cb_alloc(ice_indr_setup_block_cb,
indr_priv, indr_priv,
ice_rep_indr_tc_block_unbind,
f, netdev, sch, data, np,
cleanup);
if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
return PTR_ERR(block_cb);
}
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &ice_block_cb_list);
break;
case FLOW_BLOCK_UNBIND:
indr_priv = ice_indr_block_priv_lookup(np, netdev);
if (!indr_priv)
return -ENOENT;
block_cb = flow_block_cb_lookup(f->block,
ice_indr_setup_block_cb,
indr_priv);
if (!block_cb)
return -ENOENT;
flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int
ice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch,
void *cb_priv, enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{
switch (type) {
case TC_SETUP_BLOCK:
return ice_indr_setup_tc_block(netdev, sch, cb_priv, type_data,
data, cleanup);
default:
return -EOPNOTSUPP;
}
}
/**
* ice_open - Called when a network interface becomes active
* @netdev: network interface device structure
......
......@@ -23,6 +23,12 @@
#define ICE_TC_FLWR_FIELD_ENC_DST_MAC BIT(16)
#define ICE_TC_FLWR_FIELD_ETH_TYPE_ID BIT(17)
struct ice_indr_block_priv {
struct net_device *netdev;
struct ice_netdev_priv *np;
struct list_head list;
};
struct ice_tc_flower_action {
u32 tc_class;
enum ice_sw_fwd_act_type fltr_act;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment