The lnlb driver has a modular structure that allows developers (some kernel module developing skills required) to write custom session tracking modules.
You can replace the default module (lnlb_mod_default), or you can keep it as default handler and write your own module that will only handle a particular transport protocol (TCP,UDP,...)
The main driver exports two symbols in order to allow external modules to be registered as protocol handlers:
first argument of both functions specifies the protocol handler you're registering (e.g. 6 for TCP, 17 for UDP). A 0 value means "default handler".
Now let's take a look to the lnlb_protocol_module struct (as defined in if_lnlb.h)
struct lnlb_protocol_module {
int (*dgram_is_related)(const struct lnlb_struct*,struct sk_buff *,unsigned char *);
void (*dgram_assigned)(const struct lnlb_struct *,struct sk_buff *,unsigned char *);
void (*node_died)(const struct lnlb_struct *,unsigned char *);
void (*interface_created)(const struct lnlb_struct*);
void (*interface_deleted)(const struct lnlb_struct *);
uint32_t (*save_status)(const struct lnlb_struct*,char **);
int (*load_status)(const struct lnlb_struct*,char *,uint32_t);
};
The struct simply contains some pointers to function prototypes that the handler must expose (remember to set references to funcions in the lnlb_protocol_module struct when registering it).
Please note that all the function has a first parameter pointing to a lnlb_struct structure. This is always passed by the main driver and tells the module to which cluster we're referring (since we can have more than a cluster on a machine, each cluster is associated to a virtual interface... each virtual interface has a lnlb_struct structure... se the if_lnlb.h header for more).
You should not usually need to read parmeters in the passed, lnlb_struct. It should be only useful to you to distinguish between clusters (theorically if you implement some kind of tracking table you should have a table for each lnlb_struct in order to avoid messing tracking info between more clusters).
int dgram_is_related(const struct lnlb_struct*,struct sk_buff *,unsigned char *)
This function is called by the main driver to ask whether the module if the current sk_buff is map ped to a node or not. Module must return a a true/false value (0 is not mapped, 1 is mapped). On true value the node MAC address must be copied out in the unsigned char * parm.
void dgram_assigned(const struct lnlb_struct *,struct sk_buff *,unsigned char *)
The main driver notifies us that the current sk_buff has been assigned to the node (refernced by it's MAC addres passed as an unsigned char *). At this point we should store tracking informations in our tables (or anything else).
void node_died(const struct lnlb_struct *,unsigned char *)
The main driver notifies us that the referenced node is faulty (so we should remove it from our tracking tables).
void interface_created(const struct lnlb_struct*)
The main driver notifies us that a new cluster (and so a new lnlb_struct) has been created. At this point we should usually allocate and initialize our tracking tables.
void interface_deleted(const struct lnlb_struct*)
The main driver notifies us that a the cluster (and so the lnlb_struct) has been removed. At this point we should usually deallocate our tracking tables
uint32_t (*save_status)(const struct lnlb_struct*,char **)
The main driver asks us to serialize the tracking status of this module into a buffer (the function must kmalloc it with GFP_ATOMIC priority). Buffer lenght is returned. Buffer pointer is copied out into the char** param (*param=buf_addr)
int (*load_status)(const struct lnlb_struct*,char *,uint32_t)
The main driver tells us to clear our tracking status and deserialize the buffer (pointed by char * arg) of uint32_t length .