1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#define KMSG_COMPONENT "IPVS"
16#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
17
18#include <linux/kernel.h>
19#include <linux/jiffies.h>
20#include <linux/types.h>
21#include <linux/interrupt.h>
22#include <linux/sysctl.h>
23#include <linux/list.h>
24
25#include <net/ip_vs.h>
26
27
28
29
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
56static void ip_vs_read_cpu_stats(struct ip_vs_kstats *sum,
57 struct ip_vs_cpu_stats __percpu *stats)
58{
59 int i;
60 bool add = false;
61
62 for_each_possible_cpu(i) {
63 struct ip_vs_cpu_stats *s = per_cpu_ptr(stats, i);
64 unsigned int start;
65 u64 conns, inpkts, outpkts, inbytes, outbytes;
66
67 if (add) {
68 do {
69 start = u64_stats_fetch_begin(&s->syncp);
70 conns = s->cnt.conns;
71 inpkts = s->cnt.inpkts;
72 outpkts = s->cnt.outpkts;
73 inbytes = s->cnt.inbytes;
74 outbytes = s->cnt.outbytes;
75 } while (u64_stats_fetch_retry(&s->syncp, start));
76 sum->conns += conns;
77 sum->inpkts += inpkts;
78 sum->outpkts += outpkts;
79 sum->inbytes += inbytes;
80 sum->outbytes += outbytes;
81 } else {
82 add = true;
83 do {
84 start = u64_stats_fetch_begin(&s->syncp);
85 sum->conns = s->cnt.conns;
86 sum->inpkts = s->cnt.inpkts;
87 sum->outpkts = s->cnt.outpkts;
88 sum->inbytes = s->cnt.inbytes;
89 sum->outbytes = s->cnt.outbytes;
90 } while (u64_stats_fetch_retry(&s->syncp, start));
91 }
92 }
93}
94
95
96static void estimation_timer(struct timer_list *t)
97{
98 struct ip_vs_estimator *e;
99 struct ip_vs_stats *s;
100 u64 rate;
101 struct netns_ipvs *ipvs = from_timer(ipvs, t, est_timer);
102
103 if (!sysctl_run_estimation(ipvs))
104 goto skip;
105
106 spin_lock(&ipvs->est_lock);
107 list_for_each_entry(e, &ipvs->est_list, list) {
108 s = container_of(e, struct ip_vs_stats, est);
109
110 spin_lock(&s->lock);
111 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
112
113
114 rate = (s->kstats.conns - e->last_conns) << 9;
115 e->last_conns = s->kstats.conns;
116 e->cps += ((s64)rate - (s64)e->cps) >> 2;
117
118 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
119 e->last_inpkts = s->kstats.inpkts;
120 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
121
122 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
123 e->last_outpkts = s->kstats.outpkts;
124 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
125
126
127 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
128 e->last_inbytes = s->kstats.inbytes;
129 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
130
131 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
132 e->last_outbytes = s->kstats.outbytes;
133 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
134 spin_unlock(&s->lock);
135 }
136 spin_unlock(&ipvs->est_lock);
137
138skip:
139 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
140}
141
142void ip_vs_start_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
143{
144 struct ip_vs_estimator *est = &stats->est;
145
146 INIT_LIST_HEAD(&est->list);
147
148 spin_lock_bh(&ipvs->est_lock);
149 list_add(&est->list, &ipvs->est_list);
150 spin_unlock_bh(&ipvs->est_lock);
151}
152
153void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
154{
155 struct ip_vs_estimator *est = &stats->est;
156
157 spin_lock_bh(&ipvs->est_lock);
158 list_del(&est->list);
159 spin_unlock_bh(&ipvs->est_lock);
160}
161
162void ip_vs_zero_estimator(struct ip_vs_stats *stats)
163{
164 struct ip_vs_estimator *est = &stats->est;
165 struct ip_vs_kstats *k = &stats->kstats;
166
167
168 est->last_inbytes = k->inbytes;
169 est->last_outbytes = k->outbytes;
170 est->last_conns = k->conns;
171 est->last_inpkts = k->inpkts;
172 est->last_outpkts = k->outpkts;
173 est->cps = 0;
174 est->inpps = 0;
175 est->outpps = 0;
176 est->inbps = 0;
177 est->outbps = 0;
178}
179
180
181void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
182{
183 struct ip_vs_estimator *e = &stats->est;
184
185 dst->cps = (e->cps + 0x1FF) >> 10;
186 dst->inpps = (e->inpps + 0x1FF) >> 10;
187 dst->outpps = (e->outpps + 0x1FF) >> 10;
188 dst->inbps = (e->inbps + 0xF) >> 5;
189 dst->outbps = (e->outbps + 0xF) >> 5;
190}
191
192int __net_init ip_vs_estimator_net_init(struct netns_ipvs *ipvs)
193{
194 INIT_LIST_HEAD(&ipvs->est_list);
195 spin_lock_init(&ipvs->est_lock);
196 timer_setup(&ipvs->est_timer, estimation_timer, 0);
197 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
198 return 0;
199}
200
201void __net_exit ip_vs_estimator_net_cleanup(struct netns_ipvs *ipvs)
202{
203 del_timer_sync(&ipvs->est_timer);
204}
205