diff mbox series

[RFC,net-next,3/9] net: schedule: add action gate offloading

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

Commit Message

Po Liu March 6, 2020, 12:56 p.m. UTC
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(+)

Comments

Jakub Kicinski March 6, 2020, 7:02 p.m. UTC | #1
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;
> +}
Jakub Kicinski March 6, 2020, 7:19 p.m. UTC | #2
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.
Po Liu March 7, 2020, 4:38 a.m. UTC | #3
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 mbox series

Patch

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;