linux/net/netfilter/ipvs/ip_vs_rr.c
<<
>>
Prefs
   1/*
   2 * IPVS:        Round-Robin Scheduling module
   3 *
   4 * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
   5 *              Peter Kese <peter.kese@ijs.si>
   6 *
   7 *              This program is free software; you can redistribute it and/or
   8 *              modify it under the terms of the GNU General Public License
   9 *              as published by the Free Software Foundation; either version
  10 *              2 of the License, or (at your option) any later version.
  11 *
  12 * Fixes/Changes:
  13 *     Wensong Zhang            :     changed the ip_vs_rr_schedule to return dest
  14 *     Julian Anastasov         :     fixed the NULL pointer access bug in debugging
  15 *     Wensong Zhang            :     changed some comestics things for debugging
  16 *     Wensong Zhang            :     changed for the d-linked destination list
  17 *     Wensong Zhang            :     added the ip_vs_rr_update_svc
  18 *     Wensong Zhang            :     added any dest with weight=0 is quiesced
  19 *
  20 */
  21
  22#define KMSG_COMPONENT "IPVS"
  23#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  24
  25#include <linux/module.h>
  26#include <linux/kernel.h>
  27
  28#include <net/ip_vs.h>
  29
  30
  31static int ip_vs_rr_init_svc(struct ip_vs_service *svc)
  32{
  33        svc->sched_data = &svc->destinations;
  34        return 0;
  35}
  36
  37
  38static int ip_vs_rr_del_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest)
  39{
  40        struct list_head *p;
  41
  42        spin_lock_bh(&svc->sched_lock);
  43        p = (struct list_head *) svc->sched_data;
  44        /* dest is already unlinked, so p->prev is not valid but
  45         * p->next is valid, use it to reach previous entry.
  46         */
  47        if (p == &dest->n_list)
  48                svc->sched_data = p->next->prev;
  49        spin_unlock_bh(&svc->sched_lock);
  50        return 0;
  51}
  52
  53
  54/*
  55 * Round-Robin Scheduling
  56 */
  57static struct ip_vs_dest *
  58ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
  59                  struct ip_vs_iphdr *iph)
  60{
  61        struct list_head *p;
  62        struct ip_vs_dest *dest, *last;
  63        int pass = 0;
  64
  65        IP_VS_DBG(6, "%s(): Scheduling...\n", __func__);
  66
  67        spin_lock_bh(&svc->sched_lock);
  68        p = (struct list_head *) svc->sched_data;
  69        last = dest = list_entry(p, struct ip_vs_dest, n_list);
  70
  71        do {
  72                list_for_each_entry_continue_rcu(dest,
  73                                                 &svc->destinations,
  74                                                 n_list) {
  75                        if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
  76                            atomic_read(&dest->weight) > 0)
  77                                /* HIT */
  78                                goto out;
  79                        if (dest == last)
  80                                goto stop;
  81                }
  82                pass++;
  83                /* Previous dest could be unlinked, do not loop forever.
  84                 * If we stay at head there is no need for 2nd pass.
  85                 */
  86        } while (pass < 2 && p != &svc->destinations);
  87
  88stop:
  89        spin_unlock_bh(&svc->sched_lock);
  90        ip_vs_scheduler_err(svc, "no destination available");
  91        return NULL;
  92
  93  out:
  94        svc->sched_data = &dest->n_list;
  95        spin_unlock_bh(&svc->sched_lock);
  96        IP_VS_DBG_BUF(6, "RR: server %s:%u "
  97                      "activeconns %d refcnt %d weight %d\n",
  98                      IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
  99                      atomic_read(&dest->activeconns),
 100                      refcount_read(&dest->refcnt), atomic_read(&dest->weight));
 101
 102        return dest;
 103}
 104
 105
 106static struct ip_vs_scheduler ip_vs_rr_scheduler = {
 107        .name =                 "rr",                   /* name */
 108        .refcnt =               ATOMIC_INIT(0),
 109        .module =               THIS_MODULE,
 110        .n_list =               LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list),
 111        .init_service =         ip_vs_rr_init_svc,
 112        .add_dest =             NULL,
 113        .del_dest =             ip_vs_rr_del_dest,
 114        .schedule =             ip_vs_rr_schedule,
 115};
 116
 117static int __init ip_vs_rr_init(void)
 118{
 119        return register_ip_vs_scheduler(&ip_vs_rr_scheduler);
 120}
 121
 122static void __exit ip_vs_rr_cleanup(void)
 123{
 124        unregister_ip_vs_scheduler(&ip_vs_rr_scheduler);
 125        synchronize_rcu();
 126}
 127
 128module_init(ip_vs_rr_init);
 129module_exit(ip_vs_rr_cleanup);
 130MODULE_LICENSE("GPL");
 131