cregit-Linux how code gets into the kernel

Release 4.11 net/netfilter/ipvs/ip_vs_wrr.c

/*
 * IPVS:        Weighted Round-Robin Scheduling module
 *
 * Authors:     Wensong Zhang <wensong@linuxvirtualserver.org>
 *
 *              This program is free software; you can redistribute it and/or
 *              modify it under the terms of the GNU General Public License
 *              as published by the Free Software Foundation; either version
 *              2 of the License, or (at your option) any later version.
 *
 * Changes:
 *     Wensong Zhang            :     changed the ip_vs_wrr_schedule to return dest
 *     Wensong Zhang            :     changed some comestics things for debugging
 *     Wensong Zhang            :     changed for the d-linked destination list
 *     Wensong Zhang            :     added the ip_vs_wrr_update_svc
 *     Julian Anastasov         :     fixed the bug of returning destination
 *                                    with weight 0 when all weights are zero
 *
 */


#define KMSG_COMPONENT "IPVS"

#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/net.h>
#include <linux/gcd.h>

#include <net/ip_vs.h>

/* The WRR algorithm depends on some caclulations:
 * - mw: maximum weight
 * - di: weight step, greatest common divisor from all weights
 * - cw: current required weight
 * As result, all weights are in the [di..mw] range with a step=di.
 *
 * First, we start with cw = mw and select dests with weight >= cw.
 * Then cw is reduced with di and all dests are checked again.
 * Last pass should be with cw = di. We have mw/di passes in total:
 *
 * pass 1: cw = max weight
 * pass 2: cw = max weight - di
 * pass 3: cw = max weight - 2 * di
 * ...
 * last pass: cw = di
 *
 * Weights are supposed to be >= di but we run in parallel with
 * weight changes, it is possible some dest weight to be reduced
 * below di, bad if it is the only available dest.
 *
 * So, we modify how mw is calculated, now it is reduced with (di - 1),
 * so that last cw is 1 to catch such dests with weight below di:
 * pass 1: cw = max weight - (di - 1)
 * pass 2: cw = max weight - di - (di - 1)
 * pass 3: cw = max weight - 2 * di - (di - 1)
 * ...
 * last pass: cw = 1
 *
 */

/*
 * current destination pointer for weighted round-robin scheduling
 */

struct ip_vs_wrr_mark {
	
struct ip_vs_dest *cl;	/* current dest or head */
	
int cw;			/* current weight */
	
int mw;			/* maximum weight */
	
int di;			/* decreasing interval */
	
struct rcu_head		rcu_head;
};



static int ip_vs_wrr_gcd_weight(struct ip_vs_service *svc) { struct ip_vs_dest *dest; int weight; int g = 0; list_for_each_entry(dest, &svc->destinations, n_list) { weight = atomic_read(&dest->weight); if (weight > 0) { if (g > 0) g = gcd(weight, g); else g = weight; } } return g ? g : 1; }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang6278.48%133.33%
Julian Anastasov1215.19%133.33%
Stephen Hemminger56.33%133.33%
Total79100.00%3100.00%

/* * Get the maximum weight of the service destinations. */
static int ip_vs_wrr_max_weight(struct ip_vs_service *svc) { struct ip_vs_dest *dest; int new_weight, weight = 0; list_for_each_entry(dest, &svc->destinations, n_list) { new_weight = atomic_read(&dest->weight); if (new_weight > weight) weight = new_weight; } return weight; }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang4275.00%133.33%
Simon Horman916.07%133.33%
Stephen Hemminger58.93%133.33%
Total56100.00%3100.00%


static int ip_vs_wrr_init_svc(struct ip_vs_service *svc) { struct ip_vs_wrr_mark *mark; /* * Allocate the mark variable for WRR scheduling */ mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_KERNEL); if (mark == NULL) return -ENOMEM; mark->cl = list_entry(&svc->destinations, struct ip_vs_dest, n_list); mark->di = ip_vs_wrr_gcd_weight(svc); mark->mw = ip_vs_wrr_max_weight(svc) - (mark->di - 1); mark->cw = mark->mw; svc->sched_data = mark; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang7474.00%133.33%
Julian Anastasov2626.00%266.67%
Total100100.00%3100.00%


static void ip_vs_wrr_done_svc(struct ip_vs_service *svc) { struct ip_vs_wrr_mark *mark = svc->sched_data; /* * Release the mark variable */ kfree_rcu(mark, rcu_head); }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang1553.57%133.33%
Julian Anastasov1346.43%266.67%
Total28100.00%3100.00%


static int ip_vs_wrr_dest_changed(struct ip_vs_service *svc, struct ip_vs_dest *dest) { struct ip_vs_wrr_mark *mark = svc->sched_data; spin_lock_bh(&svc->sched_lock); mark->cl = list_entry(&svc->destinations, struct ip_vs_dest, n_list); mark->di = ip_vs_wrr_gcd_weight(svc); mark->mw = ip_vs_wrr_max_weight(svc) - (mark->di - 1); if (mark->cw > mark->mw || !mark->cw) mark->cw = mark->mw; else if (mark->di > 1) mark->cw = (mark->cw / mark->di) * mark->di + 1; spin_unlock_bh(&svc->sched_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Julian Anastasov7956.83%250.00%
Wensong Zhang6043.17%250.00%
Total139100.00%4100.00%

/* * Weighted Round-Robin Scheduling */
static struct ip_vs_dest * ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, struct ip_vs_iphdr *iph) { struct ip_vs_dest *dest, *last, *stop = NULL; struct ip_vs_wrr_mark *mark = svc->sched_data; bool last_pass = false, restarted = false; IP_VS_DBG(6, "%s(): Scheduling...\n", __func__); spin_lock_bh(&svc->sched_lock); dest = mark->cl; /* No available dests? */ if (mark->mw == 0) goto err_noavail; last = dest; /* Stop only after all dests were checked for weight >= 1 (last pass) */ while (1) { list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) { if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) && atomic_read(&dest->weight) >= mark->cw) goto found; if (dest == stop) goto err_over; } mark->cw -= mark->di; if (mark->cw <= 0) { mark->cw = mark->mw; /* Stop if we tried last pass from first dest: * 1. last_pass: we started checks when cw > di but * then all dests were checked for w >= 1 * 2. last was head: the first and only traversal * was for weight >= 1, for all dests. */ if (last_pass || &last->n_list == &svc->destinations) goto err_over; restarted = true; } last_pass = mark->cw <= mark->di; if (last_pass && restarted && &last->n_list != &svc->destinations) { /* First traversal was for w >= 1 but only * for dests after 'last', now do the same * for all dests up to 'last'. */ stop = last; } } found: IP_VS_DBG_BUF(6, "WRR: server %s:%u " "activeconns %d refcnt %d weight %d\n", IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port), atomic_read(&dest->activeconns), atomic_read(&dest->refcnt), atomic_read(&dest->weight)); mark->cl = dest; out: spin_unlock_bh(&svc->sched_lock); return dest; err_noavail: mark->cl = dest; dest = NULL; ip_vs_scheduler_err(svc, "no destination available"); goto out; err_over: mark->cl = dest; dest = NULL; ip_vs_scheduler_err(svc, "no destination available: " "all destinations are overloaded"); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang17751.45%112.50%
Julian Anastasov15745.64%562.50%
Julius Volz72.03%112.50%
Hannes Eder30.87%112.50%
Total344100.00%8100.00%

static struct ip_vs_scheduler ip_vs_wrr_scheduler = { .name = "wrr", .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list), .init_service = ip_vs_wrr_init_svc, .done_service = ip_vs_wrr_done_svc, .add_dest = ip_vs_wrr_dest_changed, .del_dest = ip_vs_wrr_dest_changed, .upd_dest = ip_vs_wrr_dest_changed, .schedule = ip_vs_wrr_schedule, };
static int __init ip_vs_wrr_init(void) { return register_ip_vs_scheduler(&ip_vs_wrr_scheduler) ; }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang16100.00%1100.00%
Total16100.00%1100.00%


static void __exit ip_vs_wrr_cleanup(void) { unregister_ip_vs_scheduler(&ip_vs_wrr_scheduler); synchronize_rcu(); }

Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang1583.33%150.00%
Julian Anastasov316.67%150.00%
Total18100.00%2100.00%

module_init(ip_vs_wrr_init); module_exit(ip_vs_wrr_cleanup); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Wensong Zhang55259.93%29.09%
Julian Anastasov30933.55%1045.45%
Hannes Eder141.52%29.09%
Sven Wegener131.41%29.09%
Stephen Hemminger101.09%14.55%
Simon Horman90.98%14.55%
Julius Volz70.76%14.55%
Tejun Heo30.33%14.55%
Florian Fainelli30.33%14.55%
Adrian Bunk10.11%14.55%
Total921100.00%22100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.