Fri, Apr 28, 2017 at 03:41:08AM CEST, j...@mojatatu.com wrote: > >Jiri, > >Good stuff! >Thanks for the effort. > >I didnt review the details - will do. I wanted to raise one issue. >This should work for all actions, not just gact (refer to the >recent commit i made on the action jumping). > >Example policy for policer: > >#if packets destined for mac address 52:54:00:3d:c7:6d >#exceed 90kbps with burst of 90K then jump to chain 11 >#for further classification, otherwise set their skb mark to 11 ># and proceed. > >tc filter add dev eth0 parent ffff: protocol ip pref 33 \ >flower dst_mac 52:54:00:3d:c7:6d \ >action police rate 1kbit burst 90k conform-exceed pipe/goto chain 11 \ >action skbedit mark 11 > >But i should also be able to do this for any other action, etc. > >For this to work, you have to be able to encode the action in the >opcode. Something like (for 2^16 chains): > >#define TC_ACT_GOTO_CHAIN 0x20000000 >#define TCA_ACT_MAX_CHAIN_MASK 0xFFFF > >So 0x20000001 is encoding of chain 1 etc. > >I will post the iproute2 code i used for jumping of actions.
You can have multiple actions in list and gact goto as the last one. Why to do this ugliness? > >cheers, >jamal > >On 17-04-27 07:12 AM, Jiri Pirko wrote: >> From: Jiri Pirko <j...@mellanox.com> >> >> Introduce new type of gact action called "goto_chain". This allows >> user to specify a chain to be processed. This action type is >> then processed as a return value in tcf_classify loop in similar >> way as "reclassify" is, only it does not reset to the first filter >> in chain but rather reset to the first filter of the desired chain. >> >> Signed-off-by: Jiri Pirko <j...@mellanox.com> >> --- >> include/net/sch_generic.h | 9 +++++-- >> include/net/tc_act/tc_gact.h | 2 ++ >> include/uapi/linux/pkt_cls.h | 1 + >> include/uapi/linux/tc_act/tc_gact.h | 1 + >> net/sched/act_gact.c | 48 >> ++++++++++++++++++++++++++++++++++++- >> net/sched/cls_api.c | 8 +++++-- >> 6 files changed, 64 insertions(+), 5 deletions(-) >> >> diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h >> index 569b565..3688501 100644 >> --- a/include/net/sch_generic.h >> +++ b/include/net/sch_generic.h >> @@ -193,8 +193,13 @@ struct Qdisc_ops { >> >> >> struct tcf_result { >> - unsigned long class; >> - u32 classid; >> + union { >> + struct { >> + unsigned long class; >> + u32 classid; >> + }; >> + const struct tcf_proto *goto_tp; >> + }; >> }; >> >> struct tcf_proto_ops { >> diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h >> index b6f1739..58bee54 100644 >> --- a/include/net/tc_act/tc_gact.h >> +++ b/include/net/tc_act/tc_gact.h >> @@ -12,6 +12,8 @@ struct tcf_gact { >> int tcfg_paction; >> atomic_t packets; >> #endif >> + struct tcf_chain *goto_chain; >> + struct rcu_head rcu; >> }; >> #define to_gact(a) ((struct tcf_gact *)a) >> >> diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h >> index f1129e3..e03ba27 100644 >> --- a/include/uapi/linux/pkt_cls.h >> +++ b/include/uapi/linux/pkt_cls.h >> @@ -37,6 +37,7 @@ enum { >> #define TC_ACT_QUEUED 5 >> #define TC_ACT_REPEAT 6 >> #define TC_ACT_REDIRECT 7 >> +#define TC_ACT_GOTO_CHAIN 8 >> #define TC_ACT_JUMP 0x10000000 >> >> /* Action type identifiers*/ >> diff --git a/include/uapi/linux/tc_act/tc_gact.h >> b/include/uapi/linux/tc_act/tc_gact.h >> index 70b536a..388733d 100644 >> --- a/include/uapi/linux/tc_act/tc_gact.h >> +++ b/include/uapi/linux/tc_act/tc_gact.h >> @@ -26,6 +26,7 @@ enum { >> TCA_GACT_PARMS, >> TCA_GACT_PROB, >> TCA_GACT_PAD, >> + TCA_GACT_CHAIN, >> __TCA_GACT_MAX >> }; >> #define TCA_GACT_MAX (__TCA_GACT_MAX - 1) >> diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c >> index c527c11..d63aebd 100644 >> --- a/net/sched/act_gact.c >> +++ b/net/sched/act_gact.c >> @@ -20,6 +20,7 @@ >> #include <linux/init.h> >> #include <net/netlink.h> >> #include <net/pkt_sched.h> >> +#include <net/pkt_cls.h> >> #include <linux/tc_act/tc_gact.h> >> #include <net/tc_act/tc_gact.h> >> >> @@ -54,6 +55,7 @@ static g_rand gact_rand[MAX_RAND] = { NULL, gact_net_rand, >> gact_determ }; >> static const struct nla_policy gact_policy[TCA_GACT_MAX + 1] = { >> [TCA_GACT_PARMS] = { .len = sizeof(struct tc_gact) }, >> [TCA_GACT_PROB] = { .len = sizeof(struct tc_gact_p) }, >> + [TCA_GACT_CHAIN] = { .type = NLA_U32 }, >> }; >> >> static int tcf_gact_init(struct net *net, struct tcf_proto *tp, >> @@ -92,6 +94,9 @@ static int tcf_gact_init(struct net *net, struct tcf_proto >> *tp, >> } >> #endif >> >> + if (parm->action == TC_ACT_GOTO_CHAIN && !tb[TCA_GACT_CHAIN]) >> + return -EINVAL; >> + >> if (!tcf_hash_check(tn, parm->index, a, bind)) { >> ret = tcf_hash_create(tn, parm->index, est, a, >> &act_gact_ops, bind, true); >> @@ -121,11 +126,43 @@ static int tcf_gact_init(struct net *net, struct >> tcf_proto *tp, >> gact->tcfg_ptype = p_parm->ptype; >> } >> #endif >> + >> + if (gact->tcf_action == TC_ACT_GOTO_CHAIN) { >> + u32 chain_index = nla_get_u32(tb[TCA_GACT_CHAIN]); >> + >> + if (!tp) { >> + if (ret == ACT_P_CREATED) >> + tcf_hash_release(*a, bind); >> + return -EINVAL; >> + } >> + gact->goto_chain = tcf_chain_get(tp->chain->block, chain_index); >> + if (!gact->goto_chain) { >> + if (ret == ACT_P_CREATED) >> + tcf_hash_release(*a, bind); >> + return -ENOMEM; >> + } >> + } >> + >> if (ret == ACT_P_CREATED) >> tcf_hash_insert(tn, *a); >> return ret; >> } >> >> +static void tcf_gact_cleanup_rcu(struct rcu_head *rcu) >> +{ >> + struct tcf_gact *gact = container_of(rcu, struct tcf_gact, rcu); >> + >> + if (gact->tcf_action == TC_ACT_GOTO_CHAIN) >> + tcf_chain_put(gact->goto_chain); >> +} >> + >> +static void tcf_gact_cleanup(struct tc_action *a, int bind) >> +{ >> + struct tcf_gact *gact = to_gact(a); >> + >> + call_rcu(&gact->rcu, tcf_gact_cleanup_rcu); >> +} >> + >> static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, >> struct tcf_result *res) >> { >> @@ -141,8 +178,13 @@ static int tcf_gact(struct sk_buff *skb, const struct >> tc_action *a, >> } >> #endif >> bstats_cpu_update(this_cpu_ptr(gact->common.cpu_bstats), skb); >> - if (action == TC_ACT_SHOT) >> + if (action == TC_ACT_SHOT) { >> qstats_drop_inc(this_cpu_ptr(gact->common.cpu_qstats)); >> + } else if (action == TC_ACT_GOTO_CHAIN) { >> + struct tcf_chain *chain = gact->goto_chain; >> + >> + res->goto_tp = rcu_dereference_bh(chain->filter_chain); >> + } >> >> tcf_lastuse_update(&gact->tcf_tm); >> >> @@ -194,6 +236,9 @@ static int tcf_gact_dump(struct sk_buff *skb, struct >> tc_action *a, >> tcf_tm_dump(&t, &gact->tcf_tm); >> if (nla_put_64bit(skb, TCA_GACT_TM, sizeof(t), &t, TCA_GACT_PAD)) >> goto nla_put_failure; >> + if (gact->tcf_action == TC_ACT_GOTO_CHAIN && >> + nla_put_u32(skb, TCA_GACT_CHAIN, gact->goto_chain->index)) >> + goto nla_put_failure; >> return skb->len; >> >> nla_put_failure: >> @@ -225,6 +270,7 @@ static struct tc_action_ops act_gact_ops = { >> .stats_update = tcf_gact_stats_update, >> .dump = tcf_gact_dump, >> .init = tcf_gact_init, >> + .cleanup = tcf_gact_cleanup, >> .walk = tcf_gact_walker, >> .lookup = tcf_gact_search, >> .size = sizeof(struct tcf_gact), >> diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c >> index dbc1348..a2d6bc7 100644 >> --- a/net/sched/cls_api.c >> +++ b/net/sched/cls_api.c >> @@ -304,10 +304,14 @@ int tcf_classify(struct sk_buff *skb, const struct >> tcf_proto *tp, >> continue; >> >> err = tp->classify(skb, tp, res); >> - if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) >> + if (err == TC_ACT_RECLASSIFY && !compat_mode) { >> goto reset; >> - if (err >= 0) >> + } else if (err == TC_ACT_GOTO_CHAIN) { >> + old_tp = res->goto_tp; >> + goto reset; >> + } else if (err >= 0) { >> return err; >> + } >> } >> >> return TC_ACT_UNSPEC; /* signal: continue lookup */ >> >