]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/netfilter/ipvs/ip_vs_ctl.c
ipvs: properly zero stats and rates
[karo-tx-linux.git] / net / netfilter / ipvs / ip_vs_ctl.c
index a2a67ad7e094bb146e0eaad560e20b3ff177470c..804fee7be694b2618b69b3f8956cba89f51d222b 100644 (file)
@@ -711,13 +711,51 @@ static void ip_vs_trash_cleanup(struct net *net)
        }
 }
 
+static void
+ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
+{
+#define IP_VS_SHOW_STATS_COUNTER(c) dst->c = src->ustats.c - src->ustats0.c
+#define IP_VS_SHOW_STATS_RATE(r) dst->r = src->ustats.r
+
+       spin_lock_bh(&src->lock);
+
+       IP_VS_SHOW_STATS_COUNTER(conns);
+       IP_VS_SHOW_STATS_COUNTER(inpkts);
+       IP_VS_SHOW_STATS_COUNTER(outpkts);
+       IP_VS_SHOW_STATS_COUNTER(inbytes);
+       IP_VS_SHOW_STATS_COUNTER(outbytes);
+
+       IP_VS_SHOW_STATS_RATE(cps);
+       IP_VS_SHOW_STATS_RATE(inpps);
+       IP_VS_SHOW_STATS_RATE(outpps);
+       IP_VS_SHOW_STATS_RATE(inbps);
+       IP_VS_SHOW_STATS_RATE(outbps);
+
+       spin_unlock_bh(&src->lock);
+}
 
 static void
 ip_vs_zero_stats(struct ip_vs_stats *stats)
 {
        spin_lock_bh(&stats->lock);
 
-       memset(&stats->ustats, 0, sizeof(stats->ustats));
+       /* get current counters as zero point, rates are zeroed */
+
+#define IP_VS_ZERO_STATS_COUNTER(c) stats->ustats0.c = stats->ustats.c
+#define IP_VS_ZERO_STATS_RATE(r) stats->ustats.r = 0
+
+       IP_VS_ZERO_STATS_COUNTER(conns);
+       IP_VS_ZERO_STATS_COUNTER(inpkts);
+       IP_VS_ZERO_STATS_COUNTER(outpkts);
+       IP_VS_ZERO_STATS_COUNTER(inbytes);
+       IP_VS_ZERO_STATS_COUNTER(outbytes);
+
+       IP_VS_ZERO_STATS_RATE(cps);
+       IP_VS_ZERO_STATS_RATE(inpps);
+       IP_VS_ZERO_STATS_RATE(outpps);
+       IP_VS_ZERO_STATS_RATE(inbps);
+       IP_VS_ZERO_STATS_RATE(outbps);
+
        ip_vs_zero_estimator(stats);
 
        spin_unlock_bh(&stats->lock);
@@ -1963,7 +2001,7 @@ static const struct file_operations ip_vs_info_fops = {
 static int ip_vs_stats_show(struct seq_file *seq, void *v)
 {
        struct net *net = seq_file_single_net(seq);
-       struct ip_vs_stats *tot_stats = &net_ipvs(net)->tot_stats;
+       struct ip_vs_stats_user show;
 
 /*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
        seq_puts(seq,
@@ -1971,22 +2009,18 @@ static int ip_vs_stats_show(struct seq_file *seq, void *v)
        seq_printf(seq,
                   "   Conns  Packets  Packets            Bytes            Bytes\n");
 
-       spin_lock_bh(&tot_stats->lock);
-       seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", tot_stats->ustats.conns,
-                  tot_stats->ustats.inpkts, tot_stats->ustats.outpkts,
-                  (unsigned long long) tot_stats->ustats.inbytes,
-                  (unsigned long long) tot_stats->ustats.outbytes);
+       ip_vs_copy_stats(&show, &net_ipvs(net)->tot_stats);
+       seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", show.conns,
+                  show.inpkts, show.outpkts,
+                  (unsigned long long) show.inbytes,
+                  (unsigned long long) show.outbytes);
 
 /*                 01234567 01234567 01234567 0123456701234567 0123456701234567 */
        seq_puts(seq,
                   " Conns/s   Pkts/s   Pkts/s          Bytes/s          Bytes/s\n");
-       seq_printf(seq,"%8X %8X %8X %16X %16X\n",
-                       tot_stats->ustats.cps,
-                       tot_stats->ustats.inpps,
-                       tot_stats->ustats.outpps,
-                       tot_stats->ustats.inbps,
-                       tot_stats->ustats.outbps);
-       spin_unlock_bh(&tot_stats->lock);
+       seq_printf(seq, "%8X %8X %8X %16X %16X\n",
+                       show.cps, show.inpps, show.outpps,
+                       show.inbps, show.outbps);
 
        return 0;
 }
@@ -2297,14 +2331,6 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 }
 
 
-static void
-ip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src)
-{
-       spin_lock_bh(&src->lock);
-       memcpy(dst, &src->ustats, sizeof(*dst));
-       spin_unlock_bh(&src->lock);
-}
-
 static void
 ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
 {
@@ -2691,31 +2717,29 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = {
 static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type,
                                 struct ip_vs_stats *stats)
 {
+       struct ip_vs_stats_user ustats;
        struct nlattr *nl_stats = nla_nest_start(skb, container_type);
        if (!nl_stats)
                return -EMSGSIZE;
 
-       spin_lock_bh(&stats->lock);
-
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, stats->ustats.conns);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, stats->ustats.inpkts);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, stats->ustats.outpkts);
-       NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, stats->ustats.inbytes);
-       NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, stats->ustats.outbytes);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, stats->ustats.cps);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, stats->ustats.inpps);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, stats->ustats.outpps);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, stats->ustats.inbps);
-       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, stats->ustats.outbps);
+       ip_vs_copy_stats(&ustats, stats);
 
-       spin_unlock_bh(&stats->lock);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_CONNS, ustats.conns);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPKTS, ustats.inpkts);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPKTS, ustats.outpkts);
+       NLA_PUT_U64(skb, IPVS_STATS_ATTR_INBYTES, ustats.inbytes);
+       NLA_PUT_U64(skb, IPVS_STATS_ATTR_OUTBYTES, ustats.outbytes);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_CPS, ustats.cps);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INPPS, ustats.inpps);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTPPS, ustats.outpps);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_INBPS, ustats.inbps);
+       NLA_PUT_U32(skb, IPVS_STATS_ATTR_OUTBPS, ustats.outbps);
 
        nla_nest_end(skb, nl_stats);
 
        return 0;
 
 nla_put_failure:
-       spin_unlock_bh(&stats->lock);
        nla_nest_cancel(skb, nl_stats);
        return -EMSGSIZE;
 }