Message ID | 20200306125608.11717-4-Po.Liu@nxp.com |
---|---|
State | RFC |
Delegated to: | David Miller |
Headers | show |
Series | Introduce a flow gate control action and apply IEEE | expand |
On Fri, 6 Mar 2020 20:56:01 +0800 Po Liu wrote: > +static int tcf_gate_get_entries(struct flow_action_entry *entry, > + const struct tc_action *act) > +{ > + entry->gate.entries = tcf_gate_get_list(act); > + > + if (!entry->gate.entries) > + return -EINVAL; > + > + entry->destructor = tcf_gate_entry_destructor; > + entry->destructor_priv = entry->gate.entries; What's this destructor stuff doing? I don't it being called. > + return 0; > +}
On Fri, 6 Mar 2020 11:02:00 -0800 Jakub Kicinski wrote: > On Fri, 6 Mar 2020 20:56:01 +0800 Po Liu wrote: > > +static int tcf_gate_get_entries(struct flow_action_entry *entry, > > + const struct tc_action *act) > > +{ > > + entry->gate.entries = tcf_gate_get_list(act); > > + > > + if (!entry->gate.entries) > > + return -EINVAL; > > + > > + entry->destructor = tcf_gate_entry_destructor; > > + entry->destructor_priv = entry->gate.entries; > > What's this destructor stuff doing? I don't it being called. Ah, it's the action destructor, not something gate specific. Disregard.
Hi Jakub, > -----Original Message----- > From: Jakub Kicinski <kuba@kernel.org> > Sent: 2020年3月7日 3:19 > To: Po Liu <po.liu@nxp.com> > Cc: davem@davemloft.net; linux-kernel@vger.kernel.org; > netdev@vger.kernel.org; vinicius.gomes@intel.com; Claudiu Manoil > <claudiu.manoil@nxp.com>; Vladimir Oltean <vladimir.oltean@nxp.com>; > Alexandru Marginean <alexandru.marginean@nxp.com>; Xiaoliang Yang > <xiaoliang.yang_1@nxp.com>; Roy Zang <roy.zang@nxp.com>; Mingkai Hu > <mingkai.hu@nxp.com>; Jerry Huang <jerry.huang@nxp.com>; Leo Li > <leoyang.li@nxp.com>; michael.chan@broadcom.com; vishal@chelsio.com; > saeedm@mellanox.com; leon@kernel.org; jiri@mellanox.com; > idosch@mellanox.com; alexandre.belloni@bootlin.com; > UNGLinuxDriver@microchip.com; jhs@mojatatu.com; > xiyou.wangcong@gmail.com; john.hurley@netronome.com; > simon.horman@netronome.com; > pieter.jansenvanvuuren@netronome.com; pablo@netfilter.org; > moshe@mellanox.com; ivan.khoronzhuk@linaro.org; m-karicheri2@ti.com; > andre.guedes@linux.intel.com; jakub.kicinski@netronome.com > Subject: [EXT] Re: [RFC,net-next 3/9] net: schedule: add action gate > offloading > > Caution: EXT Email > > On Fri, 6 Mar 2020 11:02:00 -0800 Jakub Kicinski wrote: > > On Fri, 6 Mar 2020 20:56:01 +0800 Po Liu wrote: > > > +static int tcf_gate_get_entries(struct flow_action_entry *entry, > > > + const struct tc_action *act) { > > > + entry->gate.entries = tcf_gate_get_list(act); > > > + > > > + if (!entry->gate.entries) > > > + return -EINVAL; > > > + > > > + entry->destructor = tcf_gate_entry_destructor; > > > + entry->destructor_priv = entry->gate.entries; > > > > What's this destructor stuff doing? I don't it being called. It prepare a gate list array parameters for offloading. So the driver side would not link the data with protocol side. Destructor would free the temporary gate list array. > > Ah, it's the action destructor, not something gate specific. Disregard. I understand here with actions are: Each tc flower follow up with actions. Each action defined: struct flow_action_entry { enum flow_action_id id; action_destr destructor; void *destructor_priv; union { ...... {}sample, {}police, {}gate, } } So for the destructor and destructor_priv are provided specific for the union action. So it is not gate specific. For mirror action, destructor_priv would be point to a mirror device data. I suppose it is for destroy the temporary data like it name. And after tc_setup_flow_action() loaded, the destructor function would be loaded by tc_cleanup_flow_action() to destroy and free the temporary data. Code flow is : net/sched/cls_flower.c static int fl_hw_replace_filter() { ...... tc_setup_flow_action(); ---------------------------------------> assign action parameters (with the destructor and destructor_priv if the action needed) ...... tc_setup_cb_add() ----------------------------------------------> call the driver provide rules with actions datas for device ...... tc_cleanup_flow_action(&cls_flower.rule->action); ---> loading each action''s destructor(destructor_priv) } So for each action would be with its private destructor and destructor_priv if the action needed, and then destroyed at tc_cleanup_flow_action(). Did I misunderstand anything? Thanks! Br, Po Liu
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h index eb013ffc24f3..7f5a097f5072 100644 --- a/include/net/flow_offload.h +++ b/include/net/flow_offload.h @@ -138,6 +138,7 @@ enum flow_action_id { FLOW_ACTION_MPLS_PUSH, FLOW_ACTION_MPLS_POP, FLOW_ACTION_MPLS_MANGLE, + FLOW_ACTION_GATE, NUM_FLOW_ACTIONS, }; @@ -223,6 +224,15 @@ struct flow_action_entry { u8 bos; u8 ttl; } mpls_mangle; + struct { + u32 index; + s32 prio; + u64 basetime; + u64 cycletime; + u64 cycletimeext; + u32 num_entries; + struct action_gate_entry *entries; + } gate; }; struct flow_action_cookie *cookie; /* user defined action cookie */ }; diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h index 932a2b91b944..d93fa0d6f516 100644 --- a/include/net/tc_act/tc_gate.h +++ b/include/net/tc_act/tc_gate.h @@ -7,6 +7,13 @@ #include <net/act_api.h> #include <linux/tc_act/tc_gate.h> +struct action_gate_entry { + u8 gate_state; + u32 interval; + s32 ipv; + s32 maxoctets; +}; + struct tcfg_gate_entry { int index; u8 gate_state; @@ -51,4 +58,112 @@ struct tcf_gate { #define get_gate_param(act) ((struct tcf_gate_params *)act) #define get_gate_action(p) ((struct gate_action *)p) +static inline bool is_tcf_gate(const struct tc_action *a) +{ +#ifdef CONFIG_NET_CLS_ACT + if (a->ops && a->ops->id == TCA_ID_GATE) + return true; +#endif + return false; +} + +static inline u32 tcf_gate_index(const struct tc_action *a) +{ + return a->tcfa_index; +} + +static inline s32 tcf_gate_prio(const struct tc_action *a) +{ + s32 tcfg_prio; + + rcu_read_lock(); + tcfg_prio = rcu_dereference(to_gate(a)->actg)->param.tcfg_priority; + rcu_read_unlock(); + + return tcfg_prio; +} + +static inline u64 tcf_gate_basetime(const struct tc_action *a) +{ + u64 tcfg_basetime; + + rcu_read_lock(); + tcfg_basetime = + rcu_dereference(to_gate(a)->actg)->param.tcfg_basetime; + rcu_read_unlock(); + + return tcfg_basetime; +} + +static inline u64 tcf_gate_cycletime(const struct tc_action *a) +{ + u64 tcfg_cycletime; + + rcu_read_lock(); + tcfg_cycletime = + rcu_dereference(to_gate(a)->actg)->param.tcfg_cycletime; + rcu_read_unlock(); + + return tcfg_cycletime; +} + +static inline u64 tcf_gate_cycletimeext(const struct tc_action *a) +{ + u64 tcfg_cycletimeext; + + rcu_read_lock(); + tcfg_cycletimeext = + rcu_dereference(to_gate(a)->actg)->param.tcfg_cycletime_ext; + rcu_read_unlock(); + + return tcfg_cycletimeext; +} + +static inline u32 tcf_gate_num_entries(const struct tc_action *a) +{ + u32 num_entries; + + rcu_read_lock(); + num_entries = + rcu_dereference(to_gate(a)->actg)->param.num_entries; + rcu_read_unlock(); + + return num_entries; +} + +static inline struct action_gate_entry + *tcf_gate_get_list(const struct tc_action *a) +{ + struct action_gate_entry *oe; + struct tcf_gate_params *p; + struct tcfg_gate_entry *entry; + u32 num_entries; + int i = 0; + + rcu_read_lock(); + p = &(rcu_dereference(to_gate(a)->actg)->param); + num_entries = p->num_entries; + rcu_read_unlock(); + + list_for_each_entry(entry, &p->entries, list) + i++; + + if (i != num_entries) + return NULL; + + oe = kzalloc(sizeof(*oe) * num_entries, GFP_KERNEL); + if (!oe) + return NULL; + + i = 0; + list_for_each_entry(entry, &p->entries, list) { + oe[i].gate_state = entry->gate_state; + oe[i].interval = entry->interval; + oe[i].ipv = entry->ipv; + oe[i].maxoctets = entry->maxoctets; + i++; + } + + return oe; +} #endif diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 4e766c5ab77a..0ada7b2a5c2c 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -38,6 +38,7 @@ #include <net/tc_act/tc_skbedit.h> #include <net/tc_act/tc_ct.h> #include <net/tc_act/tc_mpls.h> +#include <net/tc_act/tc_gate.h> #include <net/flow_offload.h> extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1]; @@ -3458,6 +3459,27 @@ static void tcf_sample_get_group(struct flow_action_entry *entry, #endif } +static void tcf_gate_entry_destructor(void *priv) +{ + struct action_gate_entry *oe = priv; + + kfree(oe); +} + +static int tcf_gate_get_entries(struct flow_action_entry *entry, + const struct tc_action *act) +{ + entry->gate.entries = tcf_gate_get_list(act); + + if (!entry->gate.entries) + return -EINVAL; + + entry->destructor = tcf_gate_entry_destructor; + entry->destructor_priv = entry->gate.entries; + + return 0; +} + int tc_setup_flow_action(struct flow_action *flow_action, const struct tcf_exts *exts) { @@ -3592,6 +3614,17 @@ int tc_setup_flow_action(struct flow_action *flow_action, } else if (is_tcf_skbedit_ptype(act)) { entry->id = FLOW_ACTION_PTYPE; entry->ptype = tcf_skbedit_ptype(act); + } else if (is_tcf_gate(act)) { + entry->id = FLOW_ACTION_GATE; + entry->gate.index = tcf_gate_index(act); + entry->gate.prio = tcf_gate_prio(act); + entry->gate.basetime = tcf_gate_basetime(act); + entry->gate.cycletime = tcf_gate_cycletime(act); + entry->gate.cycletimeext = tcf_gate_cycletimeext(act); + entry->gate.num_entries = tcf_gate_num_entries(act); + err = tcf_gate_get_entries(entry, act); + if (err) + goto err_out; } else { err = -EOPNOTSUPP; goto err_out_locked;
Add the gate action to the flow action entry. Add the gate parameters to the tc_setup_flow_action() queueing to the entries of flow_action_entry array provide to the driver. Signed-off-by: Po Liu <Po.Liu@nxp.com> --- include/net/flow_offload.h | 10 +++ include/net/tc_act/tc_gate.h | 115 +++++++++++++++++++++++++++++++++++ net/sched/cls_api.c | 33 ++++++++++ 3 files changed, 158 insertions(+)