aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2011-03-13 19:37:49 -0400
committerSimon Horman <horms@verge.net.au>2011-03-14 20:36:52 -0400
commit55a3d4e15c7c953ecc55b96b83d2679abf8a7899 (patch)
treed1f1c52c77c04b717ca1a26bc7a0e90adb0498df
parent2a0751af09c3099cf2837c623ca5d0436317d02d (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.h1
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c96
-rw-r--r--net/netfilter/ipvs/ip_vs_est.c15
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
714static void
715ip_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
715static void 737static void
716ip_vs_zero_stats(struct ip_vs_stats *stats) 738ip_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 = {
1963static int ip_vs_stats_show(struct seq_file *seq, void *v) 2001static 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
2300static void 2334static void
2301ip_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
2308static void
2309ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src) 2335ip_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] = {
2691static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, 2717static 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
2717nla_put_failure: 2742nla_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)
184void ip_vs_zero_estimator(struct ip_vs_stats *stats) 184void 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;