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