diff options
author | Julian Anastasov <ja@ssi.bg> | 2011-03-13 19:37:49 -0400 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2011-03-14 20:36:52 -0400 |
commit | 55a3d4e15c7c953ecc55b96b83d2679abf8a7899 (patch) | |
tree | d1f1c52c77c04b717ca1a26bc7a0e90adb0498df | |
parent | 2a0751af09c3099cf2837c623ca5d0436317d02d (diff) |
ipvs: properly zero stats and rates
Currently, the new percpu counters are not zeroed and
the zero commands do not work as expected, we still show the old
sum of percpu values. OTOH, we can not reset the percpu counters
from user context without causing the incrementing to use old
and bogus values.
So, as Eric Dumazet suggested fix that by moving all overhead
to stats reading in user context. Do not introduce overhead in
timer context (estimator) and incrementing (packet handling in
softirqs).
The new ustats0 field holds the zero point for all
counter values, the rates always use 0 as base value as before.
When showing the values to user space just give the difference
between counters and the base values. The only drawback is that
percpu stats are not zeroed, they are accessible only from /proc
and are new interface, so it should not be a compatibility problem
as long as the sum stats are correct after zeroing.
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
-rw-r--r-- | include/net/ip_vs.h | 1 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_ctl.c | 96 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_est.c | 15 |
3 files changed, 69 insertions, 43 deletions
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 9db750d9082d..06f5af4b626d 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h | |||
@@ -374,6 +374,7 @@ struct ip_vs_stats { | |||
374 | struct ip_vs_estimator est; /* estimator */ | 374 | struct ip_vs_estimator est; /* estimator */ |
375 | struct ip_vs_cpu_stats *cpustats; /* per cpu counters */ | 375 | struct ip_vs_cpu_stats *cpustats; /* per cpu counters */ |
376 | spinlock_t lock; /* spin lock */ | 376 | spinlock_t lock; /* spin lock */ |
377 | struct ip_vs_stats_user ustats0; /* reset values */ | ||
377 | }; | 378 | }; |
378 | 379 | ||
379 | /* | 380 | /* |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index a2a67ad7e094..804fee7be694 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -711,13 +711,51 @@ static void ip_vs_trash_cleanup(struct net *net) | |||
711 | } | 711 | } |
712 | } | 712 | } |
713 | 713 | ||
714 | static void | ||
715 | ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) | ||
716 | { | ||
717 | #define IP_VS_SHOW_STATS_COUNTER(c) dst->c = src->ustats.c - src->ustats0.c | ||
718 | #define IP_VS_SHOW_STATS_RATE(r) dst->r = src->ustats.r | ||
719 | |||
720 | spin_lock_bh(&src->lock); | ||
721 | |||
722 | IP_VS_SHOW_STATS_COUNTER(conns); | ||
723 | IP_VS_SHOW_STATS_COUNTER(inpkts); | ||
724 | IP_VS_SHOW_STATS_COUNTER(outpkts); | ||
725 | IP_VS_SHOW_STATS_COUNTER(inbytes); | ||
726 | IP_VS_SHOW_STATS_COUNTER(outbytes); | ||
727 | |||
728 | IP_VS_SHOW_STATS_RATE(cps); | ||
729 | IP_VS_SHOW_STATS_RATE(inpps); | ||
730 | IP_VS_SHOW_STATS_RATE(outpps); | ||
731 | IP_VS_SHOW_STATS_RATE(inbps); | ||
732 | IP_VS_SHOW_STATS_RATE(outbps); | ||
733 | |||
734 | spin_unlock_bh(&src->lock); | ||
735 | } | ||
714 | 736 | ||
715 | static void | 737 | static void |
716 | ip_vs_zero_stats(struct ip_vs_stats *stats) | 738 | ip_vs_zero_stats(struct ip_vs_stats *stats) |
717 | { | 739 | { |
718 | spin_lock_bh(&stats->lock); | 740 | spin_lock_bh(&stats->lock); |
719 | 741 | ||
720 | memset(&stats->ustats, 0, sizeof(stats->ustats)); | 742 | /* get current counters as zero point, rates are zeroed */ |
743 | |||
744 | #define IP_VS_ZERO_STATS_COUNTER(c) stats->ustats0.c = stats->ustats.c | ||
745 | #define IP_VS_ZERO_STATS_RATE(r) stats->ustats.r = 0 | ||
746 | |||
747 | IP_VS_ZERO_STATS_COUNTER(conns); | ||
748 | IP_VS_ZERO_STATS_COUNTER(inpkts); | ||
749 | IP_VS_ZERO_STATS_COUNTER(outpkts); | ||
750 | IP_VS_ZERO_STATS_COUNTER(inbytes); | ||
751 | IP_VS_ZERO_STATS_COUNTER(outbytes); | ||
752 | |||
753 | IP_VS_ZERO_STATS_RATE(cps); | ||
754 | IP_VS_ZERO_STATS_RATE(inpps); | ||
755 | IP_VS_ZERO_STATS_RATE(outpps); | ||
756 | IP_VS_ZERO_STATS_RATE(inbps); | ||
757 | IP_VS_ZERO_STATS_RATE(outbps); | ||
758 | |||
721 | ip_vs_zero_estimator(stats); | 759 | ip_vs_zero_estimator(stats); |
722 | 760 | ||
723 | spin_unlock_bh(&stats->lock); | 761 | spin_unlock_bh(&stats->lock); |
@@ -1963,7 +2001,7 @@ static const struct file_operations ip_vs_info_fops = { | |||
1963 | static int ip_vs_stats_show(struct seq_file *seq, void *v) | 2001 | static int ip_vs_stats_show(struct seq_file *seq, void *v) |
1964 | { | 2002 | { |
1965 | struct net *net = seq_file_single_net(seq); | 2003 | struct net *net = seq_file_single_net(seq); |
1966 | struct ip_vs_stats *tot_stats = &net_ipvs(net)->tot_stats; | 2004 | struct ip_vs_stats_user show; |
1967 | 2005 | ||
1968 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ | 2006 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ |
1969 | seq_puts(seq, | 2007 | seq_puts(seq, |
@@ -1971,22 +2009,18 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v) | |||
1971 | seq_printf(seq, | 2009 | seq_printf(seq, |
1972 | " Conns Packets Packets Bytes Bytes\n"); | 2010 | " Conns Packets Packets Bytes Bytes\n"); |
1973 | 2011 | ||
1974 | spin_lock_bh(&tot_stats->lock); | 2012 | ip_vs_copy_stats(&show, &net_ipvs(net)->tot_stats); |
1975 | seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", tot_stats->ustats.conns, | 2013 | seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", show.conns, |
1976 | tot_stats->ustats.inpkts, tot_stats->ustats.outpkts, | 2014 | show.inpkts, show.outpkts, |
1977 | (unsigned long long) tot_stats->ustats.inbytes, | 2015 | (unsigned long long) show.inbytes, |
1978 | (unsigned long long) tot_stats->ustats.outbytes); | 2016 | (unsigned long long) show.outbytes); |
1979 | 2017 | ||
1980 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ | 2018 | /* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ |
1981 | seq_puts(seq, | 2019 | seq_puts(seq, |
1982 | " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); | 2020 | " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); |
1983 | seq_printf(seq,"%8X %8X %8X %16X %16X\n", | 2021 | seq_printf(seq, "%8X %8X %8X %16X %16X\n", |
1984 | tot_stats->ustats.cps, | 2022 | show.cps, show.inpps, show.outpps, |
1985 | tot_stats->ustats.inpps, | 2023 | show.inbps, show.outbps); |
1986 | tot_stats->ustats.outpps, | ||
1987 | tot_stats->ustats.inbps, | ||
1988 | tot_stats->ustats.outbps); | ||
1989 | spin_unlock_bh(&tot_stats->lock); | ||
1990 | 2024 | ||
1991 | return 0; | 2025 | return 0; |
1992 | } | 2026 | } |
@@ -2298,14 +2332,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) | |||
2298 | 2332 | ||
2299 | 2333 | ||
2300 | static void | 2334 | static void |
2301 | ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src) | ||
2302 | { | ||
2303 | spin_lock_bh(&src->lock); | ||
2304 | memcpy(dst, &src->ustats, sizeof(*dst)); | ||
2305 | spin_unlock_bh(&src->lock); | ||
2306 | } | ||
2307 | |||
2308 | static void | ||
2309 | ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) | 2335 | ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) |
2310 | { | 2336 | { |
2311 | dst->protocol = src->protocol; | 2337 | dst->protocol = src->protocol; |
@@ -2691,31 +2717,29 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = { | |||
2691 | static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, | 2717 | static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, |
2692 | struct ip_vs_stats *stats) | 2718 | struct ip_vs_stats *stats) |
2693 | { | 2719 | { |
2720 | struct ip_vs_stats_user ustats; | ||
2694 | struct nlattr *nl_stats = nla_nest_start(skb, container_type); | 2721 | struct nlattr *nl_stats = nla_nest_start(skb, container_type); |
2695 | if (!nl_stats) | 2722 | if (!nl_stats) |
2696 | return -EMSGSIZE; | 2723 | return -EMSGSIZE; |
2697 | 2724 | ||
2698 | spin_lock_bh(&stats->lock); | 2725 | ip_vs_copy_stats(&ustats, stats); |
2699 | |||
2700 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns); | ||
2701 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts); | ||
2702 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts); | ||
2703 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes); | ||
2704 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes); | ||
2705 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps); | ||
2706 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps); | ||
2707 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps); | ||
2708 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps); | ||
2709 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps); | ||
2710 | 2726 | ||
2711 | spin_unlock_bh(&stats->lock); | 2727 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns); |
2728 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts); | ||
2729 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts); | ||
2730 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes); | ||
2731 | NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes); | ||
2732 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, ustats.cps); | ||
2733 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps); | ||
2734 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps); | ||
2735 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps); | ||
2736 | NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps); | ||
2712 | 2737 | ||
2713 | nla_nest_end(skb, nl_stats); | 2738 | nla_nest_end(skb, nl_stats); |
2714 | 2739 | ||
2715 | return 0; | 2740 | return 0; |
2716 | 2741 | ||
2717 | nla_put_failure: | 2742 | nla_put_failure: |
2718 | spin_unlock_bh(&stats->lock); | ||
2719 | nla_nest_cancel(skb, nl_stats); | 2743 | nla_nest_cancel(skb, nl_stats); |
2720 | return -EMSGSIZE; | 2744 | return -EMSGSIZE; |
2721 | } | 2745 | } |
diff --git a/net/netfilter/ipvs/ip_vs_est.c b/net/netfilter/ipvs/ip_vs_est.c index b3751cfede2c..a85008796370 100644 --- a/net/netfilter/ipvs/ip_vs_est.c +++ b/net/netfilter/ipvs/ip_vs_est.c | |||
@@ -184,13 +184,14 @@ void ip_vs_kill_estimator(struct net *net, struct ip_vs_stats *stats) | |||
184 | void ip_vs_zero_estimator(struct ip_vs_stats *stats) | 184 | void ip_vs_zero_estimator(struct ip_vs_stats *stats) |
185 | { | 185 | { |
186 | struct ip_vs_estimator *est = &stats->est; | 186 | struct ip_vs_estimator *est = &stats->est; |
187 | 187 | struct ip_vs_stats_user *u = &stats->ustats; | |
188 | /* set counters zero, caller must hold the stats->lock lock */ | 188 | |
189 | est->last_inbytes = 0; | 189 | /* reset counters, caller must hold the stats->lock lock */ |
190 | est->last_outbytes = 0; | 190 | est->last_inbytes = u->inbytes; |
191 | est->last_conns = 0; | 191 | est->last_outbytes = u->outbytes; |
192 | est->last_inpkts = 0; | 192 | est->last_conns = u->conns; |
193 | est->last_outpkts = 0; | 193 | est->last_inpkts = u->inpkts; |
194 | est->last_outpkts = u->outpkts; | ||
194 | est->cps = 0; | 195 | est->cps = 0; |
195 | est->inpps = 0; | 196 | est->inpps = 0; |
196 | est->outpps = 0; | 197 | est->outpps = 0; |