linux/net/netfilter/ipvs/ip_vs_est.c
<<
>>
Prefs
   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 */
  58static void ip_vs_read_cpu_stats(struct ip_vs_stats_user *sum,
  59                                 struct ip_vs_cpu_stats __percpu *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                /* 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
 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        /* reset counters, caller must hold the stats->lock lock */
 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/* Get decoded rates */
 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