LVS
lvs-users
Google
 
Web LinuxVirtualServer.org

Re: problem reading lvs source code

To: "LinuxVirtualServer.org users mailing list." <lvs-users@xxxxxxxxxxxxxxxxxxxxxx>
Subject: Re: problem reading lvs source code
From: Roberto Nibali <ratz@xxxxxx>
Date: Thu, 10 Jul 2003 11:29:08 +0200
yuanyong wrote:
Hai experts!
    Now I am reading the lvs source code.But I have met a problem.The problem is where is 
the base type of "struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,struct 
iphdr *iph); ".Where I can find it?Please can you help me,thanks.

Please fix your mailer to wrap lines correctly.

struct ip_vs_scheduler {
        struct list_head        n_list;   /* d-linked list head */
        char                    *name;    /* scheduler name */
        atomic_t                refcnt;   /* reference counter */
        struct module           *module;  /* THIS_MODULE/NULL */

        /* scheduler initializing service */
        int (*init_service)(struct ip_vs_service *svc);
        /* scheduling service finish */
        int (*done_service)(struct ip_vs_service *svc);
        /* scheduler updating service */
        int (*update_service)(struct ip_vs_service *svc);

        /* selecting a server from the given service */
        struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,
                                       struct iphdr *iph);
};

Horms, we must talk at OLS about finally getting down to writing a dev guide :)

Additionally to what Horms told you correctly I might help other readers of the code which are not very familiar with function pointers that the whole setup roughly works as follows:

Each scheduler {rr,lc,...} will have to register itself by initialisation of the ip_vs_scheduler struct object. As you can see it contains above other data types 4 function pointers:

int (*init_service)(struct ip_vs_service *svc)
int (*done_service)(struct ip_vs_service *svc)
int (*update_service)(struct ip_vs_service *svc)
struct ip_vs_dest* (*schedule)(struct ip_vs_service *svc,struct iphdr *iph)

Each scheduler will need to provide a callback function for those prototypes with his own specific implementation.

Let's have a look at ip_vs_wrr.c:

We start with the __init function which is kernel specific. It defines ip_vs_wrr_init() which in turn calls the required

register_ip_vs_scheduler(&ip_vs_wrr_scheduler). You can see the ip_vs_wrr_scheduler structure definition just above the __init function. There you will note following:

static struct ip_vs_scheduler ip_vs_wrr_scheduler = {
        {0},                    /* n_list */
        "wrr",                  /* name */
        ATOMIC_INIT(0),         /* refcnt */
        THIS_MODULE,            /* this module */
        ip_vs_wrr_init_svc,     /* service initializer */
        ip_vs_wrr_done_svc,     /* service done */
        ip_vs_wrr_update_svc,   /* service updater */
        ip_vs_wrr_schedule,     /* select a server from the destination list */
};

This now is exactly the scheduler specific object instantiation of the struct ip_vs_scheduler prototype defined in ip_vs.h. Reading this you can see that the last for "names" map the function names to be called accordingly.

So in case of the wrr scheduler, what does the init_service (mapped to the ip_vs_wrr_init_svc function) do?

It generates a mark object (used for list chain traversal and mark point) which gets filled up with initial values, such as the maximum weight and the gcd weight. This is a very intelligent thing to do, because if you do not do this, you will need to compute those values every time the scheduler needs to schedule a new incoming request.

The latter also requires a second callback. Why? Imagine someone decides to update the weights of one or more server from user space. This would mean that the initially computed weights are not valid anymore.

What can be done against it? We could compute those values every time the scheduler needs to schedule a destination but that's exactly what we don't want. So in play comes the update_service protoype (mapped to the ip_vs_wrr_update_svc function).

As you can easily see the ip_vs_wrr_update_svc function will do part of what we did for the init_service: it will compute the new max weight and the new gcd weight, so the world is saved again. The update_service callback will be called upon a user space ioctl call (you can read about this in the previous chapter of this marvellous developer guide :)).

The ip_vs_wrr_schedule function provides us with the core functionality of finding an appropriate destination (real server) when a new incoming connection is hitting our cluster. Here you could write your own algorithm. You only need to either return NULL (if no real server can be found) or a destination which is of type: struct ip_vs_dest.

The last function callback is the ip_vs_wrr_done_svc function which kfree()'s the initially kmalloc()'d mark variable.

This short tour-de-scheduler show give you enough information to write your own scheduler, at least in theory :).

Best regards,
Roberto Nibali, ratz
--
echo '[q]sa[ln0=aln256%Pln256/snlbx]sb3135071790101768542287578439snlbxq' | dc

<Prev in Thread] Current Thread [Next in Thread>