diff --git a/modules/load_balancer/README b/modules/load_balancer/README index 041421c8560..e446cf5ed3b 100644 --- a/modules/load_balancer/README +++ b/modules/load_balancer/README @@ -35,10 +35,10 @@ Bogdan-Andrei Iancu 1.6. Exported Functions - 1.6.1. lb_start(grp,resources[,flags]) - 1.6.2. lb_next() - 1.6.3. lb_start_or_next(grp,resources[,flags]) - 1.6.4. load_balance(grp,resources[,flags]) + 1.6.1. lb_start(grp,resources[,flags[,dsts_cnt]]) + 1.6.2. lb_next([dsts_cnt]) + 1.6.3. lb_start_or_next(grp,resources[,flags[,dsts_cnt]]) + 1.6.4. load_balance(grp,resources[,flags[,dsts_cnt]]) 1.6.5. lb_reset() 1.6.6. lb_is_started() 1.6.7. lb_disable_dst() @@ -249,7 +249,7 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") 1.6. Exported Functions -1.6.1. lb_start(grp,resources[,flags]) +1.6.1. lb_start(grp,resources[,flags[,dsts_cnt]]) The function starts a new load-balancing session over the available destinations. This translates into finding the less @@ -263,8 +263,8 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") numerical value. * resources - string containing a semi-colon separated list of resources required by the current call. - * flags - various flags to controll the LB algorithm ( or - computing the available load on the system): + * flags - (optional) various flags to control the LB algorithm + (or computing the available load on the system): + n - Negative availability - use destinations with negative availability (exceeded capacity); do not ignore resources with negative availability, and thus @@ -286,6 +286,12 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") when failed calls always routed to first destination, since they almost does not affect load counters of destinations. + * dsts_cnt - (optional) string containing an integer PV + (pseudo-variable) where the total number of matching + destinations (regardless of their capacity) will be stored. + This could be used to distinguish between 'no capacity' and + 'no destinations left' situations upon a failure to find out + an available destination. Returns true if a new destination URI is set, pointing to the selected destination. NOTE that the RURI will not be changed by @@ -304,7 +310,7 @@ if (lb_start("1","trascoding;conference")) { } ... -1.6.2. lb_next() +1.6.2. lb_next([dsts_cnt]) Function to be used to pull the next available (and less loaded) destination. You need to have an ongoing LB session @@ -329,13 +335,13 @@ if (t_check_status("(408)|(5[0-9][0-9])")) { ... -1.6.3. lb_start_or_next(grp,resources[,flags]) +1.6.3. lb_start_or_next(grp,resources[,flags[,dsts_cnt]]) This is just a wrapper function to simplify scripting. If there is no ongoing LB session, it acts as lb_start(); If there is an ongoing LB session, it acts as lb_next(). -1.6.4. load_balance(grp,resources[,flags]) +1.6.4. load_balance(grp,resources[,flags[,dsts_cnt]]) Old name of the lb_start_or_next() function. diff --git a/modules/load_balancer/doc/load_balancer_admin.xml b/modules/load_balancer/doc/load_balancer_admin.xml index e3af5c1d96f..5984cb6cdd1 100644 --- a/modules/load_balancer/doc/load_balancer_admin.xml +++ b/modules/load_balancer/doc/load_balancer_admin.xml @@ -286,7 +286,7 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") Exported Functions
- <function moreinfo="none">lb_start(grp,resources[,flags])</function> + <function moreinfo="none">lb_start(grp,resources[,flags[,dsts_cnt]])</function> The function starts a new load-balancing session over the available @@ -298,29 +298,30 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") grp - group id for the destinations; the - destination may be grouped in several groups you can you for + destination may be grouped in several groups you can you for differnet scenarios; this can be a number or a variable containing a numerical value. - resources - string containing a + resources - string containing a semi-colon separated list of resources required by the current call. - flags - various flags to controll the - LB algorithm ( or computing the available load on the system): + flags - (optional) various flags to + control the LB algorithm ( or computing the available load on the + system): n - Negative availability - use destinations with negative availability (exceeded capacity); - do not ignore resources with negative availability, and thus - able to select for load balancing destinations with exceeded - capacity. This might be needed in scenarios where we want to - limit generic calls volume and always pass + do not ignore resources with negative availability, and thus + able to select for load balancing destinations with exceeded + capacity. This might be needed in scenarios where we want to + limit generic calls volume and always pass important/high-priority calls. @@ -345,6 +346,15 @@ modparam("load_balancer", "lb_define_blacklist", "blist2= 2,10,6") + + dsts_cnt - (optional) string containing + an integer PV (pseudo-variable) where the total number of matching + destinations (regardless of their capacity) will be stored. + This could be used to distinguish between 'no capacity' and + 'no destinations left' situations upon a failure to find out + an available destination. + + Returns true if a new destination URI is set, pointing to the @@ -372,7 +382,7 @@ if (lb_start("1","trascoding;conference")) {
- <function moreinfo="none">lb_next()</function> + <function moreinfo="none">lb_next([dsts_cnt])</function> Function to be used to pull the next available (and less loaded) @@ -408,11 +418,11 @@ if (t_check_status("(408)|(5[0-9][0-9])")) {
- <function moreinfo="none">lb_start_or_next(grp,resources[,flags])</function> + <function moreinfo="none">lb_start_or_next(grp,resources[,flags[,dsts_cnt]])</function> This is just a wrapper function to simplify scripting. If there is no - ongoing LB session, it acts as lb_start(); If there is an ongoing LB + ongoing LB session, it acts as lb_start(); If there is an ongoing LB session, it acts as lb_next().
@@ -420,7 +430,7 @@ if (t_check_status("(408)|(5[0-9][0-9])")) {
- <function moreinfo="none">load_balance(grp,resources[,flags])</function> + <function moreinfo="none">load_balance(grp,resources[,flags[,dsts_cnt]])</function> Old name of the lb_start_or_next() function. diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 588ae1ece26..934f4c421d5 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -408,7 +408,7 @@ static int get_dst_load(struct lb_resource **res, unsigned int res_no, int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, - unsigned int flags, struct lb_data *data, int reuse) + unsigned int flags, struct lb_data *data, int reuse, int *dsts_cnt) { /* resources for previous iteration */ static struct lb_resource **res_prev = NULL; @@ -459,7 +459,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, dst_bitmap_cur = NULL; /* search and fill new resources references if we should not reuse - previous iteration data */ + * previous iteration data */ if( !reuse ) { res_new_n = rl->n; /* adjust size of statically allocated buffer */ @@ -495,7 +495,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, } /* always search for previous iteration data, - no matter if we will reuse it or not */ + * no matter if we will reuse it or not */ group_avp = search_first_avp(0, group_avp_name, &group_val, NULL); flags_avp = search_first_avp(0, flags_avp_name, &flags_val, NULL); mask_avp = search_first_avp(0, mask_avp_name, &mask_val, NULL); @@ -556,7 +556,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, /* adjust size of statically allocated buffer */ if( res_prev_n > res_prev_size ) { /* small hack: if we need to adjust 'res_prev' buffer adjust - * it according to 'res_new' size to minimize + * it according to 'res_new' size to minimize * future pkg_realloc()'s */ if( !reuse && (res_prev_n < res_new_n) ) res_prev_n = res_new_n; @@ -617,7 +617,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, if( bitmap_size_cur > res_cur[i]->bitmap_size ) bitmap_size_cur = res_cur[i]->bitmap_size; } - /* always try to reuse 'mask' buffer from AVP, even if we need + /* always try to reuse 'mask' buffer from AVP, even if we need * to reinitialize it to avoid un-neded AVP ops */ if(mask_avp && (mask_val.s.len==(bitmap_size_cur*sizeof(unsigned int)))) { dst_bitmap_cur = (unsigned int *)mask_val.s.s; @@ -708,6 +708,9 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, lock_get(res_cur[i]->lock); /* do the load-balancing */ + if( dsts_cnt ) + /* initialize place holder for remaining enabled destinations counter variable */ + *dsts_cnt = 0; /* select destinations */ cond = 0; /* use it here as a 'first iteration' flag */ @@ -720,6 +723,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, /* valid destination (group & resources & status) */ if( get_dst_load(res_cur, res_cur_n, it_d, flags, &it_l) ) { /* only valid load here */ + if( dsts_cnt ) (*dsts_cnt)++; /* count destination */ if( (it_l > 0) || (flags & LB_FLAGS_NEGATIVE) ) { /* only allowed load here */ if( !cond/*first pass*/ || (it_l > load)/*new max*/ ) { @@ -875,15 +879,15 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, int do_lb_start(struct sip_msg *req, int group, struct lb_res_str_list *rl, - unsigned int flags, struct lb_data *data) + unsigned int flags, int *dsts_cnt, struct lb_data *data) { - return lb_route(req, group, rl, flags, data, 0/*no data reusage*/); + return lb_route(req, group, rl, flags, data, 0/*no data reusage*/, dsts_cnt); } -int do_lb_next(struct sip_msg *req, struct lb_data *data) +int do_lb_next(struct sip_msg *req, int *dsts_cnt, struct lb_data *data) { - return lb_route(req, -1, NULL, 0, data, 1/*reuse previous data*/); + return lb_route(req, -1, NULL, 0, data, 1/*reuse previous data*/, dsts_cnt); } diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index 93519a9c6df..f94c1c3876f 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -92,9 +92,9 @@ int add_lb_dsturi( struct lb_data *data, int id, int group, char *uri, void free_lb_data(struct lb_data *data); int do_lb_start(struct sip_msg *req, int group, struct lb_res_str_list *rl, - unsigned int flags, struct lb_data *data); + unsigned int flags, int *dsts_cnt, struct lb_data *data); -int do_lb_next(struct sip_msg *req, struct lb_data *data); +int do_lb_next(struct sip_msg *req, int *dsts_cnt, struct lb_data *data); int do_lb_reset(struct sip_msg *req, struct lb_data *data); diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 6befd4f5124..8645e099e3f 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -89,13 +89,14 @@ static struct mi_root* mi_lb_resize(struct mi_root *cmd_tree, void *param); static struct mi_root* mi_lb_list(struct mi_root *cmd_tree, void *param); static struct mi_root* mi_lb_status(struct mi_root *cmd_tree, void *param); -static int fixup_resources(void** param, int param_no); +static int fixup_lb_start(void** param, int param_no); +static int fixup_lb_next(void** param, int param_no); static int fixup_is_dst(void** param, int param_no); static int fixup_cnt_call(void** param, int param_no); -static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl); -static int w_lb_next(struct sip_msg *req); -static int w_lb_start_or_next(struct sip_msg *req,char *grp,char *rl,char *fl); +static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl, char *dsts_cnt_pvs); +static int w_lb_next(struct sip_msg *req, char *dsts_cnt_pvs); +static int w_lb_start_or_next(struct sip_msg *req, char *grp, char *rl, char *fl, char *dsts_cnt_pvs); static int w_lb_reset(struct sip_msg *req); static int w_lb_is_started(struct sip_msg *req); static int w_lb_disable_dst(struct sip_msg *req); @@ -113,20 +114,28 @@ static void lb_prob_handler(unsigned int ticks, void* param); static cmd_export_t cmds[]={ - {"lb_start", (cmd_function)w_lb_start, 2, fixup_resources, + {"lb_start", (cmd_function)w_lb_start, 2, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"lb_start", (cmd_function)w_lb_start, 3, fixup_resources, + {"lb_start", (cmd_function)w_lb_start, 3, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"load_balance", (cmd_function)w_lb_start_or_next, 2, fixup_resources, + {"lb_start", (cmd_function)w_lb_start, 4, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"load_balance", (cmd_function)w_lb_start_or_next, 3, fixup_resources, + {"load_balance", (cmd_function)w_lb_start_or_next, 2, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"lb_start_or_next",(cmd_function)w_lb_start_or_next, 2, fixup_resources, + {"load_balance", (cmd_function)w_lb_start_or_next, 3, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"lb_start_or_next",(cmd_function)w_lb_start_or_next, 3, fixup_resources, + {"load_balance", (cmd_function)w_lb_start_or_next, 4, fixup_lb_start, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_start_or_next",(cmd_function)w_lb_start_or_next, 2, fixup_lb_start, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_start_or_next",(cmd_function)w_lb_start_or_next, 3, fixup_lb_start, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_start_or_next",(cmd_function)w_lb_start_or_next, 4, fixup_lb_start, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {"lb_next", (cmd_function)w_lb_next, 0, 0, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_next", (cmd_function)w_lb_next, 1, fixup_lb_next, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {"lb_reset", (cmd_function)w_lb_reset, 0, 0, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {"lb_is_started", (cmd_function)w_lb_is_started, 0, 0, @@ -214,7 +223,7 @@ struct lb_grp_param { }; -static int fixup_resources(void** param, int param_no) +static int fixup_lb_start(void** param, int param_no) { struct lb_res_str_list *lb_rl; struct lb_grp_param *lbgp; @@ -290,12 +299,33 @@ static int fixup_resources(void** param, int param_no) /* string with flags */ return fixup_sgp(param); + } else if (param_no==4) { + + /* pvar string with variable to hold remaining enabled destinations counter */ + if( *param && strlen((char *)*param) ) + return fixup_pvar(param); + *param = NULL; + return 0; + } return 0; } +static int fixup_lb_next(void** param, int param_no) +{ + + if (param_no==1) { + /* pvar string with variable to hold remaining enabled destinations counter */ + return fixup_lb_start(param, 4); + } + + LM_CRIT("bug - too many params (%d)\n",param_no); + return -1; +} + + static int fixup_is_dst(void** param, int param_no) { if (param_no==1) { @@ -334,10 +364,10 @@ static int fixup_cnt_call(void** param, int param_no) return fixup_is_dst(param, 2); if (param_no==3) /* group id */ - return fixup_resources(param, 1); + return fixup_lb_start(param, 1); if (param_no==4) /* resources */ - return fixup_resources(param, 2); + return fixup_lb_start(param, 2); if (param_no==5) /* count or un-count */ return fixup_uint(param); @@ -523,26 +553,40 @@ static void mod_destroy(void) } -static int w_lb_next(struct sip_msg *req) +static int w_lb_next(struct sip_msg *req, char *dsts_cnt_pvs) { int ret; + int dsts_cnt; + pv_value_t val; lock_start_read(ref_lock); /* do lb */ - ret = do_lb_next(req, *curr_data); + dsts_cnt = -1; + ret = do_lb_next(req, &dsts_cnt, *curr_data); lock_stop_read(ref_lock); + if( dsts_cnt_pvs ) { + memset(&val, 0, sizeof(pv_value_t)); + val.flags = PV_VAL_INT|PV_TYPE_INT; + val.ri = dsts_cnt; + + if( pv_set_value(req, (pv_spec_t *)dsts_cnt_pvs, (int)EQ_T, &val) < 0 ) { + LM_ERR("setting of pvar failed\n"); + } + } + if( ret < 0 ) return ret; return 1; } -static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl) +static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl, char *dsts_cnt_pvs) { int ret; + int dsts_cnt; int grp_no; struct lb_grp_param *lbgp = (struct lb_grp_param *)grp; @@ -614,24 +658,35 @@ static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl) lock_start_read( ref_lock ); /* do lb */ - ret = do_lb_start(req, grp_no, lb_rl, flags, *curr_data); + dsts_cnt = -1; + ret = do_lb_start(req, grp_no, lb_rl, flags, &dsts_cnt, *curr_data); lock_stop_read( ref_lock ); if (lbp->type & RES_ELEM) pkg_free(lb_rl); - if (ret<0) + if( dsts_cnt_pvs ) { + memset(&val, 0, sizeof(pv_value_t)); + val.flags = PV_VAL_INT|PV_TYPE_INT; + val.ri = dsts_cnt; + + if( pv_set_value(req, (pv_spec_t *)dsts_cnt_pvs, (int)EQ_T, &val) < 0 ) { + LM_ERR("setting of pvar failed\n"); + } + } + + if(ret<0) return ret; return 1; } -static int w_lb_start_or_next(struct sip_msg *req,char *grp,char *rl,char *fl) +static int w_lb_start_or_next(struct sip_msg *req, char *grp, char *rl, char *fl, char *dsts_cnt_pvs) { return (do_lb_is_started(req) > 0) ? - w_lb_next(req) : - w_lb_start(req, grp, rl, fl) + w_lb_next(req, dsts_cnt_pvs) : + w_lb_start(req, grp, rl, fl, dsts_cnt_pvs) ; }