Message ID | 20200422024852.23224-3-Po.Liu@nxp.com |
---|---|
State | Changes Requested |
Delegated to: | David Miller |
Headers | show |
Series | Introduce a flow gate control action and apply IEEE | expand |
On Wed 22 Apr 2020 at 05:48, Po Liu <Po.Liu@nxp.com> wrote: > 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(+) > > diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h > index 3619c6acf60f..94a30fe02e6d 100644 > --- a/include/net/flow_offload.h > +++ b/include/net/flow_offload.h > @@ -147,6 +147,7 @@ enum flow_action_id { > FLOW_ACTION_MPLS_PUSH, > FLOW_ACTION_MPLS_POP, > FLOW_ACTION_MPLS_MANGLE, > + FLOW_ACTION_GATE, > NUM_FLOW_ACTIONS, > }; > > @@ -255,6 +256,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 b0ace55b2aaa..62633cb02c7a 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(); Here you obtain a pointer to part of rcu-protected object and use it past rcu read lock block. > + > + 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 55bd1429678f..ca8bf74be4ba 100644 > --- a/net/sched/cls_api.c > +++ b/net/sched/cls_api.c > @@ -39,6 +39,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]; > @@ -3523,6 +3524,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) > { > @@ -3669,6 +3691,17 @@ int tc_setup_flow_action(struct flow_action *flow_action, > } else if (is_tcf_skbedit_priority(act)) { > entry->id = FLOW_ACTION_PRIORITY; > entry->priority = tcf_skbedit_priority(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;
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h index 3619c6acf60f..94a30fe02e6d 100644 --- a/include/net/flow_offload.h +++ b/include/net/flow_offload.h @@ -147,6 +147,7 @@ enum flow_action_id { FLOW_ACTION_MPLS_PUSH, FLOW_ACTION_MPLS_POP, FLOW_ACTION_MPLS_MANGLE, + FLOW_ACTION_GATE, NUM_FLOW_ACTIONS, }; @@ -255,6 +256,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 b0ace55b2aaa..62633cb02c7a 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 55bd1429678f..ca8bf74be4ba 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -39,6 +39,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]; @@ -3523,6 +3524,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) { @@ -3669,6 +3691,17 @@ int tc_setup_flow_action(struct flow_action *flow_action, } else if (is_tcf_skbedit_priority(act)) { entry->id = FLOW_ACTION_PRIORITY; entry->priority = tcf_skbedit_priority(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(+)