net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
Subsystems (3)
Jiri Pirko
maintainerPATCH v2 1/1 net: core: introduce mini_Qdisc and eliminate usage of tp->q for clsact fastpath
From: 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. This removes need for tp->q usage without added overhead.
---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
--- include/linux/netdevice.h | 9 ++++++--- include/net/pkt_cls.h | 1 + include/net/sch_generic.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++ net/core/dev.c | 21 ++++++++++++-------- net/sched/cls_api.c | 23 +++++++++++++++++----- net/sched/sch_ingress.c | 40 +++++++++++++++++++++++++++++--------- 6 files changed, 118 insertions(+), 25 deletions(-)
include/linux/netdevice.h +6 -3
@@ -1558,6 +1558,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 *
@@ -1575,7 +1577,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
@@ -1794,7 +1797,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
@@ -1825,7 +1828,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/pkt_cls.h +1 -0
@@ -25,6 +25,7 @@ enum tcf_block_binder_type {struct tcf_block_ext_info {enum tcf_block_binder_type binder_type; +tcf_chain_change_empty_t *chain_change_empty; };struct tcf_block_cb ;
include/net/sch_generic.h +49 -0
76 lines not on this page · raw message
net/core/dev.c +13 -8
@@ -3274,14 +3274,16 @@ 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; +struct tcf_proto *cl; -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);/* 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)) {case TC_ACT_OK :
@@ -3289,7 +3291,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev) 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,16 +4191,19 @@ 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; +struct tcf_proto *cl;/* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list); +if (*pt_prev) { *ret =deliver_skb (skb, *pt_prev, orig_dev); *pt_prev =NULL ;
@@ -4206,7 +4211,7 @@ 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)) {case TC_ACT_OK :
@@ -4214,7 +4219,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, 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/cls_api.c +18 -5
@@ -190,8 +190,11 @@ static void tcf_chain_flush(struct tcf_chain *chain) {struct tcf_proto *tp; -if (chain->p_filter_chain) +if (chain->p_filter_chain) { +if (chain->chain_change_empty) + chain->chain_change_empty (chain->p_filter_chain, true);RCU_INIT_POINTER (*chain->p_filter_chain,NULL ); + }while ((tp =rtnl_dereference (chain->filter_chain)) !=NULL ) {RCU_INIT_POINTER (chain->filter_chain, tp->next);tcf_chain_put (chain);
@@ -235,9 +238,11 @@ EXPORT_SYMBOL(tcf_chain_put);static void tcf_chain_filter_chain_ptr_set (struct tcf_chain *chain, -struct tcf_proto __rcu **p_filter_chain) +struct tcf_proto __rcu **p_filter_chain, +struct tcf_block_ext_info *ei) { chain->p_filter_chain = p_filter_chain; + chain->chain_change_empty = ei->chain_change_empty; } static void tcf_block_offload_cmd(struct tcf_block *block, struct Qdisc *q,
@@ -286,7 +291,7 @@ int tcf_block_get_ext(struct tcf_block **p_block, err = -ENOMEM ; goto err_chain_create; } -tcf_chain_filter_chain_ptr_set (chain, p_filter_chain); +tcf_chain_filter_chain_ptr_set (chain, p_filter_chain, ei); block->net =qdisc_net (q); block->q = q;tcf_block_offload_bind (block, q, ei);
@@ -528,8 +533,13 @@ static void tcf_chain_tp_insert(struct tcf_chain *chain, struct tcf_proto *tp) {if (chain->p_filter_chain && - *chain_info->pprev == chain->filter_chain) + *chain_info->pprev == chain->filter_chain) { +bool was_null = *chain->p_filter_chain ==NULL ; +rcu_assign_pointer (*chain->p_filter_chain, tp); +if (was_null && chain->chain_change_empty) + chain->chain_change_empty (chain->p_filter_chain, false); + }RCU_INIT_POINTER (tp->next,tcf_chain_tp_prev (chain_info));rcu_assign_pointer (*chain_info->pprev, tp);tcf_chain_hold (chain);
@@ -541,8 +551,11 @@ static void tcf_chain_tp_remove(struct tcf_chain *chain, {struct tcf_proto *next =rtnl_dereference (chain_info->next); -if (chain->p_filter_chain && tp == chain->filter_chain) +if (chain->p_filter_chain && tp == chain->filter_chain) { +if (!next && chain->chain_change_empty) + chain->chain_change_empty (chain->p_filter_chain, true);RCU_INIT_POINTER (*chain->p_filter_chain, next); + }RCU_INIT_POINTER (*chain_info->pprev, next);tcf_chain_put (chain); }
net/sched/sch_ingress.c +31 -9
@@ -21,6 +21,7 @@struct ingress_sched_data {struct tcf_block *block;struct tcf_block_ext_info block_info; +struct mini_Qdisc miniq; };static struct Qdisc *ingress_leaf (struct Qdisc *sch,unsigned long arg)
@@ -54,6 +55,19 @@ static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)return q->block; } +static void clsact_chain_change_empty (struct tcf_proto __rcu **p_filter_list, +bool empty) +{ +struct mini_Qdisc *miniq =container_of (p_filter_list, + struct mini_Qdisc, + filter_list); + +if (empty) +mini_qdisc_disable (miniq); +else +mini_qdisc_enable (miniq); +} +static int ingress_init (struct Qdisc *sch,struct nlattr *opt) {struct ingress_sched_data *q =qdisc_priv (sch);
@@ -61,8 +75,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_change_empty = clsact_chain_change_empty; - err =tcf_block_get_ext (&q->block, &dev->ingress_cl_list, +mini_qdisc_init (&q->miniq, sch, &dev->miniq_ingress); + err =tcf_block_get_ext (&q->block, &q->miniq.filter_list, sch, &q->block_info);if (err)return err;
@@ -76,9 +92,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, +tcf_block_put_ext (q->block, &q->miniq.filter_list, sch, &q->block_info);net_dec_ingress_queue (); }
@@ -122,6 +137,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 miniq_ingress; +struct mini_Qdisc miniq_egress; };static unsigned long clsact_find (struct Qdisc *sch,u32 classid)
@@ -162,15 +179,21 @@ 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_change_empty = clsact_chain_change_empty; - err =tcf_block_get_ext (&q->ingress_block, &dev->ingress_cl_list, +mini_qdisc_init (&q->miniq_ingress, sch, &dev->miniq_ingress); + err =tcf_block_get_ext (&q->ingress_block, + &q->miniq_ingress.filter_list, 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_change_empty = clsact_chain_change_empty; - err =tcf_block_get_ext (&q->egress_block, &dev->egress_cl_list, +mini_qdisc_init (&q->miniq_egress, sch, &dev->miniq_egress); + err =tcf_block_get_ext (&q->egress_block, + &q->miniq_egress.filter_list, sch, &q->egress_block_info);if (err) goto err_egress_block_get;
@@ -183,7 +206,7 @@ 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, +tcf_block_put_ext (q->ingress_block, &q->miniq_ingress.filter_list, sch, &q->ingress_block_info);return err; }
@@ -191,11 +214,10 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)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, +tcf_block_put_ext (q->egress_block, &q->miniq_egress.filter_list, sch, &q->egress_block_info); -tcf_block_put_ext (q->ingress_block, &dev->ingress_cl_list, +tcf_block_put_ext (q->ingress_block, &q->miniq_ingress.filter_list, sch, &q->ingress_block_info);net_dec_ingress_queue ();
Signature · 1 line
2.9.5
Quoted 7 lines · Jiri Pirko
From: Jiri Pirko <[email protected]>
In
sch_handle_egressandsch_handle_ingresstp->qis 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 newmini_Qdiscstruct to hold those items. This removes need fortp->qusage without added overhead.
that is false claim. The patch adds run-time overhead instead.
Quoted 5 lines
Signed-off-by Jiri Pirko <[email protected]>---
v1->v2:
- Use dev instead ofskb->devinsch_handle_egressas pointed out by Daniel
- Fixedsynchronize_rcu_bh()inmini_qdisc_disableand commented
...
Quoted 7 lines
net/core/dev.c +0
-0@@ -3274,14 +3274,16 @@ EXPORT_SYMBOL(dev_loopback_xmit);static struct sk_buff *sch_handle_egress (struct sk_buff *skb,int *ret,struct net_device *dev)
net/core/dev.c EXPORT_SYMBOL(dev_loopback_xmit); · line 3283
Quoted 10 lines
net/core/dev.c +4
-2{ -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; +struct tcf_proto *cl; -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);
Just like Daniel pointed out in the earlier version of the patch it adds another rcu dereference to critical path of execution for every packet...
Quoted 8 lines
net/core/dev.c +2
-1@@ -4189,16 +4191,19 @@ 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; +struct tcf_proto *cl;
net/core/dev.c sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, · line 4205
Quoted 10 lines
net/core/dev.c +2
-1/* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);
... both ingress and egress paths.
There gotta be very strong reasons to penalize all users for this and I don't see them in commit log.
Jiri Pirko
maintainerQuoted 48 lines · Thu, Oct 26, 2017 at 05:54:56PM CEST, [email protected] wrote:
Quoted 7 lines · Jiri Pirko
From: Jiri Pirko <[email protected]>
In
sch_handle_egressandsch_handle_ingresstp->qis 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 newmini_Qdiscstruct to hold those items. This removes need fortp->qusage without added overhead.that is false claim. The patch adds run-time overhead instead.
Quoted 5 lines
Signed-off-by Jiri Pirko <[email protected]>---
v1->v2:
- Use dev instead ofskb->devinsch_handle_egressas pointed out by Daniel
- Fixedsynchronize_rcu_bh()inmini_qdisc_disableand commented...
Quoted 7 lines
net/core/dev.c +0
-0@@ -3274,14 +3274,16 @@ EXPORT_SYMBOL(dev_loopback_xmit);static struct sk_buff *sch_handle_egress (struct sk_buff *skb,int *ret,struct net_device *dev)net/core/dev.c EXPORT_SYMBOL(dev_loopback_xmit); · line 3283
Quoted 10 lines
net/core/dev.c +4
-2{ -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; +struct tcf_proto *cl; -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);Just like Daniel pointed out in the earlier version of the patch it adds another rcu dereference to critical path of execution for every packet...
Quoted 9 lines
net/core/dev.c +2
-1@@ -4189,16 +4191,19 @@ 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; +struct tcf_proto *cl;
Quoted 13 lines
net/core/dev.c sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, · line 4205
Quoted 9 lines
net/core/dev.c +2
-1/* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);... both ingress and egress paths.
There gotta be very strong reasons to penalize all users for this and I don't see them in commit log.
Okay, the reason is that in order to make tcf_proto instances independent on qdisc instances so they could be shared amond multiple qdiscs, I have to remove tp->q.
Since tp->q is there only needed to update stats, I introduced mini_Qdisc just to hold those stats pointers and eliminate need to use tp->q at all.
I understand that the 2 rcu_dereferences are adding additional overhead (the desctiption is wrong, I admint), but I do not see another sane way to do this. Do you see it?
I think that it might be possible to have miniq->filter_list as a non-rcu pointer. However that would require allocate a new miniq and replace every time head of the list changes. That would require even more ugliness in the slow path. Is there a balance in overhead in the fast path and ugliness in the slowpath?
Quoted 63 lines · Jiri Pirko
Quoted 48 lines · Thu, Oct 26, 2017 at 05:54:56PM CEST, [email protected] wrote:
Quoted 7 lines · Jiri Pirko
From: Jiri Pirko <[email protected]>
In
sch_handle_egressandsch_handle_ingresstp->qis 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 newmini_Qdiscstruct to hold those items. This removes need fortp->qusage without added overhead.that is false claim. The patch adds run-time overhead instead.
Quoted 5 lines
Signed-off-by Jiri Pirko <[email protected]>---
v1->v2:
- Use dev instead ofskb->devinsch_handle_egressas pointed out by Daniel
- Fixedsynchronize_rcu_bh()inmini_qdisc_disableand commented...
Quoted 7 lines
net/core/dev.c +0
-0@@ -3274,14 +3274,16 @@ EXPORT_SYMBOL(dev_loopback_xmit);static struct sk_buff *sch_handle_egress (struct sk_buff *skb,int *ret,struct net_device *dev)net/core/dev.c EXPORT_SYMBOL(dev_loopback_xmit); · line 3283
Quoted 10 lines
net/core/dev.c +4
-2{ -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; +struct tcf_proto *cl; -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);Just like Daniel pointed out in the earlier version of the patch it adds another rcu dereference to critical path of execution for every packet...
Quoted 9 lines
net/core/dev.c +2
-1@@ -4189,16 +4191,19 @@ 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; +struct tcf_proto *cl;Quoted 13 lines
net/core/dev.c sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, · line 4205
Quoted 9 lines
net/core/dev.c +2
-1/* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);... both ingress and egress paths.
There gotta be very strong reasons to penalize all users for this and I don't see them in commit log.
Quoted 4 lines
Okay, the reason is that in order to make
tcf_protoinstances independent on qdisc instances so they could be shared amond multiple qdiscs, I have to removetp->q.
This is effectively trading performance for some memory savings. Also it requires a very specific use case where many filters are duplicated across multiple interfaces. At least for my use case we don't have the conditions for this to be useful so it just looks like performance overhead. I suspect for most server/workstation usages this condition of many interfaces with many identical filter chains is not the case.
Any data on how much memory we save in some use cases by sharing filter chains? If its just a usability thing a user space script could fix that.
Quoted 8 lines
Since
tp->qis there only needed to update stats, I introducedmini_Qdiscjust to hold those stats pointers and eliminate need to usetp->qat all.I understand that the 2
rcu_dereferencesare adding additional overhead (the desctiption is wrong, I admint), but I do not see another sane way to do this. Do you see it?
The only thing I can come up with is more or less what you outline below. I started to type it up for a reply to v1 of this patch but thought I would sleep on it and see if I had any better ideas. I didn't come up with anything better.
Quoted 6 lines
I think that it might be possible to have
miniq->filter_listas a non-rcu pointer. However that would require allocate a new miniq and replace every time head of the list changes. That would require even more ugliness in the slow path. Is there a balance in overhead in the fast path and ugliness in the slowpath?
We are working very hard (with XDP, RCU filters, etc) to remove per packet overheads. I would prefer slowpath ugliness over per packet costs that are going to be hard to remove once they are included. Especially when the value of sharing filter list seems limited to a few special use cases.
Thanks,
John
Jiri Pirko
maintainerQuoted 76 lines · Thu, Oct 26, 2017 at 07:18:51PM CEST, [email protected] wrote:
Quoted 63 lines · Jiri Pirko
Quoted 48 lines · Thu, Oct 26, 2017 at 05:54:56PM CEST, [email protected] wrote:
Quoted 7 lines · Jiri Pirko
From: Jiri Pirko <[email protected]>
In
sch_handle_egressandsch_handle_ingresstp->qis 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 newmini_Qdiscstruct to hold those items. This removes need fortp->qusage without added overhead.that is false claim. The patch adds run-time overhead instead.
Quoted 5 lines
Signed-off-by Jiri Pirko <[email protected]>---
v1->v2:
- Use dev instead ofskb->devinsch_handle_egressas pointed out by Daniel
- Fixedsynchronize_rcu_bh()inmini_qdisc_disableand commented...
Quoted 7 lines
net/core/dev.c +0
-0@@ -3274,14 +3274,16 @@ EXPORT_SYMBOL(dev_loopback_xmit);static struct sk_buff *sch_handle_egress (struct sk_buff *skb,int *ret,struct net_device *dev)net/core/dev.c EXPORT_SYMBOL(dev_loopback_xmit); · line 3283
Quoted 10 lines
net/core/dev.c +4
-2{ -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; +struct tcf_proto *cl; -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);Just like Daniel pointed out in the earlier version of the patch it adds another rcu dereference to critical path of execution for every packet...
Quoted 9 lines
net/core/dev.c +2
-1@@ -4189,16 +4191,19 @@ 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; +struct tcf_proto *cl;Quoted 13 lines
net/core/dev.c sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, · line 4205
Quoted 9 lines
net/core/dev.c +2
-1/* If there's at least one ingress present somewhere (so * we get here via enabled static key), remaining devices * that are not configured with an ingress qdisc will bail * out here. */ -if (!cl) +if (!miniq)return skb; + cl =rcu_dereference_bh (miniq->filter_list);... both ingress and egress paths.
There gotta be very strong reasons to penalize all users for this and I don't see them in commit log.Quoted 4 lines
Okay, the reason is that in order to make
tcf_protoinstances independent on qdisc instances so they could be shared amond multiple qdiscs, I have to removetp->q.This is effectively trading performance for some memory savings. Also it requires a very specific use case where many filters are duplicated across multiple interfaces. At least for my use case we don't have the conditions for this to be useful so it just looks like performance overhead. I suspect for most server/workstation usages this condition of many interfaces with many identical filter chains is not the case.
Quoted 3 lines
Any data on how much memory we save in some use cases by sharing filter chains? If its just a usability thing a user space script could fix that.
In case of mlxsw, when we put the rules in tcam which is quite limited, we safe quite a lot of space.
Quoted 10 lines
Quoted 9 lines
Since
tp->qis there only needed to update stats, I introducedmini_Qdiscjust to hold those stats pointers and eliminate need to usetp->qat all.I understand that the 2
rcu_dereferencesare adding additional overhead (the desctiption is wrong, I admint), but I do not see another sane way to do this. Do you see it?
Quoted 4 lines
The only thing I can come up with is more or less what you outline below. I started to type it up for a reply to v1 of this patch but thought I would sleep on it and see if I had any better ideas. I didn't come up with anything better.
Okay.
Quoted 8 lines
Quoted 7 lines
I think that it might be possible to have
miniq->filter_listas a non-rcu pointer. However that would require allocate a new miniq and replace every time head of the list changes. That would require even more ugliness in the slow path. Is there a balance in overhead in the fast path and ugliness in the slowpath?
Quoted 4 lines
We are working very hard (with XDP, RCU filters, etc) to remove per packet overheads. I would prefer slowpath ugliness over per packet costs that are going to be hard to remove once they are included. Especially when the value of sharing filter list seems limited to a few special use cases.
Okay. Going to code the ugliness then :)
Thanks.