net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
Subsystems (3)
Jiri Pirko
maintainerv4 cover net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
From: Jiri Pirko <[email protected]>
This patchset's main patch is patch number 2. It carries the description. Patch 1 is just a dependency.
---v3->v4:
- rebased to be applicable on top of the current net-next v2->v3:
- Using head change callback to replace miniq pointer every time tp head changes. This eliminates one rcu dereference and makes the claim "without added overhead" valid.v1->v2:
- Use dev instead of skb->dev in sch_handle_egress as pointed out by Daniel
- Fixed synchronize_rcu_bh() in mini_qdisc_disable and commented
Jiri Pirko (2):
net: sched: introduce chain_head_change callback
net: core: introduce mini_Qdisc and eliminate usage of tp->q for
clsact fastpath
include/linux/netdevice.h | 9 +++++--- include/net/pkt_cls.h | 14 ++++++------ include/net/sch_generic.h | 37 +++++++++++++++++++++++++++++++- net/core/dev.c | 21 +++++++++--------- net/sched/cls_api.c | 54 ++++++++++++++++++++++++++++------------------- net/sched/sch_generic.c | 46 ++++++++++++++++++++++++++++++++++++++++ net/sched/sch_ingress.c | 45 +++++++++++++++++++++++++-------------- 7 files changed, 166 insertions(+), 60 deletions(-)
Signature · 1 line
2.9.5
Jiri Pirko
maintainerPATCH v4 1/2 net: sched: introduce chain_head_change callback
From: Jiri Pirko <[email protected]>
Add a callback that is to be called whenever head of the chain changes. Also provide a callback for the default case when the caller gets a block using non-extended getter.
--- include/net/pkt_cls.h | 14 ++++++------ include/net/sch_generic.h | 5 ++++- net/sched/cls_api.c | 54 ++++++++++++++++++++++++++++------------------- net/sched/sch_ingress.c | 36 +++++++++++++++++-------------- 4 files changed, 62 insertions(+), 47 deletions(-)
include/net/pkt_cls.h +6 -8
@@ -26,6 +26,8 @@ enum tcf_block_binder_type {struct tcf_block_ext_info {enum tcf_block_binder_type binder_type; +tcf_chain_head_change_t *chain_head_change; +void *chain_head_change_priv; };struct tcf_block_cb ;
@@ -37,12 +39,10 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,void tcf_chain_put (struct tcf_chain *chain);int tcf_block_get (struct tcf_block **p_block,struct tcf_proto __rcu **p_filter_chain,struct Qdisc *q); -int tcf_block_get_ext (struct tcf_block **p_block, -struct tcf_proto __rcu **p_filter_chain,struct Qdisc *q, +int tcf_block_get_ext (struct tcf_block **p_block,struct Qdisc *q,struct tcf_block_ext_info *ei);void tcf_block_put (struct tcf_block *block); -void tcf_block_put_ext (struct tcf_block *block, -struct tcf_proto __rcu **p_filter_chain,struct Qdisc *q, +void tcf_block_put_ext (struct tcf_block *block,struct Qdisc *q,struct tcf_block_ext_info *ei);static inline struct Qdisc *tcf_block_q (struct tcf_block *block)
@@ -82,8 +82,7 @@ int tcf_block_get(struct tcf_block **p_block, }static inline -int tcf_block_get_ext (struct tcf_block **p_block, -struct tcf_proto __rcu **p_filter_chain,struct Qdisc *q, +int tcf_block_get_ext (struct tcf_block **p_block,struct Qdisc *q,struct tcf_block_ext_info *ei) {return 0 ;
@@ -94,8 +93,7 @@ static inline void tcf_block_put(struct tcf_block *block) }static inline -void tcf_block_put_ext (struct tcf_block *block, -struct tcf_proto __rcu **p_filter_chain,struct Qdisc *q, +void tcf_block_put_ext (struct tcf_block *block,struct Qdisc *q,struct tcf_block_ext_info *ei) { }
include/net/sch_generic.h +4 -1
@@ -260,9 +260,12 @@ struct qdisc_skb_cb {unsigned char data[QDISC_CB_PRIV_LEN ]; }; +typedef void tcf_chain_head_change_t (struct tcf_proto *tp_head,void *priv); +struct tcf_chain {struct tcf_proto __rcu *filter_chain; -struct tcf_proto __rcu **p_filter_chain; +tcf_chain_head_change_t *chain_head_change; +void *chain_head_change_priv;struct list_head list;struct tcf_block *block;u32 index;/* chain index */
net/sched/cls_api.c +32 -22
116 lines not on this page · raw message
net/sched/sch_ingress.c +20 -16
@@ -54,6 +54,13 @@ static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)return q->block; } +static void clsact_chain_head_change (struct tcf_proto *tp_head,void *priv) +{ +struct tcf_proto __rcu **p_filter_chain = priv; + +rcu_assign_pointer (*p_filter_chain, tp_head); +} +static int ingress_init (struct Qdisc *sch,struct nlattr *opt) {struct ingress_sched_data *q =qdisc_priv (sch);
@@ -61,9 +68,10 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt)int err; q->block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS ; + q->block_info.chain_head_change = clsact_chain_head_change; + q->block_info.chain_head_change_priv = &dev->ingress_cl_list; - err =tcf_block_get_ext (&q->block, &dev->ingress_cl_list, - sch, &q->block_info); + err =tcf_block_get_ext (&q->block, sch, &q->block_info);if (err)return err;
@@ -76,10 +84,8 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt)static void ingress_destroy (struct Qdisc *sch) {struct ingress_sched_data *q =qdisc_priv (sch); -struct net_device *dev =qdisc_dev (sch); -tcf_block_put_ext (q->block, &dev->ingress_cl_list, - sch, &q->block_info); +tcf_block_put_ext (q->block, sch, &q->block_info);net_dec_ingress_queue (); }
@@ -162,16 +168,18 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)int err; q->ingress_block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS ; + q->ingress_block_info.chain_head_change = clsact_chain_head_change; + q->ingress_block_info.chain_head_change_priv = &dev->ingress_cl_list; - err =tcf_block_get_ext (&q->ingress_block, &dev->ingress_cl_list, - sch, &q->ingress_block_info); + err =tcf_block_get_ext (&q->ingress_block, sch, &q->ingress_block_info);if (err)return err; q->egress_block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS ; + q->egress_block_info.chain_head_change = clsact_chain_head_change; + q->egress_block_info.chain_head_change_priv = &dev->egress_cl_list; - err =tcf_block_get_ext (&q->egress_block, &dev->egress_cl_list, - sch, &q->egress_block_info); + err =tcf_block_get_ext (&q->egress_block, sch, &q->egress_block_info);if (err) goto err_egress_block_get;
@@ -183,20 +191,16 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)return 0 ; err_egress_block_get: -tcf_block_put_ext (q->ingress_block, &dev->ingress_cl_list, - sch, &q->ingress_block_info); +tcf_block_put_ext (q->ingress_block, sch, &q->ingress_block_info);return err; }static void clsact_destroy (struct Qdisc *sch) {struct clsact_sched_data *q =qdisc_priv (sch); -struct net_device *dev =qdisc_dev (sch); -tcf_block_put_ext (q->egress_block, &dev->egress_cl_list, - sch, &q->egress_block_info); -tcf_block_put_ext (q->ingress_block, &dev->ingress_cl_list, - sch, &q->ingress_block_info); +tcf_block_put_ext (q->egress_block, sch, &q->egress_block_info); +tcf_block_put_ext (q->ingress_block, sch, &q->ingress_block_info);net_dec_ingress_queue ();net_dec_egress_queue ();
Signature · 1 line
2.9.5
Jiri Pirko
maintainerPATCH v4 2/2 net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
In reply to Jiri PirkoFrom: Jiri Pirko <[email protected]>
In sch_handle_egress and sch_handle_ingress tp->q is used only in order to update stats. So stats and filter list are the only things that are needed in clsact qdisc fastpath processing. Introduce new mini_Qdisc struct to hold those items. Also, introduce a helper to swap the mini_Qdisc structures in case filter list head changes.
This removes need for tp->q usage without added overhead.
--- include/linux/netdevice.h | 9 ++++++--- include/net/sch_generic.h | 32 ++++++++++++++++++++++++++++++++ net/core/dev.c | 21 +++++++++++---------- net/sched/sch_generic.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ net/sched/sch_ingress.c | 19 ++++++++++++++----- 5 files changed, 109 insertions(+), 18 deletions(-)
include/linux/netdevice.h +6 -3
@@ -1559,6 +1559,8 @@ enum netdev_priv_flags {* * @rx_handler: handler for received packets * @rx_handler_data: XXX: need comments on this one +* @miniq_ingress: ingress/clsact qdisc specific data for +* ingress processing * @ingress_queue: XXX: need comments on this one * @broadcast: hw bcast address *
@@ -1576,7 +1578,8 @@ enum netdev_priv_flags {* @tx_global_lock: XXX: need comments on this one * * @xps_maps: XXX: need comments on this one -* +* @miniq_egress: clsact qdisc specific data for +* egress processing * @watchdog_timeo: Represents the timeout that is used by * the watchdog (see dev_watchdog()) * @watchdog_timer: List of timers
@@ -1795,7 +1798,7 @@ struct net_device {void __rcu *rx_handler_data;#ifdef CONFIG_NET_CLS_ACT -struct tcf_proto __rcu *ingress_cl_list; +struct mini_Qdisc __rcu *miniq_ingress;#endif struct netdev_queue __rcu *ingress_queue;#ifdef CONFIG_NETFILTER_INGRESS
@@ -1826,7 +1829,7 @@ struct net_device {struct xps_dev_maps __rcu *xps_maps;#endif #ifdef CONFIG_NET_CLS_ACT -struct tcf_proto __rcu *egress_cl_list; +struct mini_Qdisc __rcu *miniq_egress;#endif /* These may be needed for future network-power-down code. */
include/net/sch_generic.h +32 -0
@@ -904,4 +904,36 @@ static inline void psched_ratecfg_getrate(struct tc_ratespec *res, res->linklayer = (r->linklayer & TC_LINKLAYER_MASK); } +/* Mini Qdisc serves for specific needs of ingress/clsact Qdisc. +* The fast path only needs to access filter list and to update stats +*/ +struct mini_Qdisc { +struct tcf_proto *filter_list; +struct gnet_stats_basic_cpu __percpu *cpu_bstats; +struct gnet_stats_queue __percpu *cpu_qstats; +struct rcu_head rcu; +}; + +static inline void mini_qdisc_bstats_cpu_update (struct mini_Qdisc *miniq, +const struct sk_buff *skb) +{ +bstats_cpu_update (this_cpu_ptr (miniq->cpu_bstats), skb); +} + +static inline void mini_qdisc_qstats_cpu_drop (struct mini_Qdisc *miniq) +{ +this_cpu_inc (miniq->cpu_qstats->drops); +} + +struct mini_Qdisc_pair { +struct mini_Qdisc miniq1; +struct mini_Qdisc miniq2; +struct mini_Qdisc __rcu **p_miniq; +}; + +void mini_qdisc_pair_swap (struct mini_Qdisc_pair *miniqp, +struct tcf_proto *tp_head); +void mini_qdisc_pair_init (struct mini_Qdisc_pair *miniqp,struct Qdisc *qdisc, +struct mini_Qdisc __rcu **p_miniq); +#endif
net/core/dev.c +11 -10
@@ -3274,22 +3274,22 @@ EXPORT_SYMBOL(dev_loopback_xmit);static struct sk_buff *sch_handle_egress (struct sk_buff *skb,int *ret,struct net_device *dev) { -struct tcf_proto *cl =rcu_dereference_bh (dev->egress_cl_list); +struct mini_Qdisc *miniq =rcu_dereference_bh (dev->miniq_egress);struct tcf_result cl_res; -if (!cl) +if (!miniq)return skb;/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */ -qdisc_bstats_cpu_update (cl->q, skb); +mini_qdisc_bstats_cpu_update (miniq, skb); -switch (tcf_classify (skb, cl, &cl_res, false)) { +switch (tcf_classify (skb, miniq->filter_list, &cl_res, false)) {case TC_ACT_OK :case TC_ACT_RECLASSIFY : skb->tc_index =TC_H_MIN (cl_res.classid);break ;case TC_ACT_SHOT : -qdisc_qstats_cpu_drop (cl->q); +mini_qdisc_qstats_cpu_drop (miniq); *ret =NET_XMIT_DROP ;kfree_skb (skb);return NULL ;
@@ -4189,7 +4189,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, struct net_device *orig_dev) {#ifdef CONFIG_NET_CLS_ACT -struct tcf_proto *cl =rcu_dereference_bh (skb->dev->ingress_cl_list); +struct mini_Qdisc *miniq =rcu_dereference_bh (skb->dev->miniq_ingress);struct tcf_result cl_res;/* If there's at least one ingress present somewhere (so
@@ -4197,8 +4197,9 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,* that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; +if (*pt_prev) { *ret =deliver_skb (skb, *pt_prev, orig_dev); *pt_prev =NULL ;
@@ -4206,15 +4207,15 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,qdisc_skb_cb (skb)->pkt_len = skb->len; skb->tc_at_ingress =1 ; -qdisc_bstats_cpu_update (cl->q, skb); +mini_qdisc_bstats_cpu_update (miniq, skb); -switch (tcf_classify (skb, cl, &cl_res, false)) { +switch (tcf_classify (skb, miniq->filter_list, &cl_res, false)) {case TC_ACT_OK :case TC_ACT_RECLASSIFY : skb->tc_index =TC_H_MIN (cl_res.classid);break ;case TC_ACT_SHOT : -qdisc_qstats_cpu_drop (cl->q); +mini_qdisc_qstats_cpu_drop (miniq);kfree_skb (skb);return NULL ;case TC_ACT_STOLEN :
net/sched/sch_generic.c +46 -0
49 lines not on this page · raw message
net/sched/sch_ingress.c +14 -5
@@ -21,6 +21,7 @@struct ingress_sched_data {struct tcf_block *block;struct tcf_block_ext_info block_info; +struct mini_Qdisc_pair miniqp; };static struct Qdisc *ingress_leaf (struct Qdisc *sch,unsigned long arg)
@@ -56,9 +57,9 @@ static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)static void clsact_chain_head_change (struct tcf_proto *tp_head,void *priv) { -struct tcf_proto __rcu **p_filter_chain = priv; +struct mini_Qdisc_pair *miniqp = priv; -rcu_assign_pointer (*p_filter_chain, tp_head); +mini_qdisc_pair_swap (miniqp, tp_head); }static int ingress_init (struct Qdisc *sch,struct nlattr *opt)
@@ -67,9 +68,11 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt)struct net_device *dev =qdisc_dev (sch);int err; +mini_qdisc_pair_init (&q->miniqp, sch, &dev->miniq_ingress); + q->block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS ; q->block_info.chain_head_change = clsact_chain_head_change; - q->block_info.chain_head_change_priv = &dev->ingress_cl_list; + q->block_info.chain_head_change_priv = &q->miniqp; err =tcf_block_get_ext (&q->block, sch, &q->block_info);if (err)
@@ -128,6 +131,8 @@ struct clsact_sched_data {struct tcf_block *egress_block;struct tcf_block_ext_info ingress_block_info;struct tcf_block_ext_info egress_block_info; +struct mini_Qdisc_pair miniqp_ingress; +struct mini_Qdisc_pair miniqp_egress; };static unsigned long clsact_find (struct Qdisc *sch,u32 classid)
@@ -167,17 +172,21 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)struct net_device *dev =qdisc_dev (sch);int err; +mini_qdisc_pair_init (&q->miniqp_ingress, sch, &dev->miniq_ingress); + q->ingress_block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS ; q->ingress_block_info.chain_head_change = clsact_chain_head_change; - q->ingress_block_info.chain_head_change_priv = &dev->ingress_cl_list; + q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress; err =tcf_block_get_ext (&q->ingress_block, sch, &q->ingress_block_info);if (err)return err; +mini_qdisc_pair_init (&q->miniqp_egress, sch, &dev->miniq_egress); + q->egress_block_info.binder_type =TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS ; q->egress_block_info.chain_head_change = clsact_chain_head_change; - q->egress_block_info.chain_head_change_priv = &dev->egress_cl_list; + q->egress_block_info.chain_head_change_priv = &q->miniqp_egress; err =tcf_block_get_ext (&q->egress_block, sch, &q->egress_block_info);if (err)
Signature · 1 line
2.9.5
David Miller
maintainerFrom: Jiri Pirko <[email protected]>
Date: Fri, 3 Nov 2017 11:46:23 +0100
Quoted 2 lines
This patchset's main patch is patch number 2. It carries the description. Patch 1 is just a dependency.
Series applied, thanks Jiri.