blob: 5a20f93bd7f94033e59e6cefc25c072208c2b699 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ip_vs_est.c: simple rate estimator for IPVS
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * 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:
12 *
13 */
14#include <linux/kernel.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020015#include <linux/jiffies.h>
16#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/types.h>
Adrian Bunk4ffd2e42006-01-05 12:14:43 -080018#include <linux/interrupt.h>
Pavel Emelyanov90754f82008-01-12 02:33:50 -080019#include <linux/sysctl.h>
Sven Wegener3a14a3132008-08-10 18:24:41 +000020#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
22#include <net/ip_vs.h>
23
24/*
25 This code is to estimate rate in a shorter interval (such as 8
26 seconds) for virtual services and real servers. For measure rate in a
27 long interval, it is easy to implement a user level daemon which
28 periodically reads those statistical counters and measure rate.
29
30 Currently, the measurement is activated by slow timer handler. Hope
31 this measurement will not introduce too much load.
32
33 We measure rate during the last 8 seconds every 2 seconds:
34
35 avgrate = avgrate*(1-W) + rate*W
36
37 where W = 2^(-2)
38
39 NOTES.
40
41 * The stored value for average bps is scaled by 2^5, so that maximal
42 rate is ~2.15Gbits/s, average pps and cps are scaled by 2^10.
43
44 * A lot code is taken from net/sched/estimator.c
45 */
46
47
Sven Wegener3a14a3132008-08-10 18:24:41 +000048static void estimation_timer(unsigned long arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Sven Wegener3a14a3132008-08-10 18:24:41 +000050static LIST_HEAD(est_list);
51static DEFINE_SPINLOCK(est_lock);
52static DEFINE_TIMER(est_timer, estimation_timer, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54static void estimation_timer(unsigned long arg)
55{
56 struct ip_vs_estimator *e;
57 struct ip_vs_stats *s;
58 u32 n_conns;
59 u32 n_inpkts, n_outpkts;
60 u64 n_inbytes, n_outbytes;
61 u32 rate;
62
Sven Wegener3a14a3132008-08-10 18:24:41 +000063 spin_lock(&est_lock);
64 list_for_each_entry(e, &est_list, list) {
65 s = container_of(e, struct ip_vs_stats, est);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67 spin_lock(&s->lock);
68 n_conns = s->conns;
69 n_inpkts = s->inpkts;
70 n_outpkts = s->outpkts;
71 n_inbytes = s->inbytes;
72 n_outbytes = s->outbytes;
73
74 /* scaled by 2^10, but divided 2 seconds */
75 rate = (n_conns - e->last_conns)<<9;
76 e->last_conns = n_conns;
77 e->cps += ((long)rate - (long)e->cps)>>2;
78 s->cps = (e->cps+0x1FF)>>10;
79
80 rate = (n_inpkts - e->last_inpkts)<<9;
81 e->last_inpkts = n_inpkts;
82 e->inpps += ((long)rate - (long)e->inpps)>>2;
83 s->inpps = (e->inpps+0x1FF)>>10;
84
85 rate = (n_outpkts - e->last_outpkts)<<9;
86 e->last_outpkts = n_outpkts;
87 e->outpps += ((long)rate - (long)e->outpps)>>2;
88 s->outpps = (e->outpps+0x1FF)>>10;
89
90 rate = (n_inbytes - e->last_inbytes)<<4;
91 e->last_inbytes = n_inbytes;
92 e->inbps += ((long)rate - (long)e->inbps)>>2;
93 s->inbps = (e->inbps+0xF)>>5;
94
95 rate = (n_outbytes - e->last_outbytes)<<4;
96 e->last_outbytes = n_outbytes;
97 e->outbps += ((long)rate - (long)e->outbps)>>2;
98 s->outbps = (e->outbps+0xF)>>5;
99 spin_unlock(&s->lock);
100 }
Sven Wegener3a14a3132008-08-10 18:24:41 +0000101 spin_unlock(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 mod_timer(&est_timer, jiffies + 2*HZ);
103}
104
Sven Wegener3a14a3132008-08-10 18:24:41 +0000105void ip_vs_new_estimator(struct ip_vs_stats *stats)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000107 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108
Sven Wegener3a14a3132008-08-10 18:24:41 +0000109 INIT_LIST_HEAD(&est->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 est->last_conns = stats->conns;
112 est->cps = stats->cps<<10;
113
114 est->last_inpkts = stats->inpkts;
115 est->inpps = stats->inpps<<10;
116
117 est->last_outpkts = stats->outpkts;
118 est->outpps = stats->outpps<<10;
119
120 est->last_inbytes = stats->inbytes;
121 est->inbps = stats->inbps<<5;
122
123 est->last_outbytes = stats->outbytes;
124 est->outbps = stats->outbps<<5;
125
Sven Wegener3a14a3132008-08-10 18:24:41 +0000126 spin_lock_bh(&est_lock);
127 if (list_empty(&est_list))
128 mod_timer(&est_timer, jiffies + 2 * HZ);
129 list_add(&est->list, &est_list);
130 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133void ip_vs_kill_estimator(struct ip_vs_stats *stats)
134{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000135 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
Sven Wegener3a14a3132008-08-10 18:24:41 +0000137 spin_lock_bh(&est_lock);
138 list_del(&est->list);
139 while (list_empty(&est_list) && try_to_del_timer_sync(&est_timer) < 0) {
140 spin_unlock_bh(&est_lock);
Sven Wegener8ab19ea2008-08-10 09:17:59 +0000141 cpu_relax();
Sven Wegener3a14a3132008-08-10 18:24:41 +0000142 spin_lock_bh(&est_lock);
Sven Wegener8ab19ea2008-08-10 09:17:59 +0000143 }
Sven Wegener3a14a3132008-08-10 18:24:41 +0000144 spin_unlock_bh(&est_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145}
146
147void ip_vs_zero_estimator(struct ip_vs_stats *stats)
148{
Sven Wegener3a14a3132008-08-10 18:24:41 +0000149 struct ip_vs_estimator *est = &stats->est;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Sven Wegener3a14a3132008-08-10 18:24:41 +0000151 /* set counters zero, caller must hold the stats->lock lock */
152 est->last_inbytes = 0;
153 est->last_outbytes = 0;
154 est->last_conns = 0;
155 est->last_inpkts = 0;
156 est->last_outpkts = 0;
157 est->cps = 0;
158 est->inpps = 0;
159 est->outpps = 0;
160 est->inbps = 0;
161 est->outbps = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162}