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
- lb_start(grp,resources[,flags])
+ lb_start(grp,resources[,flags[,dsts_cnt]])
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")) {
- lb_next()
+ lb_next([dsts_cnt])
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])")) {
- lb_start_or_next(grp,resources[,flags])
+ 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
+ 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])")) {
- load_balance(grp,resources[,flags])
+ load_balance(grp,resources[,flags[,dsts_cnt]])
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)
;
}