From: Paolo Abeni <pabeni@redhat.com> Date: 2017-09-27 17:15:24
When a host is under high ipv6 load, the updates of the ingress
route '__use' field are a source of relevant contention: such
field is updated for each packet and several cores can access
concurrently the dst, even if percpu dst entries are available
and used.
The __use value is just a rough indication of the dst usage: is
already updated concurrently from multiple CPUs without any lock,
so we can decrease the contention leveraging the percpu dst to perform
__use bulk updates: if a per cpu dst entry is found, we account on
such entry and we flush the percpu counter once per jiffy.
Performace gain under UDP flood is as follows:
nr RX queues before after delta
kpps kpps (%)
2 2316 2688 16
3 3033 3605 18
4 3963 4328 9
5 4379 5253 19
6 5137 6000 16
Performance gain under TCP syn flood should be measurable as well.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/ipv6/route.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
@@ -1170,12 +1170,24 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,structrt6_info*pcpu_rt;-rt->dst.lastuse=jiffies;-rt->dst.__use++;pcpu_rt=rt6_get_pcpu_route(rt);if(pcpu_rt){+unsignedlongts;+read_unlock_bh(&table->tb6_lock);++/* do lazy updates of rt->dst->__use, at most once+*perjiffy,toavoidcontentiononsuchcacheline.+*/+ts=jiffies;+pcpu_rt->dst.__use++;+if(pcpu_rt->dst.lastuse!=ts){+rt->dst.__use+=pcpu_rt->dst.__use;+rt->dst.lastuse=ts;+pcpu_rt->dst.__use=0;+pcpu_rt->dst.lastuse=ts;+}}else{/* We have to do the read_unlock first*becausert6_make_pcpu_route()maytrigger
On Wed, Sep 27, 2017 at 10:14 AM, Paolo Abeni [off-list ref] wrote:
quoted hunk
When a host is under high ipv6 load, the updates of the ingress
route '__use' field are a source of relevant contention: such
field is updated for each packet and several cores can access
concurrently the dst, even if percpu dst entries are available
and used.
The __use value is just a rough indication of the dst usage: is
already updated concurrently from multiple CPUs without any lock,
so we can decrease the contention leveraging the percpu dst to perform
__use bulk updates: if a per cpu dst entry is found, we account on
such entry and we flush the percpu counter once per jiffy.
Performace gain under UDP flood is as follows:
nr RX queues before after delta
kpps kpps (%)
2 2316 2688 16
3 3033 3605 18
4 3963 4328 9
5 4379 5253 19
6 5137 6000 16
Performance gain under TCP syn flood should be measurable as well.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
net/ipv6/route.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
@@ -1170,12 +1170,24 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,structrt6_info*pcpu_rt;-rt->dst.lastuse=jiffies;-rt->dst.__use++;pcpu_rt=rt6_get_pcpu_route(rt);if(pcpu_rt){+unsignedlongts;+read_unlock_bh(&table->tb6_lock);++/* do lazy updates of rt->dst->__use, at most once+*perjiffy,toavoidcontentiononsuchcacheline.+*/+ts=jiffies;+pcpu_rt->dst.__use++;+if(pcpu_rt->dst.lastuse!=ts){+rt->dst.__use+=pcpu_rt->dst.__use;+rt->dst.lastuse=ts;+pcpu_rt->dst.__use=0;+pcpu_rt->dst.lastuse=ts;+}}else{/* We have to do the read_unlock first*becausert6_make_pcpu_route()maytrigger
@@ -1170,8 +1170,7 @@ struct rt6_info *ip6_pol_route(struct net *net,
struct fib6_table *table,
struct rt6_info *pcpu_rt;
- rt->dst.lastuse = jiffies;
- rt->dst.__use++;
+ dst_use_noref(rt, jiffies);
pcpu_rt = rt6_get_pcpu_route(rt);
if (pcpu_rt) {
This way we always only update dst->__use and dst->lastuse at most
once per jiffy. And we don't really need to update pcpu and then do
the copy over from pcpu_rt to rt operation.
Another thing is that I don't really see any places making use of
dst->__use. So maybe we can also get rid of this dst->__use field?
Thanks.
Wei
@@ -1170,8 +1170,7 @@ struct rt6_info *ip6_pol_route(struct net *net,
struct fib6_table *table,
struct rt6_info *pcpu_rt;
- rt->dst.lastuse = jiffies;
- rt->dst.__use++;
+ dst_use_noref(rt, jiffies);
pcpu_rt = rt6_get_pcpu_route(rt);
if (pcpu_rt) {
This way we always only update dst->__use and dst->lastuse at most
once per jiffy. And we don't really need to update pcpu and then do
the copy over from pcpu_rt to rt operation.
Another thing is that I don't really see any places making use of
dst->__use. So maybe we can also get rid of this dst->__use field?
Thanks.
Wei
Paolo, given we are very close to send Wei awesome work about IPv6
routing cache,
could we ask you to wait few days before doing the same work from your side ?
Main issue is the rwlock, and we are converting it to full RCU.
You are sending patches that are making our job very difficult IMO.
We chose to mimic the change done in neighbour code years ago
( 0ed8ddf4045fcfcac36bad753dc4046118c603ec )
Thanks.
@@ -1170,8 +1170,7 @@ struct rt6_info *ip6_pol_route(struct net *net,
struct fib6_table *table,
struct rt6_info *pcpu_rt;
- rt->dst.lastuse = jiffies;
- rt->dst.__use++;
+ dst_use_noref(rt, jiffies);
pcpu_rt = rt6_get_pcpu_route(rt);
if (pcpu_rt) {
This way we always only update dst->__use and dst->lastuse at most
once per jiffy. And we don't really need to update pcpu and then do
the copy over from pcpu_rt to rt operation.
Another thing is that I don't really see any places making use of
dst->__use. So maybe we can also get rid of this dst->__use field?
Thanks.
Wei
Paolo, given we are very close to send Wei awesome work about IPv6
routing cache,
could we ask you to wait few days before doing the same work from your side ?
Main issue is the rwlock, and we are converting it to full RCU.
+1
We can get a better picture of other optimizations once
the rwlock is removed.
You are sending patches that are making our job very difficult IMO.
We chose to mimic the change done in neighbour code years ago
( 0ed8ddf4045fcfcac36bad753dc4046118c603ec )
Thanks.
@@ -1170,8 +1170,7 @@ struct rt6_info *ip6_pol_route(struct net *net,
struct fib6_table *table,
struct rt6_info *pcpu_rt;
- rt->dst.lastuse = jiffies;
- rt->dst.__use++;
+ dst_use_noref(rt, jiffies);
pcpu_rt = rt6_get_pcpu_route(rt);
if (pcpu_rt) {
This way we always only update dst->__use and dst->lastuse at most
once per jiffy. And we don't really need to update pcpu and then do
the copy over from pcpu_rt to rt operation.
Another thing is that I don't really see any places making use of
dst->__use. So maybe we can also get rid of this dst->__use field?
Thanks.
Wei
Paolo, given we are very close to send Wei awesome work about IPv6
routing cache,
could we ask you to wait few days before doing the same work from your side ?
Ok, no problem - thanks instead. I'll wait for it.
Main issue is the rwlock, and we are converting it to full RCU.
You are sending patches that are making our job very difficult IMO.
On my side I have only another small change in this area, I'll
eventually try to rebase it later, if still relevant.
Or I can share it now, if you are interested.
Cheers,
Paolo