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 * The stored value for average bps is scaled by 2^5, so that maximal
49 rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
50
51 * A lot code is taken from net/sched/estimator.c
52 */
53
54
55 /*
56 * Make a summary from each cpu
57 */
ip_vs_read_cpu_stats(struct ip_vs_stats_user * sum,struct ip_vs_cpu_stats * stats)58 static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
59 struct ip_vs_cpu_stats *stats)
60 {
61 int i;
62
63 for_each_possible_cpu(i) {
64 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
65 unsigned int start;
66 __u64 inbytes, outbytes;
67 if (i) {
68 sum->conns += s->ustats.conns;
69 sum->inpkts += s->ustats.inpkts;
70 sum->outpkts += s->ustats.outpkts;
71 do {
72 start = u64_stats_fetch_begin(&s->syncp);
73 inbytes = s->ustats.inbytes;
74 outbytes = s->ustats.outbytes;
75 } while (u64_stats_fetch_retry(&s->syncp, start));
76 sum->inbytes += inbytes;
77 sum->outbytes += outbytes;
78 } else {
79 sum->conns = s->ustats.conns;
80 sum->inpkts = s->ustats.inpkts;
81 sum->outpkts = s->ustats.outpkts;
82 do {
83 start = u64_stats_fetch_begin(&s->syncp);
84 sum->inbytes = s->ustats.inbytes;
85 sum->outbytes = s->ustats.outbytes;
86 } while (u64_stats_fetch_retry(&s->syncp, start));
87 }
88 }
89 }
90
91
estimation_timer(unsigned long arg)92 static void estimation_timer(unsigned long arg)
93 {
94 struct ip_vs_estimator *e;
95 struct ip_vs_stats *s;
96 u32 n_conns;
97 u32 n_inpkts, n_outpkts;
98 u64 n_inbytes, n_outbytes;
99 u32 rate;
100 struct net *net = (struct net *)arg;
101 struct netns_ipvs *ipvs;
102
103 ipvs = net_ipvs(net);
104 spin_lock(&ipvs->est_lock);
105 list_for_each_entry(e, &ipvs->est_list, list) {
106 s = container_of(e, struct ip_vs_stats, est);
107
108 spin_lock(&s->lock);
109 ip_vs_read_cpu_stats(&s->ustats, s->cpustats);
110 n_conns = s->ustats.conns;
111 n_inpkts = s->ustats.inpkts;
112 n_outpkts = s->ustats.outpkts;
113 n_inbytes = s->ustats.inbytes;
114 n_outbytes = s->ustats.outbytes;
115
116 /* scaled by 2^10, but divided 2 seconds */
117 rate = (n_conns - e->last_conns) << 9;
118 e->last_conns = n_conns;
119 e->cps += ((long)rate - (long)e->cps) >> 2;
120
121 rate = (n_inpkts - e->last_inpkts) << 9;
122 e->last_inpkts = n_inpkts;
123 e->inpps += ((long)rate - (long)e->inpps) >> 2;
124
125 rate = (n_outpkts - e->last_outpkts) << 9;
126 e->last_outpkts = n_outpkts;
127 e->outpps += ((long)rate - (long)e->outpps) >> 2;
128
129 rate = (n_inbytes - e->last_inbytes) << 4;
130 e->last_inbytes = n_inbytes;
131 e->inbps += ((long)rate - (long)e->inbps) >> 2;
132
133 rate = (n_outbytes - e->last_outbytes) << 4;
134 e->last_outbytes = n_outbytes;
135 e->outbps += ((long)rate - (long)e->outbps) >> 2;
136 spin_unlock(&s->lock);
137 }
138 spin_unlock(&ipvs->est_lock);
139 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
140 }
141
ip_vs_start_estimator(struct net * net,struct ip_vs_stats * stats)142 void ip_vs_start_estimator(struct net *net, struct ip_vs_stats *stats)
143 {
144 struct netns_ipvs *ipvs = net_ipvs(net);
145 struct ip_vs_estimator *est = &stats->est;
146
147 INIT_LIST_HEAD(&est->list);
148
149 spin_lock_bh(&ipvs->est_lock);
150 list_add(&est->list, &ipvs->est_list);
151 spin_unlock_bh(&ipvs->est_lock);
152 }
153
ip_vs_stop_estimator(struct net * net,struct ip_vs_stats * stats)154 void ip_vs_stop_estimator(struct net *net, struct ip_vs_stats *stats)
155 {
156 struct netns_ipvs *ipvs = net_ipvs(net);
157 struct ip_vs_estimator *est = &stats->est;
158
159 spin_lock_bh(&ipvs->est_lock);
160 list_del(&est->list);
161 spin_unlock_bh(&ipvs->est_lock);
162 }
163
ip_vs_zero_estimator(struct ip_vs_stats * stats)164 void ip_vs_zero_estimator(struct ip_vs_stats *stats)
165 {
166 struct ip_vs_estimator *est = &stats->est;
167 struct ip_vs_stats_user *u = &stats->ustats;
168
169 /* reset counters, caller must hold the stats->lock lock */
170 est->last_inbytes = u->inbytes;
171 est->last_outbytes = u->outbytes;
172 est->last_conns = u->conns;
173 est->last_inpkts = u->inpkts;
174 est->last_outpkts = u->outpkts;
175 est->cps = 0;
176 est->inpps = 0;
177 est->outpps = 0;
178 est->inbps = 0;
179 est->outbps = 0;
180 }
181
182 /* Get decoded rates */
ip_vs_read_estimator(struct ip_vs_stats_user * dst,struct ip_vs_stats * stats)183 void ip_vs_read_estimator(struct ip_vs_stats_user *dst,
184 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