Commit 95dcd892 authored by David S. Miller's avatar David S. Miller

Merge branch 'several-fixes-for-indirect-flow_blocks-offload'

wenxu says:

====================
several fixes for indirect flow_blocks offload

v2:
patch2: store the cb_priv of representor to the flow_block_cb->indr.cb_priv
in the driver. And make the correct check with the statments
this->indr.cb_priv == cb_priv

patch4: del the driver list only in the indriect cleanup callbacks

v3:
add the cover letter and changlogs.

v4:
collapsed 1/4, 2/4, 4/4 in v3 to one fix
Add the prepare patch 1 and 2

v5:
patch1: place flow_indr_block_cb_alloc() right before
flow_indr_dev_setup_offload() to avoid moving flow_block_indr_init()

This series fixes commit 1fac52da ("net: flow_offload: consolidate
indirect flow_block infrastructure") that revists the flow_block
infrastructure.

patch #1 #2: prepare for fix patch #3
add and use flow_indr_block_cb_alloc/remove function

patch #3: fix flow_indr_dev_unregister path
If the representor is removed, then identify the indirect flow_blocks
that need to be removed by the release callback and the port representor
structure. To identify the port representor structure, a new
indr.cb_priv field needs to be introduced. The flow_block also needs to
be removed from the driver list from the cleanup path

patch#4 fix block->nooffloaddevcnt warning dmesg log.
When a indr device add in offload success. The block->nooffloaddevcnt
should be 0. After the representor go away. When the dir device go away
the flow_block UNBIND operation with -EOPNOTSUPP which lead the warning
demesg log.
The block->nooffloaddevcnt should always count for indr block.
even the indr block offload successful. The representor maybe
gone away and the ingress qdisc can work in software mode.
====================
Reviewed-by: default avatarSimon Horman <simon.horman@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 56c09de3 3c005110
...@@ -1889,7 +1889,8 @@ static void bnxt_tc_setup_indr_rel(void *cb_priv) ...@@ -1889,7 +1889,8 @@ static void bnxt_tc_setup_indr_rel(void *cb_priv)
} }
static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp, static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
struct flow_block_offload *f) struct flow_block_offload *f, void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
struct bnxt_flower_indr_block_cb_priv *cb_priv; struct bnxt_flower_indr_block_cb_priv *cb_priv;
struct flow_block_cb *block_cb; struct flow_block_cb *block_cb;
...@@ -1907,9 +1908,10 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp, ...@@ -1907,9 +1908,10 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
cb_priv->bp = bp; cb_priv->bp = bp;
list_add(&cb_priv->list, &bp->tc_indr_block_list); list_add(&cb_priv->list, &bp->tc_indr_block_list);
block_cb = flow_block_cb_alloc(bnxt_tc_setup_indr_block_cb, block_cb = flow_indr_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
cb_priv, cb_priv, cb_priv, cb_priv,
bnxt_tc_setup_indr_rel); bnxt_tc_setup_indr_rel, f,
netdev, data, bp, cleanup);
if (IS_ERR(block_cb)) { if (IS_ERR(block_cb)) {
list_del(&cb_priv->list); list_del(&cb_priv->list);
kfree(cb_priv); kfree(cb_priv);
...@@ -1930,7 +1932,7 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp, ...@@ -1930,7 +1932,7 @@ static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
if (!block_cb) if (!block_cb)
return -ENOENT; return -ENOENT;
flow_block_cb_remove(block_cb, f); flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
break; break;
default: default:
...@@ -1945,14 +1947,17 @@ static bool bnxt_is_netdev_indr_offload(struct net_device *netdev) ...@@ -1945,14 +1947,17 @@ static bool bnxt_is_netdev_indr_offload(struct net_device *netdev)
} }
static int bnxt_tc_setup_indr_cb(struct net_device *netdev, void *cb_priv, static int bnxt_tc_setup_indr_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data) enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
if (!bnxt_is_netdev_indr_offload(netdev)) if (!bnxt_is_netdev_indr_offload(netdev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
switch (type) { switch (type) {
case TC_SETUP_BLOCK: case TC_SETUP_BLOCK:
return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data); return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data, data,
cleanup);
default: default:
break; break;
} }
...@@ -2074,7 +2079,7 @@ void bnxt_shutdown_tc(struct bnxt *bp) ...@@ -2074,7 +2079,7 @@ void bnxt_shutdown_tc(struct bnxt *bp)
return; return;
flow_indr_dev_unregister(bnxt_tc_setup_indr_cb, bp, flow_indr_dev_unregister(bnxt_tc_setup_indr_cb, bp,
bnxt_tc_setup_indr_block_cb); bnxt_tc_setup_indr_rel);
rhashtable_destroy(&tc_info->flow_table); rhashtable_destroy(&tc_info->flow_table);
rhashtable_destroy(&tc_info->l2_table); rhashtable_destroy(&tc_info->l2_table);
rhashtable_destroy(&tc_info->decap_l2_table); rhashtable_destroy(&tc_info->decap_l2_table);
......
...@@ -407,7 +407,9 @@ static int ...@@ -407,7 +407,9 @@ static int
mlx5e_rep_indr_setup_block(struct net_device *netdev, mlx5e_rep_indr_setup_block(struct net_device *netdev,
struct mlx5e_rep_priv *rpriv, struct mlx5e_rep_priv *rpriv,
struct flow_block_offload *f, struct flow_block_offload *f,
flow_setup_cb_t *setup_cb) flow_setup_cb_t *setup_cb,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
struct mlx5e_priv *priv = netdev_priv(rpriv->netdev); struct mlx5e_priv *priv = netdev_priv(rpriv->netdev);
struct mlx5e_rep_indr_block_priv *indr_priv; struct mlx5e_rep_indr_block_priv *indr_priv;
...@@ -438,8 +440,10 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, ...@@ -438,8 +440,10 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev,
list_add(&indr_priv->list, list_add(&indr_priv->list,
&rpriv->uplink_priv.tc_indr_block_priv_list); &rpriv->uplink_priv.tc_indr_block_priv_list);
block_cb = flow_block_cb_alloc(setup_cb, indr_priv, indr_priv, block_cb = flow_indr_block_cb_alloc(setup_cb, indr_priv, indr_priv,
mlx5e_rep_indr_block_unbind); mlx5e_rep_indr_block_unbind,
f, netdev, data, rpriv,
cleanup);
if (IS_ERR(block_cb)) { if (IS_ERR(block_cb)) {
list_del(&indr_priv->list); list_del(&indr_priv->list);
kfree(indr_priv); kfree(indr_priv);
...@@ -458,7 +462,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, ...@@ -458,7 +462,7 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev,
if (!block_cb) if (!block_cb)
return -ENOENT; return -ENOENT;
flow_block_cb_remove(block_cb, f); flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
return 0; return 0;
default: default:
...@@ -469,15 +473,19 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev, ...@@ -469,15 +473,19 @@ mlx5e_rep_indr_setup_block(struct net_device *netdev,
static static
int mlx5e_rep_indr_setup_cb(struct net_device *netdev, void *cb_priv, int mlx5e_rep_indr_setup_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data) enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
switch (type) { switch (type) {
case TC_SETUP_BLOCK: case TC_SETUP_BLOCK:
return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data, return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data,
mlx5e_rep_indr_setup_tc_cb); mlx5e_rep_indr_setup_tc_cb,
data, cleanup);
case TC_SETUP_FT: case TC_SETUP_FT:
return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data, return mlx5e_rep_indr_setup_block(netdev, cb_priv, type_data,
mlx5e_rep_indr_setup_ft_cb); mlx5e_rep_indr_setup_ft_cb,
data, cleanup);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -496,7 +504,7 @@ int mlx5e_rep_tc_netdevice_event_register(struct mlx5e_rep_priv *rpriv) ...@@ -496,7 +504,7 @@ int mlx5e_rep_tc_netdevice_event_register(struct mlx5e_rep_priv *rpriv)
void mlx5e_rep_tc_netdevice_event_unregister(struct mlx5e_rep_priv *rpriv) void mlx5e_rep_tc_netdevice_event_unregister(struct mlx5e_rep_priv *rpriv)
{ {
flow_indr_dev_unregister(mlx5e_rep_indr_setup_cb, rpriv, flow_indr_dev_unregister(mlx5e_rep_indr_setup_cb, rpriv,
mlx5e_rep_indr_setup_tc_cb); mlx5e_rep_indr_block_unbind);
} }
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT) #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
......
...@@ -861,7 +861,7 @@ static void nfp_flower_clean(struct nfp_app *app) ...@@ -861,7 +861,7 @@ static void nfp_flower_clean(struct nfp_app *app)
flush_work(&app_priv->cmsg_work); flush_work(&app_priv->cmsg_work);
flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app, flow_indr_dev_unregister(nfp_flower_indr_setup_tc_cb, app,
nfp_flower_setup_indr_block_cb); nfp_flower_setup_indr_tc_release);
if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM) if (app_priv->flower_ext_feats & NFP_FL_FEATS_VF_RLIM)
nfp_flower_qos_cleanup(app); nfp_flower_qos_cleanup(app);
......
...@@ -459,9 +459,10 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev, ...@@ -459,9 +459,10 @@ int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow); struct tc_cls_matchall_offload *flow);
void nfp_flower_stats_rlim_reply(struct nfp_app *app, struct sk_buff *skb); void nfp_flower_stats_rlim_reply(struct nfp_app *app, struct sk_buff *skb);
int nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv, int nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data); enum tc_setup_type type, void *type_data,
int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, void *type_data, void *data,
void *cb_priv); void (*cleanup)(struct flow_block_cb *block_cb));
void nfp_flower_setup_indr_tc_release(void *cb_priv);
void void
__nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv); __nfp_flower_non_repr_priv_get(struct nfp_flower_non_repr_priv *non_repr_priv);
......
...@@ -1619,8 +1619,8 @@ nfp_flower_indr_block_cb_priv_lookup(struct nfp_app *app, ...@@ -1619,8 +1619,8 @@ nfp_flower_indr_block_cb_priv_lookup(struct nfp_app *app,
return NULL; return NULL;
} }
int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, static int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
void *type_data, void *cb_priv) void *type_data, void *cb_priv)
{ {
struct nfp_flower_indr_block_cb_priv *priv = cb_priv; struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
struct flow_cls_offload *flower = type_data; struct flow_cls_offload *flower = type_data;
...@@ -1637,7 +1637,7 @@ int nfp_flower_setup_indr_block_cb(enum tc_setup_type type, ...@@ -1637,7 +1637,7 @@ int nfp_flower_setup_indr_block_cb(enum tc_setup_type type,
} }
} }
static void nfp_flower_setup_indr_tc_release(void *cb_priv) void nfp_flower_setup_indr_tc_release(void *cb_priv)
{ {
struct nfp_flower_indr_block_cb_priv *priv = cb_priv; struct nfp_flower_indr_block_cb_priv *priv = cb_priv;
...@@ -1647,7 +1647,8 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv) ...@@ -1647,7 +1647,8 @@ static void nfp_flower_setup_indr_tc_release(void *cb_priv)
static int static int
nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app, nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
struct flow_block_offload *f) struct flow_block_offload *f, void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
struct nfp_flower_indr_block_cb_priv *cb_priv; struct nfp_flower_indr_block_cb_priv *cb_priv;
struct nfp_flower_priv *priv = app->priv; struct nfp_flower_priv *priv = app->priv;
...@@ -1676,9 +1677,10 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app, ...@@ -1676,9 +1677,10 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
cb_priv->app = app; cb_priv->app = app;
list_add(&cb_priv->list, &priv->indr_block_cb_priv); list_add(&cb_priv->list, &priv->indr_block_cb_priv);
block_cb = flow_block_cb_alloc(nfp_flower_setup_indr_block_cb, block_cb = flow_indr_block_cb_alloc(nfp_flower_setup_indr_block_cb,
cb_priv, cb_priv, cb_priv, cb_priv,
nfp_flower_setup_indr_tc_release); nfp_flower_setup_indr_tc_release,
f, netdev, data, app, cleanup);
if (IS_ERR(block_cb)) { if (IS_ERR(block_cb)) {
list_del(&cb_priv->list); list_del(&cb_priv->list);
kfree(cb_priv); kfree(cb_priv);
...@@ -1699,7 +1701,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app, ...@@ -1699,7 +1701,7 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
if (!block_cb) if (!block_cb)
return -ENOENT; return -ENOENT;
flow_block_cb_remove(block_cb, f); flow_indr_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list); list_del(&block_cb->driver_list);
return 0; return 0;
default: default:
...@@ -1710,7 +1712,9 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app, ...@@ -1710,7 +1712,9 @@ nfp_flower_setup_indr_tc_block(struct net_device *netdev, struct nfp_app *app,
int int
nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv, nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data) enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
if (!nfp_fl_is_netdev_to_offload(netdev)) if (!nfp_fl_is_netdev_to_offload(netdev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -1718,7 +1722,7 @@ nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv, ...@@ -1718,7 +1722,7 @@ nfp_flower_indr_setup_tc_cb(struct net_device *netdev, void *cb_priv,
switch (type) { switch (type) {
case TC_SETUP_BLOCK: case TC_SETUP_BLOCK:
return nfp_flower_setup_indr_tc_block(netdev, cb_priv, return nfp_flower_setup_indr_tc_block(netdev, cb_priv,
type_data); type_data, data, cleanup);
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -450,6 +450,7 @@ struct flow_block_indr { ...@@ -450,6 +450,7 @@ struct flow_block_indr {
struct net_device *dev; struct net_device *dev;
enum flow_block_binder_type binder_type; enum flow_block_binder_type binder_type;
void *data; void *data;
void *cb_priv;
void (*cleanup)(struct flow_block_cb *block_cb); void (*cleanup)(struct flow_block_cb *block_cb);
}; };
...@@ -467,6 +468,13 @@ struct flow_block_cb { ...@@ -467,6 +468,13 @@ struct flow_block_cb {
struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb, struct flow_block_cb *flow_block_cb_alloc(flow_setup_cb_t *cb,
void *cb_ident, void *cb_priv, void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv)); void (*release)(void *cb_priv));
struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
void *cb_ident, void *cb_priv,
void (*release)(void *cb_priv),
struct flow_block_offload *bo,
struct net_device *dev, void *data,
void *indr_cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb));
void flow_block_cb_free(struct flow_block_cb *block_cb); void flow_block_cb_free(struct flow_block_cb *block_cb);
struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block, struct flow_block_cb *flow_block_cb_lookup(struct flow_block *block,
...@@ -488,6 +496,13 @@ static inline void flow_block_cb_remove(struct flow_block_cb *block_cb, ...@@ -488,6 +496,13 @@ static inline void flow_block_cb_remove(struct flow_block_cb *block_cb,
list_move(&block_cb->list, &offload->cb_list); list_move(&block_cb->list, &offload->cb_list);
} }
static inline void flow_indr_block_cb_remove(struct flow_block_cb *block_cb,
struct flow_block_offload *offload)
{
list_del(&block_cb->indr.list);
list_move(&block_cb->list, &offload->cb_list);
}
bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident, bool flow_block_cb_is_busy(flow_setup_cb_t *cb, void *cb_ident,
struct list_head *driver_block_list); struct list_head *driver_block_list);
...@@ -532,11 +547,13 @@ static inline void flow_block_init(struct flow_block *flow_block) ...@@ -532,11 +547,13 @@ static inline void flow_block_init(struct flow_block *flow_block)
} }
typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv, typedef int flow_indr_block_bind_cb_t(struct net_device *dev, void *cb_priv,
enum tc_setup_type type, void *type_data); enum tc_setup_type type, void *type_data,
void *data,
void (*cleanup)(struct flow_block_cb *block_cb));
int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv); int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv);
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv, void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
flow_setup_cb_t *setup_cb); void (*release)(void *cb_priv));
int flow_indr_dev_setup_offload(struct net_device *dev, int flow_indr_dev_setup_offload(struct net_device *dev,
enum tc_setup_type type, void *data, enum tc_setup_type type, void *data,
struct flow_block_offload *bo, struct flow_block_offload *bo,
......
...@@ -372,14 +372,15 @@ int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv) ...@@ -372,14 +372,15 @@ int flow_indr_dev_register(flow_indr_block_bind_cb_t *cb, void *cb_priv)
} }
EXPORT_SYMBOL(flow_indr_dev_register); EXPORT_SYMBOL(flow_indr_dev_register);
static void __flow_block_indr_cleanup(flow_setup_cb_t *setup_cb, void *cb_priv, static void __flow_block_indr_cleanup(void (*release)(void *cb_priv),
void *cb_priv,
struct list_head *cleanup_list) struct list_head *cleanup_list)
{ {
struct flow_block_cb *this, *next; struct flow_block_cb *this, *next;
list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) { list_for_each_entry_safe(this, next, &flow_block_indr_list, indr.list) {
if (this->cb == setup_cb && if (this->release == release &&
this->cb_priv == cb_priv) { this->indr.cb_priv == cb_priv) {
list_move(&this->indr.list, cleanup_list); list_move(&this->indr.list, cleanup_list);
return; return;
} }
...@@ -397,7 +398,7 @@ static void flow_block_indr_notify(struct list_head *cleanup_list) ...@@ -397,7 +398,7 @@ static void flow_block_indr_notify(struct list_head *cleanup_list)
} }
void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv, void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
flow_setup_cb_t *setup_cb) void (*release)(void *cb_priv))
{ {
struct flow_indr_dev *this, *next, *indr_dev = NULL; struct flow_indr_dev *this, *next, *indr_dev = NULL;
LIST_HEAD(cleanup_list); LIST_HEAD(cleanup_list);
...@@ -418,7 +419,7 @@ void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv, ...@@ -418,7 +419,7 @@ void flow_indr_dev_unregister(flow_indr_block_bind_cb_t *cb, void *cb_priv,
return; return;
} }
__flow_block_indr_cleanup(setup_cb, cb_priv, &cleanup_list); __flow_block_indr_cleanup(release, cb_priv, &cleanup_list);
mutex_unlock(&flow_indr_block_lock); mutex_unlock(&flow_indr_block_lock);
flow_block_indr_notify(&cleanup_list); flow_block_indr_notify(&cleanup_list);
...@@ -429,32 +430,37 @@ EXPORT_SYMBOL(flow_indr_dev_unregister); ...@@ -429,32 +430,37 @@ EXPORT_SYMBOL(flow_indr_dev_unregister);
static void flow_block_indr_init(struct flow_block_cb *flow_block, static void flow_block_indr_init(struct flow_block_cb *flow_block,
struct flow_block_offload *bo, struct flow_block_offload *bo,
struct net_device *dev, void *data, struct net_device *dev, void *data,
void *cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb)) void (*cleanup)(struct flow_block_cb *block_cb))
{ {
flow_block->indr.binder_type = bo->binder_type; flow_block->indr.binder_type = bo->binder_type;
flow_block->indr.data = data; flow_block->indr.data = data;
flow_block->indr.cb_priv = cb_priv;
flow_block->indr.dev = dev; flow_block->indr.dev = dev;
flow_block->indr.cleanup = cleanup; flow_block->indr.cleanup = cleanup;
} }
static void __flow_block_indr_binding(struct flow_block_offload *bo, struct flow_block_cb *flow_indr_block_cb_alloc(flow_setup_cb_t *cb,
struct net_device *dev, void *data, void *cb_ident, void *cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb)) void (*release)(void *cb_priv),
struct flow_block_offload *bo,
struct net_device *dev, void *data,
void *indr_cb_priv,
void (*cleanup)(struct flow_block_cb *block_cb))
{ {
struct flow_block_cb *block_cb; struct flow_block_cb *block_cb;
list_for_each_entry(block_cb, &bo->cb_list, list) { block_cb = flow_block_cb_alloc(cb, cb_ident, cb_priv, release);
switch (bo->command) { if (IS_ERR(block_cb))
case FLOW_BLOCK_BIND: goto out;
flow_block_indr_init(block_cb, bo, dev, data, cleanup);
list_add(&block_cb->indr.list, &flow_block_indr_list); flow_block_indr_init(block_cb, bo, dev, data, indr_cb_priv, cleanup);
break; list_add(&block_cb->indr.list, &flow_block_indr_list);
case FLOW_BLOCK_UNBIND:
list_del(&block_cb->indr.list); out:
break; return block_cb;
}
}
} }
EXPORT_SYMBOL(flow_indr_block_cb_alloc);
int flow_indr_dev_setup_offload(struct net_device *dev, int flow_indr_dev_setup_offload(struct net_device *dev,
enum tc_setup_type type, void *data, enum tc_setup_type type, void *data,
...@@ -465,9 +471,8 @@ int flow_indr_dev_setup_offload(struct net_device *dev, ...@@ -465,9 +471,8 @@ int flow_indr_dev_setup_offload(struct net_device *dev,
mutex_lock(&flow_indr_block_lock); mutex_lock(&flow_indr_block_lock);
list_for_each_entry(this, &flow_block_indr_dev_list, list) list_for_each_entry(this, &flow_block_indr_dev_list, list)
this->cb(dev, this->cb_priv, type, bo); this->cb(dev, this->cb_priv, type, bo, data, cleanup);
__flow_block_indr_binding(bo, dev, data, cleanup);
mutex_unlock(&flow_indr_block_lock); mutex_unlock(&flow_indr_block_lock);
return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0; return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0;
......
...@@ -950,6 +950,7 @@ static void nf_flow_table_indr_cleanup(struct flow_block_cb *block_cb) ...@@ -950,6 +950,7 @@ static void nf_flow_table_indr_cleanup(struct flow_block_cb *block_cb)
nf_flow_table_gc_cleanup(flowtable, dev); nf_flow_table_gc_cleanup(flowtable, dev);
down_write(&flowtable->flow_block_lock); down_write(&flowtable->flow_block_lock);
list_del(&block_cb->list); list_del(&block_cb->list);
list_del(&block_cb->driver_list);
flow_block_cb_free(block_cb); flow_block_cb_free(block_cb);
up_write(&flowtable->flow_block_lock); up_write(&flowtable->flow_block_lock);
} }
......
...@@ -296,6 +296,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb) ...@@ -296,6 +296,7 @@ static void nft_indr_block_cleanup(struct flow_block_cb *block_cb)
nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND, nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
basechain, &extack); basechain, &extack);
mutex_lock(&net->nft.commit_mutex); mutex_lock(&net->nft.commit_mutex);
list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list); list_move(&block_cb->list, &bo.cb_list);
nft_flow_offload_unbind(&bo, basechain); nft_flow_offload_unbind(&bo, basechain);
mutex_unlock(&net->nft.commit_mutex); mutex_unlock(&net->nft.commit_mutex);
......
...@@ -652,6 +652,7 @@ static void tc_block_indr_cleanup(struct flow_block_cb *block_cb) ...@@ -652,6 +652,7 @@ static void tc_block_indr_cleanup(struct flow_block_cb *block_cb)
&block->flow_block, tcf_block_shared(block), &block->flow_block, tcf_block_shared(block),
&extack); &extack);
down_write(&block->cb_lock); down_write(&block->cb_lock);
list_del(&block_cb->driver_list);
list_move(&block_cb->list, &bo.cb_list); list_move(&block_cb->list, &bo.cb_list);
up_write(&block->cb_lock); up_write(&block->cb_lock);
rtnl_lock(); rtnl_lock();
...@@ -671,25 +672,29 @@ static int tcf_block_offload_cmd(struct tcf_block *block, ...@@ -671,25 +672,29 @@ static int tcf_block_offload_cmd(struct tcf_block *block,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct flow_block_offload bo = {}; struct flow_block_offload bo = {};
int err;
tcf_block_offload_init(&bo, dev, command, ei->binder_type, tcf_block_offload_init(&bo, dev, command, ei->binder_type,
&block->flow_block, tcf_block_shared(block), &block->flow_block, tcf_block_shared(block),
extack); extack);
if (dev->netdev_ops->ndo_setup_tc) if (dev->netdev_ops->ndo_setup_tc) {
int err;
err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo); err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_BLOCK, &bo);
else if (err < 0) {
err = flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block, if (err != -EOPNOTSUPP)
&bo, tc_block_indr_cleanup); NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
return err;
}
if (err < 0) { return tcf_block_setup(block, &bo);
if (err != -EOPNOTSUPP)
NL_SET_ERR_MSG(extack, "Driver ndo_setup_tc failed");
return err;
} }
return tcf_block_setup(block, &bo); flow_indr_dev_setup_offload(dev, TC_SETUP_BLOCK, block, &bo,
tc_block_indr_cleanup);
tcf_block_setup(block, &bo);
return -EOPNOTSUPP;
} }
static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q, static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment