2 * ip_vs_est.c: simple rate estimator for IPVS
4 * Authors: Wensong Zhang <wensong@linuxvirtualserver.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 * Changes: Hans Schillstrom <hans.schillstrom@ericsson.com>
12 * Network name space (netns) aware.
13 * Global data moved to netns i.e struct netns_ipvs
14 * Affected data: est_list and est_lock.
15 * estimation_timer() runs with timer per netns.
16 * get_stats()) do the per cpu summing.
19 #define KMSG_COMPONENT "IPVS"
20 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
22 #include <linux/kernel.h>
23 #include <linux/jiffies.h>
24 #include <linux/types.h>
25 #include <linux/interrupt.h>
26 #include <linux/sysctl.h>
27 #include <linux/list.h>
29 #include <net/ip_vs.h>
32 This code is to estimate rate in a shorter interval (such as 8
33 seconds) for virtual services and real servers. For measure rate in a
34 long interval, it is easy to implement a user level daemon which
35 periodically reads those statistical counters and measure rate.
37 Currently, the measurement is activated by slow timer handler. Hope
38 this measurement will not introduce too much load.
40 We measure rate during the last 8 seconds every 2 seconds:
42 avgrate = avgrate*(1-W) + rate*W
48 * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10.
50 * Netlink users can see 64-bit values but sockopt users are restricted
51 to 32-bit values for conns, packets, bps, cps and pps.
53 * A lot of code is taken from net/core/gen_estimator.c
58 * Make a summary from each cpu
60 static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
61 struct ip_vs_cpu_stats __percpu *stats)
66 for_each_possible_cpu(i) {
67 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
69 u64 conns, inpkts, outpkts, inbytes, outbytes;
73 start = u64_stats_fetch_begin(&s->syncp);
75 inpkts = s->cnt.inpkts;
76 outpkts = s->cnt.outpkts;
77 inbytes = s->cnt.inbytes;
78 outbytes = s->cnt.outbytes;
79 } while (u64_stats_fetch_retry(&s->syncp, start));
81 sum->inpkts += inpkts;
82 sum->outpkts += outpkts;
83 sum->inbytes += inbytes;
84 sum->outbytes += outbytes;
88 start = u64_stats_fetch_begin(&s->syncp);
89 sum->conns = s->cnt.conns;
90 sum->inpkts = s->cnt.inpkts;
91 sum->outpkts = s->cnt.outpkts;
92 sum->inbytes = s->cnt.inbytes;
93 sum->outbytes = s->cnt.outbytes;
94 } while (u64_stats_fetch_retry(&s->syncp, start));
100 static void estimation_timer(unsigned long arg)
102 struct ip_vs_estimator *e;
103 struct ip_vs_stats *s;
105 struct net *net = (struct net *)arg;
106 struct netns_ipvs *ipvs;
108 ipvs = net_ipvs(net);
109 spin_lock(&ipvs->est_lock);
110 list_for_each_entry(e, &ipvs->est_list, list) {
111 s = container_of(e, struct ip_vs_stats, est);
114 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
116 /* scaled by 2^10, but divided 2 seconds */
117 rate = (s->kstats.conns - e->last_conns) << 9;
118 e->last_conns = s->kstats.conns;
119 e->cps += ((s64)rate - (s64)e->cps) >> 2;
121 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
122 e->last_inpkts = s->kstats.inpkts;
123 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
125 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
126 e->last_outpkts = s->kstats.outpkts;
127 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
129 /* scaled by 2^5, but divided 2 seconds */
130 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
131 e->last_inbytes = s->kstats.inbytes;
132 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
134 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
135 e->last_outbytes = s->kstats.outbytes;
136 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
137 spin_unlock(&s->lock);
139 spin_unlock(&ipvs->est_lock);
140 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
143 void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
145 struct netns_ipvs *ipvs = net_ipvs(net);
146 struct ip_vs_estimator *est = &stats->est;
148 INIT_LIST_HEAD(&est->list);
150 spin_lock_bh(&ipvs->est_lock);
151 list_add(&est->list, &ipvs->est_list);
152 spin_unlock_bh(&ipvs->est_lock);
155 void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
157 struct netns_ipvs *ipvs = net_ipvs(net);
158 struct ip_vs_estimator *est = &stats->est;
160 spin_lock_bh(&ipvs->est_lock);
161 list_del(&est->list);
162 spin_unlock_bh(&ipvs->est_lock);
165 void ip_vs_zero_estimator(struct ip_vs_stats *stats)
167 struct ip_vs_estimator *est = &stats->est;
168 struct ip_vs_kstats *k = &stats->kstats;
170 /* reset counters, caller must hold the stats->lock lock */
171 est->last_inbytes = k->inbytes;
172 est->last_outbytes = k->outbytes;
173 est->last_conns = k->conns;
174 est->last_inpkts = k->inpkts;
175 est->last_outpkts = k->outpkts;
183 /* Get decoded rates */
184 void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
186 struct ip_vs_estimator *e = &stats->est;
188 dst->cps = (e->cps + 0x1FF) >> 10;
189 dst->inpps = (e->inpps + 0x1FF) >> 10;
190 dst->outpps = (e->outpps + 0x1FF) >> 10;
191 dst->inbps = (e->inbps + 0xF) >> 5;
192 dst->outbps = (e->outbps + 0xF) >> 5;
195 int __net_init ip_vs_estimator_net_init(struct net *net)
197 struct netns_ipvs *ipvs = net_ipvs(net);
199 INIT_LIST_HEAD(&ipvs->est_list);
200 spin_lock_init(&ipvs->est_lock);
201 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net);
202 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
206 void __net_exit ip_vs_estimator_net_cleanup(struct net *net)
208 del_timer_sync(&net_ipvs(net)->est_timer);