* [PATCH 0/8] treewide: correct misuses of strscpy/strlcpy
From: Joe Perches @ 2019-07-04 23:57 UTC (permalink / raw)
To: Dan Murphy, linux-leds, linux-media, linux-arm-kernel,
linuxppc-dev, linux-nfs
Cc: linux-input, linux-kernel, netdev
These are all likely copy/paste defects where the field size of the
'copied to' array is incorrect.
Each patch in this series is independent.
Joe Perches (8):
Input: synaptics: Fix misuse of strlcpy
leds: as3645a: Fix misuse of strlcpy
media: m2m-deinterlace: Fix misuse of strscpy
media: go7007: Fix misuse of strscpy
net: ethernet: sun4i-emac: Fix misuse of strlcpy
net: nixge: Fix misuse of strlcpy
tty: hvcs: Fix odd use of strlcpy
nfsd: Fix misuse of strlcpy
drivers/input/mouse/synaptics.c | 2 +-
drivers/leds/leds-as3645a.c | 2 +-
drivers/media/platform/m2m-deinterlace.c | 2 +-
drivers/media/usb/go7007/snd-go7007.c | 2 +-
drivers/net/ethernet/allwinner/sun4i-emac.c | 4 ++--
drivers/net/ethernet/ni/nixge.c | 2 +-
drivers/tty/hvc/hvcs.c | 4 ++--
fs/nfsd/nfs4idmap.c | 2 +-
8 files changed, 10 insertions(+), 10 deletions(-)
--
2.15.0
^ permalink raw reply
* [PATCH 6/8] net: nixge: Fix misuse of strlcpy
From: Joe Perches @ 2019-07-04 23:57 UTC (permalink / raw)
To: linux-kernel; +Cc: David S. Miller, netdev
In-Reply-To: <cover.1562283944.git.joe@perches.com>
Probable cut&paste typo - use the correct field size.
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/net/ethernet/ni/nixge.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/ni/nixge.c b/drivers/net/ethernet/ni/nixge.c
index 96f7a9818294..0b384f97d2fd 100644
--- a/drivers/net/ethernet/ni/nixge.c
+++ b/drivers/net/ethernet/ni/nixge.c
@@ -990,7 +990,7 @@ static void nixge_ethtools_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *ed)
{
strlcpy(ed->driver, "nixge", sizeof(ed->driver));
- strlcpy(ed->bus_info, "platform", sizeof(ed->driver));
+ strlcpy(ed->bus_info, "platform", sizeof(ed->bus_info));
}
static int nixge_ethtools_get_coalesce(struct net_device *ndev,
--
2.15.0
^ permalink raw reply related
* [PATCH 5/8] net: ethernet: sun4i-emac: Fix misuse of strlcpy
From: Joe Perches @ 2019-07-04 23:57 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai
Cc: David S. Miller, netdev, linux-arm-kernel, linux-kernel
In-Reply-To: <cover.1562283944.git.joe@perches.com>
Probable cut&paste typo - use the correct field size.
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/net/ethernet/allwinner/sun4i-emac.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
index 9e06dff619c3..40a359dd90b4 100644
--- a/drivers/net/ethernet/allwinner/sun4i-emac.c
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -224,8 +224,8 @@ static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void emac_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, DRV_NAME, sizeof(DRV_NAME));
- strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
}
--
2.15.0
^ permalink raw reply related
* [PATCH 10/15 net-next,v2] net: flow_offload: add flow_block_cb API
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
This patch renames:
* struct tcf_block_cb to flow_block_cb.
* struct tc_block_offload to flow_block_offload.
And it exposes the flow_block_cb API through net/flow_offload.h. This
renames the existing codebase to adapt it to this name.
This patch also adds flow_block_cb_splice().
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 6 +-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 6 +-
drivers/net/ethernet/intel/i40e/i40e_main.c | 6 +-
drivers/net/ethernet/intel/iavf/iavf_main.c | 6 +-
drivers/net/ethernet/intel/igb/igb_main.c | 5 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +-
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 6 +-
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 28 ++--
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 62 ++++----
drivers/net/ethernet/mscc/ocelot_ace.h | 4 +-
drivers/net/ethernet/mscc/ocelot_flower.c | 34 ++---
drivers/net/ethernet/mscc/ocelot_tc.c | 14 +-
drivers/net/ethernet/netronome/nfp/abm/cls.c | 6 +-
drivers/net/ethernet/netronome/nfp/abm/main.h | 2 +-
drivers/net/ethernet/netronome/nfp/bpf/main.c | 6 +-
.../net/ethernet/netronome/nfp/flower/offload.c | 42 +++---
drivers/net/ethernet/qlogic/qede/qede_main.c | 6 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 +-
drivers/net/netdevsim/netdev.c | 6 +-
include/net/flow_offload.h | 52 +++++++
include/net/pkt_cls.h | 96 +------------
net/core/flow_offload.c | 115 +++++++++++++++
net/dsa/slave.c | 12 +-
net/sched/cls_api.c | 157 +++------------------
25 files changed, 328 insertions(+), 367 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index bda732ab6538..7b8d71252093 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -9854,9 +9854,9 @@ static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- bnxt_setup_tc_block_cb, bp, bp,
- true);
+ return flow_block_setup_offload(type_data,
+ bnxt_setup_tc_block_cb, bp, bp,
+ true);
case TC_SETUP_QDISC_MQPRIO: {
struct tc_mqprio_qopt *mqprio = type_data;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index c8bb104f28d4..1b78615a1384 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -168,9 +168,9 @@ static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- bnxt_vf_rep_setup_tc_block_cb,
- vf_rep, vf_rep, true);
+ return flow_block_setup_offload(type_data,
+ bnxt_vf_rep_setup_tc_block_cb,
+ vf_rep, vf_rep, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index a09b9c909be1..3d8acabb8bfd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3197,9 +3197,9 @@ static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- cxgb_setup_tc_block_cb, pi, dev,
- true);
+ return flow_block_setup_offload(type_data,
+ cxgb_setup_tc_block_cb, pi, dev,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 1e703daa50fd..f7d2616854ec 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -8186,9 +8186,9 @@ static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
case TC_SETUP_QDISC_MQPRIO:
return i40e_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- i40e_setup_tc_block_cb, np, np,
- true);
+ return flow_block_setup_offload(type_data,
+ i40e_setup_tc_block_cb, np, np,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 29640e4b15f2..8ef6aca34edd 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -3133,9 +3133,9 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
case TC_SETUP_QDISC_MQPRIO:
return __iavf_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- iavf_setup_tc_block_cb, adapter,
- adapter, true);
+ return flow_block_setup_offload(type_data,
+ iavf_setup_tc_block_cb, adapter,
+ adapter, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 75a29adce0ce..830b950f423b 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2815,8 +2815,9 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_CBS:
return igb_offload_cbs(adapter, type_data);
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data, igb_setup_tc_block_cb,
- adapter, adapter, true);
+ return flow_block_setup_offload(type_data,
+ igb_setup_tc_block_cb,
+ adapter, adapter, true);
case TC_SETUP_QDISC_ETF:
return igb_offload_txtime(adapter, type_data);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 7d3fe89ce807..144f2cca686a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9621,9 +9621,9 @@ static int __ixgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- ixgbe_setup_tc_block_cb,
- adapter, adapter, true);
+ return flow_block_setup_offload(type_data,
+ ixgbe_setup_tc_block_cb,
+ adapter, adapter, true);
case TC_SETUP_QDISC_MQPRIO:
return ixgbe_setup_tc_mqprio(dev, type_data);
default:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index ffb501cfbc8d..fa9c04129eb6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3355,9 +3355,9 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
#ifdef CONFIG_MLX5_ESWITCH
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- mlx5e_setup_tc_block_cb,
- priv, priv, true);
+ return flow_block_setup_offload(type_data,
+ mlx5e_setup_tc_block_cb,
+ priv, priv, true);
#endif
case TC_SETUP_QDISC_MQPRIO:
return mlx5e_setup_tc_mqprio(dev, type_data);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index b6ffaec4becb..925aa589a818 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -703,10 +703,10 @@ static void mlx5e_rep_indr_tc_block_unbind(void *cb_priv)
static int
mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct mlx5e_rep_indr_block_priv *indr_priv;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
@@ -726,16 +726,16 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
- block_cb = tcf_block_cb_alloc(f->net,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv, indr_priv,
- mlx5e_rep_indr_tc_block_unbind);
+ block_cb = flow_block_cb_alloc(f->net,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv, indr_priv,
+ mlx5e_rep_indr_tc_block_unbind);
if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
return PTR_ERR(block_cb);
}
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
@@ -743,13 +743,13 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
if (!indr_priv)
return -ENOENT;
- block_cb = tcf_block_cb_lookup(f->net,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv);
+ block_cb = flow_block_cb_lookup(f->net,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv);
if (!block_cb)
return -ENOENT;
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
@@ -1197,9 +1197,9 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- mlx5e_rep_setup_tc_cb,
- priv, priv, true);
+ return flow_block_setup_offload(type_data,
+ mlx5e_rep_setup_tc_cb,
+ priv, priv, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 950d09f3ecb1..6970738c070b 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1593,25 +1593,26 @@ static void mlxsw_sp_tc_block_flower_release(void *cb_priv)
static int
mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tc_block_offload *f, bool ingress)
+ struct flow_block_offload *f, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
bool register_block = false;
int err;
- block_cb = tcf_block_cb_lookup(f->net,
- mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp);
+ block_cb = flow_block_cb_lookup(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp);
if (!block_cb) {
acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, f->net);
if (!acl_block)
return -ENOMEM;
- block_cb = tcf_block_cb_alloc(f->net,
- mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp, acl_block,
- mlxsw_sp_tc_block_flower_release);
+
+ block_cb = flow_block_cb_alloc(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp, acl_block,
+ mlxsw_sp_tc_block_flower_release);
if (IS_ERR(block_cb)) {
mlxsw_sp_acl_block_destroy(acl_block);
err = PTR_ERR(block_cb);
@@ -1619,9 +1620,9 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
}
register_block = true;
} else {
- acl_block = tcf_block_cb_priv(block_cb);
+ acl_block = flow_block_cb_priv(block_cb);
}
- tcf_block_cb_incref(block_cb);
+ flow_block_cb_incref(block_cb);
err = mlxsw_sp_acl_block_bind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
if (err)
@@ -1633,29 +1634,30 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_sp_port->eg_acl_block = acl_block;
if (register_block)
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
err_block_bind:
- if (!tcf_block_cb_decref(block_cb))
- tcf_block_cb_free(block_cb);
+ if (!flow_block_cb_decref(block_cb))
+ flow_block_cb_free(block_cb);
err_cb_register:
return err;
}
static void
mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tc_block_offload *f, bool ingress)
+ struct flow_block_offload *f,
+ bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
int err;
- block_cb = tcf_block_cb_lookup(f->net,
- mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp);
+ block_cb = flow_block_cb_lookup(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp);
if (!block_cb)
return;
@@ -1664,17 +1666,17 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
else
mlxsw_sp_port->eg_acl_block = NULL;
- acl_block = tcf_block_cb_priv(block_cb);
+ acl_block = flow_block_cb_priv(block_cb);
err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
- if (!err && !tcf_block_cb_decref(block_cb))
- tcf_block_cb_remove(block_cb, f);
+ if (!err && !flow_block_cb_decref(block_cb))
+ flow_block_cb_remove(block_cb, f);
}
static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
tc_setup_cb_t *cb;
bool ingress;
int err;
@@ -1691,26 +1693,26 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = tcf_block_cb_alloc(f->net, cb, mlxsw_sp_port,
- mlxsw_sp_port, NULL);
+ block_cb = flow_block_cb_alloc(f->net, cb, mlxsw_sp_port,
+ mlxsw_sp_port, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, f,
ingress);
if (err) {
- tcf_block_cb_free(block_cb);
+ flow_block_cb_free(block_cb);
return err;
}
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
f, ingress);
- block_cb = tcf_block_cb_lookup(f->net, cb, mlxsw_sp_port);
+ block_cb = flow_block_cb_lookup(f->net, cb, mlxsw_sp_port);
if (!block_cb)
return -ENOENT;
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/mscc/ocelot_ace.h b/drivers/net/ethernet/mscc/ocelot_ace.h
index d621683643e1..e98944c87259 100644
--- a/drivers/net/ethernet/mscc/ocelot_ace.h
+++ b/drivers/net/ethernet/mscc/ocelot_ace.h
@@ -225,8 +225,8 @@ int ocelot_ace_init(struct ocelot *ocelot);
void ocelot_ace_deinit(void);
int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
- struct tc_block_offload *f);
+ struct flow_block_offload *f);
void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
- struct tc_block_offload *f);
+ struct flow_block_offload *f);
#endif /* _MSCC_OCELOT_ACE_H_ */
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index e62a7e56ec3e..3b9e4219ac7a 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -307,36 +307,36 @@ static void ocelot_tc_block_unbind(void *cb_priv)
}
int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct ocelot_port_block *port_block;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
int ret;
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
- block_cb = tcf_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
- port);
+ block_cb = flow_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ port);
if (!block_cb) {
port_block = ocelot_port_block_create(port);
if (!port_block)
return -ENOMEM;
- block_cb = tcf_block_cb_alloc(f->net,
- ocelot_setup_tc_block_cb_flower,
- port, port_block,
- ocelot_tc_block_unbind);
+ block_cb = flow_block_cb_alloc(f->net,
+ ocelot_setup_tc_block_cb_flower,
+ port, port_block,
+ ocelot_tc_block_unbind);
if (IS_ERR(block_cb)) {
ret = PTR_ERR(block_cb);
goto err_cb_register;
}
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
} else {
- port_block = tcf_block_cb_priv(block_cb);
+ port_block = flow_block_cb_priv(block_cb);
}
- tcf_block_cb_incref(block_cb);
+ flow_block_cb_incref(block_cb);
return 0;
err_cb_register:
@@ -346,15 +346,15 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
}
void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
- block_cb = tcf_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
- port);
+ block_cb = flow_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ port);
if (!block_cb)
return;
- if (!tcf_block_cb_decref(block_cb))
- tcf_block_cb_remove(block_cb, f);
+ if (!flow_block_cb_decref(block_cb))
+ flow_block_cb_remove(block_cb, f);
}
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index a52c233da571..14a9e178c3b8 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -129,9 +129,9 @@ static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
}
static int ocelot_setup_tc_block(struct ocelot_port *port,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
tc_setup_cb_t *cb;
int err;
@@ -149,24 +149,24 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = tcf_block_cb_alloc(f->net, cb, port, port, NULL);
+ block_cb = flow_block_cb_alloc(f->net, cb, port, port, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
err = ocelot_setup_tc_block_flower_bind(port, f);
if (err < 0) {
- tcf_block_cb_free(block_cb);
+ flow_block_cb_free(block_cb);
return err;
}
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = tcf_block_cb_lookup(f->net, cb, port);
+ block_cb = flow_block_cb_lookup(f->net, cb, port);
if (!block_cb)
return -ENOENT;
ocelot_setup_tc_block_flower_unbind(port, f);
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/abm/cls.c b/drivers/net/ethernet/netronome/nfp/abm/cls.c
index d99981ec04a3..96b89a7c468b 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/cls.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/cls.c
@@ -263,8 +263,8 @@ static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
}
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- return tcf_setup_block_offload(f, nfp_abm_setup_tc_block_cb, repr, repr,
- true);
+ return flow_block_setup_offload(f, nfp_abm_setup_tc_block_cb,
+ repr, repr, true);
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/main.h b/drivers/net/ethernet/netronome/nfp/abm/main.h
index 49749c60885e..48746c9c6224 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/main.h
+++ b/drivers/net/ethernet/netronome/nfp/abm/main.h
@@ -247,7 +247,7 @@ int nfp_abm_setup_tc_mq(struct net_device *netdev, struct nfp_abm_link *alink,
int nfp_abm_setup_tc_gred(struct net_device *netdev, struct nfp_abm_link *alink,
struct tc_gred_qopt_offload *opt);
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
- struct tc_block_offload *opt);
+ struct flow_block_offload *opt);
int nfp_abm_ctrl_read_params(struct nfp_abm_link *alink);
int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index fac38899dc23..3897cc4f7a7e 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -167,9 +167,9 @@ static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- nfp_bpf_setup_tc_block_cb,
- nn, nn, true);
+ return flow_block_setup_offload(type_data,
+ nfp_bpf_setup_tc_block_cb,
+ nn, nn, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index a19f4aafc3af..9b99f6936f90 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1303,11 +1303,11 @@ static int nfp_flower_setup_tc_block_cb(enum tc_setup_type type,
}
static int nfp_flower_setup_tc_block(struct net_device *netdev,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct nfp_repr *repr = netdev_priv(netdev);
struct nfp_flower_repr_priv *repr_priv;
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
@@ -1317,22 +1317,22 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = tcf_block_cb_alloc(f->net,
- nfp_flower_setup_tc_block_cb,
- repr, repr, NULL);
+ block_cb = flow_block_cb_alloc(f->net,
+ nfp_flower_setup_tc_block_cb,
+ repr, repr, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = tcf_block_cb_lookup(f->net,
- nfp_flower_setup_tc_block_cb,
- repr);
+ block_cb = flow_block_cb_lookup(f->net,
+ nfp_flower_setup_tc_block_cb,
+ repr);
if (!block_cb)
return -ENOENT;
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
@@ -1401,12 +1401,12 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
static int
nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv;
struct net *net = dev_net(netdev);
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
!(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
@@ -1423,30 +1423,30 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv);
- block_cb = tcf_block_cb_alloc(net,
- nfp_flower_setup_indr_block_cb,
- cb_priv, cb_priv,
- nfp_flower_setup_indr_tc_release);
+ block_cb = flow_block_cb_alloc(net,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv, cb_priv,
+ nfp_flower_setup_indr_tc_release);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
return PTR_ERR(block_cb);
}
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
if (!cb_priv)
return -ENOENT;
- block_cb = tcf_block_cb_lookup(net,
- nfp_flower_setup_indr_block_cb,
- cb_priv);
+ block_cb = flow_block_cb_lookup(net,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv);
if (!block_cb)
return -ENOENT;
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 013046a30732..00db21d9407f 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -588,9 +588,9 @@ qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- qede_setup_tc_block_cb,
- edev, edev, true);
+ return flow_block_setup_offload(type_data,
+ qede_setup_tc_block_cb,
+ edev, edev, true);
case TC_SETUP_QDISC_MQPRIO:
mqprio = type_data;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ffed6b51040a..341db1eed108 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3860,9 +3860,9 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- stmmac_setup_tc_block_cb,
- priv, priv, true);
+ return flow_block_setup_offload(type_data,
+ stmmac_setup_tc_block_cb,
+ priv, priv, true);
case TC_SETUP_QDISC_CBS:
return stmmac_tc_setup_cbs(priv, priv, type_data);
default:
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 240727623e9b..710b03fc8db1 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -210,9 +210,9 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
switch (type) {
case TC_SETUP_BLOCK:
- return tcf_setup_block_offload(type_data,
- nsim_setup_tc_block_cb, ns, ns,
- true);
+ return flow_block_setup_offload(type_data,
+ nsim_setup_tc_block_cb, ns, ns,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 36127c1858a4..728ded7e4361 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -232,4 +232,56 @@ static inline void flow_stats_update(struct flow_stats *flow_stats,
flow_stats->lastused = max_t(u64, flow_stats->lastused, lastused);
}
+#include <net/sch_generic.h> /* for tc_setup_cb_t. */
+
+enum flow_block_command {
+ TC_BLOCK_BIND,
+ TC_BLOCK_UNBIND,
+};
+
+enum flow_block_binder_type {
+ TCF_BLOCK_BINDER_TYPE_UNSPEC,
+ TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
+ TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
+};
+
+struct flow_block_offload {
+ enum flow_block_command command;
+ enum flow_block_binder_type binder_type;
+ struct list_head cb_list;
+ struct net *net;
+ bool block_shared;
+ struct netlink_ext_ack *extack;
+};
+
+struct flow_block_cb {
+ struct list_head global_list;
+ struct list_head list;
+ struct net *net;
+ tc_setup_cb_t *cb;
+ void (*release)(void *cb_priv);
+ void *cb_ident;
+ void *cb_priv;
+ u32 block_index;
+ unsigned int refcnt;
+};
+
+struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv));
+void flow_block_cb_free(struct flow_block_cb *block_cb);
+void *flow_block_cb_priv(struct flow_block_cb *block_cb);
+struct flow_block_cb *flow_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident);
+void flow_block_cb_incref(struct flow_block_cb *block_cb);
+unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb);
+void flow_block_cb_add(struct flow_block_cb *block_cb,
+ struct flow_block_offload *offload);
+void flow_block_cb_remove(struct flow_block_cb *block_cb,
+ struct flow_block_offload *offload);
+void flow_block_cb_splice(struct flow_block_offload *offload);
+
+int flow_block_setup_offload(struct flow_block_offload *f, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv, bool ingress_only);
+
#endif /* _NET_FLOW_OFFLOAD_H */
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 52c11e390d9e..a60c9b19f660 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -26,14 +26,8 @@ struct tcf_walker {
int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
-enum tcf_block_binder_type {
- TCF_BLOCK_BINDER_TYPE_UNSPEC,
- TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
- TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
-};
-
struct tcf_block_ext_info {
- enum tcf_block_binder_type binder_type;
+ enum flow_block_binder_type binder_type;
tcf_chain_head_change_t *chain_head_change;
void *chain_head_change_priv;
u32 block_index;
@@ -72,23 +66,6 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
return block->q;
}
-struct tcf_block_cb *tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv,
- void (*release)(void *cb_priv));
-void tcf_block_cb_free(struct tcf_block_cb *block_cb);
-
-struct tc_block_offload;
-void tcf_block_cb_add(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload);
-void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload);
-
-void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
-struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident);
-void tcf_block_cb_incref(struct tcf_block_cb *block_cb);
-unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb);
-
int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
tc_indr_block_bind_cb_t *cb, void *cb_ident);
int tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
@@ -100,9 +77,6 @@ void tc_indr_block_cb_unregister(struct net_device *dev,
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);
-
-int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv, bool ingress_only);
#else
static inline bool tcf_block_shared(struct tcf_block *block)
{
@@ -153,60 +127,6 @@ void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
{
}
-static inline int tcf_setup_block_offload(struct tc_block_offload *f,
- tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv,
- bool ingress_only)
-{
- return -EOPNOTSUPP;
-}
-
-static inline struct tcf_block_cb *
-tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv, void (*release)(void *cb_priv))
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void tcf_block_cb_free(struct tcf_block_cb *block_cb)
-{
-}
-
-struct tc_block_offload;
-static inline void tcf_block_cb_add(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload)
-{
-}
-
-static inline void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload)
-{
-}
-
-static inline
-void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
-{
- return NULL;
-}
-
-static inline
-struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{
- return NULL;
-}
-
-static inline
-void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
-{
-}
-
-static inline
-unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
-{
- return 0;
-}
-
static inline
int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
tc_indr_block_bind_cb_t *cb, void *cb_ident)
@@ -614,19 +534,7 @@ int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop);
unsigned int tcf_exts_num_actions(struct tcf_exts *exts);
-enum tc_block_command {
- TC_BLOCK_BIND,
- TC_BLOCK_UNBIND,
-};
-
-struct tc_block_offload {
- enum tc_block_command command;
- enum tcf_block_binder_type binder_type;
- struct list_head cb_list;
- struct net *net;
- bool block_shared;
- struct netlink_ext_ack *extack;
-};
+struct flow_block_offload;
struct tc_cls_common_offload {
u32 chain_index;
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index f52fe0bc4017..0b8d088d822e 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -164,3 +164,118 @@ void flow_rule_match_enc_opts(const struct flow_rule *rule,
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_OPTS, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_opts);
+
+void *flow_block_cb_priv(struct flow_block_cb *block_cb)
+{
+ return block_cb->cb_priv;
+}
+EXPORT_SYMBOL(flow_block_cb_priv);
+
+static LIST_HEAD(flow_block_cb_list);
+
+struct flow_block_cb *flow_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident)
+{
+ struct flow_block_cb *block_cb;
+
+ list_for_each_entry(block_cb, &flow_block_cb_list, global_list) {
+ if (block_cb->net == net &&
+ block_cb->cb == cb &&
+ block_cb->cb_ident == cb_ident)
+ return block_cb;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(flow_block_cb_lookup);
+
+void flow_block_cb_incref(struct flow_block_cb *block_cb)
+{
+ block_cb->refcnt++;
+}
+EXPORT_SYMBOL(flow_block_cb_incref);
+
+unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
+{
+ return --block_cb->refcnt;
+}
+EXPORT_SYMBOL(flow_block_cb_decref);
+
+struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv))
+{
+ struct flow_block_cb *block_cb;
+
+ block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
+ if (IS_ERR(block_cb))
+ return block_cb;
+
+ block_cb->net = net;
+ block_cb->cb = cb;
+ block_cb->cb_ident = cb_ident;
+ block_cb->release = release;
+ block_cb->cb_priv = cb_priv;
+
+ return block_cb;
+}
+EXPORT_SYMBOL(flow_block_cb_alloc);
+
+void flow_block_cb_free(struct flow_block_cb *block_cb)
+{
+ if (block_cb->release)
+ block_cb->release(block_cb->cb_priv);
+
+ kfree(block_cb);
+}
+EXPORT_SYMBOL(flow_block_cb_free);
+
+void flow_block_cb_add(struct flow_block_cb *block_cb,
+ struct flow_block_offload *offload)
+{
+ list_add_tail(&block_cb->global_list, &offload->cb_list);
+}
+EXPORT_SYMBOL(flow_block_cb_add);
+
+void flow_block_cb_remove(struct flow_block_cb *block_cb,
+ struct flow_block_offload *offload)
+{
+ list_move(&block_cb->global_list, &offload->cb_list);
+}
+EXPORT_SYMBOL(flow_block_cb_remove);
+
+void flow_block_cb_splice(struct flow_block_offload *offload)
+{
+ list_splice(&offload->cb_list, &flow_block_cb_list);
+}
+EXPORT_SYMBOL(flow_block_cb_splice);
+
+int flow_block_setup_offload(struct flow_block_offload *f, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv, bool ingress_only)
+{
+ struct flow_block_cb *block_cb;
+
+ if (ingress_only &&
+ f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ return -EOPNOTSUPP;
+
+ switch (f->command) {
+ case TC_BLOCK_BIND:
+ block_cb = flow_block_cb_alloc(f->net, cb, cb_ident, cb_priv,
+ NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ flow_block_cb_add(block_cb, f);
+ return 0;
+ case TC_BLOCK_UNBIND:
+ block_cb = flow_block_cb_lookup(f->net, cb, cb_ident);
+ if (!block_cb)
+ return -ENOENT;
+
+ flow_block_cb_remove(block_cb, f);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL(flow_block_setup_offload);
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 01be6dc20ba3..0323091b5cef 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -943,9 +943,9 @@ static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type,
}
static int dsa_slave_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
+ struct flow_block_offload *f)
{
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
tc_setup_cb_t *cb;
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
@@ -957,18 +957,18 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = tcf_block_cb_alloc(f->net, cb, dev, dev, NULL);
+ block_cb = flow_block_cb_alloc(f->net, cb, dev, dev, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
- tcf_block_cb_add(block_cb, f);
+ flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = tcf_block_cb_lookup(f->net, cb, dev);
+ block_cb = flow_block_cb_lookup(f->net, cb, dev);
if (!block_cb)
return -ENOENT;
- tcf_block_cb_remove(block_cb, f);
+ flow_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index aa7ab707c399..5635b6f63015 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -26,6 +26,7 @@
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
+#include <net/flow_offload.h>
#include <net/tc_act/tc_pedit.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_vlan.h>
@@ -709,97 +710,9 @@ static bool tcf_block_offload_in_use(struct tcf_block *block)
return block->offloadcnt;
}
-struct tcf_block_cb {
- struct list_head global_list;
- struct list_head list;
- struct net *net;
- tc_setup_cb_t *cb;
- void (*release)(void *cb_priv);
- void *cb_ident;
- void *cb_priv;
- unsigned int refcnt;
-};
-
-void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
-{
- return block_cb->cb_priv;
-}
-EXPORT_SYMBOL(tcf_block_cb_priv);
-
-static LIST_HEAD(tcf_block_cb_list);
-
-struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident)
-{
- struct tcf_block_cb *block_cb;
-
- list_for_each_entry(block_cb, &tcf_block_cb_list, global_list)
- if (block_cb->net == net &&
- block_cb->cb == cb &&
- block_cb->cb_ident == cb_ident)
- return block_cb;
- return NULL;
-}
-EXPORT_SYMBOL(tcf_block_cb_lookup);
-
-void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
-{
- block_cb->refcnt++;
-}
-EXPORT_SYMBOL(tcf_block_cb_incref);
-
-unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
-{
- return --block_cb->refcnt;
-}
-EXPORT_SYMBOL(tcf_block_cb_decref);
-
-struct tcf_block_cb *tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv,
- void (*release)(void *cb_priv))
-{
- struct tcf_block_cb *block_cb;
-
- block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
- if (!block_cb)
- return ERR_PTR(-ENOMEM);
-
- block_cb->net = net;
- block_cb->cb = cb;
- block_cb->cb_ident = cb_ident;
- block_cb->release = release;
- block_cb->cb_priv = cb_priv;
-
- return block_cb;
-}
-EXPORT_SYMBOL(tcf_block_cb_alloc);
-
-void tcf_block_cb_free(struct tcf_block_cb *block_cb)
-{
- if (block_cb->release)
- block_cb->release(block_cb->cb_priv);
-
- kfree(block_cb);
-}
-EXPORT_SYMBOL(tcf_block_cb_free);
-
-void tcf_block_cb_add(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload)
-{
- list_add_tail(&block_cb->global_list, &offload->cb_list);
-}
-EXPORT_SYMBOL(tcf_block_cb_add);
-
-void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
- struct tc_block_offload *offload)
-{
- list_move(&block_cb->global_list, &offload->cb_list);
-}
-EXPORT_SYMBOL(tcf_block_cb_remove);
-
-static int tcf_block_bind(struct tcf_block *block, struct tc_block_offload *bo)
+static int tcf_block_bind(struct tcf_block *block, struct flow_block_offload *bo)
{
- struct tcf_block_cb *block_cb, *next;
+ struct flow_block_cb *block_cb, *next;
int err, i = 0;
list_for_each_entry(block_cb, &bo->cb_list, global_list) {
@@ -813,7 +726,7 @@ static int tcf_block_bind(struct tcf_block *block, struct tc_block_offload *bo)
list_add(&block_cb->list, &block->cb_list);
i++;
}
- list_splice(&bo->cb_list, &tcf_block_cb_list);
+ flow_block_cb_splice(bo);
return 0;
@@ -833,9 +746,9 @@ static int tcf_block_bind(struct tcf_block *block, struct tc_block_offload *bo)
}
static void tcf_block_unbind(struct tcf_block *block,
- struct tc_block_offload *bo)
+ struct flow_block_offload *bo)
{
- struct tcf_block_cb *block_cb, *next;
+ struct flow_block_cb *block_cb, *next;
list_for_each_entry_safe(block_cb, next, &bo->cb_list, global_list) {
list_del(&block_cb->global_list);
@@ -844,11 +757,12 @@ static void tcf_block_unbind(struct tcf_block *block,
tcf_block_offload_in_use(block),
NULL);
list_del(&block_cb->list);
- tcf_block_cb_free(block_cb);
+ flow_block_cb_free(block_cb);
}
}
-static int tcf_block_setup(struct tcf_block *block, struct tc_block_offload *bo)
+static int tcf_block_setup(struct tcf_block *block,
+ struct flow_block_offload *bo)
{
int err;
@@ -868,37 +782,6 @@ static int tcf_block_setup(struct tcf_block *block, struct tc_block_offload *bo)
return err;
}
-int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv, bool ingress_only)
-{
- struct tcf_block_cb *block_cb;
-
- if (ingress_only &&
- f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- block_cb = tcf_block_cb_alloc(f->net, cb, cb_ident,
- cb_priv, NULL);
- if (IS_ERR(block_cb))
- return PTR_ERR(block_cb);
-
- tcf_block_cb_add(block_cb, f);
- return 0;
- case TC_BLOCK_UNBIND:
- block_cb = tcf_block_cb_lookup(f->net, cb, cb_ident);
- if (!block_cb)
- return -ENOENT;
-
- tcf_block_cb_remove(block_cb, f);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-EXPORT_SYMBOL(tcf_setup_block_offload);
-
static struct rhashtable indr_setup_block_ht;
struct tc_indr_block_dev {
@@ -1008,9 +891,9 @@ static void tc_indr_block_cb_del(struct tc_indr_block_cb *indr_block_cb)
static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
struct tc_indr_block_cb *indr_block_cb,
- enum tc_block_command command)
+ enum flow_block_command command)
{
- struct tc_block_offload bo = {
+ struct flow_block_offload bo = {
.command = command,
.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
.net = dev_net(indr_dev->dev),
@@ -1096,12 +979,12 @@ EXPORT_SYMBOL_GPL(tc_indr_block_cb_unregister);
static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
struct tcf_block_ext_info *ei,
- enum tc_block_command command,
+ enum flow_block_command command,
struct netlink_ext_ack *extack)
{
struct tc_indr_block_cb *indr_block_cb;
struct tc_indr_block_dev *indr_dev;
- struct tc_block_offload bo = {
+ struct flow_block_offload bo = {
.command = command,
.binder_type = ei->binder_type,
.net = dev_net(dev),
@@ -1126,10 +1009,10 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
static int tcf_block_offload_cmd(struct tcf_block *block,
struct net_device *dev,
struct tcf_block_ext_info *ei,
- enum tc_block_command command,
+ enum flow_block_command command,
struct netlink_ext_ack *extack)
{
- struct tc_block_offload bo = {};
+ struct flow_block_offload bo = {};
int err;
bo.net = dev_net(dev);
@@ -1586,13 +1469,13 @@ static void tcf_block_release(struct Qdisc *q, struct tcf_block *block,
struct tcf_block_owner_item {
struct list_head list;
struct Qdisc *q;
- enum tcf_block_binder_type binder_type;
+ enum flow_block_binder_type binder_type;
};
static void
tcf_block_owner_netif_keep_dst(struct tcf_block *block,
struct Qdisc *q,
- enum tcf_block_binder_type binder_type)
+ enum flow_block_binder_type binder_type)
{
if (block->keep_dst &&
binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
@@ -1613,7 +1496,7 @@ EXPORT_SYMBOL(tcf_block_netif_keep_dst);
static int tcf_block_owner_add(struct tcf_block *block,
struct Qdisc *q,
- enum tcf_block_binder_type binder_type)
+ enum flow_block_binder_type binder_type)
{
struct tcf_block_owner_item *item;
@@ -1628,7 +1511,7 @@ static int tcf_block_owner_add(struct tcf_block *block,
static void tcf_block_owner_del(struct tcf_block *block,
struct Qdisc *q,
- enum tcf_block_binder_type binder_type)
+ enum flow_block_binder_type binder_type)
{
struct tcf_block_owner_item *item;
@@ -3262,7 +3145,7 @@ EXPORT_SYMBOL(tcf_exts_dump_stats);
int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop)
{
- struct tcf_block_cb *block_cb;
+ struct flow_block_cb *block_cb;
int ok_count = 0;
int err;
--
2.11.0
^ permalink raw reply related
* [PATCH 15/15 net-next,v2] netfilter: nf_tables: add hardware offload support
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
This patch adds hardware offload support for nftables through the
existing netdev_ops->ndo_setup_tc() interface, the TC_SETUP_CLSFLOWER
classifier and the flow rule API. This hardware offload support is
available for the NFPROTO_NETDEV family and the ingress hook.
Each nftables expression has a new ->offload interface, that is used to
populate the flow rule object that is attached to the transaction
object.
There is a new per-table NFT_TABLE_F_HW_OFFLOAD flag, that is set on
to offload an entire table, including all of its chains.
This patch supports for basic metadata (layer 3 and 4 protocol numbers),
5-tuple payload matching and the accept/drop actions; this also includes
basechain hardware offload only.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: return -EOPNOTSUPP in case of default policy is drop.
add nft_flow_offload_unbind().
include/net/netfilter/nf_tables.h | 13 ++
include/net/netfilter/nf_tables_offload.h | 76 +++++++++
include/uapi/linux/netfilter/nf_tables.h | 2 +
net/netfilter/Makefile | 2 +-
net/netfilter/nf_tables_api.c | 22 ++-
net/netfilter/nf_tables_offload.c | 261 ++++++++++++++++++++++++++++++
net/netfilter/nft_cmp.c | 53 ++++++
net/netfilter/nft_immediate.c | 31 ++++
net/netfilter/nft_meta.c | 27 ++++
net/netfilter/nft_payload.c | 187 +++++++++++++++++++++
10 files changed, 671 insertions(+), 3 deletions(-)
create mode 100644 include/net/netfilter/nf_tables_offload.h
create mode 100644 net/netfilter/nf_tables_offload.c
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 9e8493aad49d..4f8cb85d18ce 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -161,6 +161,7 @@ struct nft_ctx {
const struct nlattr * const *nla;
u32 portid;
u32 seq;
+ u16 flags;
u8 family;
u8 level;
bool report;
@@ -735,6 +736,9 @@ enum nft_trans_phase {
NFT_TRANS_RELEASE
};
+struct nft_flow_rule;
+struct nft_offload_ctx;
+
/**
* struct nft_expr_ops - nf_tables expression operations
*
@@ -777,6 +781,10 @@ struct nft_expr_ops {
const struct nft_data **data);
bool (*gc)(struct net *net,
const struct nft_expr *expr);
+ int (*offload)(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr);
+ u32 offload_flags;
const struct nft_expr_type *type;
void *data;
};
@@ -942,6 +950,7 @@ struct nft_stats {
* @stats: per-cpu chain stats
* @chain: the chain
* @dev_name: device name that this base chain is attached to (if any)
+ * @cb_list: list of flow block callbacks (for hardware offload)
*/
struct nft_base_chain {
struct nf_hook_ops ops;
@@ -951,6 +960,7 @@ struct nft_base_chain {
struct nft_stats __percpu *stats;
struct nft_chain chain;
char dev_name[IFNAMSIZ];
+ struct list_head cb_list;
};
static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain)
@@ -1322,11 +1332,14 @@ struct nft_trans {
struct nft_trans_rule {
struct nft_rule *rule;
+ struct nft_flow_rule *flow;
u32 rule_id;
};
#define nft_trans_rule(trans) \
(((struct nft_trans_rule *)trans->data)->rule)
+#define nft_trans_flow_rule(trans) \
+ (((struct nft_trans_rule *)trans->data)->flow)
#define nft_trans_rule_id(trans) \
(((struct nft_trans_rule *)trans->data)->rule_id)
diff --git a/include/net/netfilter/nf_tables_offload.h b/include/net/netfilter/nf_tables_offload.h
new file mode 100644
index 000000000000..3196663a10e3
--- /dev/null
+++ b/include/net/netfilter/nf_tables_offload.h
@@ -0,0 +1,76 @@
+#ifndef _NET_NF_TABLES_OFFLOAD_H
+#define _NET_NF_TABLES_OFFLOAD_H
+
+#include <net/flow_offload.h>
+#include <net/netfilter/nf_tables.h>
+
+struct nft_offload_reg {
+ u32 key;
+ u32 len;
+ u32 base_offset;
+ u32 offset;
+ struct nft_data mask;
+};
+
+enum nft_offload_dep_type {
+ NFT_OFFLOAD_DEP_UNSPEC = 0,
+ NFT_OFFLOAD_DEP_NETWORK,
+ NFT_OFFLOAD_DEP_TRANSPORT,
+};
+
+struct nft_offload_ctx {
+ struct {
+ enum nft_offload_dep_type type;
+ __be16 l3num;
+ u8 protonum;
+ } dep;
+ unsigned int num_actions;
+ struct nft_offload_reg regs[NFT_REG32_15 + 1];
+};
+
+void nft_offload_set_dependency(struct nft_offload_ctx *ctx,
+ enum nft_offload_dep_type type);
+void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
+ const void *data, u32 len);
+
+struct nft_flow_key {
+ struct flow_dissector_key_basic basic;
+ union {
+ struct flow_dissector_key_ipv4_addrs ipv4;
+ struct flow_dissector_key_ipv6_addrs ipv6;
+ };
+ struct flow_dissector_key_ports tp;
+ struct flow_dissector_key_ip ip;
+ struct flow_dissector_key_vlan vlan;
+ struct flow_dissector_key_eth_addrs eth_addrs;
+} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
+
+struct nft_flow_match {
+ struct flow_dissector dissector;
+ struct nft_flow_key key;
+ struct nft_flow_key mask;
+};
+
+struct nft_flow_rule {
+ __be16 proto;
+ struct nft_flow_match match;
+ struct flow_rule *rule;
+};
+
+#define NFT_OFFLOAD_F_ACTION (1 << 0)
+
+struct nft_rule;
+struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule);
+void nft_flow_rule_destroy(struct nft_flow_rule *flow);
+int nft_flow_rule_offload_commit(struct net *net);
+
+#define NFT_OFFLOAD_MATCH(__key, __base, __field, __len, __reg) \
+ (__reg)->base_offset = \
+ offsetof(struct nft_flow_key, __base); \
+ (__reg)->offset = \
+ offsetof(struct nft_flow_key, __base.__field); \
+ (__reg)->len = __len; \
+ (__reg)->key = __key; \
+ memset(&(__reg)->mask, 0xff, (__reg)->len);
+
+#endif
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index c6c8ec5c7c00..1d076140dc5d 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -158,9 +158,11 @@ enum nft_hook_attributes {
* enum nft_table_flags - nf_tables table flags
*
* @NFT_TABLE_F_DORMANT: this table is not active
+ * @NFT_TABLE_F_HW_OFFLOAD: enable hardware offload
*/
enum nft_table_flags {
NFT_TABLE_F_DORMANT = 0x1,
+ NFT_TABLE_F_HW_OFFLOAD = 0x2,
};
/**
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 72cca6b48960..46cb1d34e750 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -78,7 +78,7 @@ nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
nf_tables_trace.o nft_immediate.o nft_cmp.o nft_range.o \
nft_bitwise.o nft_byteorder.o nft_payload.o nft_lookup.o \
nft_dynset.o nft_meta.o nft_rt.o nft_exthdr.o \
- nft_chain_route.o
+ nft_chain_route.o nf_tables_offload.o
nf_tables_set-objs := nf_tables_set_core.o \
nft_set_hash.o nft_set_bitmap.o nft_set_rbtree.o
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index cae5c46e2dd4..11843f8656e5 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -18,6 +18,7 @@
#include <net/netfilter/nf_flow_table.h>
#include <net/netfilter/nf_tables_core.h>
#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_offload.h>
#include <net/net_namespace.h>
#include <net/sock.h>
@@ -97,6 +98,7 @@ static void nft_ctx_init(struct nft_ctx *ctx,
ctx->nla = nla;
ctx->portid = NETLINK_CB(skb).portid;
ctx->report = nlmsg_report(nlh);
+ ctx->flags = nlh->nlmsg_flags;
ctx->seq = nlh->nlmsg_seq;
}
@@ -896,7 +898,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
if (nla[NFTA_TABLE_FLAGS]) {
flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
- if (flags & ~NFT_TABLE_F_DORMANT)
+ if (flags & ~(NFT_TABLE_F_DORMANT | NFT_TABLE_F_HW_OFFLOAD))
return -EINVAL;
}
@@ -1659,6 +1661,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
chain->flags |= NFT_BASE_CHAIN;
basechain->policy = NF_ACCEPT;
+ INIT_LIST_HEAD(&basechain->cb_list);
} else {
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
@@ -2638,6 +2641,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
u8 genmask = nft_genmask_next(net);
struct nft_expr_info *info = NULL;
int family = nfmsg->nfgen_family;
+ struct nft_flow_rule *flow;
struct nft_table *table;
struct nft_chain *chain;
struct nft_rule *rule, *old_rule = NULL;
@@ -2784,7 +2788,8 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
list_add_tail_rcu(&rule->list, &old_rule->list);
} else {
- if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
+ trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
+ if (!trans) {
err = -ENOMEM;
goto err2;
}
@@ -2807,6 +2812,14 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
if (net->nft.validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, table);
+ if (table->flags & NFT_TABLE_F_HW_OFFLOAD) {
+ flow = nft_flow_rule_create(rule);
+ if (IS_ERR(flow))
+ return PTR_ERR(flow);
+
+ nft_trans_flow_rule(trans) = flow;
+ }
+
return 0;
err2:
nf_tables_rule_release(&ctx, rule);
@@ -6604,6 +6617,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
struct nft_trans_elem *te;
struct nft_chain *chain;
struct nft_table *table;
+ int err;
if (list_empty(&net->nft.commit_list)) {
mutex_unlock(&net->nft.commit_mutex);
@@ -6614,6 +6628,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nf_tables_validate(net) < 0)
return -EAGAIN;
+ err = nft_flow_rule_offload_commit(net);
+ if (err < 0)
+ return err;
+
/* 1. Allocate space for next generation rules_gen_X[] */
list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
int ret;
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
new file mode 100644
index 000000000000..99e2ef94b92a
--- /dev/null
+++ b/net/netfilter/nf_tables_offload.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <net/flow_offload.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_offload.h>
+#include <net/pkt_cls.h>
+
+static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
+{
+ struct nft_flow_rule *flow;
+
+ flow = kzalloc(sizeof(struct nft_flow_rule), GFP_KERNEL);
+ if (!flow)
+ return NULL;
+
+ flow->rule = flow_rule_alloc(num_actions);
+ if (!flow->rule) {
+ kfree(flow);
+ return NULL;
+ }
+
+ flow->rule->match.dissector = &flow->match.dissector;
+ flow->rule->match.mask = &flow->match.mask;
+ flow->rule->match.key = &flow->match.key;
+
+ return flow;
+}
+
+struct nft_flow_rule *nft_flow_rule_create(const struct nft_rule *rule)
+{
+ struct nft_offload_ctx ctx = {
+ .dep = {
+ .type = NFT_OFFLOAD_DEP_UNSPEC,
+ },
+ };
+ struct nft_flow_rule *flow;
+ int num_actions = 0, err;
+ struct nft_expr *expr;
+
+ expr = nft_expr_first(rule);
+ while (expr->ops && expr != nft_expr_last(rule)) {
+ if (expr->ops->offload_flags & NFT_OFFLOAD_F_ACTION)
+ num_actions++;
+
+ expr = nft_expr_next(expr);
+ }
+
+ flow = nft_flow_rule_alloc(num_actions);
+ if (!flow)
+ return ERR_PTR(-ENOMEM);
+
+ expr = nft_expr_first(rule);
+ while (expr->ops && expr != nft_expr_last(rule)) {
+ if (!expr->ops->offload) {
+ err = -EOPNOTSUPP;
+ goto err_out;
+ }
+ err = expr->ops->offload(&ctx, flow, expr);
+ if (err < 0)
+ goto err_out;
+
+ expr = nft_expr_next(expr);
+ }
+ flow->proto = ctx.dep.l3num;
+
+ return flow;
+err_out:
+ nft_flow_rule_destroy(flow);
+
+ return ERR_PTR(err);
+}
+
+void nft_flow_rule_destroy(struct nft_flow_rule *flow)
+{
+ kfree(flow->rule);
+ kfree(flow);
+}
+
+void nft_offload_set_dependency(struct nft_offload_ctx *ctx,
+ enum nft_offload_dep_type type)
+{
+ ctx->dep.type = type;
+}
+
+void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
+ const void *data, u32 len)
+{
+ switch (ctx->dep.type) {
+ case NFT_OFFLOAD_DEP_NETWORK:
+ WARN_ON(len != sizeof(__u16));
+ memcpy(&ctx->dep.l3num, data, sizeof(__u16));
+ break;
+ case NFT_OFFLOAD_DEP_TRANSPORT:
+ WARN_ON(len != sizeof(__u8));
+ memcpy(&ctx->dep.protonum, data, sizeof(__u8));
+ break;
+ default:
+ break;
+ }
+ ctx->dep.type = NFT_OFFLOAD_DEP_UNSPEC;
+}
+
+static void nft_flow_offload_common_init(struct tc_cls_common_offload *common,
+ __be16 proto,
+ struct netlink_ext_ack *extack)
+{
+ common->protocol = proto;
+ common->extack = extack;
+}
+
+static int nft_setup_cb_call(struct nft_base_chain *basechain,
+ enum tc_setup_type type, void *type_data)
+{
+ struct flow_block_cb *block_cb;
+ int err;
+
+ list_for_each_entry(block_cb, &basechain->cb_list, list) {
+ err = block_cb->cb(type, type_data, block_cb->cb_priv);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int nft_flow_offload_rule(struct nft_trans *trans,
+ enum tc_fl_command command)
+{
+ struct nft_flow_rule *flow = nft_trans_flow_rule(trans);
+ struct nft_rule *rule = nft_trans_rule(trans);
+ struct tc_cls_flower_offload cls_flower = {};
+ struct nft_base_chain *basechain;
+ struct netlink_ext_ack extack;
+ __be16 proto = ETH_P_ALL;
+
+ if (!nft_is_base_chain(trans->ctx.chain))
+ return -EOPNOTSUPP;
+
+ basechain = nft_base_chain(trans->ctx.chain);
+
+ if (flow)
+ proto = flow->proto;
+
+ nft_flow_offload_common_init(&cls_flower.common, proto, &extack);
+ cls_flower.command = command;
+ cls_flower.cookie = (unsigned long) rule;
+ if (flow)
+ cls_flower.rule = flow->rule;
+
+ return nft_setup_cb_call(basechain, TC_SETUP_CLSFLOWER, &cls_flower);
+}
+
+static int nft_flow_offload_bind(struct flow_block_offload *bo,
+ struct nft_base_chain *basechain)
+{
+ struct flow_block_cb *block_cb;
+
+ list_for_each_entry(block_cb, &bo->cb_list, global_list)
+ list_add(&block_cb->list, &basechain->cb_list);
+
+ flow_block_cb_splice(bo);
+ return 0;
+}
+
+static int nft_flow_offload_unbind(struct flow_block_offload *bo,
+ struct nft_base_chain *basechain)
+{
+ struct flow_block_cb *block_cb, *next;
+
+ list_for_each_entry_safe(block_cb, next, &bo->cb_list, global_list) {
+ list_del(&block_cb->list);
+ flow_block_cb_free(block_cb);
+ }
+
+ return 0;
+}
+
+static int nft_flow_offload_chain(struct nft_trans *trans,
+ enum flow_block_command cmd)
+{
+ struct nft_chain *chain = trans->ctx.chain;
+ struct netlink_ext_ack extack = {};
+ struct flow_block_offload bo = {};
+ struct nft_base_chain *basechain;
+ struct net_device *dev;
+ int err;
+
+ if (!nft_is_base_chain(chain))
+ return -EOPNOTSUPP;
+
+ basechain = nft_base_chain(chain);
+ dev = basechain->ops.dev;
+ if (!dev || !dev->netdev_ops->ndo_setup_tc)
+ return -EOPNOTSUPP;
+
+ /* Only default policy to accept is supported for now. */
+ if (cmd == FLOW_BLOCK_BIND &&
+ nft_trans_chain_policy(trans) != -1 &&
+ nft_trans_chain_policy(trans) != NF_ACCEPT)
+ return -EOPNOTSUPP;
+
+ bo.command = cmd;
+ bo.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
+ bo.extack = &extack;
+ INIT_LIST_HEAD(&bo.cb_list);
+
+ err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
+ if (err < 0)
+ return err;
+
+ switch (cmd) {
+ case FLOW_BLOCK_BIND:
+ err = nft_flow_offload_bind(&bo, basechain);
+ break;
+ case FLOW_BLOCK_UNBIND:
+ err = nft_flow_offload_unbind(&bo, basechain);
+ break;
+ }
+
+ return err;
+}
+
+int nft_flow_rule_offload_commit(struct net *net)
+{
+ struct nft_trans *trans;
+ int err = 0;
+
+ list_for_each_entry(trans, &net->nft.commit_list, list) {
+ if (trans->ctx.family != NFPROTO_NETDEV ||
+ !(trans->ctx.table->flags & NFT_TABLE_F_HW_OFFLOAD))
+ continue;
+
+ switch (trans->msg_type) {
+ case NFT_MSG_NEWCHAIN:
+ err = nft_flow_offload_chain(trans, FLOW_BLOCK_BIND);
+ break;
+ case NFT_MSG_DELCHAIN:
+ err = nft_flow_offload_chain(trans, FLOW_BLOCK_UNBIND);
+ break;
+ case NFT_MSG_NEWRULE:
+ if (trans->ctx.flags & NLM_F_REPLACE ||
+ !(trans->ctx.flags & NLM_F_APPEND))
+ return -EOPNOTSUPP;
+
+ err = nft_flow_offload_rule(trans,
+ TC_CLSFLOWER_REPLACE);
+ nft_flow_rule_destroy(nft_trans_flow_rule(trans));
+ break;
+ case NFT_MSG_DELRULE:
+ err = nft_flow_offload_rule(trans,
+ TC_CLSFLOWER_DESTROY);
+ break;
+ }
+
+ if (err)
+ return err;
+ }
+
+ return err;
+}
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
index 411c0cf741e3..bd173b1824c6 100644
--- a/net/netfilter/nft_cmp.c
+++ b/net/netfilter/nft_cmp.c
@@ -12,6 +12,7 @@
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
+#include <net/netfilter/nf_tables_offload.h>
#include <net/netfilter/nf_tables.h>
struct nft_cmp_expr {
@@ -107,12 +108,44 @@ static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
return -1;
}
+static int __nft_cmp_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_cmp_expr *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->sreg];
+ u8 *mask = (u8 *)&flow->match.mask;
+ u8 *key = (u8 *)&flow->match.key;
+
+ if (priv->op != NFT_CMP_EQ)
+ return -EOPNOTSUPP;
+
+ memcpy(key + reg->offset, &priv->data, priv->len);
+ memcpy(mask + reg->offset, ®->mask, priv->len);
+
+ flow->match.dissector.used_keys |= BIT(reg->key);
+ flow->match.dissector.offset[reg->key] = reg->base_offset;
+
+ nft_offload_update_dependency(ctx, &priv->data, priv->len);
+
+ return 0;
+}
+
+static int nft_cmp_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_cmp_expr *priv = nft_expr_priv(expr);
+
+ return __nft_cmp_offload(ctx, flow, priv);
+}
+
static const struct nft_expr_ops nft_cmp_ops = {
.type = &nft_cmp_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_expr)),
.eval = nft_cmp_eval,
.init = nft_cmp_init,
.dump = nft_cmp_dump,
+ .offload = nft_cmp_offload,
};
static int nft_cmp_fast_init(const struct nft_ctx *ctx,
@@ -143,6 +176,25 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
return 0;
}
+static int nft_cmp_fast_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
+ struct nft_cmp_expr cmp = {
+ .data = {
+ .data = {
+ [0] = priv->data,
+ },
+ },
+ .sreg = priv->sreg,
+ .len = priv->len / BITS_PER_BYTE,
+ .op = NFT_CMP_EQ,
+ };
+
+ return __nft_cmp_offload(ctx, flow, &cmp);
+}
+
static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
{
const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
@@ -169,6 +221,7 @@ const struct nft_expr_ops nft_cmp_fast_ops = {
.eval = NULL, /* inlined */
.init = nft_cmp_fast_init,
.dump = nft_cmp_fast_dump,
+ .offload = nft_cmp_fast_offload,
};
static const struct nft_expr_ops *
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
index cb8547f97220..ca2ae4b95a8d 100644
--- a/net/netfilter/nft_immediate.c
+++ b/net/netfilter/nft_immediate.c
@@ -13,6 +13,7 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_offload.h>
void nft_immediate_eval(const struct nft_expr *expr,
struct nft_regs *regs,
@@ -124,6 +125,34 @@ static int nft_immediate_validate(const struct nft_ctx *ctx,
return 0;
}
+static int nft_immediate_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_immediate_expr *priv = nft_expr_priv(expr);
+ struct flow_action_entry *entry;
+ const struct nft_data *data;
+
+ if (priv->dreg != NFT_REG_VERDICT)
+ return -EOPNOTSUPP;
+
+ entry = &flow->rule->action.entries[ctx->num_actions++];
+
+ data = &priv->data;
+ switch (data->verdict.code) {
+ case NF_ACCEPT:
+ entry->id = FLOW_ACTION_ACCEPT;
+ break;
+ case NF_DROP:
+ entry->id = FLOW_ACTION_DROP;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static const struct nft_expr_ops nft_imm_ops = {
.type = &nft_imm_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
@@ -133,6 +162,8 @@ static const struct nft_expr_ops nft_imm_ops = {
.deactivate = nft_immediate_deactivate,
.dump = nft_immediate_dump,
.validate = nft_immediate_validate,
+ .offload = nft_immediate_offload,
+ .offload_flags = NFT_OFFLOAD_F_ACTION,
};
struct nft_expr_type nft_imm_type __read_mostly = {
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index a54329b8634a..e92f365aca35 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -21,6 +21,7 @@
#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
+#include <net/netfilter/nf_tables_offload.h>
#include <uapi/linux/netfilter_bridge.h> /* NF_BR_PRE_ROUTING */
@@ -515,6 +516,31 @@ static void nft_meta_set_destroy(const struct nft_ctx *ctx,
static_branch_dec(&nft_trace_enabled);
}
+static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_meta *priv = nft_expr_priv(expr);
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->key) {
+ case NFT_META_PROTOCOL:
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, n_proto,
+ sizeof(__u16), reg);
+ nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_NETWORK);
+ break;
+ case NFT_META_L4PROTO:
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
+ sizeof(__u8), reg);
+ nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
static const struct nft_expr_ops nft_meta_get_ops = {
.type = &nft_meta_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
@@ -522,6 +548,7 @@ static const struct nft_expr_ops nft_meta_get_ops = {
.init = nft_meta_get_init,
.dump = nft_meta_get_dump,
.validate = nft_meta_get_validate,
+ .offload = nft_meta_get_offload,
};
static const struct nft_expr_ops nft_meta_set_ops = {
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 1260f78a034d..22a80eb60222 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -15,10 +15,13 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_core.h>
#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_offload.h>
/* For layer 4 checksum field offset. */
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmpv6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
/* add vlan header into the user buffer for if tag was removed by offloads */
static bool
@@ -150,12 +153,195 @@ static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
return -1;
}
+static int nft_payload_offload_ll(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->offset) {
+ case offsetof(struct ethhdr, h_source):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
+ src, ETH_ALEN, reg);
+ break;
+ case offsetof(struct ethhdr, h_dest):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_ETH_ADDRS, eth_addrs,
+ dst, ETH_ALEN, reg);
+ break;
+ }
+
+ return 0;
+}
+
+static int nft_payload_offload_ip(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->offset) {
+ case offsetof(struct iphdr, saddr):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, src,
+ sizeof(struct in_addr), reg);
+ break;
+ case offsetof(struct iphdr, daddr):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV4_ADDRS, ipv4, dst,
+ sizeof(struct in_addr), reg);
+ break;
+ case offsetof(struct iphdr, protocol):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
+ sizeof(__u8), reg);
+ nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int nft_payload_offload_ip6(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->offset) {
+ case offsetof(struct ipv6hdr, saddr):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, src,
+ sizeof(struct in6_addr), reg);
+ break;
+ case offsetof(struct ipv6hdr, daddr):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6, dst,
+ sizeof(struct in6_addr), reg);
+ break;
+ case offsetof(struct ipv6hdr, nexthdr):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_BASIC, basic, ip_proto,
+ sizeof(__u8), reg);
+ nft_offload_set_dependency(ctx, NFT_OFFLOAD_DEP_TRANSPORT);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int nft_payload_offload_nh(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ int err;
+
+ switch (ctx->dep.l3num) {
+ case htons(ETH_P_IP):
+ err = nft_payload_offload_ip(ctx, flow, priv);
+ break;
+ case htons(ETH_P_IPV6):
+ err = nft_payload_offload_ip6(ctx, flow, priv);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+static int nft_payload_offload_tcp(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->offset) {
+ case offsetof(struct tcphdr, source):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
+ sizeof(__be16), reg);
+ break;
+ case offsetof(struct tcphdr, dest):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
+ sizeof(__be16), reg);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int nft_payload_offload_udp(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
+
+ switch (priv->offset) {
+ case offsetof(struct udphdr, source):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, src,
+ sizeof(__be16), reg);
+ break;
+ case offsetof(struct udphdr, dest):
+ NFT_OFFLOAD_MATCH(FLOW_DISSECTOR_KEY_PORTS, tp, dst,
+ sizeof(__be16), reg);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int nft_payload_offload_th(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_payload *priv)
+{
+ int err;
+
+ switch (ctx->dep.protonum) {
+ case IPPROTO_TCP:
+ err = nft_payload_offload_tcp(ctx, flow, priv);
+ break;
+ case IPPROTO_UDP:
+ err = nft_payload_offload_udp(ctx, flow, priv);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
+static int nft_payload_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_payload *priv = nft_expr_priv(expr);
+ int err;
+
+ switch (priv->base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ err = nft_payload_offload_ll(ctx, flow, priv);
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ err = nft_payload_offload_nh(ctx, flow, priv);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ err = nft_payload_offload_th(ctx, flow, priv);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+ return err;
+}
+
static const struct nft_expr_ops nft_payload_ops = {
.type = &nft_payload_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
.eval = nft_payload_eval,
.init = nft_payload_init,
.dump = nft_payload_dump,
+ .offload = nft_payload_offload,
};
const struct nft_expr_ops nft_payload_fast_ops = {
@@ -164,6 +350,7 @@ const struct nft_expr_ops nft_payload_fast_ops = {
.eval = nft_payload_eval,
.init = nft_payload_init,
.dump = nft_payload_dump,
+ .offload = nft_payload_offload,
};
static inline void nft_csum_replace(__sum16 *sum, __wsum fsum, __wsum tsum)
--
2.11.0
^ permalink raw reply related
* [PATCH 12/15 net-next,v2] net: flow_offload: make flow block callback list per-driver
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Remove the global flow_block_cb_list, replace it by per-driver list
of flow block objects. This will make it easier later on to support
for policy hardware offload of multiple subsystems.
Suggested-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: new patch, no previous v1.
Introduce per-driver list of flow blocks as Jiri requested.
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 4 ++-
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 3 ++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4 ++-
drivers/net/ethernet/intel/i40e/i40e_main.c | 4 ++-
drivers/net/ethernet/intel/iavf/iavf_main.c | 4 ++-
drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 8 ++++--
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 17 ++++++------
drivers/net/ethernet/mscc/ocelot_flower.c | 6 ++--
drivers/net/ethernet/mscc/ocelot_tc.c | 8 ++++--
drivers/net/ethernet/netronome/nfp/abm/cls.c | 5 +++-
drivers/net/ethernet/netronome/nfp/bpf/main.c | 3 ++
.../net/ethernet/netronome/nfp/flower/offload.c | 9 +++---
drivers/net/ethernet/qlogic/qede/qede_main.c | 4 ++-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++
drivers/net/netdevsim/netdev.c | 3 ++
include/net/flow_offload.h | 14 ++++++----
net/core/flow_offload.c | 32 ++++++++++++----------
net/dsa/slave.c | 8 ++++--
21 files changed, 99 insertions(+), 52 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 7b8d71252093..4bf13776759e 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -9847,6 +9847,8 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
+static LIST_HEAD(bnxt_block_cb_list);
+
static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -9854,7 +9856,7 @@ static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &bnxt_block_cb_list,
bnxt_setup_tc_block_cb, bp, bp,
true);
case TC_SETUP_QDISC_MQPRIO: {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index 1b78615a1384..80b8d8e54f58 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -161,6 +161,8 @@ static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type,
}
}
+static LIST_HEAD(bnxt_vf_block_cb_list);
+
static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -169,6 +171,7 @@ static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_setup_offload(type_data,
+ &bnxt_vf_block_cb_list,
bnxt_vf_rep_setup_tc_block_cb,
vf_rep, vf_rep, true);
default:
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 3d8acabb8bfd..ee98304ea0cd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3190,6 +3190,8 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
+static LIST_HEAD(cxgb_block_cb_list);
+
static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -3197,7 +3199,7 @@ static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &cxgb_block_cb_list,
cxgb_setup_tc_block_cb, pi, dev,
true);
default:
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index f7d2616854ec..2705e46fde59 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -8177,6 +8177,8 @@ static int i40e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
+static LIST_HEAD(i40e_block_cb_list);
+
static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
@@ -8186,7 +8188,7 @@ static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
case TC_SETUP_QDISC_MQPRIO:
return i40e_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &i40e_block_cb_list,
i40e_setup_tc_block_cb, np, np,
true);
default:
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 8ef6aca34edd..410cbf02e6a8 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -3113,6 +3113,8 @@ static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
+static LIST_HEAD(iavf_block_cb_list);
+
/**
* iavf_setup_tc - configure multiple traffic classes
* @netdev: network interface device structure
@@ -3133,7 +3135,7 @@ static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
case TC_SETUP_QDISC_MQPRIO:
return __iavf_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &iavf_block_cb_list,
iavf_setup_tc_block_cb, adapter,
adapter, true);
default:
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 830b950f423b..c66e66f04036 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2806,6 +2806,8 @@ static int igb_offload_txtime(struct igb_adapter *adapter,
return 0;
}
+static LIST_HEAD(igb_block_cb_list);
+
static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -2815,7 +2817,7 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_CBS:
return igb_offload_cbs(adapter, type_data);
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &igb_block_cb_list,
igb_setup_tc_block_cb,
adapter, adapter, true);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 144f2cca686a..b3d62d8e1bd0 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9614,6 +9614,8 @@ static int ixgbe_setup_tc_mqprio(struct net_device *dev,
return ixgbe_setup_tc(dev, mqprio->num_tc);
}
+static LIST_HEAD(ixgbe_block_cb_list);
+
static int __ixgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -9621,7 +9623,7 @@ static int __ixgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &ixgbe_block_cb_list,
ixgbe_setup_tc_block_cb,
adapter, adapter, true);
case TC_SETUP_QDISC_MQPRIO:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index fa9c04129eb6..6324215c7800 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3347,6 +3347,8 @@ static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
#endif
+static LIST_HEAD(mlx5e_block_cb_list);
+
static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
@@ -3355,7 +3357,7 @@ static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
#ifdef CONFIG_MLX5_ESWITCH
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &mlx5e_block_cb_list,
mlx5e_setup_tc_block_cb,
priv, priv, true);
#endif
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 925aa589a818..2d26af759997 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -700,6 +700,8 @@ static void mlx5e_rep_indr_tc_block_unbind(void *cb_priv)
kfree(indr_priv);
}
+static LIST_HEAD(mlx5e_rep_block_cb_list);
+
static int
mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv,
@@ -726,8 +728,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
- block_cb = flow_block_cb_alloc(f->net,
- mlx5e_rep_indr_setup_block_cb,
+ block_cb = flow_block_cb_alloc(f, mlx5e_rep_indr_setup_block_cb,
indr_priv, indr_priv,
mlx5e_rep_indr_tc_block_unbind);
if (IS_ERR(block_cb)) {
@@ -743,7 +744,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
if (!indr_priv)
return -ENOENT;
- block_cb = flow_block_cb_lookup(f->net,
+ block_cb = flow_block_cb_lookup(f,
mlx5e_rep_indr_setup_block_cb,
indr_priv);
if (!block_cb)
@@ -1198,6 +1199,7 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_setup_offload(type_data,
+ &mlx5e_rep_block_cb_list,
mlx5e_rep_setup_tc_cb,
priv, priv, true);
default:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 6970738c070b..3ecb51a05961 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1601,15 +1601,13 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
bool register_block = false;
int err;
- block_cb = flow_block_cb_lookup(f->net,
- mlxsw_sp_setup_tc_block_cb_flower,
+ block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb) {
acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, f->net);
if (!acl_block)
return -ENOMEM;
-
- block_cb = flow_block_cb_alloc(f->net,
+ block_cb = flow_block_cb_alloc(f,
mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp, acl_block,
mlxsw_sp_tc_block_flower_release);
@@ -1655,8 +1653,7 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
struct flow_block_cb *block_cb;
int err;
- block_cb = flow_block_cb_lookup(f->net,
- mlxsw_sp_setup_tc_block_cb_flower,
+ block_cb = flow_block_cb_lookup(f, mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb)
return;
@@ -1673,6 +1670,8 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
flow_block_cb_remove(block_cb, f);
}
+static LIST_HEAD(mlxsw_block_cb_list);
+
static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
struct flow_block_offload *f)
{
@@ -1681,6 +1680,8 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
bool ingress;
int err;
+ f->block_cb_list = &mlxsw_block_cb_list;
+
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_ig;
ingress = true;
@@ -1693,7 +1694,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = flow_block_cb_alloc(f->net, cb, mlxsw_sp_port,
+ block_cb = flow_block_cb_alloc(f, cb, mlxsw_sp_port,
mlxsw_sp_port, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
@@ -1708,7 +1709,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
case TC_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
f, ingress);
- block_cb = flow_block_cb_lookup(f->net, cb, mlxsw_sp_port);
+ block_cb = flow_block_cb_lookup(f, cb, mlxsw_sp_port);
if (!block_cb)
return -ENOENT;
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 3b9e4219ac7a..3dd8acc255ae 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -316,14 +316,14 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
- block_cb = flow_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
port);
if (!block_cb) {
port_block = ocelot_port_block_create(port);
if (!port_block)
return -ENOMEM;
- block_cb = flow_block_cb_alloc(f->net,
+ block_cb = flow_block_cb_alloc(f,
ocelot_setup_tc_block_cb_flower,
port, port_block,
ocelot_tc_block_unbind);
@@ -350,7 +350,7 @@ void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
{
struct flow_block_cb *block_cb;
- block_cb = flow_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
port);
if (!block_cb)
return;
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index 14a9e178c3b8..17fca31206c7 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -128,6 +128,8 @@ static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
cb_priv, false);
}
+static LIST_HEAD(ocelot_block_cb_list);
+
static int ocelot_setup_tc_block(struct ocelot_port *port,
struct flow_block_offload *f)
{
@@ -147,9 +149,11 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
return -EOPNOTSUPP;
}
+ f->block_cb_list = &ocelot_block_cb_list;
+
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = flow_block_cb_alloc(f->net, cb, port, port, NULL);
+ block_cb = flow_block_cb_alloc(f, cb, port, port, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
@@ -161,7 +165,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = flow_block_cb_lookup(f->net, cb, port);
+ block_cb = flow_block_cb_lookup(f, cb, port);
if (!block_cb)
return -ENOENT;
diff --git a/drivers/net/ethernet/netronome/nfp/abm/cls.c b/drivers/net/ethernet/netronome/nfp/abm/cls.c
index 96b89a7c468b..a42f92318b7a 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/cls.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/cls.c
@@ -262,9 +262,12 @@ static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
}
}
+static LIST_HEAD(nfp_abm_vf_block_cb_list);
+
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
struct flow_block_offload *f)
{
- return flow_block_setup_offload(f, nfp_abm_setup_tc_block_cb,
+ return flow_block_setup_offload(f, &nfp_abm_block_cb_list,
+ nfp_abm_setup_tc_block_cb,
repr, repr, true);
}
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 3897cc4f7a7e..5316d85261c0 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -160,6 +160,8 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
return 0;
}
+static LIST_HEAD(nfp_bfp_block_cb_list);
+
static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
enum tc_setup_type type, void *type_data)
{
@@ -168,6 +170,7 @@ static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_setup_offload(type_data,
+ &nfp_bfp_block_cb_list,
nfp_bpf_setup_tc_block_cb,
nn, nn, true);
default:
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 9b99f6936f90..6b2f31ed2315 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1317,7 +1317,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = flow_block_cb_alloc(f->net,
+ block_cb = flow_block_cb_alloc(f,
nfp_flower_setup_tc_block_cb,
repr, repr, NULL);
if (IS_ERR(block_cb))
@@ -1326,7 +1326,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = flow_block_cb_lookup(f->net,
+ block_cb = flow_block_cb_lookup(f,
nfp_flower_setup_tc_block_cb,
repr);
if (!block_cb)
@@ -1405,7 +1405,6 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
{
struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv;
- struct net *net = dev_net(netdev);
struct flow_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
@@ -1423,7 +1422,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv);
- block_cb = flow_block_cb_alloc(net,
+ block_cb = flow_block_cb_alloc(f,
nfp_flower_setup_indr_block_cb,
cb_priv, cb_priv,
nfp_flower_setup_indr_tc_release);
@@ -1440,7 +1439,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
if (!cb_priv)
return -ENOENT;
- block_cb = flow_block_cb_lookup(net,
+ block_cb = flow_block_cb_lookup(f,
nfp_flower_setup_indr_block_cb,
cb_priv);
if (!block_cb)
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 00db21d9407f..aab9c8c25d43 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -579,6 +579,8 @@ static int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
+static LIST_HEAD(qede_block_cb_list);
+
static int
qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
void *type_data)
@@ -588,7 +590,7 @@ qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return flow_block_setup_offload(type_data,
+ return flow_block_setup_offload(type_data, &qede_block_cb_list,
qede_setup_tc_block_cb,
edev, edev, true);
case TC_SETUP_QDISC_MQPRIO:
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 341db1eed108..86fef8ac2712 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3853,6 +3853,8 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
return ret;
}
+static LIST_HEAD(stmmac_block_cb_list);
+
static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
{
@@ -3861,6 +3863,7 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_setup_offload(type_data,
+ &stmmac_block_cb_list,
stmmac_setup_tc_block_cb,
priv, priv, true);
case TC_SETUP_QDISC_CBS:
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 710b03fc8db1..0612b0628cf3 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -203,6 +203,8 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
return 0;
}
+static LIST_HEAD(nsim_block_cb_list);
+
static int
nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
{
@@ -211,6 +213,7 @@ nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
switch (type) {
case TC_SETUP_BLOCK:
return flow_block_setup_offload(type_data,
+ &nsim_block_cb_list,
nsim_setup_tc_block_cb, ns, ns,
true);
default:
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 728ded7e4361..390e74ed42cb 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -249,6 +249,7 @@ struct flow_block_offload {
enum flow_block_command command;
enum flow_block_binder_type binder_type;
struct list_head cb_list;
+ struct list_head *block_cb_list;
struct net *net;
bool block_shared;
struct netlink_ext_ack *extack;
@@ -266,13 +267,14 @@ struct flow_block_cb {
unsigned int refcnt;
};
-struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+struct flow_block_cb *flow_block_cb_alloc(struct flow_block_offload *f,
+ tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv));
void flow_block_cb_free(struct flow_block_cb *block_cb);
void *flow_block_cb_priv(struct flow_block_cb *block_cb);
-struct flow_block_cb *flow_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident);
+struct flow_block_cb *flow_block_cb_lookup(struct flow_block_offload *f,
+ tc_setup_cb_t *cb, void *cb_ident);
void flow_block_cb_incref(struct flow_block_cb *block_cb);
unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb);
void flow_block_cb_add(struct flow_block_cb *block_cb,
@@ -281,7 +283,9 @@ void flow_block_cb_remove(struct flow_block_cb *block_cb,
struct flow_block_offload *offload);
void flow_block_cb_splice(struct flow_block_offload *offload);
-int flow_block_setup_offload(struct flow_block_offload *f, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv, bool ingress_only);
+int flow_block_setup_offload(struct flow_block_offload *f,
+ struct list_head *block_cb_list,
+ tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
+ bool ingress_only);
#endif /* _NET_FLOW_OFFLOAD_H */
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 8c20f4740800..8392cf2b5ea7 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -171,15 +171,13 @@ void *flow_block_cb_priv(struct flow_block_cb *block_cb)
}
EXPORT_SYMBOL(flow_block_cb_priv);
-static LIST_HEAD(flow_block_cb_list);
-
-struct flow_block_cb *flow_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
- void *cb_ident)
+struct flow_block_cb *flow_block_cb_lookup(struct flow_block_offload *f,
+ tc_setup_cb_t *cb, void *cb_ident)
{
struct flow_block_cb *block_cb;
- list_for_each_entry(block_cb, &flow_block_cb_list, global_list) {
- if (block_cb->net == net &&
+ list_for_each_entry(block_cb, f->block_cb_list, global_list) {
+ if (block_cb->net == f->net &&
block_cb->cb == cb &&
block_cb->cb_ident == cb_ident)
return block_cb;
@@ -200,13 +198,14 @@ unsigned int flow_block_cb_decref(struct flow_block_cb *block_cb)
}
EXPORT_SYMBOL(flow_block_cb_decref);
-struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
+struct flow_block_cb *flow_block_cb_alloc(struct flow_block_offload *f,
+ tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv))
{
struct flow_block_cb *block_cb;
- list_for_each_entry(block_cb, &flow_block_cb_list, global_list) {
+ list_for_each_entry(block_cb, f->block_cb_list, global_list) {
if (block_cb->cb == cb &&
block_cb->cb_ident == cb_ident)
return ERR_PTR(-EBUSY);
@@ -216,7 +215,7 @@ struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
if (IS_ERR(block_cb))
return block_cb;
- block_cb->net = net;
+ block_cb->net = f->net;
block_cb->cb = cb;
block_cb->cb_ident = cb_ident;
block_cb->release = release;
@@ -251,30 +250,33 @@ EXPORT_SYMBOL(flow_block_cb_remove);
void flow_block_cb_splice(struct flow_block_offload *offload)
{
- list_splice(&offload->cb_list, &flow_block_cb_list);
+ list_splice(&offload->cb_list, offload->block_cb_list);
}
EXPORT_SYMBOL(flow_block_cb_splice);
-int flow_block_setup_offload(struct flow_block_offload *f, tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv, bool ingress_only)
+int flow_block_setup_offload(struct flow_block_offload *f,
+ struct list_head *block_cb_list,
+ tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
+ bool ingress_only)
{
struct flow_block_cb *block_cb;
+ f->block_cb_list = block_cb_list;
+
if (ingress_only &&
f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = flow_block_cb_alloc(f->net, cb, cb_ident, cb_priv,
- NULL);
+ block_cb = flow_block_cb_alloc(f, cb, cb_ident, cb_priv, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = flow_block_cb_lookup(f->net, cb, cb_ident);
+ block_cb = flow_block_cb_lookup(f, cb, cb_ident);
if (!block_cb)
return -ENOENT;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 0323091b5cef..504c4183af71 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -942,12 +942,16 @@ static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type,
return dsa_slave_setup_tc_block_cb(type, type_data, cb_priv, false);
}
+static LIST_HEAD(dsa_slave_block_cb_list);
+
static int dsa_slave_setup_tc_block(struct net_device *dev,
struct flow_block_offload *f)
{
struct flow_block_cb *block_cb;
tc_setup_cb_t *cb;
+ f->block_cb_list = &dsa_slave_block_cb_list;
+
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
cb = dsa_slave_setup_tc_block_cb_ig;
else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
@@ -957,14 +961,14 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
switch (f->command) {
case TC_BLOCK_BIND:
- block_cb = flow_block_cb_alloc(f->net, cb, dev, dev, NULL);
+ block_cb = flow_block_cb_alloc(f, cb, dev, dev, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
- block_cb = flow_block_cb_lookup(f->net, cb, dev);
+ block_cb = flow_block_cb_lookup(f, cb, dev);
if (!block_cb)
return -ENOENT;
--
2.11.0
^ permalink raw reply related
* [PATCH 13/15 net-next,v2] net: flow_offload: rename TC_BLOCK_{UN}BIND to FLOW_BLOCK_{UN}BIND
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Not tc specific anymore, rename this.
Suggested-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: Actually a new patch (no previous v1), requested by Jiri.
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 4 ++--
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 ++--
drivers/net/ethernet/mscc/ocelot_tc.c | 4 ++--
.../net/ethernet/netronome/nfp/flower/offload.c | 8 ++++----
include/net/flow_offload.h | 4 ++--
net/core/flow_offload.c | 4 ++--
net/dsa/slave.c | 4 ++--
net/sched/cls_api.c | 24 +++++++++++-----------
8 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 2d26af759997..d05888dff503 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -714,7 +714,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
return -EOPNOTSUPP;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
if (indr_priv)
return -EEXIST;
@@ -739,7 +739,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
if (!indr_priv)
return -ENOENT;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 3ecb51a05961..8083491b2172 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1693,7 +1693,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
}
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_alloc(f, cb, mlxsw_sp_port,
mlxsw_sp_port, NULL);
if (IS_ERR(block_cb))
@@ -1706,7 +1706,7 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
}
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
f, ingress);
block_cb = flow_block_cb_lookup(f, cb, mlxsw_sp_port);
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index 17fca31206c7..d92de65176b5 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -152,7 +152,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
f->block_cb_list = &ocelot_block_cb_list;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_alloc(f, cb, port, port, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
@@ -164,7 +164,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
}
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f, cb, port);
if (!block_cb)
return -ENOENT;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 6b2f31ed2315..c52b8349b9f1 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1316,7 +1316,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
repr_priv->block_shared = f->block_shared;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_alloc(f,
nfp_flower_setup_tc_block_cb,
repr, repr, NULL);
@@ -1325,7 +1325,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f,
nfp_flower_setup_tc_block_cb,
repr);
@@ -1413,7 +1413,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
return -EOPNOTSUPP;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
if (!cb_priv)
return -ENOMEM;
@@ -1434,7 +1434,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
if (!cb_priv)
return -ENOENT;
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 390e74ed42cb..744eb474c823 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -235,8 +235,8 @@ static inline void flow_stats_update(struct flow_stats *flow_stats,
#include <net/sch_generic.h> /* for tc_setup_cb_t. */
enum flow_block_command {
- TC_BLOCK_BIND,
- TC_BLOCK_UNBIND,
+ FLOW_BLOCK_BIND,
+ FLOW_BLOCK_UNBIND,
};
enum flow_block_binder_type {
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 8392cf2b5ea7..eaff06ee313d 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -268,14 +268,14 @@ int flow_block_setup_offload(struct flow_block_offload *f,
return -EOPNOTSUPP;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_alloc(f, cb, cb_ident, cb_priv, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f, cb, cb_ident);
if (!block_cb)
return -ENOENT;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 504c4183af71..636a22201654 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -960,14 +960,14 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
return -EOPNOTSUPP;
switch (f->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
block_cb = flow_block_cb_alloc(f, cb, dev, dev, NULL);
if (IS_ERR(block_cb))
return PTR_ERR(block_cb);
flow_block_cb_add(block_cb, f);
return 0;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
block_cb = flow_block_cb_lookup(f, cb, dev);
if (!block_cb)
return -ENOENT;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 5635b6f63015..00f4303dc6e5 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -767,10 +767,10 @@ static int tcf_block_setup(struct tcf_block *block,
int err;
switch (bo->command) {
- case TC_BLOCK_BIND:
+ case FLOW_BLOCK_BIND:
err = tcf_block_bind(block, bo);
break;
- case TC_BLOCK_UNBIND:
+ case FLOW_BLOCK_UNBIND:
err = 0;
tcf_block_unbind(block, bo);
break;
@@ -904,8 +904,8 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
if (!indr_dev->block)
return;
- indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
- &bo);
+ indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv,
+ TC_SETUP_BLOCK, &bo);
tcf_block_setup(indr_dev->block, &bo);
}
@@ -925,7 +925,7 @@ int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
if (err)
goto err_dev_put;
- tc_indr_block_ing_cmd(indr_dev, indr_block_cb, TC_BLOCK_BIND);
+ tc_indr_block_ing_cmd(indr_dev, indr_block_cb, FLOW_BLOCK_BIND);
return 0;
err_dev_put:
@@ -962,7 +962,7 @@ void __tc_indr_block_cb_unregister(struct net_device *dev,
return;
/* Send unbind message if required to free any block cbs. */
- tc_indr_block_ing_cmd(indr_dev, indr_block_cb, TC_BLOCK_UNBIND);
+ tc_indr_block_ing_cmd(indr_dev, indr_block_cb, FLOW_BLOCK_UNBIND);
tc_indr_block_cb_del(indr_block_cb);
tc_indr_block_dev_put(indr_dev);
}
@@ -997,7 +997,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
if (!indr_dev)
return;
- indr_dev->block = command == TC_BLOCK_BIND ? block : NULL;
+ indr_dev->block = command == FLOW_BLOCK_BIND ? block : NULL;
list_for_each_entry(indr_block_cb, &indr_dev->cb_list, list)
indr_block_cb->cb(dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
@@ -1047,20 +1047,20 @@ static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
return -EOPNOTSUPP;
}
- err = tcf_block_offload_cmd(block, dev, ei, TC_BLOCK_BIND, extack);
+ err = tcf_block_offload_cmd(block, dev, ei, FLOW_BLOCK_BIND, extack);
if (err == -EOPNOTSUPP)
goto no_offload_dev_inc;
if (err)
return err;
- tc_indr_block_call(block, dev, ei, TC_BLOCK_BIND, extack);
+ tc_indr_block_call(block, dev, ei, FLOW_BLOCK_BIND, extack);
return 0;
no_offload_dev_inc:
if (tcf_block_offload_in_use(block))
return -EOPNOTSUPP;
block->nooffloaddevcnt++;
- tc_indr_block_call(block, dev, ei, TC_BLOCK_BIND, extack);
+ tc_indr_block_call(block, dev, ei, FLOW_BLOCK_BIND, extack);
return 0;
}
@@ -1070,11 +1070,11 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
struct net_device *dev = q->dev_queue->dev;
int err;
- tc_indr_block_call(block, dev, ei, TC_BLOCK_UNBIND, NULL);
+ tc_indr_block_call(block, dev, ei, FLOW_BLOCK_UNBIND, NULL);
if (!dev->netdev_ops->ndo_setup_tc)
goto no_offload_dev_dec;
- err = tcf_block_offload_cmd(block, dev, ei, TC_BLOCK_UNBIND, NULL);
+ err = tcf_block_offload_cmd(block, dev, ei, FLOW_BLOCK_UNBIND, NULL);
if (err == -EOPNOTSUPP)
goto no_offload_dev_dec;
return;
--
2.11.0
^ permalink raw reply related
* [PATCH 14/15 net-next,v2] net: flow_offload: rename TCF_BLOCK_BINDER_TYPE_* to FLOW_BLOCK_BINDER_TYPE_*
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Not tc specific anymore, rename this.
Suggested-by: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: Actually a new patch (no previous v1), requested by Jiri.
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 2 +-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 ++--
drivers/net/ethernet/mscc/ocelot_flower.c | 2 +-
drivers/net/ethernet/mscc/ocelot_tc.c | 4 ++--
drivers/net/ethernet/netronome/nfp/flower/offload.c | 6 +++---
include/net/flow_offload.h | 6 +++---
net/core/flow_offload.c | 2 +-
net/dsa/slave.c | 4 ++--
net/sched/cls_api.c | 6 +++---
net/sched/sch_ingress.c | 6 +++---
10 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index d05888dff503..bde200cbedd0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -710,7 +710,7 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
struct mlx5e_rep_indr_block_priv *indr_priv;
struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 8083491b2172..5b1a4160dfd9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1682,10 +1682,10 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
f->block_cb_list = &mlxsw_block_cb_list;
- if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_ig;
ingress = true;
- } else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
+ } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = mlxsw_sp_setup_tc_block_cb_matchall_eg;
ingress = false;
} else {
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 3dd8acc255ae..8921953cb32c 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -313,7 +313,7 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
struct flow_block_cb *block_cb;
int ret;
- if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
block_cb = flow_block_cb_lookup(f, ocelot_setup_tc_block_cb_flower,
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index d92de65176b5..b9769e4411e7 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -140,10 +140,10 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
f->command, f->binder_type);
- if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = ocelot_setup_tc_block_cb_ig;
port->tc.block_shared = f->block_shared;
- } else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
+ } else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = ocelot_setup_tc_block_cb_eg;
} else {
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index c52b8349b9f1..b926c1639c1d 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1309,7 +1309,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
struct nfp_flower_repr_priv *repr_priv;
struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
repr_priv = repr->app_priv;
@@ -1407,8 +1407,8 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
struct nfp_flower_priv *priv = app->priv;
struct flow_block_cb *block_cb;
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
- !(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
+ if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
+ !(f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
nfp_flower_internal_port_can_offload(app, netdev)))
return -EOPNOTSUPP;
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 744eb474c823..f955c906116b 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -240,9 +240,9 @@ enum flow_block_command {
};
enum flow_block_binder_type {
- TCF_BLOCK_BINDER_TYPE_UNSPEC,
- TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
- TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
+ FLOW_BLOCK_BINDER_TYPE_UNSPEC,
+ FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
+ FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS,
};
struct flow_block_offload {
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index eaff06ee313d..5614a637f1fd 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -264,7 +264,7 @@ int flow_block_setup_offload(struct flow_block_offload *f,
f->block_cb_list = block_cb_list;
if (ingress_only &&
- f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 636a22201654..0c1900b2f5f1 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -952,9 +952,9 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
f->block_cb_list = &dsa_slave_block_cb_list;
- if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
cb = dsa_slave_setup_tc_block_cb_ig;
- else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+ else if (f->binder_type == FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
cb = dsa_slave_setup_tc_block_cb_eg;
else
return -EOPNOTSUPP;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 00f4303dc6e5..1f9d742345a6 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -895,7 +895,7 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
{
struct flow_block_offload bo = {
.command = command,
- .binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
+ .binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
.net = dev_net(indr_dev->dev),
.block_shared = tcf_block_shared(indr_dev->block),
};
@@ -1478,8 +1478,8 @@ tcf_block_owner_netif_keep_dst(struct tcf_block *block,
enum flow_block_binder_type binder_type)
{
if (block->keep_dst &&
- binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
- binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
+ binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
+ binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
netif_keep_dst(qdisc_dev(q));
}
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 599730f804d7..bf56aa519797 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -83,7 +83,7 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
- q->block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
+ q->block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
q->block_info.chain_head_change = clsact_chain_head_change;
q->block_info.chain_head_change_priv = &q->miniqp;
@@ -217,7 +217,7 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
mini_qdisc_pair_init(&q->miniqp_ingress, sch, &dev->miniq_ingress);
- q->ingress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
+ q->ingress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS;
q->ingress_block_info.chain_head_change = clsact_chain_head_change;
q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress;
@@ -228,7 +228,7 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
mini_qdisc_pair_init(&q->miniqp_egress, sch, &dev->miniq_egress);
- q->egress_block_info.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
+ q->egress_block_info.binder_type = FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS;
q->egress_block_info.chain_head_change = clsact_chain_head_change;
q->egress_block_info.chain_head_change_priv = &q->miniqp_egress;
--
2.11.0
^ permalink raw reply related
* [PATCH 07/15 net-next,v2] net: use tcf_block_setup() infrastructure
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
This allows us to register / unregister tcf_block_cb objects from the
core. The idea is to allocate and to set up the tcf_block_cb objects
from the driver, attach them to the tc_block_offload->cb_list, then the
core iterates over this block list to registers them.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: check for IS_ERR() after tcf_block_cb_alloc(), since change in patch 2/15.
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 34 +++++++----
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 70 +++++++++++++---------
drivers/net/ethernet/mscc/ocelot_flower.c | 33 +++++-----
drivers/net/ethernet/mscc/ocelot_tc.c | 24 +++++---
.../net/ethernet/netronome/nfp/flower/offload.c | 57 ++++++++++++------
include/net/pkt_cls.h | 13 ++--
net/dsa/slave.c | 14 ++++-
net/sched/cls_api.c | 41 +++++++++----
8 files changed, 190 insertions(+), 96 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 120de25c63c8..b6ffaec4becb 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -692,13 +692,21 @@ static int mlx5e_rep_indr_setup_block_cb(enum tc_setup_type type,
}
}
+static void mlx5e_rep_indr_tc_block_unbind(void *cb_priv)
+{
+ struct mlx5e_rep_indr_block_priv *indr_priv = cb_priv;
+
+ list_del(&indr_priv->list);
+ kfree(indr_priv);
+}
+
static int
mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv,
struct tc_block_offload *f)
{
struct mlx5e_rep_indr_block_priv *indr_priv;
- int err = 0;
+ struct tcf_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
@@ -718,26 +726,30 @@ mlx5e_rep_indr_setup_tc_block(struct net_device *netdev,
list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list);
- err = tcf_block_cb_register(f->block,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv, indr_priv, f->extack);
- if (err) {
+ block_cb = tcf_block_cb_alloc(f->net,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv, indr_priv,
+ mlx5e_rep_indr_tc_block_unbind);
+ if (IS_ERR(block_cb)) {
list_del(&indr_priv->list);
kfree(indr_priv);
+ return PTR_ERR(block_cb);
}
+ tcf_block_cb_add(block_cb, f);
- return err;
+ return 0;
case TC_BLOCK_UNBIND:
indr_priv = mlx5e_rep_indr_block_priv_lookup(rpriv, netdev);
if (!indr_priv)
return -ENOENT;
- tcf_block_cb_unregister(f->block,
- mlx5e_rep_indr_setup_block_cb,
- indr_priv);
- list_del(&indr_priv->list);
- kfree(indr_priv);
+ block_cb = tcf_block_cb_lookup(f->net,
+ mlx5e_rep_indr_setup_block_cb,
+ indr_priv);
+ if (!block_cb)
+ return -ENOENT;
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 755b14b82c8f..950d09f3ecb1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1584,29 +1584,40 @@ static int mlxsw_sp_setup_tc_block_cb_flower(enum tc_setup_type type,
}
}
+static void mlxsw_sp_tc_block_flower_release(void *cb_priv)
+{
+ struct mlxsw_sp_acl_block *acl_block = cb_priv;
+
+ mlxsw_sp_acl_block_destroy(acl_block);
+}
+
static int
mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tcf_block *block, bool ingress,
- struct netlink_ext_ack *extack)
+ struct tc_block_offload *f, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
struct tcf_block_cb *block_cb;
+ bool register_block = false;
int err;
- block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
+ block_cb = tcf_block_cb_lookup(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb) {
- acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, block->net);
+ acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, f->net);
if (!acl_block)
return -ENOMEM;
- block_cb = __tcf_block_cb_register(block,
- mlxsw_sp_setup_tc_block_cb_flower,
- mlxsw_sp, acl_block, extack);
+ block_cb = tcf_block_cb_alloc(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
+ mlxsw_sp, acl_block,
+ mlxsw_sp_tc_block_flower_release);
if (IS_ERR(block_cb)) {
+ mlxsw_sp_acl_block_destroy(acl_block);
err = PTR_ERR(block_cb);
goto err_cb_register;
}
+ register_block = true;
} else {
acl_block = tcf_block_cb_priv(block_cb);
}
@@ -1621,27 +1632,29 @@ mlxsw_sp_setup_tc_block_flower_bind(struct mlxsw_sp_port *mlxsw_sp_port,
else
mlxsw_sp_port->eg_acl_block = acl_block;
+ if (register_block)
+ tcf_block_cb_add(block_cb, f);
+
return 0;
err_block_bind:
- if (!tcf_block_cb_decref(block_cb)) {
- __tcf_block_cb_unregister(block, block_cb);
+ if (!tcf_block_cb_decref(block_cb))
+ tcf_block_cb_free(block_cb);
err_cb_register:
- mlxsw_sp_acl_block_destroy(acl_block);
- }
return err;
}
static void
mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
- struct tcf_block *block, bool ingress)
+ struct tc_block_offload *f, bool ingress)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_block *acl_block;
struct tcf_block_cb *block_cb;
int err;
- block_cb = tcf_block_cb_lookup(block, mlxsw_sp_setup_tc_block_cb_flower,
+ block_cb = tcf_block_cb_lookup(f->net,
+ mlxsw_sp_setup_tc_block_cb_flower,
mlxsw_sp);
if (!block_cb)
return;
@@ -1654,15 +1667,14 @@ mlxsw_sp_setup_tc_block_flower_unbind(struct mlxsw_sp_port *mlxsw_sp_port,
acl_block = tcf_block_cb_priv(block_cb);
err = mlxsw_sp_acl_block_unbind(mlxsw_sp, acl_block,
mlxsw_sp_port, ingress);
- if (!err && !tcf_block_cb_decref(block_cb)) {
- __tcf_block_cb_unregister(block, block_cb);
- mlxsw_sp_acl_block_destroy(acl_block);
- }
+ if (!err && !tcf_block_cb_decref(block_cb))
+ tcf_block_cb_remove(block_cb, f);
}
static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
struct tc_block_offload *f)
{
+ struct tcf_block_cb *block_cb;
tc_setup_cb_t *cb;
bool ingress;
int err;
@@ -1679,22 +1691,26 @@ static int mlxsw_sp_setup_tc_block(struct mlxsw_sp_port *mlxsw_sp_port,
switch (f->command) {
case TC_BLOCK_BIND:
- err = tcf_block_cb_register(f->block, cb, mlxsw_sp_port,
- mlxsw_sp_port, f->extack);
- if (err)
- return err;
- err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port,
- f->block, ingress,
- f->extack);
+ block_cb = tcf_block_cb_alloc(f->net, cb, mlxsw_sp_port,
+ mlxsw_sp_port, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+ err = mlxsw_sp_setup_tc_block_flower_bind(mlxsw_sp_port, f,
+ ingress);
if (err) {
- tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+ tcf_block_cb_free(block_cb);
return err;
}
+ tcf_block_cb_add(block_cb, f);
return 0;
case TC_BLOCK_UNBIND:
mlxsw_sp_setup_tc_block_flower_unbind(mlxsw_sp_port,
- f->block, ingress);
- tcf_block_cb_unregister(f->block, cb, mlxsw_sp_port);
+ f, ingress);
+ block_cb = tcf_block_cb_lookup(f->net, cb, mlxsw_sp_port);
+ if (!block_cb)
+ return -ENOENT;
+
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 8778dee5a471..e62a7e56ec3e 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -299,6 +299,13 @@ static void ocelot_port_block_destroy(struct ocelot_port_block *block)
kfree(block);
}
+static void ocelot_tc_block_unbind(void *cb_priv)
+{
+ struct ocelot_port_block *port_block = cb_priv;
+
+ ocelot_port_block_destroy(port_block);
+}
+
int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
struct tc_block_offload *f)
{
@@ -309,21 +316,22 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
return -EOPNOTSUPP;
- block_cb = tcf_block_cb_lookup(f->block,
- ocelot_setup_tc_block_cb_flower, port);
+ block_cb = tcf_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ port);
if (!block_cb) {
port_block = ocelot_port_block_create(port);
if (!port_block)
return -ENOMEM;
- block_cb =
- __tcf_block_cb_register(f->block,
- ocelot_setup_tc_block_cb_flower,
- port, port_block, f->extack);
+ block_cb = tcf_block_cb_alloc(f->net,
+ ocelot_setup_tc_block_cb_flower,
+ port, port_block,
+ ocelot_tc_block_unbind);
if (IS_ERR(block_cb)) {
ret = PTR_ERR(block_cb);
goto err_cb_register;
}
+ tcf_block_cb_add(block_cb, f);
} else {
port_block = tcf_block_cb_priv(block_cb);
}
@@ -340,18 +348,13 @@ int ocelot_setup_tc_block_flower_bind(struct ocelot_port *port,
void ocelot_setup_tc_block_flower_unbind(struct ocelot_port *port,
struct tc_block_offload *f)
{
- struct ocelot_port_block *port_block;
struct tcf_block_cb *block_cb;
- block_cb = tcf_block_cb_lookup(f->block,
- ocelot_setup_tc_block_cb_flower, port);
+ block_cb = tcf_block_cb_lookup(f->net, ocelot_setup_tc_block_cb_flower,
+ port);
if (!block_cb)
return;
- port_block = tcf_block_cb_priv(block_cb);
- if (!tcf_block_cb_decref(block_cb)) {
- tcf_block_cb_unregister(f->block,
- ocelot_setup_tc_block_cb_flower, port);
- ocelot_port_block_destroy(port_block);
- }
+ if (!tcf_block_cb_decref(block_cb))
+ tcf_block_cb_remove(block_cb, f);
}
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index 72084306240d..5c3bf639f87c 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -131,8 +131,9 @@ static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type,
static int ocelot_setup_tc_block(struct ocelot_port *port,
struct tc_block_offload *f)
{
+ struct tcf_block_cb *block_cb;
tc_setup_cb_t *cb;
- int ret;
+ int err;
netdev_dbg(port->dev, "tc_block command %d, binder_type %d\n",
f->command, f->binder_type);
@@ -148,15 +149,24 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
switch (f->command) {
case TC_BLOCK_BIND:
- ret = tcf_block_cb_register(f->block, cb, port,
- port, f->extack);
- if (ret)
- return ret;
+ block_cb = tcf_block_cb_alloc(f->net, cb, port, port, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
- return ocelot_setup_tc_block_flower_bind(port, f);
+ err = ocelot_setup_tc_block_flower_bind(port, f);
+ if (err < 0) {
+ tcf_block_cb_free(block_cb);
+ return err;
+ }
+ tcf_block_cb_add(block_cb, f);
+ return 0;
case TC_BLOCK_UNBIND:
+ block_cb = tcf_block_cb_lookup(f->net, cb, port);
+ if (!block_cb)
+ return -ENOENT;
+
ocelot_setup_tc_block_flower_unbind(port, f);
- tcf_block_cb_unregister(f->block, cb, port);
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index 6dbe947269c3..fa44dce810ed 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1307,6 +1307,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
{
struct nfp_repr *repr = netdev_priv(netdev);
struct nfp_flower_repr_priv *repr_priv;
+ struct tcf_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
@@ -1316,13 +1317,22 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
switch (f->command) {
case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_flower_setup_tc_block_cb,
- repr, repr, f->extack);
+ block_cb = tcf_block_cb_alloc(f->net,
+ nfp_flower_setup_tc_block_cb,
+ repr, repr, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ tcf_block_cb_add(block_cb, f);
+ return 0;
case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- nfp_flower_setup_tc_block_cb,
- repr);
+ block_cb = tcf_block_cb_lookup(f->net,
+ nfp_flower_setup_tc_block_cb,
+ repr);
+ if (!block_cb)
+ return -ENOENT;
+
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
@@ -1381,13 +1391,22 @@ static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
}
}
+static void nfp_flower_setup_indr_tc_release(void *cb_priv)
+{
+ struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
+
+ list_del(&priv->list);
+ kfree(priv);
+}
+
static int
nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
struct tc_block_offload *f)
{
struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv;
- int err;
+ struct net *net = dev_net(netdev);
+ struct tcf_block_cb *block_cb;
if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
!(f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS &&
@@ -1404,26 +1423,30 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv);
- err = tcf_block_cb_register(f->block,
- nfp_flower_setup_indr_block_cb,
- cb_priv, cb_priv, f->extack);
- if (err) {
+ block_cb = tcf_block_cb_alloc(net,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv, cb_priv,
+ nfp_flower_setup_indr_tc_release);
+ if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
+ return PTR_ERR(block_cb);
}
- return err;
+ tcf_block_cb_add(block_cb, f);
+ return 0;
case TC_BLOCK_UNBIND:
cb_priv = nfp_flower_indr_block_cb_priv_lookup(app, netdev);
if (!cb_priv)
return -ENOENT;
- tcf_block_cb_unregister(f->block,
- nfp_flower_setup_indr_block_cb,
- cb_priv);
- list_del(&cb_priv->list);
- kfree(cb_priv);
+ block_cb = tcf_block_cb_lookup(net,
+ nfp_flower_setup_indr_block_cb,
+ cb_priv);
+ if (!block_cb)
+ return -ENOENT;
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index d35711758ddb..cb899c4552f4 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -72,7 +72,7 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
return block->q;
}
-struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+struct tcf_block_cb *tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv));
void tcf_block_cb_free(struct tcf_block_cb *block_cb);
@@ -84,8 +84,8 @@ void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
struct tc_block_offload *offload);
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident);
+struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident);
void tcf_block_cb_incref(struct tcf_block_cb *block_cb);
unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb);
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
@@ -172,8 +172,8 @@ static inline int tcf_setup_block_offload(struct tc_block_offload *f,
}
static inline struct tcf_block_cb *
-tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
- void (*release)(void *cb_priv))
+tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb, void *cb_ident,
+ void *cb_priv, void (*release)(void *cb_priv))
{
return ERR_PTR(-EOPNOTSUPP);
}
@@ -200,7 +200,7 @@ void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
}
static inline
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
+struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{
return NULL;
@@ -662,6 +662,7 @@ struct tc_block_offload {
enum tc_block_command command;
enum tcf_block_binder_type binder_type;
struct list_head cb_list;
+ struct net *net;
struct tcf_block *block;
struct netlink_ext_ack *extack;
};
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 99673f6b07f6..01be6dc20ba3 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -945,6 +945,7 @@ static int dsa_slave_setup_tc_block_cb_eg(enum tc_setup_type type,
static int dsa_slave_setup_tc_block(struct net_device *dev,
struct tc_block_offload *f)
{
+ struct tcf_block_cb *block_cb;
tc_setup_cb_t *cb;
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
@@ -956,9 +957,18 @@ static int dsa_slave_setup_tc_block(struct net_device *dev,
switch (f->command) {
case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, cb, dev, dev, f->extack);
+ block_cb = tcf_block_cb_alloc(f->net, cb, dev, dev, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ tcf_block_cb_add(block_cb, f);
+ return 0;
case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, cb, dev);
+ block_cb = tcf_block_cb_lookup(f->net, cb, dev);
+ if (!block_cb)
+ return -ENOENT;
+
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 003f24a1323f..3f036d50af65 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -712,6 +712,7 @@ static bool tcf_block_offload_in_use(struct tcf_block *block)
struct tcf_block_cb {
struct list_head global_list;
struct list_head list;
+ struct net *net;
tc_setup_cb_t *cb;
void (*release)(void *cb_priv);
void *cb_ident;
@@ -727,12 +728,15 @@ EXPORT_SYMBOL(tcf_block_cb_priv);
static LIST_HEAD(tcf_block_cb_list);
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{ struct tcf_block_cb *block_cb;
+struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
+ void *cb_ident)
+{
+ struct tcf_block_cb *block_cb;
- list_for_each_entry(block_cb, &block->cb_list, list)
- if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
+ list_for_each_entry(block_cb, &tcf_block_cb_list, global_list)
+ if (block_cb->net == net &&
+ block_cb->cb == cb &&
+ block_cb->cb_ident == cb_ident)
return block_cb;
return NULL;
}
@@ -750,7 +754,7 @@ unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
}
EXPORT_SYMBOL(tcf_block_cb_decref);
-struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+struct tcf_block_cb *tcf_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv))
{
@@ -760,6 +764,7 @@ struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
if (!block_cb)
return ERR_PTR(-ENOMEM);
+ block_cb->net = net;
block_cb->cb = cb;
block_cb->cb_ident = cb_ident;
block_cb->release = release;
@@ -807,7 +812,7 @@ struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
if (err)
return ERR_PTR(err);
- block_cb = tcf_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
+ block_cb = tcf_block_cb_alloc(block->net, cb, cb_ident, cb_priv, NULL);
if (IS_ERR(block_cb))
return block_cb;
@@ -844,7 +849,7 @@ void tcf_block_cb_unregister(struct tcf_block *block,
{
struct tcf_block_cb *block_cb;
- block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
+ block_cb = tcf_block_cb_lookup(block->net, cb, cb_ident);
if (!block_cb)
return;
__tcf_block_cb_unregister(block, block_cb);
@@ -925,16 +930,27 @@ static int tcf_block_setup(struct tcf_block *block, struct tc_block_offload *bo)
int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv, bool ingress_only)
{
+ struct tcf_block_cb *block_cb;
+
if (ingress_only &&
f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, cb, cb_ident, cb_priv,
- f->extack);
+ block_cb = tcf_block_cb_alloc(f->net, cb, cb_ident,
+ cb_priv, NULL);
+ if (IS_ERR(block_cb))
+ return PTR_ERR(block_cb);
+
+ tcf_block_cb_add(block_cb, f);
+ return 0;
case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, cb, cb_ident);
+ block_cb = tcf_block_cb_lookup(f->net, cb, cb_ident);
+ if (!block_cb)
+ return -ENOENT;
+
+ tcf_block_cb_remove(block_cb, f);
return 0;
default:
return -EOPNOTSUPP;
@@ -1056,6 +1072,7 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
struct tc_block_offload bo = {
.command = command,
.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
+ .net = dev_net(indr_dev->dev),
.block = indr_dev->block,
};
INIT_LIST_HEAD(&bo.cb_list);
@@ -1146,6 +1163,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
struct tc_block_offload bo = {
.command = command,
.binder_type = ei->binder_type,
+ .net = dev_net(dev),
.block = block,
.extack = extack,
};
@@ -1173,6 +1191,7 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
struct tc_block_offload bo = {};
int err;
+ bo.net = dev_net(dev);
bo.command = command;
bo.binder_type = ei->binder_type;
bo.block = block;
--
2.11.0
^ permalink raw reply related
* [PATCH 11/15 net-next,v2] net: flow_offload: don't allow subsystem to reuse blocks
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Drivers need to be updated to support this, return EBUSY by now.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
net/core/flow_offload.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/core/flow_offload.c b/net/core/flow_offload.c
index 0b8d088d822e..8c20f4740800 100644
--- a/net/core/flow_offload.c
+++ b/net/core/flow_offload.c
@@ -206,6 +206,12 @@ struct flow_block_cb *flow_block_cb_alloc(struct net *net, tc_setup_cb_t *cb,
{
struct flow_block_cb *block_cb;
+ list_for_each_entry(block_cb, &flow_block_cb_list, global_list) {
+ if (block_cb->cb == cb &&
+ block_cb->cb_ident == cb_ident)
+ return ERR_PTR(-EBUSY);
+ }
+
block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
if (IS_ERR(block_cb))
return block_cb;
--
2.11.0
^ permalink raw reply related
* [PATCH 09/15 net-next,v2] net: sched: remove tcf_block_cb_{register,unregister}()
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Now replaced by the tcf_block_setup() core registration, remove this.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/pkt_cls.h | 41 +----------------------------------
net/sched/cls_api.c | 59 ---------------------------------------------------
2 files changed, 1 insertion(+), 99 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index cc64dd45dfc2..52c11e390d9e 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -88,17 +88,7 @@ struct tcf_block_cb *tcf_block_cb_lookup(struct net *net, tc_setup_cb_t *cb,
void *cb_ident);
void tcf_block_cb_incref(struct tcf_block_cb *block_cb);
unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb);
-struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv,
- struct netlink_ext_ack *extack);
-int tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv, struct netlink_ext_ack *extack);
-void __tcf_block_cb_unregister(struct tcf_block *block,
- struct tcf_block_cb *block_cb);
-void tcf_block_cb_unregister(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident);
+
int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
tc_indr_block_bind_cb_t *cb, void *cb_ident);
int tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
@@ -218,35 +208,6 @@ unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
}
static inline
-struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv,
- struct netlink_ext_ack *extack)
-{
- return NULL;
-}
-
-static inline
-int tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv, struct netlink_ext_ack *extack)
-{
- return 0;
-}
-
-static inline
-void __tcf_block_cb_unregister(struct tcf_block *block,
- struct tcf_block_cb *block_cb)
-{
-}
-
-static inline
-void tcf_block_cb_unregister(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{
-}
-
-static inline
int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
tc_indr_block_bind_cb_t *cb, void *cb_ident)
{
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index e546d56c1a39..aa7ab707c399 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -797,65 +797,6 @@ void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
}
EXPORT_SYMBOL(tcf_block_cb_remove);
-struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv,
- struct netlink_ext_ack *extack)
-{
- struct tcf_block_cb *block_cb;
- int err;
-
- /* Replay any already present rules */
- err = tcf_block_playback_offloads(block, cb, cb_priv, true,
- tcf_block_offload_in_use(block),
- extack);
- if (err)
- return ERR_PTR(err);
-
- block_cb = tcf_block_cb_alloc(block->net, cb, cb_ident, cb_priv, NULL);
- if (IS_ERR(block_cb))
- return block_cb;
-
- list_add(&block_cb->list, &block->cb_list);
- return block_cb;
-}
-EXPORT_SYMBOL(__tcf_block_cb_register);
-
-int tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv, struct netlink_ext_ack *extack)
-{
- struct tcf_block_cb *block_cb;
-
- block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv,
- extack);
- return PTR_ERR_OR_ZERO(block_cb);
-}
-EXPORT_SYMBOL(tcf_block_cb_register);
-
-void __tcf_block_cb_unregister(struct tcf_block *block,
- struct tcf_block_cb *block_cb)
-{
- tcf_block_playback_offloads(block, block_cb->cb, block_cb->cb_priv,
- false, tcf_block_offload_in_use(block),
- NULL);
- list_del(&block_cb->list);
- kfree(block_cb);
-}
-EXPORT_SYMBOL(__tcf_block_cb_unregister);
-
-void tcf_block_cb_unregister(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{
- struct tcf_block_cb *block_cb;
-
- block_cb = tcf_block_cb_lookup(block->net, cb, cb_ident);
- if (!block_cb)
- return;
- __tcf_block_cb_unregister(block, block_cb);
-}
-EXPORT_SYMBOL(tcf_block_cb_unregister);
-
static int tcf_block_bind(struct tcf_block *block, struct tc_block_offload *bo)
{
struct tcf_block_cb *block_cb, *next;
--
2.11.0
^ permalink raw reply related
* [PATCH 08/15 net-next,v2] net: cls_api: do not expose tcf_block to drivers
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Expose the block_shared flag which is what drivers.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: fix incorrect correction of block_shared in net/sched/cls_api.c
drivers/net/ethernet/mscc/ocelot_tc.c | 2 +-
drivers/net/ethernet/netronome/nfp/flower/offload.c | 2 +-
include/net/pkt_cls.h | 2 +-
net/sched/cls_api.c | 6 +++---
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/mscc/ocelot_tc.c b/drivers/net/ethernet/mscc/ocelot_tc.c
index 5c3bf639f87c..a52c233da571 100644
--- a/drivers/net/ethernet/mscc/ocelot_tc.c
+++ b/drivers/net/ethernet/mscc/ocelot_tc.c
@@ -140,7 +140,7 @@ static int ocelot_setup_tc_block(struct ocelot_port *port,
if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) {
cb = ocelot_setup_tc_block_cb_ig;
- port->tc.block_shared = tcf_block_shared(f->block);
+ port->tc.block_shared = f->block_shared;
} else if (f->binder_type == TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS) {
cb = ocelot_setup_tc_block_cb_eg;
} else {
diff --git a/drivers/net/ethernet/netronome/nfp/flower/offload.c b/drivers/net/ethernet/netronome/nfp/flower/offload.c
index fa44dce810ed..a19f4aafc3af 100644
--- a/drivers/net/ethernet/netronome/nfp/flower/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/flower/offload.c
@@ -1313,7 +1313,7 @@ static int nfp_flower_setup_tc_block(struct net_device *netdev,
return -EOPNOTSUPP;
repr_priv = repr->app_priv;
- repr_priv->block_shared = tcf_block_shared(f->block);
+ repr_priv->block_shared = f->block_shared;
switch (f->command) {
case TC_BLOCK_BIND:
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index cb899c4552f4..cc64dd45dfc2 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -663,7 +663,7 @@ struct tc_block_offload {
enum tcf_block_binder_type binder_type;
struct list_head cb_list;
struct net *net;
- struct tcf_block *block;
+ bool block_shared;
struct netlink_ext_ack *extack;
};
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 3f036d50af65..e546d56c1a39 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1073,7 +1073,7 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
.command = command,
.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
.net = dev_net(indr_dev->dev),
- .block = indr_dev->block,
+ .block_shared = tcf_block_shared(indr_dev->block),
};
INIT_LIST_HEAD(&bo.cb_list);
@@ -1164,7 +1164,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
.command = command,
.binder_type = ei->binder_type,
.net = dev_net(dev),
- .block = block,
+ .block_shared = tcf_block_shared(block),
.extack = extack,
};
INIT_LIST_HEAD(&bo.cb_list);
@@ -1194,7 +1194,7 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
bo.net = dev_net(dev);
bo.command = command;
bo.binder_type = ei->binder_type;
- bo.block = block;
+ bo.block_shared = tcf_block_shared(block);
bo.extack = extack;
INIT_LIST_HEAD(&bo.cb_list);
--
2.11.0
^ permalink raw reply related
* [PATCH 06/15 net-next,v2] net: sched: add tcf_setup_block_offload()
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Most drivers do the same thing to set up the block, add a helper
function to do this.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 ++++-------------
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 28 ++++--------------
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 26 ++++-------------
drivers/net/ethernet/intel/i40e/i40e_main.c | 26 ++++-------------
drivers/net/ethernet/intel/iavf/iavf_main.c | 35 ++++-------------------
drivers/net/ethernet/intel/igb/igb_main.c | 23 ++-------------
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 27 ++++-------------
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 27 ++++-------------
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 26 ++++-------------
drivers/net/ethernet/netronome/nfp/abm/cls.c | 17 ++---------
drivers/net/ethernet/netronome/nfp/bpf/main.c | 29 ++++---------------
drivers/net/ethernet/qlogic/qede/qede_main.c | 23 ++-------------
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 22 ++------------
drivers/net/netdevsim/netdev.c | 26 ++++-------------
include/net/pkt_cls.h | 10 +++++++
net/sched/cls_api.c | 20 +++++++++++++
16 files changed, 91 insertions(+), 300 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index b7b62273c955..bda732ab6538 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -9847,32 +9847,16 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int bnxt_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct bnxt *bp = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, bnxt_setup_tc_block_cb,
- bp, bp, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, bnxt_setup_tc_block_cb, bp);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct bnxt *bp = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return bnxt_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ bnxt_setup_tc_block_cb, bp, bp,
+ true);
case TC_SETUP_QDISC_MQPRIO: {
struct tc_mqprio_qopt *mqprio = type_data;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
index f760921389a3..c8bb104f28d4 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c
@@ -161,34 +161,16 @@ static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type,
}
}
-static int bnxt_vf_rep_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- bnxt_vf_rep_setup_tc_block_cb,
- vf_rep, vf_rep, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- bnxt_vf_rep_setup_tc_block_cb, vf_rep);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return bnxt_vf_rep_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ bnxt_vf_rep_setup_tc_block_cb,
+ vf_rep, vf_rep, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index b08efc48d42f..a09b9c909be1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3190,32 +3190,16 @@ static int cxgb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int cxgb_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct port_info *pi = netdev2pinfo(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, cxgb_setup_tc_block_cb,
- pi, dev, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, cxgb_setup_tc_block_cb, pi);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int cxgb_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct port_info *pi = netdev2pinfo(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return cxgb_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ cxgb_setup_tc_block_cb, pi, dev,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 5361c08328f7..1e703daa50fd 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -8177,34 +8177,18 @@ static int i40e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int i40e_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct i40e_netdev_priv *np = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, i40e_setup_tc_block_cb,
- np, np, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, i40e_setup_tc_block_cb, np);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
+ struct i40e_netdev_priv *np = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_QDISC_MQPRIO:
return i40e_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return i40e_setup_tc_block(netdev, type_data);
+ return tcf_setup_block_offload(type_data,
+ i40e_setup_tc_block_cb, np, np,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index 881561b36083..29640e4b15f2 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -3114,35 +3114,6 @@ static int iavf_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
/**
- * iavf_setup_tc_block - register callbacks for tc
- * @netdev: network interface device structure
- * @f: tc offload data
- *
- * This function registers block callbacks for tc
- * offloads
- **/
-static int iavf_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct iavf_adapter *adapter = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, iavf_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, iavf_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/**
* iavf_setup_tc - configure multiple traffic classes
* @netdev: network interface device structure
* @type: type of offload
@@ -3156,11 +3127,15 @@ static int iavf_setup_tc_block(struct net_device *dev,
static int iavf_setup_tc(struct net_device *netdev, enum tc_setup_type type,
void *type_data)
{
+ struct iavf_adapter *adapter = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_QDISC_MQPRIO:
return __iavf_setup_tc(netdev, type_data);
case TC_SETUP_BLOCK:
- return iavf_setup_tc_block(netdev, type_data);
+ return tcf_setup_block_offload(type_data,
+ iavf_setup_tc_block_cb, adapter,
+ adapter, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index f66dae72fe37..75a29adce0ce 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2783,25 +2783,6 @@ static int igb_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int igb_setup_tc_block(struct igb_adapter *adapter,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, igb_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, igb_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int igb_offload_txtime(struct igb_adapter *adapter,
struct tc_etf_qopt_offload *qopt)
{
@@ -2834,7 +2815,9 @@ static int igb_setup_tc(struct net_device *dev, enum tc_setup_type type,
case TC_SETUP_QDISC_CBS:
return igb_offload_cbs(adapter, type_data);
case TC_SETUP_BLOCK:
- return igb_setup_tc_block(adapter, type_data);
+ return tcf_setup_block_offload(type_data, igb_setup_tc_block_cb,
+ adapter, adapter, true);
+
case TC_SETUP_QDISC_ETF:
return igb_offload_txtime(adapter, type_data);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index b613e72c8ee4..7d3fe89ce807 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9607,27 +9607,6 @@ static int ixgbe_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int ixgbe_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct ixgbe_adapter *adapter = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, ixgbe_setup_tc_block_cb,
- adapter, adapter, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, ixgbe_setup_tc_block_cb,
- adapter);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int ixgbe_setup_tc_mqprio(struct net_device *dev,
struct tc_mqprio_qopt *mqprio)
{
@@ -9638,9 +9617,13 @@ static int ixgbe_setup_tc_mqprio(struct net_device *dev,
static int __ixgbe_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return ixgbe_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ ixgbe_setup_tc_block_cb,
+ adapter, adapter, true);
case TC_SETUP_QDISC_MQPRIO:
return ixgbe_setup_tc_mqprio(dev, type_data);
default:
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 1085040675ae..ffb501cfbc8d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3345,36 +3345,19 @@ static int mlx5e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
return -EOPNOTSUPP;
}
}
-
-static int mlx5e_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, mlx5e_setup_tc_block_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, mlx5e_setup_tc_block_cb,
- priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
#endif
static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
switch (type) {
#ifdef CONFIG_MLX5_ESWITCH
case TC_SETUP_BLOCK:
- return mlx5e_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ mlx5e_setup_tc_block_cb,
+ priv, priv, true);
#endif
case TC_SETUP_QDISC_MQPRIO:
return mlx5e_setup_tc_mqprio(dev, type_data);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
index 330034fcdfc5..120de25c63c8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
@@ -1178,32 +1178,16 @@ static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
}
}
-static int mlx5e_rep_setup_tc_block(struct net_device *dev,
- struct tc_block_offload *f)
-{
- struct mlx5e_priv *priv = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, mlx5e_rep_setup_tc_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, mlx5e_rep_setup_tc_cb, priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
+ struct mlx5e_priv *priv = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return mlx5e_rep_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ mlx5e_rep_setup_tc_cb,
+ priv, priv, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/netronome/nfp/abm/cls.c b/drivers/net/ethernet/netronome/nfp/abm/cls.c
index ff3913085665..d99981ec04a3 100644
--- a/drivers/net/ethernet/netronome/nfp/abm/cls.c
+++ b/drivers/net/ethernet/netronome/nfp/abm/cls.c
@@ -265,19 +265,6 @@ static int nfp_abm_setup_tc_block_cb(enum tc_setup_type type,
int nfp_abm_setup_cls_block(struct net_device *netdev, struct nfp_repr *repr,
struct tc_block_offload *f)
{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_abm_setup_tc_block_cb,
- repr, repr, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, nfp_abm_setup_tc_block_cb,
- repr);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
+ return tcf_setup_block_offload(f, nfp_abm_setup_tc_block_cb, repr, repr,
+ true);
}
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 9c136da25221..fac38899dc23 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -160,35 +160,16 @@ static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
return 0;
}
-static int nfp_bpf_setup_tc_block(struct net_device *netdev,
- struct tc_block_offload *f)
-{
- struct nfp_net *nn = netdev_priv(netdev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- nfp_bpf_setup_tc_block_cb,
- nn, nn, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block,
- nfp_bpf_setup_tc_block_cb,
- nn);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
enum tc_setup_type type, void *type_data)
{
+ struct nfp_net *nn = netdev_priv(netdev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return nfp_bpf_setup_tc_block(netdev, type_data);
+ return tcf_setup_block_offload(type_data,
+ nfp_bpf_setup_tc_block_cb,
+ nn, nn, true);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c
index d4a29660751d..013046a30732 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -579,25 +579,6 @@ static int qede_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
}
}
-static int qede_setup_tc_block(struct qede_dev *edev,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block,
- qede_setup_tc_block_cb,
- edev, edev, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, qede_setup_tc_block_cb, edev);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int
qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
void *type_data)
@@ -607,7 +588,9 @@ qede_setup_tc_offload(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return qede_setup_tc_block(edev, type_data);
+ return tcf_setup_block_offload(type_data,
+ qede_setup_tc_block_cb,
+ edev, edev, true);
case TC_SETUP_QDISC_MQPRIO:
mqprio = type_data;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3425d4dda03d..ffed6b51040a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3853,24 +3853,6 @@ static int stmmac_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
return ret;
}
-static int stmmac_setup_tc_block(struct stmmac_priv *priv,
- struct tc_block_offload *f)
-{
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, stmmac_setup_tc_block_cb,
- priv, priv, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, stmmac_setup_tc_block_cb, priv);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
void *type_data)
{
@@ -3878,7 +3860,9 @@ static int stmmac_setup_tc(struct net_device *ndev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
- return stmmac_setup_tc_block(priv, type_data);
+ return tcf_setup_block_offload(type_data,
+ stmmac_setup_tc_block_cb,
+ priv, priv, true);
case TC_SETUP_QDISC_CBS:
return stmmac_tc_setup_cbs(priv, priv, type_data);
default:
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index e5c8aa08e1cd..240727623e9b 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -78,26 +78,6 @@ nsim_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
return nsim_bpf_setup_tc_block_cb(type, type_data, cb_priv);
}
-static int
-nsim_setup_tc_block(struct net_device *dev, struct tc_block_offload *f)
-{
- struct netdevsim *ns = netdev_priv(dev);
-
- if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
- return -EOPNOTSUPP;
-
- switch (f->command) {
- case TC_BLOCK_BIND:
- return tcf_block_cb_register(f->block, nsim_setup_tc_block_cb,
- ns, ns, f->extack);
- case TC_BLOCK_UNBIND:
- tcf_block_cb_unregister(f->block, nsim_setup_tc_block_cb, ns);
- return 0;
- default:
- return -EOPNOTSUPP;
- }
-}
-
static int nsim_set_vf_mac(struct net_device *dev, int vf, u8 *mac)
{
struct netdevsim *ns = netdev_priv(dev);
@@ -226,9 +206,13 @@ static int nsim_set_vf_link_state(struct net_device *dev, int vf, int state)
static int
nsim_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
{
+ struct netdevsim *ns = netdev_priv(dev);
+
switch (type) {
case TC_SETUP_BLOCK:
- return nsim_setup_tc_block(dev, type_data);
+ return tcf_setup_block_offload(type_data,
+ nsim_setup_tc_block_cb, ns, ns,
+ true);
default:
return -EOPNOTSUPP;
}
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index fd0bfb63ab70..d35711758ddb 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -111,6 +111,8 @@ void tc_indr_block_cb_unregister(struct net_device *dev,
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);
+int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv, bool ingress_only);
#else
static inline bool tcf_block_shared(struct tcf_block *block)
{
@@ -161,6 +163,14 @@ void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
{
}
+static inline int tcf_setup_block_offload(struct tc_block_offload *f,
+ tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv,
+ bool ingress_only)
+{
+ return -EOPNOTSUPP;
+}
+
static inline struct tcf_block_cb *
tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv))
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 534a545ea51e..003f24a1323f 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -922,6 +922,26 @@ static int tcf_block_setup(struct tcf_block *block, struct tc_block_offload *bo)
return err;
}
+int tcf_setup_block_offload(struct tc_block_offload *f, tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv, bool ingress_only)
+{
+ if (ingress_only &&
+ f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+ return -EOPNOTSUPP;
+
+ switch (f->command) {
+ case TC_BLOCK_BIND:
+ return tcf_block_cb_register(f->block, cb, cb_ident, cb_priv,
+ f->extack);
+ case TC_BLOCK_UNBIND:
+ tcf_block_cb_unregister(f->block, cb, cb_ident);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL(tcf_setup_block_offload);
+
static struct rhashtable indr_setup_block_ht;
struct tc_indr_block_dev {
--
2.11.0
^ permalink raw reply related
* [PATCH 05/15 net-next,v2] net: sched: add release callback to struct tcf_block_cb
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Call it on tcf_block_cb object to release the driver private block area.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/pkt_cls.h | 6 ++++--
net/sched/cls_api.c | 10 ++++++++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index d660cb4fad75..fd0bfb63ab70 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -73,7 +73,8 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
}
struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv);
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv));
void tcf_block_cb_free(struct tcf_block_cb *block_cb);
struct tc_block_offload;
@@ -161,7 +162,8 @@ void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
}
static inline struct tcf_block_cb *
-tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv)
+tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv))
{
return ERR_PTR(-EOPNOTSUPP);
}
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a2c1258cc8dc..534a545ea51e 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -713,6 +713,7 @@ struct tcf_block_cb {
struct list_head global_list;
struct list_head list;
tc_setup_cb_t *cb;
+ void (*release)(void *cb_priv);
void *cb_ident;
void *cb_priv;
unsigned int refcnt;
@@ -750,7 +751,8 @@ unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
EXPORT_SYMBOL(tcf_block_cb_decref);
struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
- void *cb_ident, void *cb_priv)
+ void *cb_ident, void *cb_priv,
+ void (*release)(void *cb_priv))
{
struct tcf_block_cb *block_cb;
@@ -760,6 +762,7 @@ struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
block_cb->cb = cb;
block_cb->cb_ident = cb_ident;
+ block_cb->release = release;
block_cb->cb_priv = cb_priv;
return block_cb;
@@ -768,6 +771,9 @@ EXPORT_SYMBOL(tcf_block_cb_alloc);
void tcf_block_cb_free(struct tcf_block_cb *block_cb)
{
+ if (block_cb->release)
+ block_cb->release(block_cb->cb_priv);
+
kfree(block_cb);
}
EXPORT_SYMBOL(tcf_block_cb_free);
@@ -801,7 +807,7 @@ struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
if (err)
return ERR_PTR(err);
- block_cb = tcf_block_cb_alloc(cb, cb_ident, cb_priv);
+ block_cb = tcf_block_cb_alloc(cb, cb_ident, cb_priv, NULL);
if (IS_ERR(block_cb))
return block_cb;
--
2.11.0
^ permalink raw reply related
* [PATCH 04/15 net-next,v2] net: sched: add tcf_block_setup()
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
This new function allows us to handle tcf_block_cb registrations /
unregistrations from the core, in order to remove a dependency with the
tcf_block object and the .reoffload cls_api callback.
The tcf_block_cb_add() call places the tcf_block_cb object, which has
been set up by the driver, in the tc_block_offload->cb_list. This is a
temporary list that is used to convey the tcf_block_cb objects back to
the core for registration.
Note that this patch introduces a global tcf_block_cb_list, however,
this is a temporary artifact to make it easy for me to update the code
to use this new infrastructure. This global list goes away in a follow
up patch to add per-driver flow block lists.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/pkt_cls.h | 19 ++++++++++
net/sched/cls_api.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 1 deletion(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index b50df3b9456c..d660cb4fad75 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -75,6 +75,13 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv);
void tcf_block_cb_free(struct tcf_block_cb *block_cb);
+
+struct tc_block_offload;
+void tcf_block_cb_add(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload);
+void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload);
+
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident);
@@ -163,6 +170,17 @@ static inline void tcf_block_cb_free(struct tcf_block_cb *block_cb)
{
}
+struct tc_block_offload;
+static inline void tcf_block_cb_add(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload)
+{
+}
+
+static inline void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload)
+{
+}
+
static inline
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
@@ -631,6 +649,7 @@ enum tc_block_command {
struct tc_block_offload {
enum tc_block_command command;
enum tcf_block_binder_type binder_type;
+ struct list_head cb_list;
struct tcf_block *block;
struct netlink_ext_ack *extack;
};
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 93b74a15e7ac..a2c1258cc8dc 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -710,6 +710,7 @@ static bool tcf_block_offload_in_use(struct tcf_block *block)
}
struct tcf_block_cb {
+ struct list_head global_list;
struct list_head list;
tc_setup_cb_t *cb;
void *cb_ident;
@@ -723,6 +724,8 @@ void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
}
EXPORT_SYMBOL(tcf_block_cb_priv);
+static LIST_HEAD(tcf_block_cb_list);
+
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident)
{ struct tcf_block_cb *block_cb;
@@ -769,6 +772,20 @@ void tcf_block_cb_free(struct tcf_block_cb *block_cb)
}
EXPORT_SYMBOL(tcf_block_cb_free);
+void tcf_block_cb_add(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload)
+{
+ list_add_tail(&block_cb->global_list, &offload->cb_list);
+}
+EXPORT_SYMBOL(tcf_block_cb_add);
+
+void tcf_block_cb_remove(struct tcf_block_cb *block_cb,
+ struct tc_block_offload *offload)
+{
+ list_move(&block_cb->global_list, &offload->cb_list);
+}
+EXPORT_SYMBOL(tcf_block_cb_remove);
+
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv,
@@ -828,6 +845,77 @@ void tcf_block_cb_unregister(struct tcf_block *block,
}
EXPORT_SYMBOL(tcf_block_cb_unregister);
+static int tcf_block_bind(struct tcf_block *block, struct tc_block_offload *bo)
+{
+ struct tcf_block_cb *block_cb, *next;
+ int err, i = 0;
+
+ list_for_each_entry(block_cb, &bo->cb_list, global_list) {
+ err = tcf_block_playback_offloads(block, block_cb->cb,
+ block_cb->cb_priv, true,
+ tcf_block_offload_in_use(block),
+ bo->extack);
+ if (err)
+ goto err_unroll;
+
+ list_add(&block_cb->list, &block->cb_list);
+ i++;
+ }
+ list_splice(&bo->cb_list, &tcf_block_cb_list);
+
+ return 0;
+
+err_unroll:
+ list_for_each_entry_safe(block_cb, next, &bo->cb_list, global_list) {
+ if (i-- > 0) {
+ list_del(&block_cb->list);
+ tcf_block_playback_offloads(block, block_cb->cb,
+ block_cb->cb_priv, false,
+ tcf_block_offload_in_use(block),
+ NULL);
+ }
+ kfree(block_cb);
+ }
+
+ return err;
+}
+
+static void tcf_block_unbind(struct tcf_block *block,
+ struct tc_block_offload *bo)
+{
+ struct tcf_block_cb *block_cb, *next;
+
+ list_for_each_entry_safe(block_cb, next, &bo->cb_list, global_list) {
+ list_del(&block_cb->global_list);
+ tcf_block_playback_offloads(block, block_cb->cb,
+ block_cb->cb_priv, false,
+ tcf_block_offload_in_use(block),
+ NULL);
+ list_del(&block_cb->list);
+ tcf_block_cb_free(block_cb);
+ }
+}
+
+static int tcf_block_setup(struct tcf_block *block, struct tc_block_offload *bo)
+{
+ int err;
+
+ switch (bo->command) {
+ case TC_BLOCK_BIND:
+ err = tcf_block_bind(block, bo);
+ break;
+ case TC_BLOCK_UNBIND:
+ err = 0;
+ tcf_block_unbind(block, bo);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ err = -EOPNOTSUPP;
+ }
+
+ return err;
+}
+
static struct rhashtable indr_setup_block_ht;
struct tc_indr_block_dev {
@@ -944,12 +1032,14 @@ static void tc_indr_block_ing_cmd(struct tc_indr_block_dev *indr_dev,
.binder_type = TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS,
.block = indr_dev->block,
};
+ INIT_LIST_HEAD(&bo.cb_list);
if (!indr_dev->block)
return;
indr_block_cb->cb(indr_dev->dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
&bo);
+ tcf_block_setup(indr_dev->block, &bo);
}
int __tc_indr_block_cb_register(struct net_device *dev, void *cb_priv,
@@ -1033,6 +1123,7 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
.block = block,
.extack = extack,
};
+ INIT_LIST_HEAD(&bo.cb_list);
indr_dev = tc_indr_block_dev_lookup(dev);
if (!indr_dev)
@@ -1043,6 +1134,8 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
list_for_each_entry(indr_block_cb, &indr_dev->cb_list, list)
indr_block_cb->cb(dev, indr_block_cb->cb_priv, TC_SETUP_BLOCK,
&bo);
+
+ tcf_block_setup(block, &bo);
}
static int tcf_block_offload_cmd(struct tcf_block *block,
@@ -1052,12 +1145,19 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
struct netlink_ext_ack *extack)
{
struct tc_block_offload bo = {};
+ int err;
bo.command = command;
bo.binder_type = ei->binder_type;
bo.block = block;
bo.extack = extack;
- return dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
+ INIT_LIST_HEAD(&bo.cb_list);
+
+ err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
+ if (err < 0)
+ return err;
+
+ return tcf_block_setup(block, &bo);
}
static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
--
2.11.0
^ permalink raw reply related
* [PATCH 01/15 net-next,v2] net: sched: move tcf_block_cb before indr_block
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
The indr_block infrastructure will depend on the tcf_block_cb object,
move this code on top to avoid forward declarations.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
net/sched/cls_api.c | 484 ++++++++++++++++++++++++++--------------------------
1 file changed, 242 insertions(+), 242 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index ad36bbcc583e..b2417fda26ec 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -565,6 +565,248 @@ static struct tcf_block *tc_dev_ingress_block(struct net_device *dev)
return cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL);
}
+static struct tcf_chain *
+__tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
+{
+ mutex_lock(&block->lock);
+ if (chain)
+ chain = list_is_last(&chain->list, &block->chain_list) ?
+ NULL : list_next_entry(chain, list);
+ else
+ chain = list_first_entry_or_null(&block->chain_list,
+ struct tcf_chain, list);
+
+ /* skip all action-only chains */
+ while (chain && tcf_chain_held_by_acts_only(chain))
+ chain = list_is_last(&chain->list, &block->chain_list) ?
+ NULL : list_next_entry(chain, list);
+
+ if (chain)
+ tcf_chain_hold(chain);
+ mutex_unlock(&block->lock);
+
+ return chain;
+}
+
+/* Function to be used by all clients that want to iterate over all chains on
+ * block. It properly obtains block->lock and takes reference to chain before
+ * returning it. Users of this function must be tolerant to concurrent chain
+ * insertion/deletion or ensure that no concurrent chain modification is
+ * possible. Note that all netlink dump callbacks cannot guarantee to provide
+ * consistent dump because rtnl lock is released each time skb is filled with
+ * data and sent to user-space.
+ */
+
+struct tcf_chain *
+tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
+{
+ struct tcf_chain *chain_next = __tcf_get_next_chain(block, chain);
+
+ if (chain)
+ tcf_chain_put(chain);
+
+ return chain_next;
+}
+EXPORT_SYMBOL(tcf_get_next_chain);
+
+static struct tcf_proto *
+__tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
+{
+ u32 prio = 0;
+
+ ASSERT_RTNL();
+ mutex_lock(&chain->filter_chain_lock);
+
+ if (!tp) {
+ tp = tcf_chain_dereference(chain->filter_chain, chain);
+ } else if (tcf_proto_is_deleting(tp)) {
+ /* 'deleting' flag is set and chain->filter_chain_lock was
+ * unlocked, which means next pointer could be invalid. Restart
+ * search.
+ */
+ prio = tp->prio + 1;
+ tp = tcf_chain_dereference(chain->filter_chain, chain);
+
+ for (; tp; tp = tcf_chain_dereference(tp->next, chain))
+ if (!tp->deleting && tp->prio >= prio)
+ break;
+ } else {
+ tp = tcf_chain_dereference(tp->next, chain);
+ }
+
+ if (tp)
+ tcf_proto_get(tp);
+
+ mutex_unlock(&chain->filter_chain_lock);
+
+ return tp;
+}
+
+/* Function to be used by all clients that want to iterate over all tp's on
+ * chain. Users of this function must be tolerant to concurrent tp
+ * insertion/deletion or ensure that no concurrent chain modification is
+ * possible. Note that all netlink dump callbacks cannot guarantee to provide
+ * consistent dump because rtnl lock is released each time skb is filled with
+ * data and sent to user-space.
+ */
+
+struct tcf_proto *
+tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp,
+ bool rtnl_held)
+{
+ struct tcf_proto *tp_next = __tcf_get_next_proto(chain, tp);
+
+ if (tp)
+ tcf_proto_put(tp, rtnl_held, NULL);
+
+ return tp_next;
+}
+EXPORT_SYMBOL(tcf_get_next_proto);
+
+static int
+tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
+ void *cb_priv, bool add, bool offload_in_use,
+ struct netlink_ext_ack *extack)
+{
+ struct tcf_chain *chain, *chain_prev;
+ struct tcf_proto *tp, *tp_prev;
+ int err;
+
+ for (chain = __tcf_get_next_chain(block, NULL);
+ chain;
+ chain_prev = chain,
+ chain = __tcf_get_next_chain(block, chain),
+ tcf_chain_put(chain_prev)) {
+ for (tp = __tcf_get_next_proto(chain, NULL); tp;
+ tp_prev = tp,
+ tp = __tcf_get_next_proto(chain, tp),
+ tcf_proto_put(tp_prev, true, NULL)) {
+ if (tp->ops->reoffload) {
+ err = tp->ops->reoffload(tp, add, cb, cb_priv,
+ extack);
+ if (err && add)
+ goto err_playback_remove;
+ } else if (add && offload_in_use) {
+ err = -EOPNOTSUPP;
+ NL_SET_ERR_MSG(extack, "Filter HW offload failed - classifier without re-offloading support");
+ goto err_playback_remove;
+ }
+ }
+ }
+
+ return 0;
+
+err_playback_remove:
+ tcf_proto_put(tp, true, NULL);
+ tcf_chain_put(chain);
+ tcf_block_playback_offloads(block, cb, cb_priv, false, offload_in_use,
+ extack);
+ return err;
+}
+
+static bool tcf_block_offload_in_use(struct tcf_block *block)
+{
+ return block->offloadcnt;
+}
+
+struct tcf_block_cb {
+ struct list_head list;
+ tc_setup_cb_t *cb;
+ void *cb_ident;
+ void *cb_priv;
+ unsigned int refcnt;
+};
+
+void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
+{
+ return block_cb->cb_priv;
+}
+EXPORT_SYMBOL(tcf_block_cb_priv);
+
+struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
+ tc_setup_cb_t *cb, void *cb_ident)
+{ struct tcf_block_cb *block_cb;
+
+ list_for_each_entry(block_cb, &block->cb_list, list)
+ if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
+ return block_cb;
+ return NULL;
+}
+EXPORT_SYMBOL(tcf_block_cb_lookup);
+
+void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
+{
+ block_cb->refcnt++;
+}
+EXPORT_SYMBOL(tcf_block_cb_incref);
+
+unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
+{
+ return --block_cb->refcnt;
+}
+EXPORT_SYMBOL(tcf_block_cb_decref);
+
+struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
+ tc_setup_cb_t *cb, void *cb_ident,
+ void *cb_priv,
+ struct netlink_ext_ack *extack)
+{
+ struct tcf_block_cb *block_cb;
+ int err;
+
+ /* Replay any already present rules */
+ err = tcf_block_playback_offloads(block, cb, cb_priv, true,
+ tcf_block_offload_in_use(block),
+ extack);
+ if (err)
+ return ERR_PTR(err);
+
+ block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
+ if (!block_cb)
+ return ERR_PTR(-ENOMEM);
+ block_cb->cb = cb;
+ block_cb->cb_ident = cb_ident;
+ block_cb->cb_priv = cb_priv;
+ list_add(&block_cb->list, &block->cb_list);
+ return block_cb;
+}
+EXPORT_SYMBOL(__tcf_block_cb_register);
+
+int tcf_block_cb_register(struct tcf_block *block,
+ tc_setup_cb_t *cb, void *cb_ident,
+ void *cb_priv, struct netlink_ext_ack *extack)
+{
+ struct tcf_block_cb *block_cb;
+
+ block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv,
+ extack);
+ return PTR_ERR_OR_ZERO(block_cb);
+}
+EXPORT_SYMBOL(tcf_block_cb_register);
+
+void __tcf_block_cb_unregister(struct tcf_block *block,
+ struct tcf_block_cb *block_cb)
+{
+ tcf_block_playback_offloads(block, block_cb->cb, block_cb->cb_priv,
+ false, tcf_block_offload_in_use(block),
+ NULL);
+ list_del(&block_cb->list);
+ kfree(block_cb);
+}
+EXPORT_SYMBOL(__tcf_block_cb_unregister);
+
+void tcf_block_cb_unregister(struct tcf_block *block,
+ tc_setup_cb_t *cb, void *cb_ident)
+{
+ struct tcf_block_cb *block_cb;
+
+ block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
+ if (!block_cb)
+ return;
+ __tcf_block_cb_unregister(block, block_cb);
+}
+EXPORT_SYMBOL(tcf_block_cb_unregister);
+
static struct rhashtable indr_setup_block_ht;
struct tc_indr_block_dev {
@@ -782,11 +1024,6 @@ static void tc_indr_block_call(struct tcf_block *block, struct net_device *dev,
&bo);
}
-static bool tcf_block_offload_in_use(struct tcf_block *block)
-{
- return block->offloadcnt;
-}
-
static int tcf_block_offload_cmd(struct tcf_block *block,
struct net_device *dev,
struct tcf_block_ext_info *ei,
@@ -1003,104 +1240,6 @@ static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index)
return block;
}
-static struct tcf_chain *
-__tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
-{
- mutex_lock(&block->lock);
- if (chain)
- chain = list_is_last(&chain->list, &block->chain_list) ?
- NULL : list_next_entry(chain, list);
- else
- chain = list_first_entry_or_null(&block->chain_list,
- struct tcf_chain, list);
-
- /* skip all action-only chains */
- while (chain && tcf_chain_held_by_acts_only(chain))
- chain = list_is_last(&chain->list, &block->chain_list) ?
- NULL : list_next_entry(chain, list);
-
- if (chain)
- tcf_chain_hold(chain);
- mutex_unlock(&block->lock);
-
- return chain;
-}
-
-/* Function to be used by all clients that want to iterate over all chains on
- * block. It properly obtains block->lock and takes reference to chain before
- * returning it. Users of this function must be tolerant to concurrent chain
- * insertion/deletion or ensure that no concurrent chain modification is
- * possible. Note that all netlink dump callbacks cannot guarantee to provide
- * consistent dump because rtnl lock is released each time skb is filled with
- * data and sent to user-space.
- */
-
-struct tcf_chain *
-tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
-{
- struct tcf_chain *chain_next = __tcf_get_next_chain(block, chain);
-
- if (chain)
- tcf_chain_put(chain);
-
- return chain_next;
-}
-EXPORT_SYMBOL(tcf_get_next_chain);
-
-static struct tcf_proto *
-__tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
-{
- u32 prio = 0;
-
- ASSERT_RTNL();
- mutex_lock(&chain->filter_chain_lock);
-
- if (!tp) {
- tp = tcf_chain_dereference(chain->filter_chain, chain);
- } else if (tcf_proto_is_deleting(tp)) {
- /* 'deleting' flag is set and chain->filter_chain_lock was
- * unlocked, which means next pointer could be invalid. Restart
- * search.
- */
- prio = tp->prio + 1;
- tp = tcf_chain_dereference(chain->filter_chain, chain);
-
- for (; tp; tp = tcf_chain_dereference(tp->next, chain))
- if (!tp->deleting && tp->prio >= prio)
- break;
- } else {
- tp = tcf_chain_dereference(tp->next, chain);
- }
-
- if (tp)
- tcf_proto_get(tp);
-
- mutex_unlock(&chain->filter_chain_lock);
-
- return tp;
-}
-
-/* Function to be used by all clients that want to iterate over all tp's on
- * chain. Users of this function must be tolerant to concurrent tp
- * insertion/deletion or ensure that no concurrent chain modification is
- * possible. Note that all netlink dump callbacks cannot guarantee to provide
- * consistent dump because rtnl lock is released each time skb is filled with
- * data and sent to user-space.
- */
-
-struct tcf_proto *
-tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp,
- bool rtnl_held)
-{
- struct tcf_proto *tp_next = __tcf_get_next_proto(chain, tp);
-
- if (tp)
- tcf_proto_put(tp, rtnl_held, NULL);
-
- return tp_next;
-}
-EXPORT_SYMBOL(tcf_get_next_proto);
-
static void tcf_block_flush_all_chains(struct tcf_block *block, bool rtnl_held)
{
struct tcf_chain *chain;
@@ -1494,145 +1633,6 @@ void tcf_block_put(struct tcf_block *block)
EXPORT_SYMBOL(tcf_block_put);
-struct tcf_block_cb {
- struct list_head list;
- tc_setup_cb_t *cb;
- void *cb_ident;
- void *cb_priv;
- unsigned int refcnt;
-};
-
-void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
-{
- return block_cb->cb_priv;
-}
-EXPORT_SYMBOL(tcf_block_cb_priv);
-
-struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{ struct tcf_block_cb *block_cb;
-
- list_for_each_entry(block_cb, &block->cb_list, list)
- if (block_cb->cb == cb && block_cb->cb_ident == cb_ident)
- return block_cb;
- return NULL;
-}
-EXPORT_SYMBOL(tcf_block_cb_lookup);
-
-void tcf_block_cb_incref(struct tcf_block_cb *block_cb)
-{
- block_cb->refcnt++;
-}
-EXPORT_SYMBOL(tcf_block_cb_incref);
-
-unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
-{
- return --block_cb->refcnt;
-}
-EXPORT_SYMBOL(tcf_block_cb_decref);
-
-static int
-tcf_block_playback_offloads(struct tcf_block *block, tc_setup_cb_t *cb,
- void *cb_priv, bool add, bool offload_in_use,
- struct netlink_ext_ack *extack)
-{
- struct tcf_chain *chain, *chain_prev;
- struct tcf_proto *tp, *tp_prev;
- int err;
-
- for (chain = __tcf_get_next_chain(block, NULL);
- chain;
- chain_prev = chain,
- chain = __tcf_get_next_chain(block, chain),
- tcf_chain_put(chain_prev)) {
- for (tp = __tcf_get_next_proto(chain, NULL); tp;
- tp_prev = tp,
- tp = __tcf_get_next_proto(chain, tp),
- tcf_proto_put(tp_prev, true, NULL)) {
- if (tp->ops->reoffload) {
- err = tp->ops->reoffload(tp, add, cb, cb_priv,
- extack);
- if (err && add)
- goto err_playback_remove;
- } else if (add && offload_in_use) {
- err = -EOPNOTSUPP;
- NL_SET_ERR_MSG(extack, "Filter HW offload failed - classifier without re-offloading support");
- goto err_playback_remove;
- }
- }
- }
-
- return 0;
-
-err_playback_remove:
- tcf_proto_put(tp, true, NULL);
- tcf_chain_put(chain);
- tcf_block_playback_offloads(block, cb, cb_priv, false, offload_in_use,
- extack);
- return err;
-}
-
-struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv,
- struct netlink_ext_ack *extack)
-{
- struct tcf_block_cb *block_cb;
- int err;
-
- /* Replay any already present rules */
- err = tcf_block_playback_offloads(block, cb, cb_priv, true,
- tcf_block_offload_in_use(block),
- extack);
- if (err)
- return ERR_PTR(err);
-
- block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
- if (!block_cb)
- return ERR_PTR(-ENOMEM);
- block_cb->cb = cb;
- block_cb->cb_ident = cb_ident;
- block_cb->cb_priv = cb_priv;
- list_add(&block_cb->list, &block->cb_list);
- return block_cb;
-}
-EXPORT_SYMBOL(__tcf_block_cb_register);
-
-int tcf_block_cb_register(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident,
- void *cb_priv, struct netlink_ext_ack *extack)
-{
- struct tcf_block_cb *block_cb;
-
- block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv,
- extack);
- return PTR_ERR_OR_ZERO(block_cb);
-}
-EXPORT_SYMBOL(tcf_block_cb_register);
-
-void __tcf_block_cb_unregister(struct tcf_block *block,
- struct tcf_block_cb *block_cb)
-{
- tcf_block_playback_offloads(block, block_cb->cb, block_cb->cb_priv,
- false, tcf_block_offload_in_use(block),
- NULL);
- list_del(&block_cb->list);
- kfree(block_cb);
-}
-EXPORT_SYMBOL(__tcf_block_cb_unregister);
-
-void tcf_block_cb_unregister(struct tcf_block *block,
- tc_setup_cb_t *cb, void *cb_ident)
-{
- struct tcf_block_cb *block_cb;
-
- block_cb = tcf_block_cb_lookup(block, cb, cb_ident);
- if (!block_cb)
- return;
- __tcf_block_cb_unregister(block, block_cb);
-}
-EXPORT_SYMBOL(tcf_block_cb_unregister);
-
/* Main classifier routine: scans classifier chain attached
* to this qdisc, (optionally) tests for protocol and asks
* specific classifiers.
--
2.11.0
^ permalink raw reply related
* [PATCH 03/15 net-next,v2] net: sched: add tcf_block_cb_free()
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Just a stub to release tcf_block_cb objects, follow up patch extends it
to have a release callback in it for the private data.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: no changes.
include/net/pkt_cls.h | 5 +++++
net/sched/cls_api.c | 6 ++++++
2 files changed, 11 insertions(+)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index a756d895c7a4..b50df3b9456c 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -74,6 +74,7 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
void *cb_ident, void *cb_priv);
+void tcf_block_cb_free(struct tcf_block_cb *block_cb);
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident);
@@ -158,6 +159,10 @@ tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv)
return ERR_PTR(-EOPNOTSUPP);
}
+static inline void tcf_block_cb_free(struct tcf_block_cb *block_cb)
+{
+}
+
static inline
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 6cd76e3df2be..93b74a15e7ac 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -763,6 +763,12 @@ struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
}
EXPORT_SYMBOL(tcf_block_cb_alloc);
+void tcf_block_cb_free(struct tcf_block_cb *block_cb)
+{
+ kfree(block_cb);
+}
+EXPORT_SYMBOL(tcf_block_cb_free);
+
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv,
--
2.11.0
^ permalink raw reply related
* [PATCH 02/15 net-next,v2] net: sched: add tcf_block_cb_alloc()
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
In-Reply-To: <20190704234843.6601-1-pablo@netfilter.org>
Add a new helper function to allocate tcf_block_cb objects.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: return -EOPNOTSUPP if sched/cls_api is disabled, per Marcelo Ricardo Leitner .
include/net/pkt_cls.h | 8 ++++++++
net/sched/cls_api.c | 27 +++++++++++++++++++++------
2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 1a7596ba0dbe..a756d895c7a4 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -72,6 +72,8 @@ static inline struct Qdisc *tcf_block_q(struct tcf_block *block)
return block->q;
}
+struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv);
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb);
struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident);
@@ -150,6 +152,12 @@ void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb,
{
}
+static inline struct tcf_block_cb *
+tcf_block_cb_alloc(tc_setup_cb_t *cb, void *cb_ident, void *cb_priv)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
static inline
void *tcf_block_cb_priv(struct tcf_block_cb *block_cb)
{
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index b2417fda26ec..6cd76e3df2be 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -746,6 +746,23 @@ unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb)
}
EXPORT_SYMBOL(tcf_block_cb_decref);
+struct tcf_block_cb *tcf_block_cb_alloc(tc_setup_cb_t *cb,
+ void *cb_ident, void *cb_priv)
+{
+ struct tcf_block_cb *block_cb;
+
+ block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
+ if (!block_cb)
+ return ERR_PTR(-ENOMEM);
+
+ block_cb->cb = cb;
+ block_cb->cb_ident = cb_ident;
+ block_cb->cb_priv = cb_priv;
+
+ return block_cb;
+}
+EXPORT_SYMBOL(tcf_block_cb_alloc);
+
struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
tc_setup_cb_t *cb, void *cb_ident,
void *cb_priv,
@@ -761,12 +778,10 @@ struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block,
if (err)
return ERR_PTR(err);
- block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL);
- if (!block_cb)
- return ERR_PTR(-ENOMEM);
- block_cb->cb = cb;
- block_cb->cb_ident = cb_ident;
- block_cb->cb_priv = cb_priv;
+ block_cb = tcf_block_cb_alloc(cb, cb_ident, cb_priv);
+ if (IS_ERR(block_cb))
+ return block_cb;
+
list_add(&block_cb->list, &block->cb_list);
return block_cb;
}
--
2.11.0
^ permalink raw reply related
* [PATCH 00/15 net-next,v2] netfilter: add hardware offload infrastructure
From: Pablo Neira Ayuso @ 2019-07-04 23:48 UTC (permalink / raw)
To: netdev
Cc: netfilter-devel, davem, thomas.lendacky, f.fainelli, ariel.elior,
michael.chan, madalin.bucur, yisen.zhuang, salil.mehta,
jeffrey.t.kirsher, tariqt, saeedm, jiri, idosch, jakub.kicinski,
peppe.cavallaro, grygorii.strashko, andrew, vivien.didelot,
alexandre.torgue, joabreu, linux-net-drivers, ogerlitz,
Manish.Chopra, marcelo.leitner, mkubecek, venkatkumar.duvvuru,
maxime.chevallier, cphealy
Hi,
This patchset adds support for Netfilter hardware offloads.
This patchset reuses the existing block infrastructure, the
netdev_ops->ndo_setup_tc() interface, TC_SETUP_CLSFLOWER classifier and
the flow rule API.
Patch #1 moves tcf_block_cb code before the indirect block
infrastructure to avoid forward declarations in the next
patches. This is just a preparation patch.
Patch #2 adds tcf_block_cb_alloc() to allocate flow block callbacks.
Patch #3 adds tcf_block_cb_free() to release flow block callbacks.
Patch #4 adds the tcf_block_setup() infrastructure, which allows drivers
to set up flow block callbacks. This infrastructure transports
these objects via list (through the tc_block_offload object)
back to the core for registration.
CLS_API DRIVER
TC_SETUP_BLOCK ----------> setup flow_block_cb object &
it adds object to flow_block_offload->cb_list
|
CLS_API <-----------------------'
registers list with flow blocks
flow_block_cb & travels back to
calls ->reoffload the core for registration
This patch introduces a global flow block list for all drivers
which is a temporary artifact to make incremental changes, it
is removed in patch #12!
Patch #5 extends tcf_block_cb_alloc() to allow drivers to set a release
callback that is invoked from tcf_block_cb_free() to release
private driver block information.
Patch #6 adds tcf_setup_block_offload(), this helper function is used by
most drivers to setup the block, including common bind and
unbind operations.
Patch #7 adapts drivers to use the infrastructure introduced in Patch #4.
Patch #8 stops exposing the tc block structure to drivers, by caching
the only information that drivers need, ie. block is shared
flag.
Patch #9 removes the tcf_block_cb_register() / _unregister()
infrastructure, since it is now unused after Patch #7.
Patch #10 moves the flow_block API to the net/core/flow_offload.c file.
This renames from tcf_block_cb to flow_block_cb as well as the
functions to allocate, release, lookup and setup flow block
callbacks.
Patch #11 makes sure that only one flow block callback per device is
possible by now. This means only one of the ethtool / tc /
netfilter subsystems can use hardware offloads, until drivers
are updated to remove this limitation.
Patch #12 introduces a flow block list per-driver, this is a step
towards offloading multiple subsystems. This needs more work
on the driver side to support for this.
Patch #13 renames TC_BLOCK_{UN}BIND to FLOW_BLOCK_{UN}BIND.
Patch #14 renames TCF_BLOCK_BINDER_TYPE_* to FLOW_BLOCK_BINDER_TYPE_*.
Patch #15 introduces basic netfilter hardware offload infrastructure
for the ingress chain. This includes 5-tuple exact matching
and accept / drop rule actions. Only basechains are supported
at this stage, no .reoffload callback is implemented either.
Default policy to "accept" is only supported for now.
An example ruleset looks like this:
table netdev filter {
flags offload;
chain ingress {
type filter hook ingress device eth0 priority 0;
ip daddr 192.168.0.10 tcp dport 22 drop
}
}
The 'offload' flag specifies that this table (and anything that is enclosed
into this table) belongs to hardware.
Please, apply, thanks.
Pablo Neira Ayuso (15):
net: sched: move tcf_block_cb before indr_block
net: sched: add tcf_block_cb_alloc()
net: sched: add tcf_block_cb_free()
net: sched: add tcf_block_setup()
net: sched: add release callback to struct tcf_block_cb
net: sched: add tcf_setup_block_offload()
net: use tcf_block_setup() infrastructure
net: cls_api: do not expose tcf_block to drivers
net: sched: remove tcf_block_cb_{register,unregister}()
net: flow_offload: add flow_block_cb API
net: flow_offload: don't allow subsystem to reuse blocks
net: flow_offload: make flow block callback list per-driver
net: flow_offload: rename TC_BLOCK_{UN}BIND to FLOW_BLOCK_{UN}BIND
net: flow_offload: rename TCF_BLOCK_BINDER_TYPE_* to FLOW_BLOCK_BINDER_TYPE_*
netfilter: nf_tables: add hardware offload support
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 +-
drivers/net/ethernet/broadcom/bnxt/bnxt_vfr.c | 29 +-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 26 +-
drivers/net/ethernet/intel/i40e/i40e_main.c | 26 +-
drivers/net/ethernet/intel/iavf/iavf_main.c | 35 +-
drivers/net/ethernet/intel/igb/igb_main.c | 26 +-
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 29 +-
drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 29 +-
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c | 70 ++-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 97 ++--
drivers/net/ethernet/mscc/ocelot_ace.h | 4 +-
drivers/net/ethernet/mscc/ocelot_flower.c | 47 +-
drivers/net/ethernet/mscc/ocelot_tc.c | 42 +-
drivers/net/ethernet/netronome/nfp/abm/cls.c | 22 +-
drivers/net/ethernet/netronome/nfp/abm/main.h | 2 +-
drivers/net/ethernet/netronome/nfp/bpf/main.c | 30 +-
.../net/ethernet/netronome/nfp/flower/offload.c | 76 +--
drivers/net/ethernet/qlogic/qede/qede_main.c | 23 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 23 +-
drivers/net/netdevsim/netdev.c | 29 +-
include/net/flow_offload.h | 56 +++
include/net/netfilter/nf_tables.h | 13 +
include/net/netfilter/nf_tables_offload.h | 76 +++
include/net/pkt_cls.h | 90 +---
include/uapi/linux/netfilter/nf_tables.h | 2 +
net/core/flow_offload.c | 123 +++++
net/dsa/slave.c | 28 +-
net/netfilter/Makefile | 2 +-
net/netfilter/nf_tables_api.c | 22 +-
net/netfilter/nf_tables_offload.c | 261 ++++++++++
net/netfilter/nft_cmp.c | 53 +++
net/netfilter/nft_immediate.c | 31 ++
net/netfilter/nft_meta.c | 27 ++
net/netfilter/nft_payload.c | 187 ++++++++
net/sched/cls_api.c | 526 ++++++++++-----------
net/sched/sch_ingress.c | 6 +-
36 files changed, 1411 insertions(+), 783 deletions(-)
create mode 100644 include/net/netfilter/nf_tables_offload.h
create mode 100644 net/netfilter/nf_tables_offload.c
--
2.11.0
^ permalink raw reply
* Re: [PATCH net-next 4/6] arm64: dts: fsl: ls1028a: Add Felix switch port DT node
From: Vladimir Oltean @ 2019-07-04 23:32 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Andrew Lunn, Allan W. Nielsen, Claudiu Manoil, David S . Miller,
devicetree@vger.kernel.org, netdev@vger.kernel.org,
Alexandru Marginean, linux-kernel@vger.kernel.org,
UNGLinuxDriver@microchip.com, Allan Nielsen, Rob Herring,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190624182614.GC5690@piout.net>
On Tue, 25 Jun 2019 at 00:23, Alexandre Belloni
<alexandre.belloni@bootlin.com> wrote:
>
> On 24/06/2019 18:24:31+0200, Andrew Lunn wrote:
> > On Mon, Jun 24, 2019 at 05:23:45PM +0200, Allan W. Nielsen wrote:
> > > Hi Andrew,
> > >
> > > The 06/24/2019 16:26, Andrew Lunn wrote:
> > > > > > Yeah, there are 2 ethernet controller ports (managed by the enetc driver)
> > > > > > connected inside the SoC via SGMII links to 2 of the switch ports, one of
> > > > > > these switch ports can be configured as CPU port (with follow-up patches).
> > > > > >
> > > > > > This configuration may look prettier on DSA, but the main restriction here
> > > > > > is that the entire functionality is provided by the ocelot driver which is a
> > > > > > switchdev driver. I don't think it would be a good idea to copy-paste code
> > > > > > from ocelot to a separate dsa driver.
> > > > > >
> > > > >
> > > > > We should probably make the ocelot driver a DSA driver then...
> > > > An important part of DSA is being able to direct frames out specific
> > > > ports when they ingress via the CPU port. Does the silicon support
> > > > this? At the moment, i think it is using polled IO.
> > >
> > > That is supported, it requires a bit of initial configuration of the Chip, but
> > > nothing big (I believe this configuration is part of Claudiu's change-set).
> > >
> > > But how do you envision this done?
> > >
> > > - Let the existing SwitchDev driver and the DSA driver use a set of common
> > > functions.
> > > - Convert the existing Ocelot driver from SwitchDev to DSA
> > > - Fork (copy) the existing driver of Ocelot, and modify it as needed for the
> > > Felix driver
> > >
> > > My guess is the first one, but I would like to understand what you have in mind.
> >
> > I don't know the various architectures the switch is used in. But it
> > does seem like a core library, and then a switchdev wrapper for Ocelot
> > and a DSA wrapper for Felix would make sense.
>
> Ocelot could also be used in a DSA setting where one port can be
> connected to an external MAC and be used to inject/extract frames
> to/from any other ports. In that case, the IFH would serve as the DSA
> tag.
>
>
> --
> Alexandre Belloni, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com
Hi everyone,
Thank you for the nice discussion.
I've been talking off-list to Claudiu and Alexandru about switchdev vs
DSA for the Felix/Ocelot switches.
My initial reaction was the same as Andrew's - there's a CPU-facing
Ethernet MAC with some vendor-defined injection and extraction
headers? Sounds like DSA.
But then we discussed about what DSA for Felix/Ocelot would look like.
Here are some points to consider:
- DSA is typically used for discrete switches, switchdev is typically
used for embedded ones. As far as I understand from Allan's message,
Ocelot is really an entire switching SoC that's running Linux inside
(on the MIPS CPU) with a switchdev driver. There is no (mainline?)
driver that would control the Ocelot SoC from a higher-level Linux
system. The latter would (maybe) fit DSA more.
- The D in DSA is for cascaded switches. Apart from the absence of
such a "Ocelot SoC" driver (which maybe can be written, I don't know),
I think the switching core itself has some fundamental limitations
that make a DSA implementation questionable:
1. The switch has a single port which can apply these vendor tags.
Also the injection header is different than the extraction header. See
more at #4.
2. The switch will tag all frames that go upstream on this port
towards the CPU, no matter what source port they came from. It can't
be told "hey, don't add a tag for frames coming from this
downstream-facing port, because it's a DSA port and not front-panel,
so there's another switch underneath you who already added a tag to
the frame". So frames that arrive at the CPU through an array of N
cascaded Felix/Ocelot switches will need to be peeled off, one by one,
by N vendor tags.
3. The extraction header does not contain a field for the "switch
id", only for the "source port". This means that if you want to figure
out the switch id, you really *need* to make a topology out of those
stacked vendor tags and figure out which switch it was by counting the
tags. It also means that you can only have Felix/Ocelot in a linear
topology.
4. The switch cannot parse its own vendor tags. This is a big one,
because it means that for an autonomously forwarded frame which
transits two cascaded switches but doesn't reach the CPU, there is no
one in the path who's going to consume the vendor tag. So the frame
will exit the other front-panel port with extra bytes in it.
Ok, let's say that all of the above limitations have one thing in
common - the vendor tags aren't really thought out with DSA-like
setups in mind. In theory it's possible to not use the native tags and
instead implement a dsa_8021q tagger for it. But then, RX timestamps
for PTP are also transmitted to the CPU through this vendor header,
and losing PTP is a big no-no.
So my conclusion is that DSA for Felix/Ocelot doesn't make a lot of
sense if the whole purpose is to hide the CPU-facing netdev.
In a cascaded setup, these switches could only sit at the top of tree,
and ironically, they'd be better modeled as a switchdev DSA master
port than part of the DSA tree itself. Put these switches anywhere
else in the tree and they're just troublemakers.
As for the LS1028A, I think that connecting this embedded switch via
two Ethernet MACs is just poorly thought out design, but that doesn't
mean DSA is going to help it in any way other than perhaps cosmetic.
Regards,
-Vladimir
^ permalink raw reply
* [PATCH v7 net-next 2/5] net: ethernet: ti: davinci_cpdma: add dma mapped submit
From: Ivan Khoronzhuk @ 2019-07-04 23:14 UTC (permalink / raw)
To: grygorii.strashko, hawk, davem
Cc: ast, linux-kernel, linux-omap, xdp-newbies, ilias.apalodimas,
netdev, daniel, jakub.kicinski, john.fastabend, Ivan Khoronzhuk
In-Reply-To: <20190704231406.27083-1-ivan.khoronzhuk@linaro.org>
In case if dma mapped packet needs to be sent, like with XDP
page pool, the "mapped" submit can be used. This patch adds dma
mapped submit based on regular one.
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
drivers/net/ethernet/ti/davinci_cpdma.c | 89 ++++++++++++++++++++++---
drivers/net/ethernet/ti/davinci_cpdma.h | 4 ++
2 files changed, 83 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 5cf1758d425b..8da46394c0e7 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -139,6 +139,7 @@ struct submit_info {
int directed;
void *token;
void *data;
+ int flags;
int len;
};
@@ -184,6 +185,8 @@ static struct cpdma_control_info controls[] = {
(directed << CPDMA_TO_PORT_SHIFT)); \
} while (0)
+#define CPDMA_DMA_EXT_MAP BIT(16)
+
static void cpdma_desc_pool_destroy(struct cpdma_ctlr *ctlr)
{
struct cpdma_desc_pool *pool = ctlr->pool;
@@ -1015,6 +1018,7 @@ static int cpdma_chan_submit_si(struct submit_info *si)
struct cpdma_chan *chan = si->chan;
struct cpdma_ctlr *ctlr = chan->ctlr;
int len = si->len;
+ int swlen = len;
struct cpdma_desc __iomem *desc;
dma_addr_t buffer;
u32 mode;
@@ -1036,16 +1040,22 @@ static int cpdma_chan_submit_si(struct submit_info *si)
chan->stats.runt_transmit_buff++;
}
- buffer = dma_map_single(ctlr->dev, si->data, len, chan->dir);
- ret = dma_mapping_error(ctlr->dev, buffer);
- if (ret) {
- cpdma_desc_free(ctlr->pool, desc, 1);
- return -EINVAL;
- }
-
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
cpdma_desc_to_port(chan, mode, si->directed);
+ if (si->flags & CPDMA_DMA_EXT_MAP) {
+ buffer = (u32)si->data;
+ dma_sync_single_for_device(ctlr->dev, buffer, len, chan->dir);
+ swlen |= CPDMA_DMA_EXT_MAP;
+ } else {
+ buffer = dma_map_single(ctlr->dev, si->data, len, chan->dir);
+ ret = dma_mapping_error(ctlr->dev, buffer);
+ if (ret) {
+ cpdma_desc_free(ctlr->pool, desc, 1);
+ return -EINVAL;
+ }
+ }
+
/* Relaxed IO accessors can be used here as there is read barrier
* at the end of write sequence.
*/
@@ -1055,7 +1065,7 @@ static int cpdma_chan_submit_si(struct submit_info *si)
writel_relaxed(mode | len, &desc->hw_mode);
writel_relaxed((uintptr_t)si->token, &desc->sw_token);
writel_relaxed(buffer, &desc->sw_buffer);
- writel_relaxed(len, &desc->sw_len);
+ writel_relaxed(swlen, &desc->sw_len);
desc_read(desc, sw_len);
__cpdma_chan_submit(chan, desc);
@@ -1079,6 +1089,32 @@ int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data,
si.data = data;
si.len = len;
si.directed = directed;
+ si.flags = 0;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state == CPDMA_STATE_TEARDOWN) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data = (void *)(u32)data;
+ si.len = len;
+ si.directed = directed;
+ si.flags = CPDMA_DMA_EXT_MAP;
spin_lock_irqsave(&chan->lock, flags);
if (chan->state == CPDMA_STATE_TEARDOWN) {
@@ -1103,6 +1139,32 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
si.data = data;
si.len = len;
si.directed = directed;
+ si.flags = 0;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ if (chan->state != CPDMA_STATE_ACTIVE) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit_si(&si);
+ spin_unlock_irqrestore(&chan->lock, flags);
+ return ret;
+}
+
+int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed)
+{
+ struct submit_info si;
+ unsigned long flags;
+ int ret;
+
+ si.chan = chan;
+ si.token = token;
+ si.data = (void *)(u32)data;
+ si.len = len;
+ si.directed = directed;
+ si.flags = CPDMA_DMA_EXT_MAP;
spin_lock_irqsave(&chan->lock, flags);
if (chan->state != CPDMA_STATE_ACTIVE) {
@@ -1140,10 +1202,17 @@ static void __cpdma_chan_free(struct cpdma_chan *chan,
uintptr_t token;
token = desc_read(desc, sw_token);
- buff_dma = desc_read(desc, sw_buffer);
origlen = desc_read(desc, sw_len);
- dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+ buff_dma = desc_read(desc, sw_buffer);
+ if (origlen & CPDMA_DMA_EXT_MAP) {
+ origlen &= ~CPDMA_DMA_EXT_MAP;
+ dma_sync_single_for_cpu(ctlr->dev, buff_dma, origlen,
+ chan->dir);
+ } else {
+ dma_unmap_single(ctlr->dev, buff_dma, origlen, chan->dir);
+ }
+
cpdma_desc_free(pool, desc, 1);
(*chan->handler)((void *)token, outlen, status);
}
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index 9343c8c73c1b..0271a20c2e09 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -77,8 +77,12 @@ int cpdma_chan_stop(struct cpdma_chan *chan);
int cpdma_chan_get_stats(struct cpdma_chan *chan,
struct cpdma_chan_stats *stats);
+int cpdma_chan_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed);
int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data,
int len, int directed);
+int cpdma_chan_idle_submit_mapped(struct cpdma_chan *chan, void *token,
+ dma_addr_t data, int len, int directed);
int cpdma_chan_idle_submit(struct cpdma_chan *chan, void *token, void *data,
int len, int directed);
int cpdma_chan_process(struct cpdma_chan *chan, int quota);
--
2.17.1
^ permalink raw reply related
* [PATCH v7 net-next 5/5] net: ethernet: ti: cpsw: add XDP support
From: Ivan Khoronzhuk @ 2019-07-04 23:14 UTC (permalink / raw)
To: grygorii.strashko, hawk, davem
Cc: ast, linux-kernel, linux-omap, xdp-newbies, ilias.apalodimas,
netdev, daniel, jakub.kicinski, john.fastabend, Ivan Khoronzhuk
In-Reply-To: <20190704231406.27083-1-ivan.khoronzhuk@linaro.org>
Add XDP support based on rx page_pool allocator, one frame per page.
Page pool allocator is used with assumption that only one rx_handler
is running simultaneously. DMA map/unmap is reused from page pool
despite there is no need to map whole page.
Due to specific of cpsw, the same TX/RX handler can be used by 2
network devices, so special fields in buffer are added to identify
an interface the frame is destined to. Thus XDP works for both
interfaces, that allows to test xdp redirect between two interfaces
easily. Aslo, each rx queue have own page pools, but common for both
netdevs.
XDP prog is common for all channels till appropriate changes are added
in XDP infrastructure. Also, once page_pool recycling becomes part of
skb netstack some simplifications can be added, like removing
page_pool_release_page() before skb receive.
In order to keep rx_dev while redirect, that can be somehow used in
future, do flush in rx_handler, that allows to keep rx dev the same
while reidrect. It allows to conform with tracing rx_dev pointed
by Jesper.
Also, there is probability, that XDP generic code can be extended to
support multi ndev drivers like this one, using same rx queue for
several ndevs, based on switchdev for instance or else. In this case,
driver can be modified like exposed here:
https://lkml.org/lkml/2019/7/3/243
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
drivers/net/ethernet/ti/Kconfig | 1 +
drivers/net/ethernet/ti/cpsw.c | 502 ++++++++++++++++++++++---
drivers/net/ethernet/ti/cpsw_ethtool.c | 37 +-
drivers/net/ethernet/ti/cpsw_priv.h | 7 +
4 files changed, 488 insertions(+), 59 deletions(-)
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index a800d3417411..834afca3a019 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -50,6 +50,7 @@ config TI_CPSW
depends on ARCH_DAVINCI || ARCH_OMAP2PLUS || COMPILE_TEST
select TI_DAVINCI_MDIO
select MFD_SYSCON
+ select PAGE_POOL
select REGMAP
---help---
This driver supports TI's CPSW Ethernet Switch.
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 32b7b3b74a6b..c17bb9381116 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -31,6 +31,10 @@
#include <linux/if_vlan.h>
#include <linux/kmemleak.h>
#include <linux/sys_soc.h>
+#include <net/page_pool.h>
+#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
+#include <linux/filter.h>
#include <linux/pinctrl/consumer.h>
#include <net/pkt_cls.h>
@@ -60,6 +64,10 @@ static int descs_pool_size = CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT;
module_param(descs_pool_size, int, 0444);
MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool");
+/* The buf includes headroom compatible with both skb and xdpf */
+#define CPSW_HEADROOM_NA (max(XDP_PACKET_HEADROOM, NET_SKB_PAD) + NET_IP_ALIGN)
+#define CPSW_HEADROOM ALIGN(CPSW_HEADROOM_NA, sizeof(long))
+
#define for_each_slave(priv, func, arg...) \
do { \
struct cpsw_slave *slave; \
@@ -74,6 +82,11 @@ MODULE_PARM_DESC(descs_pool_size, "Number of CPDMA CPPI descriptors in pool");
(func)(slave++, ##arg); \
} while (0)
+#define CPSW_XMETA_OFFSET ALIGN(sizeof(struct xdp_frame), sizeof(long))
+
+#define CPSW_XDP_CONSUMED 1
+#define CPSW_XDP_PASS 0
+
static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
__be16 proto, u16 vid);
@@ -337,24 +350,58 @@ void cpsw_intr_disable(struct cpsw_common *cpsw)
return;
}
+static int cpsw_is_xdpf_handle(void *handle)
+{
+ return (unsigned long)handle & BIT(0);
+}
+
+static void *cpsw_xdpf_to_handle(struct xdp_frame *xdpf)
+{
+ return (void *)((unsigned long)xdpf | BIT(0));
+}
+
+static struct xdp_frame *cpsw_handle_to_xdpf(void *handle)
+{
+ return (struct xdp_frame *)((unsigned long)handle & ~BIT(0));
+}
+
+struct __aligned(sizeof(long)) cpsw_meta_xdp {
+ struct net_device *ndev;
+ int ch;
+};
+
void cpsw_tx_handler(void *token, int len, int status)
{
+ struct cpsw_meta_xdp *xmeta;
+ struct xdp_frame *xdpf;
+ struct net_device *ndev;
struct netdev_queue *txq;
- struct sk_buff *skb = token;
- struct net_device *ndev = skb->dev;
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct sk_buff *skb;
+ int ch;
+
+ if (cpsw_is_xdpf_handle(token)) {
+ xdpf = cpsw_handle_to_xdpf(token);
+ xmeta = (void *)xdpf + CPSW_XMETA_OFFSET;
+ ndev = xmeta->ndev;
+ ch = xmeta->ch;
+ xdp_return_frame(xdpf);
+ } else {
+ skb = token;
+ ndev = skb->dev;
+ ch = skb_get_queue_mapping(skb);
+ cpts_tx_timestamp(ndev_to_cpsw(ndev)->cpts, skb);
+ dev_kfree_skb_any(skb);
+ }
/* Check whether the queue is stopped due to stalled tx dma, if the
* queue is stopped then start the queue as we have free desc for tx
*/
- txq = netdev_get_tx_queue(ndev, skb_get_queue_mapping(skb));
+ txq = netdev_get_tx_queue(ndev, ch);
if (unlikely(netif_tx_queue_stopped(txq)))
netif_tx_wake_queue(txq);
- cpts_tx_timestamp(cpsw->cpts, skb);
ndev->stats.tx_packets++;
ndev->stats.tx_bytes += len;
- dev_kfree_skb_any(skb);
}
static void cpsw_rx_vlan_encap(struct sk_buff *skb)
@@ -400,24 +447,252 @@ static void cpsw_rx_vlan_encap(struct sk_buff *skb)
}
}
+static int cpsw_xdp_tx_frame(struct cpsw_priv *priv, struct xdp_frame *xdpf,
+ struct page *page)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct cpsw_meta_xdp *xmeta;
+ struct cpdma_chan *txch;
+ dma_addr_t dma;
+ int ret, port;
+
+ xmeta = (void *)xdpf + CPSW_XMETA_OFFSET;
+ xmeta->ndev = priv->ndev;
+ xmeta->ch = 0;
+ txch = cpsw->txv[0].ch;
+
+ port = priv->emac_port + cpsw->data.dual_emac;
+ if (page) {
+ dma = page_pool_get_dma_addr(page);
+ dma += xdpf->data - (void *)xdpf;
+ ret = cpdma_chan_submit_mapped(txch, cpsw_xdpf_to_handle(xdpf),
+ dma, xdpf->len, port);
+ } else {
+ if (sizeof(*xmeta) > xdpf->headroom) {
+ xdp_return_frame_rx_napi(xdpf);
+ return -EINVAL;
+ }
+
+ ret = cpdma_chan_submit(txch, cpsw_xdpf_to_handle(xdpf),
+ xdpf->data, xdpf->len, port);
+ }
+
+ if (ret) {
+ priv->ndev->stats.tx_dropped++;
+ xdp_return_frame_rx_napi(xdpf);
+ }
+
+ return ret;
+}
+
+static int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,
+ struct page *page)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct net_device *ndev = priv->ndev;
+ int ret = CPSW_XDP_CONSUMED;
+ struct xdp_frame *xdpf;
+ struct bpf_prog *prog;
+ u32 act;
+
+ rcu_read_lock();
+
+ prog = READ_ONCE(priv->xdp_prog);
+ if (!prog) {
+ ret = CPSW_XDP_PASS;
+ goto out;
+ }
+
+ act = bpf_prog_run_xdp(prog, xdp);
+ switch (act) {
+ case XDP_PASS:
+ ret = CPSW_XDP_PASS;
+ break;
+ case XDP_TX:
+ xdpf = convert_to_xdp_frame(xdp);
+ if (unlikely(!xdpf))
+ goto drop;
+
+ cpsw_xdp_tx_frame(priv, xdpf, page);
+ break;
+ case XDP_REDIRECT:
+ if (xdp_do_redirect(ndev, xdp, prog))
+ goto drop;
+
+ /* Have to flush here, per packet, instead of doing it in bulk
+ * at the end of the napi handler. The RX devices on this
+ * particular hardware is sharing a common queue, so the
+ * incoming device might change per packet.
+ */
+ xdp_do_flush_map();
+ break;
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fall through */
+ case XDP_ABORTED:
+ trace_xdp_exception(ndev, prog, act);
+ /* fall through -- handle aborts by dropping packet */
+ case XDP_DROP:
+ goto drop;
+ }
+out:
+ rcu_read_unlock();
+ return ret;
+drop:
+ rcu_read_unlock();
+ page_pool_recycle_direct(cpsw->page_pool[ch], page);
+ return ret;
+}
+
+static unsigned int cpsw_rxbuf_total_len(unsigned int len)
+{
+ len += CPSW_HEADROOM;
+ len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ return SKB_DATA_ALIGN(len);
+}
+
+static struct page_pool *cpsw_create_page_pool(struct cpsw_common *cpsw,
+ int size)
+{
+ struct page_pool_params pp_params;
+ struct page_pool *pool;
+
+ pp_params.order = 0;
+ pp_params.flags = PP_FLAG_DMA_MAP;
+ pp_params.pool_size = size;
+ pp_params.nid = NUMA_NO_NODE;
+ pp_params.dma_dir = DMA_BIDIRECTIONAL;
+ pp_params.dev = cpsw->dev;
+
+ pool = page_pool_create(&pp_params);
+ if (IS_ERR(pool))
+ dev_err(cpsw->dev, "cannot create rx page pool\n");
+
+ return pool;
+}
+
+static int cpsw_ndev_create_xdp_rxq(struct cpsw_priv *priv, int ch)
+{
+ struct cpsw_common *cpsw = priv->cpsw;
+ struct xdp_rxq_info *rxq;
+ struct page_pool *pool;
+ int ret;
+
+ pool = cpsw->page_pool[ch];
+ rxq = &priv->xdp_rxq[ch];
+
+ ret = xdp_rxq_info_reg(rxq, priv->ndev, ch);
+ if (ret)
+ return ret;
+
+ ret = xdp_rxq_info_reg_mem_model(rxq, MEM_TYPE_PAGE_POOL, pool);
+ if (ret)
+ xdp_rxq_info_unreg(rxq);
+
+ return ret;
+}
+
+static void cpsw_ndev_destroy_xdp_rxq(struct cpsw_priv *priv, int ch)
+{
+ struct xdp_rxq_info *rxq = &priv->xdp_rxq[ch];
+
+ if (!xdp_rxq_info_is_reg(rxq))
+ return;
+
+ xdp_rxq_info_unreg(rxq);
+}
+
+static int cpsw_create_rx_pool(struct cpsw_common *cpsw, int ch)
+{
+ struct page_pool *pool;
+ int ret = 0, pool_size;
+
+ pool_size = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch);
+ pool = cpsw_create_page_pool(cpsw, pool_size);
+ if (IS_ERR(pool))
+ ret = PTR_ERR(pool);
+ else
+ cpsw->page_pool[ch] = pool;
+
+ return ret;
+}
+
+void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i, ch;
+
+ for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (!ndev)
+ continue;
+
+ cpsw_ndev_destroy_xdp_rxq(netdev_priv(ndev), ch);
+ }
+
+ page_pool_destroy(cpsw->page_pool[ch]);
+ cpsw->page_pool[ch] = NULL;
+ }
+}
+
+int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i, ch, ret;
+
+ for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ ret = cpsw_create_rx_pool(cpsw, ch);
+ if (ret)
+ goto err_cleanup;
+
+ /* using same page pool is allowed as no running rx handlers
+ * simultaneously for both ndevs
+ */
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (!ndev)
+ continue;
+
+ ret = cpsw_ndev_create_xdp_rxq(netdev_priv(ndev), ch);
+ if (ret)
+ goto err_cleanup;
+ }
+ }
+
+ return 0;
+
+err_cleanup:
+ cpsw_destroy_xdp_rxqs(cpsw);
+
+ return ret;
+}
+
static void cpsw_rx_handler(void *token, int len, int status)
{
- struct cpdma_chan *ch;
- struct sk_buff *skb = token;
- struct sk_buff *new_skb;
- struct net_device *ndev = skb->dev;
- int ret = 0, port;
- struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
+ struct page *new_page, *page = token;
+ void *pa = page_address(page);
+ struct cpsw_meta_xdp *xmeta = pa + CPSW_XMETA_OFFSET;
+ struct cpsw_common *cpsw = ndev_to_cpsw(xmeta->ndev);
+ int pkt_size = cpsw->rx_packet_max;
+ int ret = 0, port, ch = xmeta->ch;
+ int headroom = CPSW_HEADROOM;
+ struct net_device *ndev = xmeta->ndev;
struct cpsw_priv *priv;
+ struct page_pool *pool;
+ struct sk_buff *skb;
+ struct xdp_buff xdp;
+ dma_addr_t dma;
- if (cpsw->data.dual_emac) {
+ if (cpsw->data.dual_emac && status >= 0) {
port = CPDMA_RX_SOURCE_PORT(status);
- if (port) {
+ if (port)
ndev = cpsw->slaves[--port].ndev;
- skb->dev = ndev;
- }
}
+ priv = netdev_priv(ndev);
+ pool = cpsw->page_pool[ch];
if (unlikely(status < 0) || unlikely(!netif_running(ndev))) {
/* In dual emac mode check for all interfaces */
if (cpsw->data.dual_emac && cpsw->usage_count &&
@@ -426,43 +701,87 @@ static void cpsw_rx_handler(void *token, int len, int status)
* is already down and the other interface is up
* and running, instead of freeing which results
* in reducing of the number of rx descriptor in
- * DMA engine, requeue skb back to cpdma.
+ * DMA engine, requeue page back to cpdma.
*/
- new_skb = skb;
+ new_page = page;
goto requeue;
}
- /* the interface is going down, skbs are purged */
- dev_kfree_skb_any(skb);
+ /* the interface is going down, pages are purged */
+ page_pool_recycle_direct(pool, page);
return;
}
- new_skb = netdev_alloc_skb_ip_align(ndev, cpsw->rx_packet_max);
- if (new_skb) {
- skb_copy_queue_mapping(new_skb, skb);
- skb_put(skb, len);
- if (status & CPDMA_RX_VLAN_ENCAP)
- cpsw_rx_vlan_encap(skb);
- priv = netdev_priv(ndev);
- if (priv->rx_ts_enabled)
- cpts_rx_timestamp(cpsw->cpts, skb);
- skb->protocol = eth_type_trans(skb, ndev);
- netif_receive_skb(skb);
- ndev->stats.rx_bytes += len;
- ndev->stats.rx_packets++;
- kmemleak_not_leak(new_skb);
- } else {
+ new_page = page_pool_dev_alloc_pages(pool);
+ if (unlikely(!new_page)) {
+ new_page = page;
ndev->stats.rx_dropped++;
- new_skb = skb;
+ goto requeue;
+ }
+
+ if (priv->xdp_prog) {
+ if (status & CPDMA_RX_VLAN_ENCAP) {
+ xdp.data = pa + CPSW_HEADROOM +
+ CPSW_RX_VLAN_ENCAP_HDR_SIZE;
+ xdp.data_end = xdp.data + len -
+ CPSW_RX_VLAN_ENCAP_HDR_SIZE;
+ } else {
+ xdp.data = pa + CPSW_HEADROOM;
+ xdp.data_end = xdp.data + len;
+ }
+
+ xdp_set_data_meta_invalid(&xdp);
+
+ xdp.data_hard_start = pa;
+ xdp.rxq = &priv->xdp_rxq[ch];
+
+ ret = cpsw_run_xdp(priv, ch, &xdp, page);
+ if (ret != CPSW_XDP_PASS)
+ goto requeue;
+
+ /* XDP prog might have changed packet data and boundaries */
+ len = xdp.data_end - xdp.data;
+ headroom = xdp.data - xdp.data_hard_start;
+
+ /* XDP prog can modify vlan tag, so can't use encap header */
+ status &= ~CPDMA_RX_VLAN_ENCAP;
}
+ /* pass skb to netstack if no XDP prog or returned XDP_PASS */
+ skb = build_skb(pa, cpsw_rxbuf_total_len(pkt_size));
+ if (!skb) {
+ ndev->stats.rx_dropped++;
+ page_pool_recycle_direct(pool, page);
+ goto requeue;
+ }
+
+ skb_reserve(skb, headroom);
+ skb_put(skb, len);
+ skb->dev = ndev;
+ if (status & CPDMA_RX_VLAN_ENCAP)
+ cpsw_rx_vlan_encap(skb);
+ if (priv->rx_ts_enabled)
+ cpts_rx_timestamp(cpsw->cpts, skb);
+ skb->protocol = eth_type_trans(skb, ndev);
+
+ /* unmap page as no netstack skb page recycling */
+ page_pool_release_page(pool, page);
+ netif_receive_skb(skb);
+
+ ndev->stats.rx_bytes += len;
+ ndev->stats.rx_packets++;
+
requeue:
- ch = cpsw->rxv[skb_get_queue_mapping(new_skb)].ch;
- ret = cpdma_chan_submit(ch, new_skb, new_skb->data,
- skb_tailroom(new_skb), 0);
+ xmeta = page_address(new_page) + CPSW_XMETA_OFFSET;
+ xmeta->ndev = ndev;
+ xmeta->ch = ch;
+
+ dma = page_pool_get_dma_addr(new_page) + CPSW_HEADROOM;
+ ret = cpdma_chan_submit_mapped(cpsw->rxv[ch].ch, new_page, dma,
+ pkt_size, 0);
if (ret < 0) {
WARN_ON(ret == -ENOMEM);
- dev_kfree_skb_any(new_skb);
+ page_pool_recycle_direct(pool, new_page);
}
}
@@ -1032,33 +1351,39 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
int cpsw_fill_rx_channels(struct cpsw_priv *priv)
{
struct cpsw_common *cpsw = priv->cpsw;
- struct sk_buff *skb;
+ struct cpsw_meta_xdp *xmeta;
+ struct page_pool *pool;
+ struct page *page;
int ch_buf_num;
int ch, i, ret;
+ dma_addr_t dma;
for (ch = 0; ch < cpsw->rx_ch_num; ch++) {
+ pool = cpsw->page_pool[ch];
ch_buf_num = cpdma_chan_get_rx_buf_num(cpsw->rxv[ch].ch);
for (i = 0; i < ch_buf_num; i++) {
- skb = __netdev_alloc_skb_ip_align(priv->ndev,
- cpsw->rx_packet_max,
- GFP_KERNEL);
- if (!skb) {
- cpsw_err(priv, ifup, "cannot allocate skb\n");
+ page = page_pool_dev_alloc_pages(pool);
+ if (!page) {
+ cpsw_err(priv, ifup, "allocate rx page err\n");
return -ENOMEM;
}
- skb_set_queue_mapping(skb, ch);
- ret = cpdma_chan_idle_submit(cpsw->rxv[ch].ch, skb,
- skb->data,
- skb_tailroom(skb), 0);
+ xmeta = page_address(page) + CPSW_XMETA_OFFSET;
+ xmeta->ndev = priv->ndev;
+ xmeta->ch = ch;
+
+ dma = page_pool_get_dma_addr(page) + CPSW_HEADROOM;
+ ret = cpdma_chan_idle_submit_mapped(cpsw->rxv[ch].ch,
+ page, dma,
+ cpsw->rx_packet_max,
+ 0);
if (ret < 0) {
cpsw_err(priv, ifup,
- "cannot submit skb to channel %d rx, error %d\n",
+ "cannot submit page to channel %d rx, error %d\n",
ch, ret);
- kfree_skb(skb);
+ page_pool_recycle_direct(pool, page);
return ret;
}
- kmemleak_not_leak(skb);
}
cpsw_info(priv, ifup, "ch %d rx, submitted %d descriptors\n",
@@ -1394,6 +1719,13 @@ static int cpsw_ndo_open(struct net_device *ndev)
enable_irq(cpsw->irqs_table[0]);
}
+ /* create rxqs for both infs in dual mac as they use same pool
+ * and must be destroyed together when no users.
+ */
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret < 0)
+ goto err_cleanup;
+
ret = cpsw_fill_rx_channels(priv);
if (ret < 0)
goto err_cleanup;
@@ -1422,9 +1754,10 @@ static int cpsw_ndo_open(struct net_device *ndev)
err_cleanup:
if (!cpsw->usage_count) {
cpdma_ctlr_stop(cpsw->dma);
- for_each_slave(priv, cpsw_slave_stop, cpsw);
+ cpsw_destroy_xdp_rxqs(cpsw);
}
+ for_each_slave(priv, cpsw_slave_stop, cpsw);
pm_runtime_put_sync(cpsw->dev);
netif_carrier_off(priv->ndev);
return ret;
@@ -1447,6 +1780,7 @@ static int cpsw_ndo_stop(struct net_device *ndev)
cpsw_intr_disable(cpsw);
cpdma_ctlr_stop(cpsw->dma);
cpsw_ale_stop(cpsw->ale);
+ cpsw_destroy_xdp_rxqs(cpsw);
}
for_each_slave(priv, cpsw_slave_stop, cpsw);
@@ -2004,6 +2338,64 @@ static int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
}
}
+static int cpsw_xdp_prog_setup(struct cpsw_priv *priv, struct netdev_bpf *bpf)
+{
+ struct bpf_prog *prog = bpf->prog;
+
+ if (!priv->xdpi.prog && !prog)
+ return 0;
+
+ if (!xdp_attachment_flags_ok(&priv->xdpi, bpf))
+ return -EBUSY;
+
+ WRITE_ONCE(priv->xdp_prog, prog);
+
+ xdp_attachment_setup(&priv->xdpi, bpf);
+
+ return 0;
+}
+
+static int cpsw_ndo_bpf(struct net_device *ndev, struct netdev_bpf *bpf)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+
+ switch (bpf->command) {
+ case XDP_SETUP_PROG:
+ return cpsw_xdp_prog_setup(priv, bpf);
+
+ case XDP_QUERY_PROG:
+ return xdp_attachment_query(&priv->xdpi, bpf);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cpsw_ndo_xdp_xmit(struct net_device *ndev, int n,
+ struct xdp_frame **frames, u32 flags)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ struct xdp_frame *xdpf;
+ int i, drops = 0;
+
+ if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+ return -EINVAL;
+
+ for (i = 0; i < n; i++) {
+ xdpf = frames[i];
+ if (xdpf->len < CPSW_MIN_PACKET_SIZE) {
+ xdp_return_frame_rx_napi(xdpf);
+ drops++;
+ continue;
+ }
+
+ if (cpsw_xdp_tx_frame(priv, xdpf, NULL))
+ drops++;
+ }
+
+ return n - drops;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void cpsw_ndo_poll_controller(struct net_device *ndev)
{
@@ -2032,6 +2424,8 @@ static const struct net_device_ops cpsw_netdev_ops = {
.ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid,
.ndo_setup_tc = cpsw_ndo_setup_tc,
+ .ndo_bpf = cpsw_ndo_bpf,
+ .ndo_xdp_xmit = cpsw_ndo_xdp_xmit,
};
static void cpsw_get_drvinfo(struct net_device *ndev,
diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c
index e4d7185fde49..31248a6cc642 100644
--- a/drivers/net/ethernet/ti/cpsw_ethtool.c
+++ b/drivers/net/ethernet/ti/cpsw_ethtool.c
@@ -578,6 +578,18 @@ static int cpsw_update_channels_res(struct cpsw_priv *priv, int ch_num, int rx,
return 0;
}
+static void cpsw_fail(struct cpsw_common *cpsw)
+{
+ struct net_device *ndev;
+ int i;
+
+ for (i = 0; i < cpsw->data.slaves; i++) {
+ ndev = cpsw->slaves[i].ndev;
+ if (ndev)
+ dev_close(ndev);
+ }
+}
+
int cpsw_set_channels_common(struct net_device *ndev,
struct ethtool_channels *chs,
cpdma_handler_fn rx_handler)
@@ -585,7 +597,7 @@ int cpsw_set_channels_common(struct net_device *ndev,
struct cpsw_priv *priv = netdev_priv(ndev);
struct cpsw_common *cpsw = priv->cpsw;
struct net_device *sl_ndev;
- int i, ret;
+ int i, new_pools, ret;
ret = cpsw_check_ch_settings(cpsw, chs);
if (ret < 0)
@@ -593,6 +605,8 @@ int cpsw_set_channels_common(struct net_device *ndev,
cpsw_suspend_data_pass(ndev);
+ new_pools = (chs->rx_count != cpsw->rx_ch_num) && cpsw->usage_count;
+
ret = cpsw_update_channels_res(priv, chs->rx_count, 1, rx_handler);
if (ret)
goto err;
@@ -622,12 +636,19 @@ int cpsw_set_channels_common(struct net_device *ndev,
cpsw_split_res(cpsw);
+ if (new_pools) {
+ cpsw_destroy_xdp_rxqs(cpsw);
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret)
+ goto err;
+ }
+
ret = cpsw_resume_data_pass(ndev);
if (!ret)
return 0;
err:
dev_err(priv->dev, "cannot update channels number, closing device\n");
- dev_close(ndev);
+ cpsw_fail(cpsw);
return ret;
}
@@ -647,8 +668,7 @@ void cpsw_get_ringparam(struct net_device *ndev,
int cpsw_set_ringparam(struct net_device *ndev,
struct ethtool_ringparam *ering)
{
- struct cpsw_priv *priv = netdev_priv(ndev);
- struct cpsw_common *cpsw = priv->cpsw;
+ struct cpsw_common *cpsw = ndev_to_cpsw(ndev);
int descs_num, ret;
/* ignore ering->tx_pending - only rx_pending adjustment is supported */
@@ -672,13 +692,20 @@ int cpsw_set_ringparam(struct net_device *ndev,
return ret;
}
+ if (cpsw->usage_count) {
+ cpsw_destroy_xdp_rxqs(cpsw);
+ ret = cpsw_create_xdp_rxqs(cpsw);
+ if (ret)
+ goto err;
+ }
+
ret = cpsw_resume_data_pass(ndev);
if (!ret)
return 0;
err:
cpdma_set_num_rx_descs(cpsw->dma, descs_num);
dev_err(cpsw->dev, "cannot set ring params, closing device\n");
- dev_close(ndev);
+ cpsw_fail(cpsw);
return ret;
}
diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h
index 04795b97ee71..086bf38a4736 100644
--- a/drivers/net/ethernet/ti/cpsw_priv.h
+++ b/drivers/net/ethernet/ti/cpsw_priv.h
@@ -346,6 +346,7 @@ struct cpsw_common {
int rx_ch_num, tx_ch_num;
int speed;
int usage_count;
+ struct page_pool *page_pool[CPSW_MAX_QUEUES];
};
struct cpsw_priv {
@@ -360,6 +361,10 @@ struct cpsw_priv {
int shp_cfg_speed;
int tx_ts_enabled;
int rx_ts_enabled;
+ struct bpf_prog *xdp_prog;
+ struct xdp_rxq_info xdp_rxq[CPSW_MAX_QUEUES];
+ struct xdp_attachment_info xdpi;
+
u32 emac_port;
struct cpsw_common *cpsw;
};
@@ -391,6 +396,8 @@ int cpsw_fill_rx_channels(struct cpsw_priv *priv);
void cpsw_intr_enable(struct cpsw_common *cpsw);
void cpsw_intr_disable(struct cpsw_common *cpsw);
void cpsw_tx_handler(void *token, int len, int status);
+int cpsw_create_xdp_rxqs(struct cpsw_common *cpsw);
+void cpsw_destroy_xdp_rxqs(struct cpsw_common *cpsw);
/* ethtool */
u32 cpsw_get_msglevel(struct net_device *ndev);
--
2.17.1
^ permalink raw reply related
* [PATCH v7 net-next 3/5] net: ethernet: ti: davinci_cpdma: allow desc split while down
From: Ivan Khoronzhuk @ 2019-07-04 23:14 UTC (permalink / raw)
To: grygorii.strashko, hawk, davem
Cc: ast, linux-kernel, linux-omap, xdp-newbies, ilias.apalodimas,
netdev, daniel, jakub.kicinski, john.fastabend, Ivan Khoronzhuk
In-Reply-To: <20190704231406.27083-1-ivan.khoronzhuk@linaro.org>
That's possible to set ring params while interfaces are down. When
interface gets up it uses number of descs to fill rx queue and on
later on changes to create rx pools. Usually, this resplit can happen
after phy is up, but it can be needed before this, so allow it to
happen while setting number of rx descs, when interfaces are down.
Also, if no dependency on intf state, move it to cpdma layer, where
it should be.
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
drivers/net/ethernet/ti/cpsw_ethtool.c | 17 +++++++++++------
drivers/net/ethernet/ti/davinci_cpdma.c | 17 ++++++++++++++++-
drivers/net/ethernet/ti/davinci_cpdma.h | 3 +--
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c
index f60dc1dfc443..c477e6b620d6 100644
--- a/drivers/net/ethernet/ti/cpsw_ethtool.c
+++ b/drivers/net/ethernet/ti/cpsw_ethtool.c
@@ -650,7 +650,7 @@ int cpsw_set_ringparam(struct net_device *ndev,
{
struct cpsw_priv *priv = netdev_priv(ndev);
struct cpsw_common *cpsw = priv->cpsw;
- int ret;
+ int descs_num, ret;
/* ignore ering->tx_pending - only rx_pending adjustment is supported */
@@ -659,20 +659,25 @@ int cpsw_set_ringparam(struct net_device *ndev,
ering->rx_pending > (cpsw->descs_pool_size - CPSW_MAX_QUEUES))
return -EINVAL;
- if (ering->rx_pending == cpdma_get_num_rx_descs(cpsw->dma))
+ descs_num = cpdma_get_num_rx_descs(cpsw->dma);
+ if (ering->rx_pending == descs_num)
return 0;
cpsw_suspend_data_pass(ndev);
- cpdma_set_num_rx_descs(cpsw->dma, ering->rx_pending);
+ ret = cpdma_set_num_rx_descs(cpsw->dma, ering->rx_pending);
+ if (ret) {
+ if (cpsw_resume_data_pass(ndev))
+ goto err;
- if (cpsw->usage_count)
- cpdma_chan_split_pool(cpsw->dma);
+ return ret;
+ }
ret = cpsw_resume_data_pass(ndev);
if (!ret)
return 0;
-
+err:
+ cpdma_set_num_rx_descs(cpsw->dma, descs_num);
dev_err(cpsw->dev, "cannot set ring params, closing device\n");
dev_close(ndev);
return ret;
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 8da46394c0e7..a3b6aeb4e935 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -1423,8 +1423,23 @@ int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr)
return ctlr->num_tx_desc;
}
-void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
+int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc)
{
+ unsigned long flags;
+ int temp, ret;
+
+ spin_lock_irqsave(&ctlr->lock, flags);
+
+ temp = ctlr->num_rx_desc;
ctlr->num_rx_desc = num_rx_desc;
ctlr->num_tx_desc = ctlr->pool->num_desc - ctlr->num_rx_desc;
+ ret = cpdma_chan_split_pool(ctlr);
+ if (ret) {
+ ctlr->num_rx_desc = temp;
+ ctlr->num_tx_desc = ctlr->pool->num_desc - ctlr->num_rx_desc;
+ }
+
+ spin_unlock_irqrestore(&ctlr->lock, flags);
+
+ return ret;
}
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h
index 0271a20c2e09..d3cfe234d16a 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.h
+++ b/drivers/net/ethernet/ti/davinci_cpdma.h
@@ -116,8 +116,7 @@ enum cpdma_control {
int cpdma_control_get(struct cpdma_ctlr *ctlr, int control);
int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value);
int cpdma_get_num_rx_descs(struct cpdma_ctlr *ctlr);
-void cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc);
+int cpdma_set_num_rx_descs(struct cpdma_ctlr *ctlr, int num_rx_desc);
int cpdma_get_num_tx_descs(struct cpdma_ctlr *ctlr);
-int cpdma_chan_split_pool(struct cpdma_ctlr *ctlr);
#endif
--
2.17.1
^ permalink raw reply related
* [PATCH v7 net-next 4/5] net: ethernet: ti: cpsw_ethtool: allow res split while down
From: Ivan Khoronzhuk @ 2019-07-04 23:14 UTC (permalink / raw)
To: grygorii.strashko, hawk, davem
Cc: ast, linux-kernel, linux-omap, xdp-newbies, ilias.apalodimas,
netdev, daniel, jakub.kicinski, john.fastabend, Ivan Khoronzhuk
In-Reply-To: <20190704231406.27083-1-ivan.khoronzhuk@linaro.org>
That's possible to set channel num while interfaces are down. When
interface gets up it should resplit budget. This resplit can happen
after phy is up but only if speed is changed, so should be set before
this, for this allow it to happen while changing number of channels,
when interfaces are down.
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
drivers/net/ethernet/ti/cpsw_ethtool.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c
index c477e6b620d6..e4d7185fde49 100644
--- a/drivers/net/ethernet/ti/cpsw_ethtool.c
+++ b/drivers/net/ethernet/ti/cpsw_ethtool.c
@@ -620,8 +620,7 @@ int cpsw_set_channels_common(struct net_device *ndev,
}
}
- if (cpsw->usage_count)
- cpsw_split_res(cpsw);
+ cpsw_split_res(cpsw);
ret = cpsw_resume_data_pass(ndev);
if (!ret)
--
2.17.1
^ permalink raw reply related
* [PATCH v7 net-next 1/5] net: core: page_pool: add user refcnt and reintroduce page_pool_destroy
From: Ivan Khoronzhuk @ 2019-07-04 23:14 UTC (permalink / raw)
To: grygorii.strashko, hawk, davem
Cc: ast, linux-kernel, linux-omap, xdp-newbies, ilias.apalodimas,
netdev, daniel, jakub.kicinski, john.fastabend, Ivan Khoronzhuk,
Jesper Dangaard Brouer
In-Reply-To: <20190704231406.27083-1-ivan.khoronzhuk@linaro.org>
Jesper recently removed page_pool_destroy() (from driver invocation)
and moved shutdown and free of page_pool into xdp_rxq_info_unreg(),
in-order to handle in-flight packets/pages. This created an asymmetry
in drivers create/destroy pairs.
This patch reintroduce page_pool_destroy and add page_pool user
refcnt. This serves the purpose to simplify drivers error handling as
driver now drivers always calls page_pool_destroy() and don't need to
track if xdp_rxq_info_reg_mem_model() was unsuccessful.
This could be used for a special cases where a single RX-queue (with a
single page_pool) provides packets for two net_device'es, and thus
needs to register the same page_pool twice with two xdp_rxq_info
structures.
This patch is primarily to ease API usage for drivers. The recently
merged netsec driver, actually have a bug in this area, which is
solved by this API change.
This patch is a modified version of Ivan Khoronzhu's original patch.
Link: https://lore.kernel.org/netdev/20190625175948.24771-2-ivan.khoronzhuk@linaro.org/
Fixes: 5c67bf0ec4d0 ("net: netsec: Use page_pool API")
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ivan Khoronzhuk <ivan.khoronzhuk@linaro.org>
---
.../net/ethernet/mellanox/mlx5/core/en_main.c | 4 +--
drivers/net/ethernet/socionext/netsec.c | 8 ++----
include/net/page_pool.h | 25 +++++++++++++++++++
net/core/page_pool.c | 8 ++++++
net/core/xdp.c | 3 +++
5 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 2f9093ba82aa..ac882b2341d0 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -575,8 +575,6 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
}
err = xdp_rxq_info_reg_mem_model(&rq->xdp_rxq,
MEM_TYPE_PAGE_POOL, rq->page_pool);
- if (err)
- page_pool_free(rq->page_pool);
}
if (err)
goto err_free;
@@ -644,6 +642,7 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
if (rq->xdp_prog)
bpf_prog_put(rq->xdp_prog);
xdp_rxq_info_unreg(&rq->xdp_rxq);
+ page_pool_destroy(rq->page_pool);
mlx5_wq_destroy(&rq->wq_ctrl);
return err;
@@ -678,6 +677,7 @@ static void mlx5e_free_rq(struct mlx5e_rq *rq)
}
xdp_rxq_info_unreg(&rq->xdp_rxq);
+ page_pool_destroy(rq->page_pool);
mlx5_wq_destroy(&rq->wq_ctrl);
}
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index 5544a722543f..43ab0ce90704 100644
--- a/drivers/net/ethernet/socionext/netsec.c
+++ b/drivers/net/ethernet/socionext/netsec.c
@@ -1210,15 +1210,11 @@ static void netsec_uninit_pkt_dring(struct netsec_priv *priv, int id)
}
}
- /* Rx is currently using page_pool
- * since the pool is created during netsec_setup_rx_dring(), we need to
- * free the pool manually if the registration failed
- */
+ /* Rx is currently using page_pool */
if (id == NETSEC_RING_RX) {
if (xdp_rxq_info_is_reg(&dring->xdp_rxq))
xdp_rxq_info_unreg(&dring->xdp_rxq);
- else
- page_pool_free(dring->page_pool);
+ page_pool_destroy(dring->page_pool);
}
memset(dring->desc, 0, sizeof(struct netsec_desc) * DESC_NUM);
diff --git a/include/net/page_pool.h b/include/net/page_pool.h
index ee9c871d2043..2cbcdbdec254 100644
--- a/include/net/page_pool.h
+++ b/include/net/page_pool.h
@@ -101,6 +101,12 @@ struct page_pool {
struct ptr_ring ring;
atomic_t pages_state_release_cnt;
+
+ /* A page_pool is strictly tied to a single RX-queue being
+ * protected by NAPI, due to above pp_alloc_cache. This
+ * refcnt serves purpose is to simplify drivers error handling.
+ */
+ refcount_t user_cnt;
};
struct page *page_pool_alloc_pages(struct page_pool *pool, gfp_t gfp);
@@ -134,6 +140,15 @@ static inline void page_pool_free(struct page_pool *pool)
#endif
}
+/* Drivers use this instead of page_pool_free */
+static inline void page_pool_destroy(struct page_pool *pool)
+{
+ if (!pool)
+ return;
+
+ page_pool_free(pool);
+}
+
/* Never call this directly, use helpers below */
void __page_pool_put_page(struct page_pool *pool,
struct page *page, bool allow_direct);
@@ -201,4 +216,14 @@ static inline bool is_page_pool_compiled_in(void)
#endif
}
+static inline void page_pool_get(struct page_pool *pool)
+{
+ refcount_inc(&pool->user_cnt);
+}
+
+static inline bool page_pool_put(struct page_pool *pool)
+{
+ return refcount_dec_and_test(&pool->user_cnt);
+}
+
#endif /* _NET_PAGE_POOL_H */
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
index b366f59885c1..3272dc7a8c81 100644
--- a/net/core/page_pool.c
+++ b/net/core/page_pool.c
@@ -49,6 +49,9 @@ static int page_pool_init(struct page_pool *pool,
atomic_set(&pool->pages_state_release_cnt, 0);
+ /* Driver calling page_pool_create() also call page_pool_destroy() */
+ refcount_set(&pool->user_cnt, 1);
+
if (pool->p.flags & PP_FLAG_DMA_MAP)
get_device(pool->p.dev);
@@ -70,6 +73,7 @@ struct page_pool *page_pool_create(const struct page_pool_params *params)
kfree(pool);
return ERR_PTR(err);
}
+
return pool;
}
EXPORT_SYMBOL(page_pool_create);
@@ -356,6 +360,10 @@ static void __warn_in_flight(struct page_pool *pool)
void __page_pool_free(struct page_pool *pool)
{
+ /* Only last user actually free/release resources */
+ if (!page_pool_put(pool))
+ return;
+
WARN(pool->alloc.count, "API usage violation");
WARN(!ptr_ring_empty(&pool->ring), "ptr_ring is not empty");
diff --git a/net/core/xdp.c b/net/core/xdp.c
index 829377cc83db..d7bf62ffbb5e 100644
--- a/net/core/xdp.c
+++ b/net/core/xdp.c
@@ -370,6 +370,9 @@ int xdp_rxq_info_reg_mem_model(struct xdp_rxq_info *xdp_rxq,
goto err;
}
+ if (type == MEM_TYPE_PAGE_POOL)
+ page_pool_get(xdp_alloc->page_pool);
+
mutex_unlock(&mem_id_lock);
trace_mem_connect(xdp_alloc, xdp_rxq);
--
2.17.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox