Commit b274f6db authored by David S. Miller's avatar David S. Miller

Merge branch 'net-sched-get-rid-of-cls_flower-egress_dev'

Jiri Pirko says:

====================
net: sched: get rid of cls_flower->egress_dev

Introduction of cls_flower->egress_dev was a workaround. Turned out
to be a bit ugly hack. So replace it with more generic and reusable
infrastructure.

This is a dependency of shared block introduction that will be send as
a follow-up patchsets group.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7c6a86b4 7578d7b4
...@@ -1081,6 +1081,9 @@ int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, ...@@ -1081,6 +1081,9 @@ int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
struct ethtool_flash *flash); struct ethtool_flash *flash);
int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
/* mlx5e generic netdev management API */ /* mlx5e generic netdev management API */
struct net_device* struct net_device*
mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile, mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile,
......
...@@ -3108,7 +3108,7 @@ static int mlx5e_setup_tc_cls_flower(struct net_device *dev, ...@@ -3108,7 +3108,7 @@ static int mlx5e_setup_tc_cls_flower(struct net_device *dev,
} }
#endif #endif
static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type, int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data) void *type_data)
{ {
switch (type) { switch (type) {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/mlx5/fs.h> #include <linux/mlx5/fs.h>
#include <net/switchdev.h> #include <net/switchdev.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/act_api.h>
#include <net/netevent.h> #include <net/netevent.h>
#include <net/arp.h> #include <net/arp.h>
...@@ -667,14 +668,6 @@ mlx5e_rep_setup_tc_cls_flower(struct net_device *dev, ...@@ -667,14 +668,6 @@ mlx5e_rep_setup_tc_cls_flower(struct net_device *dev,
cls_flower->common.chain_index) cls_flower->common.chain_index)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (cls_flower->egress_dev) {
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
dev = mlx5_eswitch_get_uplink_netdev(esw);
return dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER,
cls_flower);
}
switch (cls_flower->command) { switch (cls_flower->command) {
case TC_CLSFLOWER_REPLACE: case TC_CLSFLOWER_REPLACE:
return mlx5e_configure_flower(priv, cls_flower); return mlx5e_configure_flower(priv, cls_flower);
...@@ -698,6 +691,14 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, ...@@ -698,6 +691,14 @@ static int mlx5e_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
} }
} }
static int mlx5e_rep_setup_tc_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
struct net_device *dev = cb_priv;
return mlx5e_setup_tc(dev, type, type_data);
}
bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv) bool mlx5e_is_uplink_rep(struct mlx5e_priv *priv)
{ {
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
...@@ -1017,15 +1018,24 @@ mlx5e_vport_rep_load(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep) ...@@ -1017,15 +1018,24 @@ mlx5e_vport_rep_load(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep)
goto err_detach_netdev; goto err_detach_netdev;
} }
err = tc_setup_cb_egdev_register(netdev, mlx5e_rep_setup_tc_cb,
mlx5_eswitch_get_uplink_netdev(esw));
if (err)
goto err_neigh_cleanup;
err = register_netdev(netdev); err = register_netdev(netdev);
if (err) { if (err) {
pr_warn("Failed to register representor netdev for vport %d\n", pr_warn("Failed to register representor netdev for vport %d\n",
rep->vport); rep->vport);
goto err_neigh_cleanup; goto err_egdev_cleanup;
} }
return 0; return 0;
err_egdev_cleanup:
tc_setup_cb_egdev_unregister(netdev, mlx5e_rep_setup_tc_cb,
mlx5_eswitch_get_uplink_netdev(esw));
err_neigh_cleanup: err_neigh_cleanup:
mlx5e_rep_neigh_cleanup(rpriv); mlx5e_rep_neigh_cleanup(rpriv);
...@@ -1047,7 +1057,8 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep) ...@@ -1047,7 +1057,8 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch *esw, struct mlx5_eswitch_rep *rep)
void *ppriv = priv->ppriv; void *ppriv = priv->ppriv;
unregister_netdev(rep->netdev); unregister_netdev(rep->netdev);
tc_setup_cb_egdev_unregister(netdev, mlx5e_rep_setup_tc_cb,
mlx5_eswitch_get_uplink_netdev(esw));
mlx5e_rep_neigh_cleanup(rpriv); mlx5e_rep_neigh_cleanup(rpriv);
mlx5e_detach_netdev(priv); mlx5e_detach_netdev(priv);
mlx5e_destroy_netdev(priv); mlx5e_destroy_netdev(priv);
......
...@@ -93,8 +93,7 @@ struct tc_action_ops { ...@@ -93,8 +93,7 @@ struct tc_action_ops {
int (*walk)(struct net *, struct sk_buff *, int (*walk)(struct net *, struct sk_buff *,
struct netlink_callback *, int, const struct tc_action_ops *); struct netlink_callback *, int, const struct tc_action_ops *);
void (*stats_update)(struct tc_action *, u64, u32, u64); void (*stats_update)(struct tc_action *, u64, u32, u64);
int (*get_dev)(const struct tc_action *a, struct net *net, struct net_device *(*get_dev)(const struct tc_action *a);
struct net_device **mirred_dev);
}; };
struct tc_action_net { struct tc_action_net {
...@@ -175,4 +174,38 @@ static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes, ...@@ -175,4 +174,38 @@ static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes,
#endif #endif
} }
typedef int tc_setup_cb_t(enum tc_setup_type type,
void *type_data, void *cb_priv);
#ifdef CONFIG_NET_CLS_ACT
int tc_setup_cb_egdev_register(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv);
void tc_setup_cb_egdev_unregister(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv);
int tc_setup_cb_egdev_call(const struct net_device *dev,
enum tc_setup_type type, void *type_data,
bool err_stop);
#else
static inline
int tc_setup_cb_egdev_register(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
return 0;
}
static inline
void tc_setup_cb_egdev_unregister(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
}
static inline
int tc_setup_cb_egdev_call(const struct net_device *dev,
enum tc_setup_type type, void *type_data,
bool err_stop)
{
return 0;
}
#endif
#endif #endif
...@@ -204,8 +204,6 @@ void tcf_exts_destroy(struct tcf_exts *exts); ...@@ -204,8 +204,6 @@ void tcf_exts_destroy(struct tcf_exts *exts);
void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src); void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src);
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts); int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts);
int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts); int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts);
int tcf_exts_get_dev(struct net_device *dev, struct tcf_exts *exts,
struct net_device **hw_dev);
/** /**
* struct tcf_pkt_info - packet information * struct tcf_pkt_info - packet information
...@@ -405,6 +403,9 @@ tcf_match_indev(struct sk_buff *skb, int ifindex) ...@@ -405,6 +403,9 @@ tcf_match_indev(struct sk_buff *skb, int ifindex)
} }
#endif /* CONFIG_NET_CLS_IND */ #endif /* CONFIG_NET_CLS_IND */
int tc_setup_cb_call(struct tcf_exts *exts, enum tc_setup_type type,
void *type_data, bool err_stop);
struct tc_cls_common_offload { struct tc_cls_common_offload {
u32 chain_index; u32 chain_index;
__be16 protocol; __be16 protocol;
...@@ -514,7 +515,6 @@ struct tc_cls_flower_offload { ...@@ -514,7 +515,6 @@ struct tc_cls_flower_offload {
struct fl_flow_key *mask; struct fl_flow_key *mask;
struct fl_flow_key *key; struct fl_flow_key *key;
struct tcf_exts *exts; struct tcf_exts *exts;
bool egress_dev;
}; };
enum tc_matchall_command { enum tc_matchall_command {
......
...@@ -10,6 +10,7 @@ struct tcf_mirred { ...@@ -10,6 +10,7 @@ struct tcf_mirred {
int tcfm_ifindex; int tcfm_ifindex;
bool tcfm_mac_header_xmit; bool tcfm_mac_header_xmit;
struct net_device __rcu *tcfm_dev; struct net_device __rcu *tcfm_dev;
struct net *net;
struct list_head tcfm_list; struct list_head tcfm_list;
}; };
#define to_mirred(a) ((struct tcf_mirred *)a) #define to_mirred(a) ((struct tcf_mirred *)a)
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/rhashtable.h>
#include <linux/list.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/sch_generic.h> #include <net/sch_generic.h>
...@@ -1249,8 +1251,226 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1249,8 +1251,226 @@ static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
struct tcf_action_net {
struct rhashtable egdev_ht;
};
static unsigned int tcf_action_net_id;
struct tcf_action_egdev_cb {
struct list_head list;
tc_setup_cb_t *cb;
void *cb_priv;
};
struct tcf_action_egdev {
struct rhash_head ht_node;
const struct net_device *dev;
unsigned int refcnt;
struct list_head cb_list;
};
static const struct rhashtable_params tcf_action_egdev_ht_params = {
.key_offset = offsetof(struct tcf_action_egdev, dev),
.head_offset = offsetof(struct tcf_action_egdev, ht_node),
.key_len = sizeof(const struct net_device *),
};
static struct tcf_action_egdev *
tcf_action_egdev_lookup(const struct net_device *dev)
{
struct net *net = dev_net(dev);
struct tcf_action_net *tan = net_generic(net, tcf_action_net_id);
return rhashtable_lookup_fast(&tan->egdev_ht, &dev,
tcf_action_egdev_ht_params);
}
static struct tcf_action_egdev *
tcf_action_egdev_get(const struct net_device *dev)
{
struct tcf_action_egdev *egdev;
struct tcf_action_net *tan;
egdev = tcf_action_egdev_lookup(dev);
if (egdev)
goto inc_ref;
egdev = kzalloc(sizeof(*egdev), GFP_KERNEL);
if (!egdev)
return NULL;
INIT_LIST_HEAD(&egdev->cb_list);
tan = net_generic(dev_net(dev), tcf_action_net_id);
rhashtable_insert_fast(&tan->egdev_ht, &egdev->ht_node,
tcf_action_egdev_ht_params);
inc_ref:
egdev->refcnt++;
return egdev;
}
static void tcf_action_egdev_put(struct tcf_action_egdev *egdev)
{
struct tcf_action_net *tan;
if (--egdev->refcnt)
return;
tan = net_generic(dev_net(egdev->dev), tcf_action_net_id);
rhashtable_remove_fast(&tan->egdev_ht, &egdev->ht_node,
tcf_action_egdev_ht_params);
kfree(egdev);
}
static struct tcf_action_egdev_cb *
tcf_action_egdev_cb_lookup(struct tcf_action_egdev *egdev,
tc_setup_cb_t *cb, void *cb_priv)
{
struct tcf_action_egdev_cb *egdev_cb;
list_for_each_entry(egdev_cb, &egdev->cb_list, list)
if (egdev_cb->cb == cb && egdev_cb->cb_priv == cb_priv)
return egdev_cb;
return NULL;
}
static int tcf_action_egdev_cb_call(struct tcf_action_egdev *egdev,
enum tc_setup_type type,
void *type_data, bool err_stop)
{
struct tcf_action_egdev_cb *egdev_cb;
int ok_count = 0;
int err;
list_for_each_entry(egdev_cb, &egdev->cb_list, list) {
err = egdev_cb->cb(type, type_data, egdev_cb->cb_priv);
if (err) {
if (err_stop)
return err;
} else {
ok_count++;
}
}
return ok_count;
}
static int tcf_action_egdev_cb_add(struct tcf_action_egdev *egdev,
tc_setup_cb_t *cb, void *cb_priv)
{
struct tcf_action_egdev_cb *egdev_cb;
egdev_cb = tcf_action_egdev_cb_lookup(egdev, cb, cb_priv);
if (WARN_ON(egdev_cb))
return -EEXIST;
egdev_cb = kzalloc(sizeof(*egdev_cb), GFP_KERNEL);
if (!egdev_cb)
return -ENOMEM;
egdev_cb->cb = cb;
egdev_cb->cb_priv = cb_priv;
list_add(&egdev_cb->list, &egdev->cb_list);
return 0;
}
static void tcf_action_egdev_cb_del(struct tcf_action_egdev *egdev,
tc_setup_cb_t *cb, void *cb_priv)
{
struct tcf_action_egdev_cb *egdev_cb;
egdev_cb = tcf_action_egdev_cb_lookup(egdev, cb, cb_priv);
if (WARN_ON(!egdev_cb))
return;
list_del(&egdev_cb->list);
kfree(egdev_cb);
}
static int __tc_setup_cb_egdev_register(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
struct tcf_action_egdev *egdev = tcf_action_egdev_get(dev);
int err;
if (!egdev)
return -ENOMEM;
err = tcf_action_egdev_cb_add(egdev, cb, cb_priv);
if (err)
goto err_cb_add;
return 0;
err_cb_add:
tcf_action_egdev_put(egdev);
return err;
}
int tc_setup_cb_egdev_register(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
int err;
rtnl_lock();
err = __tc_setup_cb_egdev_register(dev, cb, cb_priv);
rtnl_unlock();
return err;
}
EXPORT_SYMBOL_GPL(tc_setup_cb_egdev_register);
static void __tc_setup_cb_egdev_unregister(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
struct tcf_action_egdev *egdev = tcf_action_egdev_lookup(dev);
if (WARN_ON(!egdev))
return;
tcf_action_egdev_cb_del(egdev, cb, cb_priv);
tcf_action_egdev_put(egdev);
}
void tc_setup_cb_egdev_unregister(const struct net_device *dev,
tc_setup_cb_t *cb, void *cb_priv)
{
rtnl_lock();
__tc_setup_cb_egdev_unregister(dev, cb, cb_priv);
rtnl_unlock();
}
EXPORT_SYMBOL_GPL(tc_setup_cb_egdev_unregister);
int tc_setup_cb_egdev_call(const struct net_device *dev,
enum tc_setup_type type, void *type_data,
bool err_stop)
{
struct tcf_action_egdev *egdev = tcf_action_egdev_lookup(dev);
if (!egdev)
return 0;
return tcf_action_egdev_cb_call(egdev, type, type_data, err_stop);
}
EXPORT_SYMBOL_GPL(tc_setup_cb_egdev_call);
static __net_init int tcf_action_net_init(struct net *net)
{
struct tcf_action_net *tan = net_generic(net, tcf_action_net_id);
return rhashtable_init(&tan->egdev_ht, &tcf_action_egdev_ht_params);
}
static void __net_exit tcf_action_net_exit(struct net *net)
{
struct tcf_action_net *tan = net_generic(net, tcf_action_net_id);
rhashtable_destroy(&tan->egdev_ht);
}
static struct pernet_operations tcf_action_net_ops = {
.init = tcf_action_net_init,
.exit = tcf_action_net_exit,
.id = &tcf_action_net_id,
.size = sizeof(struct tcf_action_net),
};
static int __init tc_action_init(void) static int __init tc_action_init(void)
{ {
int err;
err = register_pernet_subsys(&tcf_action_net_ops);
if (err)
return err;
rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, 0); rtnl_register(PF_UNSPEC, RTM_NEWACTION, tc_ctl_action, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, 0); rtnl_register(PF_UNSPEC, RTM_DELACTION, tc_ctl_action, NULL, 0);
rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action, rtnl_register(PF_UNSPEC, RTM_GETACTION, tc_ctl_action, tc_dump_action,
......
...@@ -140,6 +140,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, ...@@ -140,6 +140,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
m->tcfm_eaction = parm->eaction; m->tcfm_eaction = parm->eaction;
if (dev != NULL) { if (dev != NULL) {
m->tcfm_ifindex = parm->ifindex; m->tcfm_ifindex = parm->ifindex;
m->net = net;
if (ret != ACT_P_CREATED) if (ret != ACT_P_CREATED)
dev_put(rcu_dereference_protected(m->tcfm_dev, 1)); dev_put(rcu_dereference_protected(m->tcfm_dev, 1));
dev_hold(dev); dev_hold(dev);
...@@ -313,15 +314,11 @@ static struct notifier_block mirred_device_notifier = { ...@@ -313,15 +314,11 @@ static struct notifier_block mirred_device_notifier = {
.notifier_call = mirred_device_event, .notifier_call = mirred_device_event,
}; };
static int tcf_mirred_device(const struct tc_action *a, struct net *net, static struct net_device *tcf_mirred_get_dev(const struct tc_action *a)
struct net_device **mirred_dev)
{ {
int ifindex = tcf_mirred_ifindex(a); struct tcf_mirred *m = to_mirred(a);
*mirred_dev = __dev_get_by_index(net, ifindex); return __dev_get_by_index(m->net, m->tcfm_ifindex);
if (!*mirred_dev)
return -EINVAL;
return 0;
} }
static struct tc_action_ops act_mirred_ops = { static struct tc_action_ops act_mirred_ops = {
...@@ -336,7 +333,7 @@ static struct tc_action_ops act_mirred_ops = { ...@@ -336,7 +333,7 @@ static struct tc_action_ops act_mirred_ops = {
.walk = tcf_mirred_walker, .walk = tcf_mirred_walker,
.lookup = tcf_mirred_search, .lookup = tcf_mirred_search,
.size = sizeof(struct tcf_mirred), .size = sizeof(struct tcf_mirred),
.get_dev = tcf_mirred_device, .get_dev = tcf_mirred_get_dev,
}; };
static __net_init int mirred_init_net(struct net *net) static __net_init int mirred_init_net(struct net *net)
......
...@@ -1004,29 +1004,42 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts) ...@@ -1004,29 +1004,42 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
} }
EXPORT_SYMBOL(tcf_exts_dump_stats); EXPORT_SYMBOL(tcf_exts_dump_stats);
int tcf_exts_get_dev(struct net_device *dev, struct tcf_exts *exts, static int tc_exts_setup_cb_egdev_call(struct tcf_exts *exts,
struct net_device **hw_dev) enum tc_setup_type type,
void *type_data, bool err_stop)
{ {
int ok_count = 0;
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
const struct tc_action *a; const struct tc_action *a;
struct net_device *dev;
LIST_HEAD(actions); LIST_HEAD(actions);
int ret;
if (!tcf_exts_has_actions(exts)) if (!tcf_exts_has_actions(exts))
return -EINVAL; return 0;
tcf_exts_to_list(exts, &actions); tcf_exts_to_list(exts, &actions);
list_for_each_entry(a, &actions, list) { list_for_each_entry(a, &actions, list) {
if (a->ops->get_dev) { if (!a->ops->get_dev)
a->ops->get_dev(a, dev_net(dev), hw_dev); continue;
break; dev = a->ops->get_dev(a);
} if (!dev || !tc_can_offload(dev))
continue;
ret = tc_setup_cb_egdev_call(dev, type, type_data, err_stop);
if (ret < 0)
return ret;
ok_count += ret;
} }
if (*hw_dev)
return 0;
#endif #endif
return -EOPNOTSUPP; return ok_count;
}
int tc_setup_cb_call(struct tcf_exts *exts, enum tc_setup_type type,
void *type_data, bool err_stop)
{
return tc_exts_setup_cb_egdev_call(exts, type, type_data, err_stop);
} }
EXPORT_SYMBOL(tcf_exts_get_dev); EXPORT_SYMBOL(tc_setup_cb_call);
static int __init tc_filter_init(void) static int __init tc_filter_init(void)
{ {
......
...@@ -88,7 +88,6 @@ struct cls_fl_filter { ...@@ -88,7 +88,6 @@ struct cls_fl_filter {
u32 handle; u32 handle;
u32 flags; u32 flags;
struct rcu_head rcu; struct rcu_head rcu;
struct net_device *hw_dev;
}; };
static unsigned short int fl_mask_range(const struct fl_flow_mask *mask) static unsigned short int fl_mask_range(const struct fl_flow_mask *mask)
...@@ -201,16 +200,17 @@ static void fl_destroy_filter(struct rcu_head *head) ...@@ -201,16 +200,17 @@ static void fl_destroy_filter(struct rcu_head *head)
static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f)
{ {
struct tc_cls_flower_offload cls_flower = {}; struct tc_cls_flower_offload cls_flower = {};
struct net_device *dev = f->hw_dev; struct net_device *dev = tp->q->dev_queue->dev;
if (!tc_can_offload(dev))
return;
tc_cls_common_offload_init(&cls_flower.common, tp); tc_cls_common_offload_init(&cls_flower.common, tp);
cls_flower.command = TC_CLSFLOWER_DESTROY; cls_flower.command = TC_CLSFLOWER_DESTROY;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, &cls_flower); if (tc_can_offload(dev))
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER,
&cls_flower);
tc_setup_cb_call(&f->exts, TC_SETUP_CLSFLOWER,
&cls_flower, false);
} }
static int fl_hw_replace_filter(struct tcf_proto *tp, static int fl_hw_replace_filter(struct tcf_proto *tp,
...@@ -220,20 +220,9 @@ static int fl_hw_replace_filter(struct tcf_proto *tp, ...@@ -220,20 +220,9 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
{ {
struct net_device *dev = tp->q->dev_queue->dev; struct net_device *dev = tp->q->dev_queue->dev;
struct tc_cls_flower_offload cls_flower = {}; struct tc_cls_flower_offload cls_flower = {};
bool skip_sw = tc_skip_sw(f->flags);
int err; int err;
if (!tc_can_offload(dev)) {
if (tcf_exts_get_dev(dev, &f->exts, &f->hw_dev) ||
(f->hw_dev && !tc_can_offload(f->hw_dev))) {
f->hw_dev = dev;
return tc_skip_sw(f->flags) ? -EINVAL : 0;
}
dev = f->hw_dev;
cls_flower.egress_dev = true;
} else {
f->hw_dev = dev;
}
tc_cls_common_offload_init(&cls_flower.common, tp); tc_cls_common_offload_init(&cls_flower.common, tp);
cls_flower.command = TC_CLSFLOWER_REPLACE; cls_flower.command = TC_CLSFLOWER_REPLACE;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
...@@ -242,31 +231,47 @@ static int fl_hw_replace_filter(struct tcf_proto *tp, ...@@ -242,31 +231,47 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
cls_flower.key = &f->mkey; cls_flower.key = &f->mkey;
cls_flower.exts = &f->exts; cls_flower.exts = &f->exts;
if (tc_can_offload(dev)) {
err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER,
&cls_flower); &cls_flower);
if (!err) if (err) {
if (skip_sw)
return err;
} else {
f->flags |= TCA_CLS_FLAGS_IN_HW; f->flags |= TCA_CLS_FLAGS_IN_HW;
}
}
if (tc_skip_sw(f->flags)) err = tc_setup_cb_call(&f->exts, TC_SETUP_CLSFLOWER,
&cls_flower, skip_sw);
if (err < 0) {
fl_hw_destroy_filter(tp, f);
return err; return err;
} else if (err > 0) {
f->flags |= TCA_CLS_FLAGS_IN_HW;
}
if (skip_sw && !(f->flags & TCA_CLS_FLAGS_IN_HW))
return -EINVAL;
return 0; return 0;
} }
static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
{ {
struct tc_cls_flower_offload cls_flower = {}; struct tc_cls_flower_offload cls_flower = {};
struct net_device *dev = f->hw_dev; struct net_device *dev = tp->q->dev_queue->dev;
if (!tc_can_offload(dev))
return;
tc_cls_common_offload_init(&cls_flower.common, tp); tc_cls_common_offload_init(&cls_flower.common, tp);
cls_flower.command = TC_CLSFLOWER_STATS; cls_flower.command = TC_CLSFLOWER_STATS;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
cls_flower.exts = &f->exts; cls_flower.exts = &f->exts;
if (tc_can_offload(dev))
dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER, dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_CLSFLOWER,
&cls_flower); &cls_flower);
tc_setup_cb_call(&f->exts, TC_SETUP_CLSFLOWER,
&cls_flower, false);
} }
static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f)
......
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