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 */ 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 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 s->ustats.cps = (e->cps + 0x1FF) >> 10; 121 122 rate = (n_inpkts - e->last_inpkts) << 9; 123 e->last_inpkts = n_inpkts; 124 e->inpps += ((long)rate - (long)e->inpps) >> 2; 125 s->ustats.inpps = (e->inpps + 0x1FF) >> 10; 126 127 rate = (n_outpkts - e->last_outpkts) << 9; 128 e->last_outpkts = n_outpkts; 129 e->outpps += ((long)rate - (long)e->outpps) >> 2; 130 s->ustats.outpps = (e->outpps + 0x1FF) >> 10; 131 132 rate = (n_inbytes - e->last_inbytes) << 4; 133 e->last_inbytes = n_inbytes; 134 e->inbps += ((long)rate - (long)e->inbps) >> 2; 135 s->ustats.inbps = (e->inbps + 0xF) >> 5; 136 137 rate = (n_outbytes - e->last_outbytes) << 4; 138 e->last_outbytes = n_outbytes; 139 e->outbps += ((long)rate - (long)e->outbps) >> 2; 140 s->ustats.outbps = (e->outbps + 0xF) >> 5; 141 spin_unlock(&s->lock); 142 } 143 spin_unlock(&ipvs->est_lock); 144 mod_timer(&ipvs->est_timer, jiffies + 2*HZ); 145 } 146 147 void ip_vs_new_estimator(struct net *net, struct ip_vs_stats *stats) 148 { 149 struct netns_ipvs *ipvs = net_ipvs(net); 150 struct ip_vs_estimator *est = &stats->est; 151 152 INIT_LIST_HEAD(&est->list); 153 154 est->last_conns = stats->ustats.conns; 155 est->cps = stats->ustats.cps<<10; 156 157 est->last_inpkts = stats->ustats.inpkts; 158 est->inpps = stats->ustats.inpps<<10; 159 160 est->last_outpkts = stats->ustats.outpkts; 161 est->outpps = stats->ustats.outpps<<10; 162 163 est->last_inbytes = stats->ustats.inbytes; 164 est->inbps = stats->ustats.inbps<<5; 165 166 est->last_outbytes = stats->ustats.outbytes; 167 est->outbps = stats->ustats.outbps<<5; 168 169 spin_lock_bh(&ipvs->est_lock); 170 list_add(&est->list, &ipvs->est_list); 171 spin_unlock_bh(&ipvs->est_lock); 172 } 173 174 void ip_vs_kill_estimator(struct net *net, struct ip_vs_stats *stats) 175 { 176 struct netns_ipvs *ipvs = net_ipvs(net); 177 struct ip_vs_estimator *est = &stats->est; 178 179 spin_lock_bh(&ipvs->est_lock); 180 list_del(&est->list); 181 spin_unlock_bh(&ipvs->est_lock); 182 } 183 184 void ip_vs_zero_estimator(struct ip_vs_stats *stats) 185 { 186 struct ip_vs_estimator *est = &stats->est; 187 188 /* set counters zero, caller must hold the stats->lock lock */ 189 est->last_inbytes = 0; 190 est->last_outbytes = 0; 191 est->last_conns = 0; 192 est->last_inpkts = 0; 193 est->last_outpkts = 0; 194 est->cps = 0; 195 est->inpps = 0; 196 est->outpps = 0; 197 est->inbps = 0; 198 est->outbps = 0; 199 } 200 201 static int __net_init __ip_vs_estimator_init(struct net *net) 202 { 203 struct netns_ipvs *ipvs = net_ipvs(net); 204 205 INIT_LIST_HEAD(&ipvs->est_list); 206 spin_lock_init(&ipvs->est_lock); 207 setup_timer(&ipvs->est_timer, estimation_timer, (unsigned long)net); 208 mod_timer(&ipvs->est_timer, jiffies + 2 * HZ); 209 return 0; 210 } 211 212 static void __net_exit __ip_vs_estimator_exit(struct net *net) 213 { 214 del_timer_sync(&net_ipvs(net)->est_timer); 215 } 216 static struct pernet_operations ip_vs_app_ops = { 217 .init = __ip_vs_estimator_init, 218 .exit = __ip_vs_estimator_exit, 219 }; 220 221 int __init ip_vs_estimator_init(void) 222 { 223 int rv; 224 225 rv = register_pernet_subsys(&ip_vs_app_ops); 226 return rv; 227 } 228 229 void ip_vs_estimator_cleanup(void) 230 { 231 unregister_pernet_subsys(&ip_vs_app_ops); 232 } 233