1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58static 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
92static 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
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
142void 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
154void 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
164void 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
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
183void 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
195int __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
206void __net_exit ip_vs_estimator_net_cleanup(struct net *net)
207{
208 del_timer_sync(&net_ipvs(net)->est_timer);
209}
210