@@ -27,6 +27,7 @@ struct tc_action {
struct tcf_idrinfo *idrinfo;
u32 tcfa_index;
+ u32 tcfa_flags;
refcount_t tcfa_refcnt;
atomic_t tcfa_bindcnt;
int tcfa_action;
@@ -43,6 +44,7 @@ struct tc_action {
struct tcf_chain __rcu *goto_chain;
};
#define tcf_index common.tcfa_index
+#define tcf_flags common.tcfa_flags
#define tcf_refcnt common.tcfa_refcnt
#define tcf_bindcnt common.tcfa_bindcnt
#define tcf_action common.tcfa_action
@@ -154,7 +156,7 @@ int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
int tcf_idr_search(struct tc_action_net *tn, struct tc_action **a, u32 index);
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
struct tc_action **a, const struct tc_action_ops *ops,
- int bind, bool cpustats);
+ int bind, u32 flags);
void tcf_idr_insert(struct tc_action_net *tn, struct tc_action *a);
void tcf_idr_cleanup(struct tc_action_net *tn, u32 index);
@@ -230,6 +232,12 @@ int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
struct netlink_ext_ack *newchain);
struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action,
struct tcf_chain *newchain);
+
+static inline bool tc_act_fast_init(u32 flags)
+{
+ return (flags & TCA_ACT_FLAGS_FAST_INIT) ? true : false;
+}
+
#endif /* CONFIG_NET_CLS_ACT */
static inline void tcf_action_stats_update(struct tc_action *a, u64 bytes,
@@ -11,6 +11,9 @@
/* TC action not accessible from user space */
#define TC_ACT_CONSUMED (TC_ACT_VALUE_MAX + 1)
+/* Default allowed action flags. */
+static const u32 tca_flags_allowed = TCA_ACT_FLAGS_FAST_INIT;
+
/* Basic packet classifier frontend definitions. */
struct tcf_walker {
@@ -113,6 +113,14 @@ enum tca_id {
#define TCA_ID_MAX __TCA_ID_MAX
+/* act flags definitions */
+#define TCA_ACT_FLAGS_FAST_INIT (1 << 0) /* prefer action update rate
+ * (slow-path), even at the cost of
+ * reduced software data-path
+ * performance (intended to be used for
+ * hardware-offloaded actions)
+ */
+
struct tc_police {
__u32 index;
int action;
@@ -399,7 +399,7 @@ static int tcf_idr_delete_index(struct tcf_idrinfo *idrinfo, u32 index)
int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
struct tc_action **a, const struct tc_action_ops *ops,
- int bind, bool cpustats)
+ int bind, u32 flags)
{
struct tc_action *p = kzalloc(ops->size, GFP_KERNEL);
struct tcf_idrinfo *idrinfo = tn->idrinfo;
@@ -411,7 +411,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
if (bind)
atomic_set(&p->tcfa_bindcnt, 1);
- if (cpustats) {
+ if (!tc_act_fast_init(flags)) {
p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu);
if (!p->cpu_bstats)
goto err1;
@@ -437,6 +437,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
p->idrinfo = idrinfo;
p->ops = ops;
+ p->tcfa_flags = flags;
*a = p;
return 0;
err4:
@@ -303,7 +303,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
ret = tcf_idr_check_alloc(tn, &index, act, bind);
if (!ret) {
ret = tcf_idr_create(tn, index, est, act,
- &act_bpf_ops, bind, true);
+ &act_bpf_ops, bind, 0);
if (ret < 0) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -121,7 +121,8 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla,
ret = tcf_idr_check_alloc(tn, &index, a, bind);
if (!ret) {
ret = tcf_idr_create(tn, index, est, a,
- &act_connmark_ops, bind, false);
+ &act_connmark_ops, bind,
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -69,7 +69,7 @@ static int tcf_csum_init(struct net *net, struct nlattr *nla,
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
ret = tcf_idr_create(tn, index, est, a,
- &act_csum_ops, bind, true);
+ &act_csum_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -689,7 +689,7 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
if (!err) {
err = tcf_idr_create(tn, index, est, a,
- &act_ct_ops, bind, true);
+ &act_ct_ops, bind, 0);
if (err) {
tcf_idr_cleanup(tn, index);
return err;
@@ -210,7 +210,8 @@ static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
ret = tcf_idr_create(tn, index, est, a,
- &act_ctinfo_ops, bind, false);
+ &act_ctinfo_ops, bind,
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -99,7 +99,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
ret = tcf_idr_create(tn, index, est, a,
- &act_gact_ops, bind, true);
+ &act_gact_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -522,7 +522,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a, &act_ife_ops,
- bind, true);
+ bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
kfree(p);
@@ -95,7 +95,7 @@ static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
struct nlattr *est, struct tc_action **a,
const struct tc_action_ops *ops, int ovr, int bind,
- struct tcf_proto *tp)
+ struct tcf_proto *tp, struct netlink_ext_ack *extack)
{
struct tc_action_net *tn = net_generic(net, id);
struct nlattr *tb[TCA_IPT_MAX + 1];
@@ -144,7 +144,7 @@ static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a, ops, bind,
- false);
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -208,7 +208,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla,
struct netlink_ext_ack *extack)
{
return __tcf_ipt_init(net, ipt_net_id, nla, est, a, &act_ipt_ops, ovr,
- bind, tp);
+ bind, tp, extack);
}
static int tcf_xt_init(struct net *net, struct nlattr *nla,
@@ -217,7 +217,7 @@ static int tcf_xt_init(struct net *net, struct nlattr *nla,
struct netlink_ext_ack *extack)
{
return __tcf_ipt_init(net, xt_net_id, nla, est, a, &act_xt_ops, ovr,
- bind, tp);
+ bind, tp, extack);
}
static int tcf_ipt_act(struct sk_buff *skb, const struct tc_action *a,
@@ -149,7 +149,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
ret = tcf_idr_create(tn, index, est, a,
- &act_mirred_ops, bind, true);
+ &act_mirred_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -224,7 +224,7 @@ static int tcf_mpls_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_mpls_ops, bind, true);
+ &act_mpls_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -61,7 +61,8 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
err = tcf_idr_check_alloc(tn, &index, a, bind);
if (!err) {
ret = tcf_idr_create(tn, index, est, a,
- &act_nat_ops, bind, false);
+ &act_nat_ops, bind,
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -190,7 +190,8 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
goto out_free;
}
ret = tcf_idr_create(tn, index, est, a,
- &act_pedit_ops, bind, false);
+ &act_pedit_ops, bind,
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
goto out_free;
@@ -87,7 +87,7 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, NULL, a,
- &act_police_ops, bind, true);
+ &act_police_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -69,7 +69,7 @@ static int tcf_sample_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_sample_ops, bind, true);
+ &act_sample_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -127,7 +127,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_simp_ops, bind, false);
+ &act_simp_ops, bind,
+ TCA_ACT_FLAGS_FAST_INIT);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -165,7 +165,7 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_skbedit_ops, bind, true);
+ &act_skbedit_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -143,7 +143,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_skbmod_ops, bind, true);
+ &act_skbmod_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;
@@ -348,7 +348,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_tunnel_key_ops, bind, true);
+ &act_tunnel_key_ops, bind, 0);
if (ret) {
NL_SET_ERR_MSG(extack, "Cannot create TC IDR");
goto release_tun_meta;
@@ -189,7 +189,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
if (!exists) {
ret = tcf_idr_create(tn, index, est, a,
- &act_vlan_ops, bind, true);
+ &act_vlan_ops, bind, 0);
if (ret) {
tcf_idr_cleanup(tn, index);
return ret;