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
58
59
60static 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
100static void estimation_timer(struct timer_list *t)
101{
102 struct ip_vs_estimator *e;
103 struct ip_vs_stats *s;
104 u64 rate;
105 struct netns_ipvs *ipvs = from_timer(ipvs, t, est_timer);
106
107 spin_lock(&ipvs->est_lock);
108 list_for_each_entry(e, &ipvs->est_list, list) {
109 s = container_of(e, struct ip_vs_stats, est);
110
111 spin_lock(&s->lock);
112 ip_vs_read_cpu_stats(&s->kstats, s->cpustats);
113
114
115 rate = (s->kstats.conns - e->last_conns) << 9;
116 e->last_conns = s->kstats.conns;
117 e->cps += ((s64)rate - (s64)e->cps) >> 2;
118
119 rate = (s->kstats.inpkts - e->last_inpkts) << 9;
120 e->last_inpkts = s->kstats.inpkts;
121 e->inpps += ((s64)rate - (s64)e->inpps) >> 2;
122
123 rate = (s->kstats.outpkts - e->last_outpkts) << 9;
124 e->last_outpkts = s->kstats.outpkts;
125 e->outpps += ((s64)rate - (s64)e->outpps) >> 2;
126
127
128 rate = (s->kstats.inbytes - e->last_inbytes) << 4;
129 e->last_inbytes = s->kstats.inbytes;
130 e->inbps += ((s64)rate - (s64)e->inbps) >> 2;
131
132 rate = (s->kstats.outbytes - e->last_outbytes) << 4;
133 e->last_outbytes = s->kstats.outbytes;
134 e->outbps += ((s64)rate - (s64)e->outbps) >> 2;
135 spin_unlock(&s->lock);
136 }
137 spin_unlock(&ipvs->est_lock);
138 mod_timer(&ipvs->est_timer, jiffies + 2*HZ);
139}
140
141void ip_vs_start_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
142{
143 struct ip_vs_estimator *est = &stats->est;
144
145 INIT_LIST_HEAD(&est->list);
146
147 spin_lock_bh(&ipvs->est_lock);
148 list_add(&est->list, &ipvs->est_list);
149 spin_unlock_bh(&ipvs->est_lock);
150}
151
152void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
153{
154 struct ip_vs_estimator *est = &stats->est;
155
156 spin_lock_bh(&ipvs->est_lock);
157 list_del(&est->list);
158 spin_unlock_bh(&ipvs->est_lock);
159}
160
161void ip_vs_zero_estimator(struct ip_vs_stats *stats)
162{
163 struct ip_vs_estimator *est = &stats->est;
164 struct ip_vs_kstats *k = &stats->kstats;
165
166
167 est->last_inbytes = k->inbytes;
168 est->last_outbytes = k->outbytes;
169 est->last_conns = k->conns;
170 est->last_inpkts = k->inpkts;
171 est->last_outpkts = k->outpkts;
172 est->cps = 0;
173 est->inpps = 0;
174 est->outpps = 0;
175 est->inbps = 0;
176 est->outbps = 0;
177}
178
179
180void ip_vs_read_estimator(struct ip_vs_kstats *dst, struct ip_vs_stats *stats)
181{
182 struct ip_vs_estimator *e = &stats->est;
183
184 dst->cps = (e->cps + 0x1FF) >> 10;
185 dst->inpps = (e->inpps + 0x1FF) >> 10;
186 dst->outpps = (e->outpps + 0x1FF) >> 10;
187 dst->inbps = (e->inbps + 0xF) >> 5;
188 dst->outbps = (e->outbps + 0xF) >> 5;
189}
190
191int __net_init ip_vs_estimator_net_init(struct netns_ipvs *ipvs)
192{
193 INIT_LIST_HEAD(&ipvs->est_list);
194 spin_lock_init(&ipvs->est_lock);
195 timer_setup(&ipvs->est_timer, estimation_timer, 0);
196 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ);
197 return 0;
198}
199
200void __net_exit ip_vs_estimator_net_cleanup(struct netns_ipvs *ipvs)
201{
202 del_timer_sync(&ipvs->est_timer);
203}
204