1 /*
2  * ip_vs_est.c: simple rate estimator for IPVS
3  *
4  * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
5  *
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.
10  *
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.
17  */
18 
19 #define KMSG_COMPONENT "IPVS"
20 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
21 
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>
28 
29 #include <net/ip_vs.h>
30 
31 /*
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.
36 
37   Currently, the measurement is activated by slow timer handler. Hope
38   this measurement will not introduce too much load.
39 
40   We measure rate during the last 8 seconds every 2 seconds:
41 
42     avgrate = avgrate*(1-W) + rate*W
43 
44     where W = 2^(-2)
45 
46   NOTES.
47 
48   * Average bps is scaled by 2^5, while average pps and cps are scaled by 2^10.
49 
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.
52 
53   * A lot of code is taken from net/core/gen_estimator.c
54  */
55 
56 
57 /*
58  * Make a summary from each cpu
59  */
ip_vs_read_cpu_stats(struct ip_vs_kstats * sum,struct ip_vs_cpu_stats __percpu * stats)60 static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
61 				 struct ip_vs_cpu_stats __percpu *stats)
62 {
63 	int i;
64 	bool add = false;
65 
66 	for_each_possible_cpu(i) {
67 		struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
68 		unsigned int start;
69 		u64 conns, inpkts, outpkts, inbytes, outbytes;
70 
71 		if (add) {
72 			do {
73 				start = u64_stats_fetch_begin(&s->syncp);
74 				conns = s->cnt.conns;
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));
80 			sum->conns += conns;
81 			sum->inpkts += inpkts;
82 			sum->outpkts += outpkts;
83 			sum->inbytes += inbytes;
84 			sum->outbytes += outbytes;
85 		} else {
86 			add = true;
87 			do {
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));
95 		}
96 	}
97 }
98 
99 
estimation_timer(unsigned long arg)100 static void estimation_timer(unsigned long arg)
101 {
102 	struct ip_vs_estimator *e;
103 	struct ip_vs_stats *s;
104 	u64 rate;
105 	struct net *net = (struct net *)arg;
106 	struct netns_ipvs *ipvs;
107 
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);
112 
113 		spin_lock(&s->lock);
114 		ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
115 
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;
120 
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;
124 
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;
128 
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;
133 
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);
138 	}
139 	spin_unlock(&ipvs->est_lock);
140 	mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
141 }
142 
ip_vs_start_estimator(struct net * net,struct ip_vs_stats * stats)143 void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
144 {
145 	struct netns_ipvs *ipvs = net_ipvs(net);
146 	struct ip_vs_estimator *est = &stats->est;
147 
148 	INIT_LIST_HEAD(&est->list);
149 
150 	spin_lock_bh(&ipvs->est_lock);
151 	list_add(&est->list, &ipvs->est_list);
152 	spin_unlock_bh(&ipvs->est_lock);
153 }
154 
ip_vs_stop_estimator(struct net * net,struct ip_vs_stats * stats)155 void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
156 {
157 	struct netns_ipvs *ipvs = net_ipvs(net);
158 	struct ip_vs_estimator *est = &stats->est;
159 
160 	spin_lock_bh(&ipvs->est_lock);
161 	list_del(&est->list);
162 	spin_unlock_bh(&ipvs->est_lock);
163 }
164 
ip_vs_zero_estimator(struct ip_vs_stats * stats)165 void ip_vs_zero_estimator(struct ip_vs_stats *stats)
166 {
167 	struct ip_vs_estimator *est = &stats->est;
168 	struct ip_vs_kstats *k = &stats->kstats;
169 
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;
176 	est->cps = 0;
177 	est->inpps = 0;
178 	est->outpps = 0;
179 	est->inbps = 0;
180 	est->outbps = 0;
181 }
182 
183 /* Get decoded rates */
ip_vs_read_estimator(struct ip_vs_kstats * dst,struct ip_vs_stats * stats)184 void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
185 {
186 	struct ip_vs_estimator *e = &stats->est;
187 
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;
193 }
194 
ip_vs_estimator_net_init(struct net * net)195 int __net_init ip_vs_estimator_net_init(struct net *net)
196 {
197 	struct netns_ipvs *ipvs = net_ipvs(net);
198 
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);
203 	return 0;
204 }
205 
ip_vs_estimator_net_cleanup(struct net * net)206 void __net_exit ip_vs_estimator_net_cleanup(struct net *net)
207 {
208 	del_timer_sync(&net_ipvs(net)->est_timer);
209 }
210