From a7549e00bdd3fd13fc20777bccf935d41303980e Mon Sep 17 00:00:00 2001 From: shripchenko Date: Wed, 1 Oct 2014 06:14:09 -0700 Subject: [PATCH 1/7] changed load_ballance() function to 1. save profiles applied in the current iteration 2. process previous iteration's profiles to clean them up 3. allow group and/or resources list changes in subsequent calls 4. sanity check if dst_bitmap size chaged --- modules/load_balancer/lb_data.c | 384 +++++++++++++++++--------- modules/load_balancer/lb_data.h | 1 + modules/load_balancer/load_balancer.c | 8 +- 3 files changed, 268 insertions(+), 125 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 44bc5a1a434..d0198b89ac5 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -416,184 +416,323 @@ static unsigned int get_dst_load(struct lb_resource **res, unsigned int res_no, int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, unsigned int alg, struct lb_data *data) { + /* resources for current iteration */ static struct lb_resource **call_res = NULL; - static unsigned int call_res_no = 0; + static unsigned int call_res_size = 0; + /* probed destinations bitmap */ static unsigned int *dst_bitmap = NULL; static unsigned int bitmap_size = 0; - unsigned int * used_dst_bitmap; - struct lb_resource *res; - int size; - int i,j; - unsigned int load, ld; - struct lb_dst *dst; - struct lb_dst *it; + /* profiles from previous iteration */ + static struct dlg_profile_table **call_prfs = NULL; + static unsigned int call_prfs_size = 0; + + int call_prfs_n, call_res_n; struct lb_dst *last_dst; + unsigned int *used_dst_bitmap; + unsigned int bitmap_size_cur; + struct usr_avp *grp_avp; struct usr_avp *mask_avp; struct usr_avp *id_avp; + struct usr_avp *prfs_avp, *del_prfs_avp; int_str grp_val; int_str mask_val; int_str id_val; + int_str prfs_val; - /* get references to the resources */ - if (rl->n>call_res_no) { - call_res = (struct lb_resource**)pkg_realloc - (call_res, rl->n*sizeof(struct lb_resorce*)); - if (call_res==NULL) { - LM_ERR("no more pkg mem - res ptr realloc\n"); + struct lb_dst *it_d, *dst; + struct lb_resource *it_r; + struct dlg_profile_table *it_p; + int it_l, load; + int i, j, again; + + + /* adjust size of statically allocated buffer */ + call_res_n = rl->n; + if( call_res_n > call_res_size ) { + call_res = (struct lb_resource **)pkg_realloc(call_res, (call_res_n * sizeof(struct lb_resource *))); + if( call_res == NULL ) { + LM_ERR("no more pkg mem - resources ptr buffer realloc failure\n"); return -1; } - call_res_no = rl->n; + call_res_size = call_res_n; } - for( i=0,res=data->resources ; (in)&&res ; res=res->next) { - if (search_resource_str( rl, &res->name)) { - call_res[i++] = res; - LM_DBG("found requested (%d) resource %.*s\n", - i-1, res->name.len,res->name.s); + /* fill resource references */ + for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) { + if( search_resource_str(rl, &it_r->name) ) { + call_res[i++] = it_r; + LM_DBG("found requested %d/%d resource [%.*s]\n", i, call_res_n, it_r->name.len, it_r->name.s); } } - if (i!=rl->n) { - LM_ERR("unknown resource in input string\n"); + if( i != call_res_n ) { + LM_ERR("unknown resource found in input string\n"); return -1; } - /* any previous iteration due failover ? */ - grp_avp = search_first_avp( 0, grp_avp_name, &grp_val, 0); - mask_avp = search_first_avp( 0, mask_avp_name, &mask_val, 0); - id_avp = search_first_avp( 0, id_avp_name, &id_val, 0); - if ( grp_avp && mask_avp && id_avp && ((grp_avp->flags&AVP_VAL_STR)==0) && - (mask_avp->flags&AVP_VAL_STR) && ((id_avp->flags&AVP_VAL_STR)==0) ) { - /* not the first iteration -> use data from AVPs */ - grp = grp_val.n ; - used_dst_bitmap = (unsigned int*)mask_val.s.s; - /* set the previous dst as used (not selected) */ - for(last_dst=data->dsts,i=0,j=0 ; last_dst ; last_dst=last_dst->next) { - if (last_dst->id==id_val.n) {used_dst_bitmap[i] &= ~(1<n ; i++) { - if (call_res[i]->bitmap_sizebitmap_size; - } - if (size>bitmap_size) { - dst_bitmap = (unsigned int*)pkg_realloc - ( dst_bitmap, size*sizeof(unsigned int) ); - if (dst_bitmap==NULL) { - LM_ERR("no more pkg mem - bitmap realloc\n"); + /* get data from previous iteration due to failover */ + grp_avp = search_first_avp(0, grp_avp_name, &grp_val, 0); + mask_avp = search_first_avp(0, mask_avp_name, &mask_val, 0); + id_avp = search_first_avp(0, id_avp_name, &id_val, 0); + /* sanity checks for fetched AVPs */ + if( grp_avp && !(is_avp_str_val(grp_avp) == 0) ) { destroy_avp(grp_avp); grp_avp = NULL; } + if( mask_avp && !(is_avp_str_val(mask_avp) != 0) ) { destroy_avp(mask_avp); mask_avp = NULL; } + if( id_avp && !(is_avp_str_val(id_avp) == 0) ) { destroy_avp(id_avp); id_avp = NULL; } + + + /* get previous iteration group and mask, if any, and check that they are valid */ + used_dst_bitmap = NULL; + for( bitmap_size_cur=(unsigned int)(-1),i=0 ; ibitmap_size */ + if( call_res[i]->bitmap_size < bitmap_size_cur ) + bitmap_size_cur = call_res[i]->bitmap_size; + } + if( grp_avp && mask_avp ) { + /* reuse previous mask only if... */ + if( (grp_val.n == grp) && (mask_val.s.len == (bitmap_size_cur * sizeof(unsigned int))) ) { + used_dst_bitmap = (unsigned int *)mask_val.s.s; + LM_DBG("sequential call of LB - use previous group and mask\n"); + } + } + /* initialize dst_bitmap from scratch */ + if( used_dst_bitmap == NULL ) { + /* adjust size of statically allocated buffer */ + if( bitmap_size_cur > bitmap_size ) { + dst_bitmap = (unsigned int *)pkg_realloc(dst_bitmap, (bitmap_size_cur * sizeof(unsigned int))); + if( dst_bitmap == NULL ) { + LM_ERR("no more pkg mem - dst_bitmap buffer realloc failure\n"); return -1; } - bitmap_size = size; + bitmap_size = bitmap_size_cur; } - memset( dst_bitmap, 0xff , size*sizeof(unsigned int) ); - for( i=0 ; in ; i++) { - for( j=0 ; jdst_bitmap[j]; } used_dst_bitmap = dst_bitmap; + } - /* create dialog */ - if (lb_dlg_binds.create_dlg( req , 0)!=1 ) { - LM_ERR("failed to create dialog\n"); - return -1; + /* get previous iteration destination, if any */ + last_dst = NULL; + if( id_avp ) { + for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { + if( it_d->id == id_val.n ) { + last_dst = it_d; + LM_DBG("sequential call of LB - use previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + break; + } } - } /* end - first LB run */ + } + /* search and fill previous iteration profiles, if any */ + do { + again = 0; + call_prfs_n = 0; + for( prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; prfs_avp ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { + /* ignore AVPs with invalid type */ + if( !(is_avp_str_val(prfs_avp) != 0) ) continue; + + it_p = NULL; + + /* first try: check in existing data->resources */ + for( it_r=data->resources ; it_r ; it_r=it_r->next ) { + if( (it_r->profile->name.len == prfs_val.s.len) && (memcmp(it_r->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { + it_p = it_r->profile; + break; + } + } + /* second try: search in dialog module */ + if( it_p == NULL ) { + it_p = lb_dlg_binds.search_profile(&prfs_val.s); + } + /* else: complain and ignore */ + if( it_p == NULL ) { + LM_WARN("sequential call of LB - ignore previous unknown profile [%.*s]\n", prfs_val.s.len, prfs_val.s.s); + continue; + } + + /* fill buffer only if buffer size not exeeded */ + if( call_prfs_n < call_prfs_size ) { + call_prfs[call_prfs_n] = it_p; + LM_DBG("sequential call of LB - use previous profile [%.*s]\n", it_p->name.len, it_p->name.s); + } + call_prfs_n++; + } + /* adjust size of statically allocated buffer */ + if( call_prfs_n > call_prfs_size ) { + call_prfs = (struct dlg_profile_table **)pkg_realloc(call_prfs, (call_prfs_n * sizeof(struct dlg_profile_table *))); + if( call_prfs == NULL ) { + LM_ERR("no more pkg mem - profiles ptr buffer realloc failure\n"); + return -1; + } + call_prfs_size = call_prfs_n; + again = 1; + } + } + while( again ); + + + /* do initialize stuff if (grp_avp and mask_avp are unset) and we assume it a first LB run */ + if( (grp_avp == NULL) && (mask_avp == NULL) ) { + /* create dialog, if needed */ + if( !lb_dlg_binds.get_dlg() ) { + if( lb_dlg_binds.create_dlg(req, 0) != 1 ) { + LM_ERR("failed to create dialog\n"); + return -1; + } + } + } + + + /* lock resources */ + for( i=0 ; ilock); - /* lock the resources */ - for( i=0 ; in ; i++) - lock_get( call_res[i]->lock ); /* do the load-balancing */ load = 0; dst = NULL; - for( it=data->dsts,i=0,j=0 ; it ; it=it->next) { - if ( (used_dst_bitmap[i] & (1<group==grp && - (it->flags&LB_DST_STAT_DSBL_FLAG)==0 ) { - /* valid destination (resources & group & status) */ - if ( (ld = get_dst_load(call_res, rl->n, it, alg)) > load) { - /* computing a max */ - load = ld; - dst = it; + for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) { + if( it_d->group == grp ) { + if( (used_dst_bitmap[i] & (1 << j)) && ((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) { + /* valid destination (group & resources & status) */ + if( (it_l = get_dst_load(call_res, call_res_n, it_d, alg)) > load ) { + /* computing a max */ + load = it_l; + dst = it_d; + } + LM_DBG("destination %d <%.*s> selected for LB set with free=%d\n", it_d->id, it_d->uri.len, it_d->uri.s, it_l); + } + else { + LM_DBG("skipping destination %d <%.*s> (used=%d , disabled=%d)\n", + it_d->id, it_d->uri.len, it_d->uri.s, + ((used_dst_bitmap[i] & (1 << j)) ? 0 : 1), ((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0) + ); } - LM_DBG("destination <%.*s> selected for LB set with free=%d " - "(max=%d)\n",it->uri.len, it->uri.s,ld, load); - } else { - if (it->group==grp) - LM_DBG("skipping destination <%.*s> (used=%d , disabled=%d)\n", - it->uri.len, it->uri.s, - (used_dst_bitmap[i] & (1<flags&LB_DST_STAT_DSBL_FLAG)?1:0 ); } - j++; - if (j==8*sizeof(unsigned int)) {i++;j=0;} + if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; } } /* if re-trying, remove the dialog from previous profiles */ - if (last_dst) { - for( i=0 ; in ; i++) { - if (lb_dlg_binds.unset_profile( req, &last_dst->profile_id, - call_res[i]->profile)!=1) - LM_ERR("failed to remove from profile\n"); + if( last_dst && (call_prfs_n > 0) ) { + for( i=0 ; iprofile_id, call_prfs[i]) != 1 ) + LM_ERR("failed to remove from profile [%.*s] -> [%.*s]\n", call_prfs[i]->name.len, call_prfs[i]->name.s, last_dst->profile_id.len, last_dst->profile_id.s); } } - if (dst==NULL) { - LM_DBG("no destination found\n"); - } else { + if( dst != NULL ) { + LM_DBG("winning destination %d <%.*s> selected for LB set with free=%d\n", dst->id, dst->uri.len, dst->uri.s, load); + /* add to the profiles */ - for( i=0 ; in ; i++) { - if (lb_dlg_binds.set_profile( req, &dst->profile_id, - call_res[i]->profile, 0)!=0) - LM_ERR("failed to add to profile\n"); + for( i=0 ; iprofile_id, call_res[i]->profile, 0) != 0 ) + LM_ERR("failed to add to profile [%.*s] -> [%.*s]\n", call_res[i]->profile->name.len, call_res[i]->profile->name.s, dst->profile_id.len, dst->profile_id.s); } + + /* set dst as used (not selected) */ + for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) { + if( it_d == dst ) { used_dst_bitmap[i] &= ~(1 << j); break; } + if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; } + } + } + else { + LM_DBG("no destination found\n"); } - /* unlock the resources*/ - for( i=0 ; in ; i++) - lock_release( call_res[i]->lock ); - if (dst) { - LM_DBG("winning destination <%.*s> selected for LB set with free=%d\n", - dst->uri.len, dst->uri.s,load); - /* change (add/edit) the AVPs for the next iteration */ - if (grp_avp==NULL && mask_avp==NULL) { - grp_val.n = grp; - if (add_avp( 0, grp_avp_name, grp_val)!=0) { - LM_ERR("failed to add GRP AVP"); - } - mask_val.s.s = (char*)used_dst_bitmap; - mask_val.s.len = bitmap_size*sizeof(unsigned int); - if (add_avp( AVP_VAL_STR, mask_avp_name, mask_val)!=0) { - LM_ERR("failed to add MASK AVP"); - } + /* unlock resources, in reverse order maybe? */ + for( i=0 ; ilock); + + + /* save state - group */ + if( grp_avp == NULL ) { + grp_val.n = grp; + if( add_avp(0, grp_avp_name, grp_val) != 0 ) { + LM_ERR("failed to add GRP AVP\n"); } - if (id_avp) { - id_avp->data = (void*)(long)dst->id; - } else { + } + else if( grp_val.n != grp ) { + grp_avp->data = (void *)(long)grp; + } + /* save state - dst_bitmap mask */ + if( (mask_avp != NULL) && (used_dst_bitmap != (unsigned int *)mask_val.s.s) ) { + destroy_avp(mask_avp); + mask_avp = NULL; + } + if( mask_avp == NULL ) { + mask_val.s.s = (char *)used_dst_bitmap; + mask_val.s.len = bitmap_size_cur * sizeof(unsigned int); + if( add_avp(AVP_VAL_STR, mask_avp_name, mask_val) != 0 ) { + LM_ERR("failed to add MASK AVP\n"); + } + } + /* save state - dst */ + if( id_avp == NULL ) { + if( dst != NULL ) { id_val.n = dst->id; - if (add_avp( 0, id_avp_name, id_val)!=0) { - LM_ERR("failed to add ID AVP"); + if( add_avp(0, id_avp_name, id_val) != 0 ) { + LM_ERR("failed to add ID AVP\n"); + } + } + } + else { + if( dst != NULL ) { + id_avp->data = (void *)(long)dst->id; + } + else { + destroy_avp(id_avp); + id_avp = NULL; + } + } + /* save state - prfs */ + /* iterate AVPs once and delete old profiles */ + for( del_prfs_avp=NULL,prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { + if( del_prfs_avp != NULL ) { + destroy_avp(del_prfs_avp); + del_prfs_avp = NULL; + }; + if( prfs_avp == NULL ) break; + + /* process AVPs if we have dst and AVP of the right type */ + if( (dst != NULL) && (is_avp_str_val(prfs_avp) != 0) ) { + /* skip existing profiles */ + again = 0; + for( i=0 ; (iprofile->name.len == prfs_val.s.len) && (memcmp(call_res[i]->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { + call_res[i] = NULL; + again = 1; + break; + } } + if( again ) continue; } - /* set dst uri */ - if (set_dst_uri( req, &dst->uri )!=0) { - LM_ERR("failed to set duri\n"); - return -2; + del_prfs_avp = prfs_avp; + } + if( dst != NULL ) { + /* add new profiles */ + for( i=0 ; (iprofile->name; + if( add_avp(AVP_VAL_STR, prfs_avp_name, prfs_val) != 0 ) { + LM_ERR("failed to add RES AVP\n"); + } } } - return dst?0:-2; + + /* outcome: set dst uri */ + if( (dst != NULL) && (set_dst_uri(req, &dst->uri ) !=0) ) { + LM_ERR("failed to set duri\n"); + return -2; + } + + return dst ? 0 : -2; } + /* events */ static event_id_t lb_evi_id; static str lb_event = str_init("E_LOAD_BALANCER_STATUS"); @@ -814,6 +953,3 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, return 0; } - - - diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index 6e3870bd519..e26f1e6d8ea 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -108,4 +108,5 @@ void lb_raise_event(struct lb_dst *dst); extern int grp_avp_name; extern int mask_avp_name; extern int id_avp_name; +extern int prfs_avp_name; #endif diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 92d11b7f427..45961486f21 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -75,9 +75,11 @@ static int mi_child_init(); static str grp_avp_name_s = str_init("lb_grp"); static str mask_avp_name_s = str_init("lb_mask"); static str id_avp_name_s = str_init("lb_id"); +static str prfs_avp_name_s = str_init("lb_prfs"); int grp_avp_name; int mask_avp_name; int id_avp_name; +int prfs_avp_name; @@ -90,7 +92,7 @@ static int fixup_resources(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_load_balance(struct sip_msg *req, char *grp, char *rl, char* al); +static int w_load_balance(struct sip_msg *req, char *grp, char *rl, char* al); static int w_lb_disable(struct sip_msg *req); static int w_lb_is_dst2(struct sip_msg *msg, char *ip, char *port); static int w_lb_is_dst3(struct sip_msg *msg, char *ip, char *port, char *grp); @@ -444,6 +446,10 @@ static int mod_init(void) LM_ERR("cannot init event\n"); return -1; } + if (parse_avp_spec(&prfs_avp_name_s, &prfs_avp_name)) { + LM_ERR("cannot parse resources avp\n"); + return -1; + } return 0; } From 301e6d321d00b75afd93aa6dd4238b7fb96dcde1 Mon Sep 17 00:00:00 2001 From: shripchenko Date: Wed, 1 Oct 2014 06:31:11 -0700 Subject: [PATCH 2/7] add lb_reset() function to reset LB state in case you want to stop load-ballancing call and proxy call somewere else and clean LB usage (dialog profiles) for this call. (or re-start LB process from the beginning) --- modules/load_balancer/lb_data.c | 72 +++++++++++++++++++++++++++ modules/load_balancer/lb_data.h | 2 + modules/load_balancer/load_balancer.c | 20 ++++++++ 3 files changed, 94 insertions(+) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index d0198b89ac5..f65f6cd35e3 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -733,6 +733,78 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, } +int do_lb_reset(struct sip_msg *req, struct lb_data *data) +{ + struct usr_avp *id_avp; + struct usr_avp *prfs_avp, *del_prfs_avp; + int_str id_val; + int_str prfs_val; + + struct lb_dst *it_d, *last_dst; + struct lb_resource *it_r; + struct dlg_profile_table *it_p; + + + /* get previous iteration destination, if any */ + last_dst = NULL; + id_avp = search_first_avp(0, id_avp_name, &id_val, 0); + if( id_avp ) { + if( is_avp_str_val(id_avp) == 0 ) { + for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { + if( it_d->id == id_val.n ) { + last_dst = it_d; + LM_DBG("sequential call of LB - use previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + break; + } + } + } + destroy_avp(id_avp); + } + + /* search and clean up previous iteration profiles, if any */ + for( del_prfs_avp=NULL,prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { + if( del_prfs_avp != NULL ) { + destroy_avp(del_prfs_avp); + del_prfs_avp = NULL; + }; + if( prfs_avp == NULL ) break; + + /* process AVPs if we have last_dst and AVP of the right type */ + if( (last_dst != NULL) && (is_avp_str_val(prfs_avp) != 0) ) { + it_p = NULL; + + /* first try: check in existing data->resources */ + for( it_r=data->resources ; it_r ; it_r=it_r->next ) { + if( (it_r->profile->name.len == prfs_val.s.len) && (memcmp(it_r->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { + it_p = it_r->profile; + break; + } + } + /* second try: search in dialog module */ + if( it_p == NULL ) { + it_p = lb_dlg_binds.search_profile(&prfs_val.s); + } + /* else: complain and ignore */ + if( it_p == NULL ) { + LM_WARN("sequential call of LB - ignore previous unknown profile [%.*s]\n", prfs_val.s.len, prfs_val.s.s); + continue; + } + + /* remove profile */ + if( lb_dlg_binds.unset_profile(req, &last_dst->profile_id, it_p) != 1 ) + LM_ERR("failed to remove from profile [%.*s] -> [%.*s]\n", it_p->name.len, it_p->name.s, last_dst->profile_id.len, last_dst->profile_id.s); + } + del_prfs_avp = prfs_avp; + } + + /* remove any saved AVPs */ + destroy_avps(0, grp_avp_name, 0); + destroy_avps(0, mask_avp_name, 0); + + return 0; +} + + /* events */ static event_id_t lb_evi_id; static str lb_event = str_init("E_LOAD_BALANCER_STATUS"); diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index e26f1e6d8ea..0d8571a04f1 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -95,6 +95,8 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, int do_lb_disable(struct sip_msg *req, struct lb_data *data); +int do_lb_reset(struct sip_msg *req, struct lb_data *data); + int lb_is_dst(struct lb_data *data, struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, int grp, int active); diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 45961486f21..75544dde2ec 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -94,6 +94,7 @@ static int fixup_cnt_call(void** param, int param_no); static int w_load_balance(struct sip_msg *req, char *grp, char *rl, char* al); static int w_lb_disable(struct sip_msg *req); +static int w_lb_reset(struct sip_msg *req); static int w_lb_is_dst2(struct sip_msg *msg, char *ip, char *port); static int w_lb_is_dst3(struct sip_msg *msg, char *ip, char *port, char *grp); static int w_lb_is_dst4(struct sip_msg *msg, char *ip, char *port, char *grp, @@ -114,6 +115,8 @@ static cmd_export_t cmds[]={ 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {"lb_disable", (cmd_function)w_lb_disable, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE}, + {"lb_reset", (cmd_function)w_lb_reset, 0, 0, + 0, REQUEST_ROUTE|FAILURE_ROUTE}, {"lb_is_destination",(cmd_function)w_lb_is_dst2, 2, fixup_is_dst, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"lb_is_destination",(cmd_function)w_lb_is_dst3, 3, fixup_is_dst, @@ -568,6 +571,23 @@ static int w_lb_disable(struct sip_msg *req) } +static int w_lb_reset(struct sip_msg *req) +{ + int ret; + + lock_start_read( ref_lock ); + + /* do lb */ + ret = do_lb_reset( req , *curr_data); + + lock_stop_read( ref_lock ); + + if (ret<0) + return ret; + return 1; +} + + static int w_lb_is_dst2(struct sip_msg *msg, char *ip, char *port) { int ret; From cd0ac1465bf589319df18cea043be3ccd5404622 Mon Sep 17 00:00:00 2001 From: shripchenko Date: Wed, 1 Oct 2014 06:57:44 -0700 Subject: [PATCH 3/7] changed lb_count_call(ip,port,grp,resources[,mode]) function to allow one parameter that trigger whenever this function will actually 'count' call (add LB profiles) or 'un-count' call (clean up things after convential lb_count_call() call) this might be needed if we count call for particular resources and then need to un-count it. --- modules/load_balancer/lb_data.c | 15 +++++++++++---- modules/load_balancer/lb_data.h | 2 +- modules/load_balancer/load_balancer.c | 12 +++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index f65f6cd35e3..3ee1ab1effc 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -951,7 +951,7 @@ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, int lb_count_call(struct lb_data *data, struct sip_msg *req, - struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl) + struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl, int mode) { static struct lb_resource **call_res = NULL; static unsigned int call_res_no = 0; @@ -1014,9 +1014,16 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, /* add to the profiles */ for( i=0 ; in ; i++) { - if (lb_dlg_binds.set_profile( req, &dst->profile_id, - call_res[i]->profile, 0)!=0) - LM_ERR("failed to add to profile\n"); + if( !mode ) { + if (lb_dlg_binds.set_profile( req, &dst->profile_id, + call_res[i]->profile, 0)!=0) + LM_ERR("failed to add to profile\n"); + } + else { + if (lb_dlg_binds.unset_profile( req, &dst->profile_id, + call_res[i]->profile)!=1) + LM_ERR("failed to remove from profile\n"); + } } /* unlock the resources*/ diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index 0d8571a04f1..007a7da8e48 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -101,7 +101,7 @@ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, int grp, int active); int lb_count_call(struct lb_data *data, struct sip_msg *req, - struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl); + struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl, int mode); int lb_init_event(void); void lb_raise_event(struct lb_dst *dst); diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 75544dde2ec..89fd0b06281 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -100,7 +100,7 @@ static int w_lb_is_dst3(struct sip_msg *msg, char *ip, char *port, char *grp); static int w_lb_is_dst4(struct sip_msg *msg, char *ip, char *port, char *grp, char *active); static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, - char *rl); + char *rl, char *mode); static void lb_prob_handler(unsigned int ticks, void* param); @@ -125,6 +125,8 @@ static cmd_export_t cmds[]={ 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, {"lb_count_call", (cmd_function)w_count_call, 4, fixup_cnt_call, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_count_call", (cmd_function)w_count_call, 5, fixup_cnt_call, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {0,0,0,0,0,0} }; @@ -317,6 +319,9 @@ static int fixup_cnt_call(void** param, int param_no) if (param_no==4) /* resources */ return fixup_resources(param, 2); + if (param_no==5) + /* count or un-count */ + return fixup_uint(param); return -1; } @@ -634,7 +639,7 @@ static int w_lb_is_dst4(struct sip_msg *msg,char *ip,char *port,char *grp, static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, - char *rl) + char *rl, char *mode) { struct lb_grp_param *lbgp = (struct lb_grp_param *)grp; struct lb_res_str_list *lb_rl; @@ -709,7 +714,8 @@ static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, lock_start_read( ref_lock ); - ret = lb_count_call( *curr_data, req, ipa, port_no, grp_no, lb_rl); + ret = lb_count_call( *curr_data, req, ipa, port_no, grp_no, lb_rl, + (unsigned int)(long)mode); lock_stop_read( ref_lock ); From 598607431a15f44157376aba26bb3669eb60067b Mon Sep 17 00:00:00 2001 From: shripchenko Date: Wed, 1 Oct 2014 07:22:39 -0700 Subject: [PATCH 4/7] introduced two more algorithms for load_balance() that the same as existing, but 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. --- modules/load_balancer/lb_data.c | 69 ++++++++++++++++++--------------- modules/load_balancer/lb_data.h | 6 ++- 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 3ee1ab1effc..36e5942d0e4 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -372,44 +372,39 @@ void free_lb_data(struct lb_data *data) } -static unsigned int get_dst_load(struct lb_resource **res, unsigned int res_no, - struct lb_dst *dst, unsigned int alg) +static int get_dst_load(struct lb_resource **res, unsigned int res_no, + struct lb_dst *dst, unsigned int alg, int *load) { - int k,l; - unsigned int available; - int av; + int k, l, av; - available = (unsigned int)(-1); /* iterate through requested resources */ for( k=0 ; krmap_no ; l++) - if (res[k]==dst->rmap[l].resource) + for (l=0 ; lrmap_no ; l++ ) + if( res[k] == dst->rmap[l].resource ) break; - if (l==dst->rmap_no) { + if( l == dst->rmap_no ) { LM_CRIT("bug - cannot find request resource in dst\n"); return 0; } - if (alg==LB_RELATIVE_LOAD_ALG) { - if (dst->rmap[l].max_load) { - av = 100 - ( 100*lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id) / dst->rmap[l].max_load ); - } else { - av = 0; + av = 0; + if( (alg == LB_ALG_REL) || (alg == LB_ALG_REL_NEG) ) { + if( dst->rmap[l].max_load ) { + av = 100 - (100 * lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id) / dst->rmap[l].max_load); } - } else { - /* LB_ABSOLUTE_LOAD_ALG */ - av = dst->rmap[l].max_load - - lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id); } - if (av < 0) { - LM_WARN("negative availability for resource in dst\n"); - av = 0; + else if( (alg == LB_ALG_ABS) || (alg == LB_ALG_ABS_NEG) ) { + av = dst->rmap[l].max_load - lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id); } - if (av < available) /* computing a minimum */ - available = av; - } - return available; + if( (k == 0/*first iteration*/) || (av < *load ) ) + *load = av; + /* + we possibly could have negative avaliability for any resource, + because we could use ALG=2,3 or manually increment resource with lb_count_call() + */ + } + return (k > 0); /* load initialized */ } @@ -591,18 +586,30 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, /* do the load-balancing */ - load = 0; + again = 0; + load = it_l = 0; dst = NULL; for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) { if( it_d->group == grp ) { if( (used_dst_bitmap[i] & (1 << j)) && ((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) { /* valid destination (group & resources & status) */ - if( (it_l = get_dst_load(call_res, call_res_n, it_d, alg)) > load ) { - /* computing a max */ - load = it_l; - dst = it_d; + if( get_dst_load(call_res, call_res_n, it_d, alg, &it_l) ) { + if( + (((alg == LB_ALG_REL_NEG) || (alg == LB_ALG_ABS_NEG)) || (it_l > 0)) && + (!again || (it_l > load)) + ) { + /* computing a max, or first iteration */ + load = it_l; + dst = it_d; + again = 1; + }; + LM_DBG("destination %d <%.*s> selected for LB set with free=%d\n", it_d->id, it_d->uri.len, it_d->uri.s, it_l); + } + else { + LM_WARN("skipping destination %d <%.*s> - unable to calculate free resources\n", + it_d->id, it_d->uri.len, it_d->uri.s + ); } - LM_DBG("destination %d <%.*s> selected for LB set with free=%d\n", it_d->id, it_d->uri.len, it_d->uri.s, it_l); } else { LM_DBG("skipping destination %d <%.*s> (used=%d , disabled=%d)\n", diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index 007a7da8e48..e42e58fe92d 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -36,8 +36,10 @@ #include "../dialog/dlg_load.h" #include "lb_parser.h" -#define LB_ABSOLUTE_LOAD_ALG 0 -#define LB_RELATIVE_LOAD_ALG 1 +#define LB_ALG_ABS 0 +#define LB_ALG_REL 1 +#define LB_ALG_ABS_NEG 2 +#define LB_ALG_REL_NEG 3 #define LB_DST_PING_DSBL_FLAG (1<<0) #define LB_DST_PING_PERM_FLAG (1<<1) From f43a40561ad55602be09ed3e9f7ae8f819b30d7b Mon Sep 17 00:00:00 2001 From: Sergey Khripchenko Date: Mon, 24 Nov 2014 07:58:19 -0800 Subject: [PATCH 5/7] next round of changes. cumulative commit: 1. get rid of load_balance() in favor of lb_*() family of functions to make the workflow more clear and defined: lb_start() - strictly used to start LB session. if sessions already started, old session will be lost and re-started again. lb_next() - strictly used to to continue LB session previousely started by lb_start(). lb_is_started() - used to check whenever LB session is already started or not. lb_reset() - used to clean up LB session and everything LB internally does for this dialog. ln_disable_dst() - mark destination currently choosen by LB in current active LB session as disabled. lb_start_and_next() - is simply a shorthand for 'lb_is_started()?lb_next():lb_start()' to simplify scripting. this function logically almost the same as old load_balance() function, so we could leave old name for compatibility reasons. lb_count_call() - manually register call as a load for particular resource(es). 2. lb_start(..., alg) parameter changed to 'flags' parameter with possible values: 'r' - use relative versus absolute estimation 'n' - do not skip negative loads 3. new module parameter 'probing_verbose' to log INFO message whenever we enable/disable destinations by probing/MI. --- modules/load_balancer/lb_data.c | 712 +++++++++++++++----------- modules/load_balancer/lb_data.h | 27 +- modules/load_balancer/load_balancer.c | 189 +++++-- 3 files changed, 566 insertions(+), 362 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 36e5942d0e4..d5dcfcc24fa 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -373,9 +373,10 @@ void free_lb_data(struct lb_data *data) static int get_dst_load(struct lb_resource **res, unsigned int res_no, - struct lb_dst *dst, unsigned int alg, int *load) + struct lb_dst *dst, unsigned int flags, int *load) { - int k, l, av; + unsigned int k, l; + int av; /* iterate through requested resources */ for( k=0 ; krmap[l].max_load ) { av = 100 - (100 * lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id) / dst->rmap[l].max_load); } } - else if( (alg == LB_ALG_ABS) || (alg == LB_ALG_ABS_NEG) ) { + else { av = dst->rmap[l].max_load - lb_dlg_binds.get_profile_size(res[k]->profile, &dst->profile_id); } @@ -401,282 +402,371 @@ static int get_dst_load(struct lb_resource **res, unsigned int res_no, *load = av; /* we possibly could have negative avaliability for any resource, - because we could use ALG=2,3 or manually increment resource with lb_count_call() + because we could use LB_FLAGS_NEGATIVE or manually increment resource with lb_count_call() */ } return (k > 0); /* load initialized */ } -int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, - unsigned int alg, struct lb_data *data) +int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigned int flags, struct lb_data *data, int reuse) { - /* resources for current iteration */ - static struct lb_resource **call_res = NULL; - static unsigned int call_res_size = 0; + /* resources for previous iteration */ + static struct lb_resource **res_prev = NULL; + static unsigned int res_prev_size = 0; + /* resources for new iteration */ + static struct lb_resource **res_new = NULL; + static unsigned int res_new_size = 0; /* probed destinations bitmap */ static unsigned int *dst_bitmap = NULL; static unsigned int bitmap_size = 0; - /* profiles from previous iteration */ - static struct dlg_profile_table **call_prfs = NULL; - static unsigned int call_prfs_size = 0; - int call_prfs_n, call_res_n; - struct lb_dst *last_dst; - unsigned int *used_dst_bitmap; + /* control vars */ + struct lb_resource **res_cur; + int res_prev_n, res_new_n, res_cur_n; + struct lb_dst *last_dst, *dst; + unsigned int *dst_bitmap_cur; unsigned int bitmap_size_cur; - struct usr_avp *grp_avp; + /* AVP related vars */ + struct usr_avp *group_avp; + struct usr_avp *flags_avp; struct usr_avp *mask_avp; struct usr_avp *id_avp; - struct usr_avp *prfs_avp, *del_prfs_avp; - int_str grp_val; + struct usr_avp *res_avp, *del_res_avp; + int_str group_val; + int_str flags_val; int_str mask_val; int_str id_val; - int_str prfs_val; + int_str res_val; - struct lb_dst *it_d, *dst; + /* iterators, e.t.c. */ + struct lb_dst *it_d; struct lb_resource *it_r; - struct dlg_profile_table *it_p; int it_l, load; - int i, j, again; + int i, j, cond; - /* adjust size of statically allocated buffer */ - call_res_n = rl->n; - if( call_res_n > call_res_size ) { - call_res = (struct lb_resource **)pkg_realloc(call_res, (call_res_n * sizeof(struct lb_resource *))); - if( call_res == NULL ) { - LM_ERR("no more pkg mem - resources ptr buffer realloc failure\n"); - return -1; - } - call_res_size = call_res_n; - } - /* fill resource references */ - for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) { - if( search_resource_str(rl, &it_r->name) ) { - call_res[i++] = it_r; - LM_DBG("found requested %d/%d resource [%.*s]\n", i, call_res_n, it_r->name.len, it_r->name.s); - } - } - if( i != call_res_n ) { - LM_ERR("unknown resource found in input string\n"); - return -1; - } + /* init control vars state */ + res_cur = NULL; + res_cur_n = res_prev_n = res_new_n = 0; + last_dst = dst = NULL; + dst_bitmap_cur = NULL; - /* get data from previous iteration due to failover */ - grp_avp = search_first_avp(0, grp_avp_name, &grp_val, 0); - mask_avp = search_first_avp(0, mask_avp_name, &mask_val, 0); - id_avp = search_first_avp(0, id_avp_name, &id_val, 0); - /* sanity checks for fetched AVPs */ - if( grp_avp && !(is_avp_str_val(grp_avp) == 0) ) { destroy_avp(grp_avp); grp_avp = NULL; } - if( mask_avp && !(is_avp_str_val(mask_avp) != 0) ) { destroy_avp(mask_avp); mask_avp = NULL; } - if( id_avp && !(is_avp_str_val(id_avp) == 0) ) { destroy_avp(id_avp); id_avp = NULL; } - - - /* get previous iteration group and mask, if any, and check that they are valid */ - used_dst_bitmap = NULL; - for( bitmap_size_cur=(unsigned int)(-1),i=0 ; ibitmap_size */ - if( call_res[i]->bitmap_size < bitmap_size_cur ) - bitmap_size_cur = call_res[i]->bitmap_size; - } - if( grp_avp && mask_avp ) { - /* reuse previous mask only if... */ - if( (grp_val.n == grp) && (mask_val.s.len == (bitmap_size_cur * sizeof(unsigned int))) ) { - used_dst_bitmap = (unsigned int *)mask_val.s.s; - LM_DBG("sequential call of LB - use previous group and mask\n"); - } - } - /* initialize dst_bitmap from scratch */ - if( used_dst_bitmap == NULL ) { + /* search and fill new resources references if we should not reuse previous iteration data */ + if( !reuse ) { + res_new_n = rl->n; /* adjust size of statically allocated buffer */ - if( bitmap_size_cur > bitmap_size ) { - dst_bitmap = (unsigned int *)pkg_realloc(dst_bitmap, (bitmap_size_cur * sizeof(unsigned int))); - if( dst_bitmap == NULL ) { - LM_ERR("no more pkg mem - dst_bitmap buffer realloc failure\n"); + if( res_new_n > res_new_size ) { + res_new = (struct lb_resource **)pkg_realloc(res_new, (res_new_n * sizeof(struct lb_resource *))); + if( res_new == NULL ) { + LM_ERR("no more pkg mem - resources ptr buffer realloc failure\n"); return -1; } - bitmap_size = bitmap_size_cur; + res_new_size = res_new_n; } - memset(dst_bitmap, 0xff, (bitmap_size * sizeof(unsigned int))); - for( i=0 ; idst_bitmap[j]; + /* fill resource references */ + for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) { + if( search_resource_str(rl, &it_r->name) ) { + res_new[i++] = it_r; + /*LM_DBG*/LM_ERR("initial call of LB - found requested %d/%d resource [%.*s]\n", i, res_new_n, it_r->name.len, it_r->name.s); + } } - used_dst_bitmap = dst_bitmap; + if( i != res_new_n ) { + LM_ERR("initial call of LB - unknown resource found in input string\n"); + return -1; + } + + /* set 'res_new' as current iteration buffer */ + res_cur = res_new; + res_cur_n = res_new_n; } + + /* always search for previous iteration data, no matter will we 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); + id_avp = search_first_avp(0, id_avp_name, &id_val, NULL); + /* sanity checks for fetched AVPs */ + if( group_avp && !(is_avp_str_val(group_avp) == 0) ) { destroy_avp(group_avp); group_avp = NULL; } + if( flags_avp && !(is_avp_str_val(flags_avp) == 0) ) { destroy_avp(flags_avp); flags_avp = NULL; } + if( mask_avp && !(is_avp_str_val(mask_avp) != 0) ) { destroy_avp(mask_avp); mask_avp = NULL; } + if( id_avp && !(is_avp_str_val(id_avp) == 0) ) { destroy_avp(id_avp); id_avp = NULL; } + /* get previous iteration destination, if any */ - last_dst = NULL; if( id_avp ) { for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { if( it_d->id == id_val.n ) { last_dst = it_d; - LM_DBG("sequential call of LB - use previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + /*LM_DBG*/LM_ERR("%s call of LB - found previous dst %d [%.*s]\n", (reuse ? "sequential" : "initial"), last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); break; } } } - - /* search and fill previous iteration profiles, if any */ - do { - again = 0; - call_prfs_n = 0; - for( prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; prfs_avp ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { - /* ignore AVPs with invalid type */ - if( !(is_avp_str_val(prfs_avp) != 0) ) continue; - - it_p = NULL; - - /* first try: check in existing data->resources */ - for( it_r=data->resources ; it_r ; it_r=it_r->next ) { - if( (it_r->profile->name.len == prfs_val.s.len) && (memcmp(it_r->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { - it_p = it_r->profile; - break; + /* search and fill previous iteration resources references only if... */ + if( + reuse || /* we should reuse previous resources list */ + (last_dst != NULL) /* we have 'last_dst', i.e. previous iteration was successfull and we need to clean it up */ + ) { + do { + cond = 0; /* use it here as a 'start loop again' flag */ + res_prev_n = 0; + for( res_avp=search_first_avp(0, res_avp_name, &res_val, NULL) ; res_avp ; res_avp=search_next_avp(res_avp, &res_val) ) { + /* ignore AVPs with invalid type */ + if( !(is_avp_str_val(res_avp) != 0) ) continue; + + for( it_r=data->resources ; it_r ; it_r=it_r->next ) { + if( (it_r->name.len == res_val.s.len) && (memcmp(it_r->name.s, res_val.s.s, res_val.s.len) == 0) ) + break; } + if( it_r == NULL ) { + LM_WARN("%s call of LB - ignore unknown previous resource [%.*s]\n", (reuse ? "sequential" : "initial"), res_val.s.len, res_val.s.s); + continue; + } + /* fill buffer only if buffer size not exeeded */ + if( res_prev_n < res_prev_size ) { + res_prev[res_prev_n] = it_r; + /*LM_DBG*/LM_ERR("%s call of LB - found previous resource [%.*s]\n", (reuse ? "sequential" : "initial"), it_r->name.len, it_r->name.s); + } + res_prev_n++; } - /* second try: search in dialog module */ - if( it_p == NULL ) { - it_p = lb_dlg_binds.search_profile(&prfs_val.s); - } - /* else: complain and ignore */ - if( it_p == NULL ) { - LM_WARN("sequential call of LB - ignore previous unknown profile [%.*s]\n", prfs_val.s.len, prfs_val.s.s); - continue; + /* 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 future pkg_realloc()'s */ + if( !reuse && (res_prev_n < res_new_n) ) + res_prev_n = res_new_n; + + res_prev = (struct lb_resource **)pkg_realloc(res_prev, (res_prev_n * sizeof(struct lb_resource *))); + if( res_prev == NULL ) { + LM_ERR("no more pkg mem - previous resources ptr buffer realloc failure\n"); + return -1; + } + res_prev_size = res_prev_n; + cond = 1; } + } + while( cond ); + } - /* fill buffer only if buffer size not exeeded */ - if( call_prfs_n < call_prfs_size ) { - call_prfs[call_prfs_n] = it_p; - LM_DBG("sequential call of LB - use previous profile [%.*s]\n", it_p->name.len, it_p->name.s); - } - call_prfs_n++; + + /* reuse previous iteration resources, group and flags */ + if( reuse ) { + /* set 'res_prev' as current iteration buffer */ + res_cur = res_prev; + res_cur_n = res_prev_n; + if( res_cur_n == 0 ) { + LM_ERR("sequential call of LB - cannot find previous resources\n"); + return -1; } + if( group_avp ) + group = group_val.n; + else { + LM_ERR("sequential call of LB - cannot find previous group\n"); + return -1; + } + if( flags_avp ) + flags = flags_val.n; + else + flags = LB_FLAGS_DEFAULT; + + /*LM_DBG*/LM_ERR("sequential call of LB - found previous group %d and flags 0x%x\n", group, flags); + } + + + /* sanity check - double check that we have a resource list to work with */ + if( (res_cur == NULL) || (res_cur_n == 0) ) { + LM_ERR("%s call of LB - no resources list to work with\n", (reuse ? "sequential" : "initial")); + return -1; + } + + + /* [re-]initialize/reuse destinations mask */ + + /* sanity check - always calculate current iteration res_cur[]->bitmap_size */ + bitmap_size_cur=(unsigned int)(-1); + for( i=0 ; i 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 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; + }; + /* ...or use our static buffer */ + if( dst_bitmap_cur == NULL ) { /* adjust size of statically allocated buffer */ - if( call_prfs_n > call_prfs_size ) { - call_prfs = (struct dlg_profile_table **)pkg_realloc(call_prfs, (call_prfs_n * sizeof(struct dlg_profile_table *))); - if( call_prfs == NULL ) { - LM_ERR("no more pkg mem - profiles ptr buffer realloc failure\n"); + if( bitmap_size_cur > bitmap_size ) { + dst_bitmap = (unsigned int *)pkg_realloc(dst_bitmap, (bitmap_size_cur * sizeof(unsigned int))); + if( dst_bitmap == NULL ) { + LM_ERR("no more pkg mem - dst bitmap buffer realloc failure\n"); return -1; } - call_prfs_size = call_prfs_n; - again = 1; + bitmap_size = bitmap_size_cur; + } + dst_bitmap_cur = dst_bitmap; + } + /* reinitalize buffer if... */ + if( + (dst_bitmap_cur == dst_bitmap) || /* it is our static buffer */ + !reuse /* should not reuse previous iteration data */ + ) { + if( reuse ) { + LM_WARN("sequential call of LB - cannot %s previous mask, routing will be re-started", (mask_avp ? "reuse" : "find")); + } + + memset(dst_bitmap_cur, 0xff, (bitmap_size_cur * sizeof(unsigned int))); + for( i=0 ; idst_bitmap[j]; } } - while( again ); - /* do initialize stuff if (grp_avp and mask_avp are unset) and we assume it a first LB run */ - if( (grp_avp == NULL) && (mask_avp == NULL) ) { + /* final initialization stuff */ + if( (group_avp == NULL) && (mask_avp == NULL) ) { + /* no group and mask AVPs are set -> assume it is first LB run */ /* create dialog, if needed */ if( !lb_dlg_binds.get_dlg() ) { if( lb_dlg_binds.create_dlg(req, 0) != 1 ) { - LM_ERR("failed to create dialog\n"); + LM_ERR("%s call of LB - failed to create dialog\n", (reuse ? "sequential" : "initial")); return -1; } } } + /* we're initialized from here and no errors could abort us */ + + + /* remove the dialog from previous profiles, if any */ + if( (last_dst != NULL) && (res_prev_n > 0) ) { + for( i=0 ; iprofile_id, res_prev[i]->profile) != 1 ) + LM_ERR("%s call of LB - failed to remove from profile [%.*s]->[%.*s]\n", + (reuse ? "sequential" : "initial"), + res_prev[i]->profile->name.len, res_prev[i]->profile->name.s, last_dst->profile_id.len, last_dst->profile_id.s + ); + } + } + + /* lock resources */ - for( i=0 ; ilock); + for( i=0 ; ilock); /* do the load-balancing */ - again = 0; + cond = 0; /* use it here as a 'first iteration' flag */ load = it_l = 0; - dst = NULL; for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) { - if( it_d->group == grp ) { - if( (used_dst_bitmap[i] & (1 << j)) && ((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) { + if( it_d->group == group ) { + if( (dst_bitmap_cur[i] & (1 << j)) && ((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) { /* valid destination (group & resources & status) */ - if( get_dst_load(call_res, call_res_n, it_d, alg, &it_l) ) { + if( get_dst_load(res_cur, res_cur_n, it_d, flags, &it_l) ) { if( - (((alg == LB_ALG_REL_NEG) || (alg == LB_ALG_ABS_NEG)) || (it_l > 0)) && - (!again || (it_l > load)) + ((it_l > 0) || (flags & LB_FLAGS_NEGATIVE)) && + (!cond/*first pass*/ || (it_l > load)/*new max*/) ) { - /* computing a max, or first iteration */ + /* computing a max, or first pass */ load = it_l; dst = it_d; - again = 1; - }; - LM_DBG("destination %d <%.*s> selected for LB set with free=%d\n", it_d->id, it_d->uri.len, it_d->uri.s, it_l); + cond = 1; + } + /*LM_DBG*/LM_ERR("%s call of LB - destination %d <%.*s> selected for LB set with free=%d\n", + (reuse ? "sequential" : "initial"), + it_d->id, it_d->uri.len, it_d->uri.s, it_l + ); } else { - LM_WARN("skipping destination %d <%.*s> - unable to calculate free resources\n", + LM_WARN("%s call of LB - skipping destination %d <%.*s> - unable to calculate free resources\n", + (reuse ? "sequential" : "initial"), it_d->id, it_d->uri.len, it_d->uri.s ); } } else { - LM_DBG("skipping destination %d <%.*s> (used=%d , disabled=%d)\n", + /*LM_DBG*/LM_ERR("%s call of LB - skipping destination %d <%.*s> (filtered=%d , disabled=%d)\n", + (reuse ? "sequential" : "initial"), it_d->id, it_d->uri.len, it_d->uri.s, - ((used_dst_bitmap[i] & (1 << j)) ? 0 : 1), ((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0) + ((dst_bitmap_cur[i] & (1 << j)) ? 0 : 1), ((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0) ); } } if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; } } - /* if re-trying, remove the dialog from previous profiles */ - if( last_dst && (call_prfs_n > 0) ) { - for( i=0 ; iprofile_id, call_prfs[i]) != 1 ) - LM_ERR("failed to remove from profile [%.*s] -> [%.*s]\n", call_prfs[i]->name.len, call_prfs[i]->name.s, last_dst->profile_id.len, last_dst->profile_id.s); - } - } if( dst != NULL ) { - LM_DBG("winning destination %d <%.*s> selected for LB set with free=%d\n", dst->id, dst->uri.len, dst->uri.s, load); + /*LM_DBG*/LM_ERR("%s call of LB - winning destination %d <%.*s> selected for LB set with free=%d\n", + (reuse ? "sequential" : "initial"), + dst->id, dst->uri.len, dst->uri.s, load + ); /* add to the profiles */ - for( i=0 ; iprofile_id, call_res[i]->profile, 0) != 0 ) - LM_ERR("failed to add to profile [%.*s] -> [%.*s]\n", call_res[i]->profile->name.len, call_res[i]->profile->name.s, dst->profile_id.len, dst->profile_id.s); + for( i=0 ; iprofile_id, res_cur[i]->profile, 0) != 0 ) + LM_ERR("%s call of LB - failed to add to profile [%.*s]->[%.*s]\n", + (reuse ? "sequential" : "initial"), + res_cur[i]->profile->name.len, res_cur[i]->profile->name.s, dst->profile_id.len, dst->profile_id.s + ); } /* set dst as used (not selected) */ for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) { - if( it_d == dst ) { used_dst_bitmap[i] &= ~(1 << j); break; } + if( it_d == dst ) { dst_bitmap_cur[i] &= ~(1 << j); break; } if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; } } } else { - LM_DBG("no destination found\n"); + /*LM_DBG*/LM_ERR("%s call of LB - no destination found\n", (reuse ? "sequential" : "initial")); } - /* unlock resources, in reverse order maybe? */ - for( i=0 ; ilock); + /* unlock resources */ + for( i=0 ; ilock); + + + /* we're done with load-ballancing from here, now save state */ /* save state - group */ - if( grp_avp == NULL ) { - grp_val.n = grp; - if( add_avp(0, grp_avp_name, grp_val) != 0 ) { - LM_ERR("failed to add GRP AVP\n"); + if( group_avp == NULL ) { + group_val.n = group; + if( add_avp(0, group_avp_name, group_val) != 0 ) { + LM_ERR("failed to add GROUP AVP\n"); } } - else if( grp_val.n != grp ) { - grp_avp->data = (void *)(long)grp; + else if( group_val.n != group ) { + group_avp->data = (void *)(long)group; + } + /* save state - flags, only if they are set */ + if( flags_avp == NULL ) { + if( flags != LB_FLAGS_DEFAULT ) { + flags_val.n = flags; + if( add_avp(0, flags_avp_name, flags_val) != 0 ) { + LM_ERR("failed to add FLAGS AVP\n"); + } + } + } + else if( flags_val.n != flags ) { + flags_avp->data = (void *)(long)flags; } /* save state - dst_bitmap mask */ - if( (mask_avp != NULL) && (used_dst_bitmap != (unsigned int *)mask_val.s.s) ) { + if( (mask_avp != NULL) && (dst_bitmap_cur != (unsigned int *)mask_val.s.s) ) { destroy_avp(mask_avp); mask_avp = NULL; } if( mask_avp == NULL ) { - mask_val.s.s = (char *)used_dst_bitmap; + mask_val.s.s = (char *)dst_bitmap_cur; mask_val.s.len = bitmap_size_cur * sizeof(unsigned int); if( add_avp(AVP_VAL_STR, mask_avp_name, mask_val) != 0 ) { LM_ERR("failed to add MASK AVP\n"); } } - /* save state - dst */ + /* save state - dst, only save if we have one */ if( id_avp == NULL ) { if( dst != NULL ) { id_val.n = dst->id; @@ -694,36 +784,36 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, id_avp = NULL; } } - /* save state - prfs */ - /* iterate AVPs once and delete old profiles */ - for( del_prfs_avp=NULL,prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { - if( del_prfs_avp != NULL ) { - destroy_avp(del_prfs_avp); - del_prfs_avp = NULL; + /* save state - res */ + /* iterate AVPs once and delete old resources */ + for( del_res_avp=NULL,res_avp=search_first_avp(0, res_avp_name, &res_val, NULL) ; ; res_avp=search_next_avp(res_avp, &res_val) ) { + if( del_res_avp != NULL ) { + destroy_avp(del_res_avp); + del_res_avp = NULL; }; - if( prfs_avp == NULL ) break; - - /* process AVPs if we have dst and AVP of the right type */ - if( (dst != NULL) && (is_avp_str_val(prfs_avp) != 0) ) { - /* skip existing profiles */ - again = 0; - for( i=0 ; (iprofile->name.len == prfs_val.s.len) && (memcmp(call_res[i]->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { - call_res[i] = NULL; - again = 1; - break; + if( res_avp == NULL ) break; + + if( is_avp_str_val(res_avp) != 0 ) { + cond = 0; /* use it here as a 'resource exists' flag */ + for( i=0 ; iname.len == res_val.s.len) && (memcmp(res_cur[i]->name.s, res_val.s.s, res_val.s.len) == 0) ) { + res_cur[i] = NULL; + cond = 1; + break; + } } } - if( again ) continue; + if( cond ) continue; } - - del_prfs_avp = prfs_avp; - } - if( dst != NULL ) { - /* add new profiles */ - for( i=0 ; (iprofile->name; - if( add_avp(AVP_VAL_STR, prfs_avp_name, prfs_val) != 0 ) { + /* wrong type or not exist */ + del_res_avp = res_avp; + } + /* add remaining resources */ + for( i=0 ; iname; + if( add_avp(AVP_VAL_STR, res_avp_name, res_val) != 0 ) { LM_ERR("failed to add RES AVP\n"); } } @@ -731,7 +821,7 @@ int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, /* outcome: set dst uri */ - if( (dst != NULL) && (set_dst_uri(req, &dst->uri ) !=0) ) { + if( (dst != NULL) && (set_dst_uri(req, &dst->uri) != 0) ) { LM_ERR("failed to set duri\n"); return -2; } @@ -740,158 +830,111 @@ int do_load_balance(struct sip_msg *req, int grp, 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) +{ + return lb_route(req, group, rl, flags, data, 0/* should NOT reuse previous data */); +} + +int do_lb_next(struct sip_msg *req, struct lb_data *data) +{ + return lb_route(req, -1, NULL, 0, data, 1/* reuse previous data */); +} + + int do_lb_reset(struct sip_msg *req, struct lb_data *data) { struct usr_avp *id_avp; - struct usr_avp *prfs_avp, *del_prfs_avp; + struct usr_avp *res_avp, *del_res_avp; int_str id_val; - int_str prfs_val; + int_str res_val; struct lb_dst *it_d, *last_dst; struct lb_resource *it_r; - struct dlg_profile_table *it_p; + /* remove any saved AVPs */ + destroy_avps(0, group_avp_name, 0); + destroy_avps(0, flags_avp_name, 0); + destroy_avps(0, mask_avp_name, 0); + /* get previous iteration destination, if any */ last_dst = NULL; - id_avp = search_first_avp(0, id_avp_name, &id_val, 0); - if( id_avp ) { - if( is_avp_str_val(id_avp) == 0 ) { - for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { - if( it_d->id == id_val.n ) { - last_dst = it_d; - LM_DBG("sequential call of LB - use previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); - break; - } + id_avp = search_first_avp(0, id_avp_name, &id_val, NULL); + if( id_avp && (is_avp_str_val(id_avp) == 0) ) { + for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { + if( it_d->id == id_val.n ) { + last_dst = it_d; + /*LM_DBG*/LM_ERR("reset LB - found previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + break; } } - destroy_avp(id_avp); } + destroy_avps(0, id_avp_name, 0); - /* search and clean up previous iteration profiles, if any */ - for( del_prfs_avp=NULL,prfs_avp=search_first_avp(0, prfs_avp_name, &prfs_val, 0) ; ; prfs_avp=search_next_avp(prfs_avp, &prfs_val) ) { - if( del_prfs_avp != NULL ) { - destroy_avp(del_prfs_avp); - del_prfs_avp = NULL; + /* search and clean up previous iteration resources, if any */ + for( del_res_avp=NULL,res_avp=search_first_avp(0, res_avp_name, &res_val, NULL) ; ; res_avp=search_next_avp(res_avp, &res_val) ) { + if( del_res_avp != NULL ) { + destroy_avp(del_res_avp); + del_res_avp = NULL; }; - if( prfs_avp == NULL ) break; + if( res_avp == NULL ) break; /* process AVPs if we have last_dst and AVP of the right type */ - if( (last_dst != NULL) && (is_avp_str_val(prfs_avp) != 0) ) { - it_p = NULL; - - /* first try: check in existing data->resources */ + if( (last_dst != NULL) && (is_avp_str_val(res_avp) != 0) ) { for( it_r=data->resources ; it_r ; it_r=it_r->next ) { - if( (it_r->profile->name.len == prfs_val.s.len) && (memcmp(it_r->profile->name.s, prfs_val.s.s, prfs_val.s.len) == 0) ) { - it_p = it_r->profile; + if( (it_r->name.len == res_val.s.len) && (memcmp(it_r->name.s, res_val.s.s, res_val.s.len) == 0) ) { + /*LM_DBG*/LM_ERR("reset LB - found previous resource [%.*s]\n", it_r->name.len, it_r->name.s); break; } } - /* second try: search in dialog module */ - if( it_p == NULL ) { - it_p = lb_dlg_binds.search_profile(&prfs_val.s); - } - /* else: complain and ignore */ - if( it_p == NULL ) { - LM_WARN("sequential call of LB - ignore previous unknown profile [%.*s]\n", prfs_val.s.len, prfs_val.s.s); - continue; + if( it_r != NULL ) { + if( lb_dlg_binds.unset_profile(req, &last_dst->profile_id, it_r->profile) != 1 ) + LM_ERR("reset LB - failed to remove from profile [%.*s]->[%.*s]\n", + it_r->profile->name.len, it_r->profile->name.s, last_dst->profile_id.len, last_dst->profile_id.s + ); } - - /* remove profile */ - if( lb_dlg_binds.unset_profile(req, &last_dst->profile_id, it_p) != 1 ) - LM_ERR("failed to remove from profile [%.*s] -> [%.*s]\n", it_p->name.len, it_p->name.s, last_dst->profile_id.len, last_dst->profile_id.s); + else + LM_WARN("reset LB - ignore unknown previous resource [%.*s]\n", res_val.s.len, res_val.s.s); } - del_prfs_avp = prfs_avp; + del_res_avp = res_avp; } - /* remove any saved AVPs */ - destroy_avps(0, grp_avp_name, 0); - destroy_avps(0, mask_avp_name, 0); - return 0; } -/* events */ -static event_id_t lb_evi_id; -static str lb_event = str_init("E_LOAD_BALANCER_STATUS"); -static str lb_group_str = str_init("group"); -static str lb_uri_str = str_init("uri"); -static str lb_state_str = str_init("status"); -static str lb_disabled_str = str_init("disabled"); -static str lb_enabled_str = str_init("enabled"); - -int lb_init_event(void) -{ - lb_evi_id = evi_publish_event(lb_event); - if (lb_evi_id == EVI_ERROR) { - LM_ERR("cannot register %.*s event\n", lb_event.len, lb_event.s); - return -1; - } - return 0; -} - -void lb_raise_event(struct lb_dst *dst) +int do_lb_is_started(struct sip_msg *req) { - evi_params_p list = NULL; - - if (lb_evi_id == EVI_ERROR || !evi_probe_event(lb_evi_id)) - return; - - list = evi_get_params(); - if (!list) { - LM_ERR("cannot create event params\n"); - return; - } - - if (evi_param_add_int(list, &lb_group_str, &dst->group) < 0) { - LM_ERR("cannot add destination group\n"); - goto error; - } - - if (evi_param_add_str(list, &lb_uri_str, &dst->uri) < 0) { - LM_ERR("cannot add destination uri\n"); - goto error; - } - - if (evi_param_add_str(list, &lb_state_str, - dst->flags&LB_DST_STAT_DSBL_FLAG ? &lb_disabled_str : &lb_enabled_str) < 0) { - LM_ERR("cannot add destination state\n"); - goto error; - } - - if (evi_raise_event(lb_evi_id, list)) { - LM_ERR("unable to send %.*s event\n", lb_event.len, lb_event.s); - } - return; + struct usr_avp *group_avp; + struct usr_avp *mask_avp; + struct usr_avp *res_avp; -error: - evi_free_params(list); + return ( + ((group_avp = search_first_avp(0, group_avp_name, NULL, NULL)) != NULL) && (is_avp_str_val(group_avp) == 0) && + ((mask_avp = search_first_avp(0, mask_avp_name, NULL, NULL)) != NULL) && (is_avp_str_val(mask_avp) != 0) && + ((res_avp = search_first_avp(0, res_avp_name, NULL, NULL)) != NULL) && (is_avp_str_val(res_avp) != 0) + ) ? 1 : -1; } - -int do_lb_disable(struct sip_msg *req, struct lb_data *data) +int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data) { struct usr_avp *id_avp; int_str id_val; - struct lb_dst *dst; - unsigned int old_flags; - id_avp = search_first_avp( 0, id_avp_name, &id_val, 0); - if (id_avp==NULL) { - LM_DBG(" no AVP ID ->nothing to disable\n"); - return -1; - } + struct lb_dst *dst; - for( dst=data->dsts ; dst ; dst=dst->next) { - if (dst->id==id_val.n) { - old_flags = dst->flags; - dst->flags |= LB_DST_STAT_DSBL_FLAG; - if (dst->flags != old_flags) - lb_raise_event(dst); + id_avp = search_first_avp( 0, id_avp_name, &id_val, NULL); + if( id_avp && (is_avp_str_val(id_avp) == 0) ) { + for( dst=data->dsts ; dst ; dst=dst->next ) { + if( dst->id == id_val.n ) { + dst->flags |= LB_DST_STAT_DSBL_FLAG; + return 0; + } } } + else + LM_DBG("no AVP ID -> nothing to disable\n"); return -1; } @@ -900,7 +943,7 @@ int do_lb_disable(struct sip_msg *req, struct lb_data *data) /* Checks, if the IP PORT is a LB destination */ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, - pv_spec_t *pv_ip, pv_spec_t *pv_port, int grp, int active) + pv_spec_t *pv_ip, pv_spec_t *pv_port, int group, int active) { pv_value_t val; struct ip_addr *ip; @@ -939,7 +982,7 @@ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, /* and now search !*/ for( dst=data->dsts ; dst ; dst=dst->next) { - if ( ((grp==-1) || (dst->group==grp)) && /*group matches*/ + if ( ((group==-1) || (dst->group==group)) && /*group matches*/ ( !active || (active && (dst->flags&LB_DST_STAT_DSBL_FLAG)==0 ) ) ) { /* check the IPs */ @@ -958,7 +1001,7 @@ int lb_is_dst(struct lb_data *data, struct sip_msg *_m, int lb_count_call(struct lb_data *data, struct sip_msg *req, - struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl, int mode) + struct ip_addr *ip, int port, int group, struct lb_res_str_list *rl, int dir) { static struct lb_resource **call_res = NULL; static unsigned int call_res_no = 0; @@ -968,7 +1011,7 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, /* search for the destination we need to count for */ for( dst=data->dsts ; dst ; dst=dst->next) { - if ( (grp==-1) || (dst->group==grp) ) { + if ( (group==-1) || (dst->group==group) ) { /* check the IPs */ for(k=0 ; kips_cnt ; k++ ) { if ( (dst->ports[k]==0 || port==0 || port==dst->ports[k]) && @@ -1021,7 +1064,7 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, /* add to the profiles */ for( i=0 ; in ; i++) { - if( !mode ) { + if( !dir ) { if (lb_dlg_binds.set_profile( req, &dst->profile_id, call_res[i]->profile, 0)!=0) LM_ERR("failed to add to profile\n"); @@ -1039,3 +1082,62 @@ int lb_count_call(struct lb_data *data, struct sip_msg *req, return 0; } + + + +/* events */ +static event_id_t lb_evi_id; +static str lb_event = str_init("E_LOAD_BALANCER_STATUS"); +static str lb_group_str = str_init("group"); +static str lb_uri_str = str_init("uri"); +static str lb_state_str = str_init("status"); +static str lb_disabled_str = str_init("disabled"); +static str lb_enabled_str = str_init("enabled"); + +int lb_init_event(void) +{ + lb_evi_id = evi_publish_event(lb_event); + if (lb_evi_id == EVI_ERROR) { + LM_ERR("cannot register %.*s event\n", lb_event.len, lb_event.s); + return -1; + } + return 0; +} + +void lb_raise_event(struct lb_dst *dst) +{ + evi_params_p list = NULL; + + if (lb_evi_id == EVI_ERROR || !evi_probe_event(lb_evi_id)) + return; + + list = evi_get_params(); + if (!list) { + LM_ERR("cannot create event params\n"); + return; + } + + if (evi_param_add_int(list, &lb_group_str, &dst->group) < 0) { + LM_ERR("cannot add destination group\n"); + goto error; + } + + if (evi_param_add_str(list, &lb_uri_str, &dst->uri) < 0) { + LM_ERR("cannot add destination uri\n"); + goto error; + } + + if (evi_param_add_str(list, &lb_state_str, + dst->flags&LB_DST_STAT_DSBL_FLAG ? &lb_disabled_str : &lb_enabled_str) < 0) { + LM_ERR("cannot add destination state\n"); + goto error; + } + + if (evi_raise_event(lb_evi_id, list)) { + LM_ERR("unable to send %.*s event\n", lb_event.len, lb_event.s); + } + return; + +error: + evi_free_params(list); +} diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index e42e58fe92d..f2679913315 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -30,16 +30,16 @@ #ifndef LB_LB_DATA_H_ #define LB_LB_DATA_H_ + #include "../../str.h" #include "../../locking.h" #include "../../parser/msg_parser.h" #include "../dialog/dlg_load.h" #include "lb_parser.h" -#define LB_ALG_ABS 0 -#define LB_ALG_REL 1 -#define LB_ALG_ABS_NEG 2 -#define LB_ALG_REL_NEG 3 +#define LB_FLAGS_RELATIVE (1<<0) /* do relative versus absolute estimation. default is absolute */ +#define LB_FLAGS_NEGATIVE (1<<1) /* do not skip negative loads. default to skip */ +#define LB_FLAGS_DEFAULT 0 #define LB_DST_PING_DSBL_FLAG (1<<0) #define LB_DST_PING_PERM_FLAG (1<<1) @@ -92,25 +92,30 @@ int add_lb_dsturi( struct lb_data *data, int id, int group, char *uri, void free_lb_data(struct lb_data *data); -int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl, - unsigned int alg, 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); -int do_lb_disable(struct sip_msg *req, struct lb_data *data); +int do_lb_next(struct sip_msg *req, struct lb_data *data); int do_lb_reset(struct sip_msg *req, struct lb_data *data); +int do_lb_is_started(struct sip_msg *req); + +int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data); + int lb_is_dst(struct lb_data *data, struct sip_msg *_m, - pv_spec_t *pv_ip, pv_spec_t *pv_port, int grp, int active); + pv_spec_t *pv_ip, pv_spec_t *pv_port, int group, int active); int lb_count_call(struct lb_data *data, struct sip_msg *req, - struct ip_addr *ip, int port, int grp, struct lb_res_str_list *rl, int mode); + struct ip_addr *ip, int port, int group, struct lb_res_str_list *rl, int dir); int lb_init_event(void); void lb_raise_event(struct lb_dst *dst); /* failover stuff */ -extern int grp_avp_name; +extern int group_avp_name; +extern int flags_avp_name; extern int mask_avp_name; extern int id_avp_name; -extern int prfs_avp_name; +extern int res_avp_name; #endif diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 89fd0b06281..79536870eaf 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -59,6 +59,7 @@ struct lb_data **curr_data = NULL; /* probing related stuff */ static unsigned int lb_prob_interval = 30; +static unsigned int lb_prob_verbose = 0; static str lb_probe_replies = {NULL,0}; struct tm_binds lb_tmb; str lb_probe_method = str_init("OPTIONS"); @@ -72,14 +73,16 @@ static void mod_destroy(void); static int mi_child_init(); /* failover stuff */ -static str grp_avp_name_s = str_init("lb_grp"); +static str group_avp_name_s = str_init("lb_grp"); +static str flags_avp_name_s = str_init("lb_flg"); static str mask_avp_name_s = str_init("lb_mask"); static str id_avp_name_s = str_init("lb_id"); -static str prfs_avp_name_s = str_init("lb_prfs"); -int grp_avp_name; +static str res_avp_name_s = str_init("lb_res"); +int group_avp_name; +int flags_avp_name; int mask_avp_name; int id_avp_name; -int prfs_avp_name; +int res_avp_name; @@ -92,15 +95,18 @@ static int fixup_resources(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_load_balance(struct sip_msg *req, char *grp, char *rl, char* al); -static int w_lb_disable(struct sip_msg *req); +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_and_next(struct sip_msg *req, char *grp, char *rl, char *fl); 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); static int w_lb_is_dst2(struct sip_msg *msg, char *ip, char *port); static int w_lb_is_dst3(struct sip_msg *msg, char *ip, char *port, char *grp); static int w_lb_is_dst4(struct sip_msg *msg, char *ip, char *port, char *grp, char *active); -static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, - char *rl, char *mode); +static int w_lb_count_call(struct sip_msg *req, char *ip, char *port, char *grp, + char *rl, char *dir); static void lb_prob_handler(unsigned int ticks, void* param); @@ -109,23 +115,31 @@ static void lb_prob_handler(unsigned int ticks, void* param); static cmd_export_t cmds[]={ - {"load_balance", (cmd_function)w_load_balance, 2, fixup_resources, + {"lb_start", (cmd_function)w_lb_start, 2, fixup_resources, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"load_balance", (cmd_function)w_load_balance, 3, fixup_resources, + {"lb_start", (cmd_function)w_lb_start, 3, fixup_resources, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"lb_disable", (cmd_function)w_lb_disable, 0, 0, - 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"lb_reset", (cmd_function)w_lb_reset, 0, 0, + {"lb_start_and_next",(cmd_function)w_lb_start_and_next,2, fixup_resources, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_start_and_next",(cmd_function)w_lb_start_and_next,3, fixup_resources, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_next", (cmd_function)w_lb_next, 0, 0, + 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, + 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, + {"lb_disable_dst", (cmd_function)w_lb_disable_dst, 0, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE}, - {"lb_is_destination",(cmd_function)w_lb_is_dst2, 2, fixup_is_dst, + {"lb_is_destination",(cmd_function)w_lb_is_dst2, 2, fixup_is_dst, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"lb_is_destination",(cmd_function)w_lb_is_dst3, 3, fixup_is_dst, + {"lb_is_destination",(cmd_function)w_lb_is_dst3, 3, fixup_is_dst, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"lb_is_destination",(cmd_function)w_lb_is_dst4, 4, fixup_is_dst, + {"lb_is_destination",(cmd_function)w_lb_is_dst4, 4, fixup_is_dst, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE|LOCAL_ROUTE}, - {"lb_count_call", (cmd_function)w_count_call, 4, fixup_cnt_call, + {"lb_count_call", (cmd_function)w_lb_count_call, 4, fixup_cnt_call, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, - {"lb_count_call", (cmd_function)w_count_call, 5, fixup_cnt_call, + {"lb_count_call", (cmd_function)w_lb_count_call, 5, fixup_cnt_call, 0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE}, {0,0,0,0,0,0} }; @@ -135,6 +149,7 @@ static param_export_t mod_params[]={ { "db_url", STR_PARAM, &db_url.s }, { "db_table", STR_PARAM, &table_name }, { "probing_interval", INT_PARAM, &lb_prob_interval }, + { "probing_verbose", INT_PARAM, &lb_prob_verbose }, { "probing_method", STR_PARAM, &lb_probe_method.s }, { "probing_from", STR_PARAM, &lb_probe_from.s }, { "probing_reply_codes", STR_PARAM, &lb_probe_replies.s }, @@ -269,7 +284,8 @@ static int fixup_resources(void** param, int param_no) } else if (param_no==3) { - fixup_uint(param); + /* string with flags */ + return fixup_sgp(param); } @@ -433,14 +449,17 @@ static int mod_init(void) return -1; } } - } /* parse avps */ - if (parse_avp_spec(&grp_avp_name_s, &grp_avp_name)) { + if (parse_avp_spec(&group_avp_name_s, &group_avp_name)) { LM_ERR("cannot parse group avp\n"); return -1; } + if (parse_avp_spec(&flags_avp_name_s, &flags_avp_name)) { + LM_ERR("cannot parse flags avp\n"); + return -1; + } if (parse_avp_spec(&mask_avp_name_s, &mask_avp_name)) { LM_ERR("cannot parse mask avp\n"); return -1; @@ -449,15 +468,15 @@ static int mod_init(void) LM_ERR("cannot parse id avp\n"); return -1; } + if (parse_avp_spec(&res_avp_name_s, &res_avp_name)) { + LM_ERR("cannot parse resources avp\n"); + return -1; + } if (lb_init_event() < 0) { LM_ERR("cannot init event\n"); return -1; } - if (parse_avp_spec(&prfs_avp_name_s, &prfs_avp_name)) { - LM_ERR("cannot parse resources avp\n"); - return -1; - } return 0; } @@ -502,17 +521,40 @@ static void mod_destroy(void) } -static int w_load_balance(struct sip_msg *req, char *grp, char *rl, char *al) +static int w_lb_next(struct sip_msg *req) { int ret; + + lock_start_read(ref_lock); + + /* do lb */ + ret = do_lb_next(req, *curr_data); + + lock_stop_read(ref_lock); + + if( ret < 0 ) + return ret; + return 1; +} + + +static int w_lb_start(struct sip_msg *req, char *grp, char *rl, char *fl) +{ + int ret; + int grp_no; struct lb_grp_param *lbgp = (struct lb_grp_param *)grp; pv_value_t val; + struct lb_res_str_list *lb_rl; struct lb_res_parse *lbp; pv_elem_t *model; str dest; + str flstr = {0,0}; + int flags=LB_FLAGS_DEFAULT; + char *f; + if (lbgp->grp_pv) { if (pv_get_spec_value( req, (pv_spec_p)lbgp->grp_pv, &val)!=0) { LM_ERR("failed to get PV value\n"); @@ -542,11 +584,31 @@ static int w_load_balance(struct sip_msg *req, char *grp, char *rl, char *al) } else lb_rl = (struct lb_res_str_list *)lbp->param; + if( fl ) { + if( fixup_get_svalue(req, (gparam_p)fl, &flstr) != 0 ) { + LM_ERR("failed to extract flags\n"); + return -1; + } + for( f=flstr.s ; f 0) ? + w_lb_next(req) : + w_lb_start(req, grp, rl, fl) + ; +} + + +static int w_lb_reset(struct sip_msg *req) { int ret; - lock_start_read( ref_lock ); + lock_start_read(ref_lock); /* do lb */ - ret = do_lb_disable( req , *curr_data); + ret = do_lb_reset(req, *curr_data); - lock_stop_read( ref_lock ); + lock_stop_read(ref_lock); - if (ret<0) + if( ret < 0 ) return ret; return 1; } -static int w_lb_reset(struct sip_msg *req) +static int w_lb_is_started(struct sip_msg *req) { int ret; - lock_start_read( ref_lock ); + /* do lb, do not need a lock, since do not use '*curr_data' */ + ret = do_lb_is_started(req); + + if( ret < 0 ) + return ret; + return 1; +} + + +static int w_lb_disable_dst(struct sip_msg *req) +{ + int ret; + + lock_start_read(ref_lock); /* do lb */ - ret = do_lb_reset( req , *curr_data); + ret = do_lb_disable_dst(req, *curr_data); - lock_stop_read( ref_lock ); + lock_stop_read(ref_lock); - if (ret<0) + if( ret < 0 ) return ret; return 1; } @@ -638,8 +722,8 @@ static int w_lb_is_dst4(struct sip_msg *msg,char *ip,char *port,char *grp, } -static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, - char *rl, char *mode) +static int w_lb_count_call(struct sip_msg *req, char *ip, char *port, char *grp, + char *rl, char *dir) { struct lb_grp_param *lbgp = (struct lb_grp_param *)grp; struct lb_res_str_list *lb_rl; @@ -715,7 +799,7 @@ static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, lock_start_read( ref_lock ); ret = lb_count_call( *curr_data, req, ipa, port_no, grp_no, lb_rl, - (unsigned int)(long)mode); + (unsigned int)(long)dir); lock_stop_read( ref_lock ); @@ -728,6 +812,7 @@ static int w_count_call(struct sip_msg *req, char *ip, char *port, char *grp, } + /******************** PROBING Stuff ***********************/ @@ -766,8 +851,11 @@ void set_dst_state_from_rplcode( int id, int code) } old_flags = dst->flags; dst->flags &= ~LB_DST_STAT_DSBL_FLAG; - if (dst->flags != old_flags) + if (dst->flags != old_flags) { lb_raise_event(dst); + if (lb_prob_verbose) + LM_INFO("re-enable destination %d <%.*s> after %d reply on probe\n", dst->id, dst->uri.len, dst->uri.s, code); + } lock_stop_read( ref_lock ); return; } @@ -775,8 +863,11 @@ void set_dst_state_from_rplcode( int id, int code) if (code>=400) { old_flags = dst->flags; dst->flags |= LB_DST_STAT_DSBL_FLAG; - if (dst->flags != old_flags) + if (dst->flags != old_flags) { lb_raise_event(dst); + if (lb_prob_verbose) + LM_INFO("disable destination %d <%.*s> after %d reply on probe\n", dst->id, dst->uri.len, dst->uri.s, code); + } } lock_stop_read( ref_lock ); @@ -944,8 +1035,14 @@ static struct mi_root* mi_lb_status(struct mi_root *cmd, void *param) dst->flags |= LB_DST_STAT_DSBL_FLAG|LB_DST_STAT_NOEN_FLAG; } - if (old_flags != dst->flags) + if (old_flags != dst->flags) { lb_raise_event(dst); + if( lb_prob_verbose ) + LM_INFO("manually %s destination %d <%.*s>\n", + (stat ? "enable" : "disable"), + dst->id, dst->uri.len, dst->uri.s + ); + } lock_stop_read( ref_lock ); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); } @@ -1006,9 +1103,9 @@ static struct mi_root* mi_lb_list(struct mi_root *cmd_tree, void *param) goto error; if (dst->flags&LB_DST_STAT_NOEN_FLAG) { - attr = add_mi_attr( dst_node, 0, "auto-reenable", 7, "off", 3); + attr = add_mi_attr( dst_node, 0, "auto-reenable", 13, "off", 3); } else { - attr = add_mi_attr( dst_node, 0, "auto-reenable", 7, "on", 2); + attr = add_mi_attr( dst_node, 0, "auto-reenable", 13, "on", 2); } if (attr==0) goto error; From b7180d04c2baeaafe84f7eb4350ebde6693017ec Mon Sep 17 00:00:00 2001 From: Sergey Khripchenko Date: Tue, 25 Nov 2014 04:35:10 -0800 Subject: [PATCH 6/7] correct logging levels from dev LM_ERR to production LM_DBG --- modules/load_balancer/lb_data.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index d5dcfcc24fa..93d16b7e886 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -470,7 +470,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) { if( search_resource_str(rl, &it_r->name) ) { res_new[i++] = it_r; - /*LM_DBG*/LM_ERR("initial call of LB - found requested %d/%d resource [%.*s]\n", i, res_new_n, it_r->name.len, it_r->name.s); + LM_DBG("initial call of LB - found requested %d/%d resource [%.*s]\n", i, res_new_n, it_r->name.len, it_r->name.s); } } if( i != res_new_n ) { @@ -500,7 +500,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { if( it_d->id == id_val.n ) { last_dst = it_d; - /*LM_DBG*/LM_ERR("%s call of LB - found previous dst %d [%.*s]\n", (reuse ? "sequential" : "initial"), last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + LM_DBG("%s call of LB - found previous dst %d [%.*s]\n", (reuse ? "sequential" : "initial"), last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); break; } } @@ -528,7 +528,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne /* fill buffer only if buffer size not exeeded */ if( res_prev_n < res_prev_size ) { res_prev[res_prev_n] = it_r; - /*LM_DBG*/LM_ERR("%s call of LB - found previous resource [%.*s]\n", (reuse ? "sequential" : "initial"), it_r->name.len, it_r->name.s); + LM_DBG("%s call of LB - found previous resource [%.*s]\n", (reuse ? "sequential" : "initial"), it_r->name.len, it_r->name.s); } res_prev_n++; } @@ -571,7 +571,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne else flags = LB_FLAGS_DEFAULT; - /*LM_DBG*/LM_ERR("sequential call of LB - found previous group %d and flags 0x%x\n", group, flags); + LM_DBG("sequential call of LB - found previous group %d and flags 0x%x\n", group, flags); } @@ -674,7 +674,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne dst = it_d; cond = 1; } - /*LM_DBG*/LM_ERR("%s call of LB - destination %d <%.*s> selected for LB set with free=%d\n", + LM_DBG("%s call of LB - destination %d <%.*s> selected for LB set with free=%d\n", (reuse ? "sequential" : "initial"), it_d->id, it_d->uri.len, it_d->uri.s, it_l ); @@ -687,7 +687,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne } } else { - /*LM_DBG*/LM_ERR("%s call of LB - skipping destination %d <%.*s> (filtered=%d , disabled=%d)\n", + LM_DBG("%s call of LB - skipping destination %d <%.*s> (filtered=%d , disabled=%d)\n", (reuse ? "sequential" : "initial"), it_d->id, it_d->uri.len, it_d->uri.s, ((dst_bitmap_cur[i] & (1 << j)) ? 0 : 1), ((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0) @@ -699,7 +699,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne if( dst != NULL ) { - /*LM_DBG*/LM_ERR("%s call of LB - winning destination %d <%.*s> selected for LB set with free=%d\n", + LM_DBG("%s call of LB - winning destination %d <%.*s> selected for LB set with free=%d\n", (reuse ? "sequential" : "initial"), dst->id, dst->uri.len, dst->uri.s, load ); @@ -720,7 +720,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne } } else { - /*LM_DBG*/LM_ERR("%s call of LB - no destination found\n", (reuse ? "sequential" : "initial")); + LM_DBG("%s call of LB - no destination found\n", (reuse ? "sequential" : "initial")); } @@ -729,7 +729,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne lock_release(res_cur[i]->lock); - /* we're done with load-ballancing from here, now save state */ + /* we're done with load-balancing, now save state */ /* save state - group */ @@ -742,7 +742,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne else if( group_val.n != group ) { group_avp->data = (void *)(long)group; } - /* save state - flags, only if they are set */ + /* save state - flags, save only if they are set */ if( flags_avp == NULL ) { if( flags != LB_FLAGS_DEFAULT ) { flags_val.n = flags; @@ -766,7 +766,7 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne LM_ERR("failed to add MASK AVP\n"); } } - /* save state - dst, only save if we have one */ + /* save state - dst, save only if we have one */ if( id_avp == NULL ) { if( dst != NULL ) { id_val.n = dst->id; @@ -832,12 +832,12 @@ int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigne int do_lb_start(struct sip_msg *req, int group, struct lb_res_str_list *rl, unsigned int flags, struct lb_data *data) { - return lb_route(req, group, rl, flags, data, 0/* should NOT reuse previous data */); + return lb_route(req, group, rl, flags, data, 0/*should NOT reuse previous data*/); } int do_lb_next(struct sip_msg *req, 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*/); } @@ -864,7 +864,7 @@ int do_lb_reset(struct sip_msg *req, struct lb_data *data) for( it_d=data->dsts ; it_d ; it_d=it_d->next ) { if( it_d->id == id_val.n ) { last_dst = it_d; - /*LM_DBG*/LM_ERR("reset LB - found previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); + LM_DBG("reset LB - found previous dst %d [%.*s]\n", last_dst->id, last_dst->profile_id.len, last_dst->profile_id.s); break; } } @@ -883,7 +883,7 @@ int do_lb_reset(struct sip_msg *req, struct lb_data *data) if( (last_dst != NULL) && (is_avp_str_val(res_avp) != 0) ) { for( it_r=data->resources ; it_r ; it_r=it_r->next ) { if( (it_r->name.len == res_val.s.len) && (memcmp(it_r->name.s, res_val.s.s, res_val.s.len) == 0) ) { - /*LM_DBG*/LM_ERR("reset LB - found previous resource [%.*s]\n", it_r->name.len, it_r->name.s); + LM_DBG("reset LB - found previous resource [%.*s]\n", it_r->name.len, it_r->name.s); break; } } From f45733447611d4e6bd3d2f2a31225941809c6b50 Mon Sep 17 00:00:00 2001 From: Sergey Khripchenko Date: Thu, 27 Nov 2014 05:31:04 -0800 Subject: [PATCH 7/7] changed lb_disable_dst() to rize event if we disable destination from script and do logging if 'prob_verbose' is set --- modules/load_balancer/lb_data.c | 10 +++++++++- modules/load_balancer/lb_data.h | 2 +- modules/load_balancer/load_balancer.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/load_balancer/lb_data.c b/modules/load_balancer/lb_data.c index 93d16b7e886..fed9aabee04 100644 --- a/modules/load_balancer/lb_data.c +++ b/modules/load_balancer/lb_data.c @@ -917,18 +917,26 @@ int do_lb_is_started(struct sip_msg *req) } -int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data) +int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data, unsigned int verbose) { struct usr_avp *id_avp; int_str id_val; struct lb_dst *dst; + int old_flags; id_avp = search_first_avp( 0, id_avp_name, &id_val, NULL); if( id_avp && (is_avp_str_val(id_avp) == 0) ) { for( dst=data->dsts ; dst ; dst=dst->next ) { if( dst->id == id_val.n ) { + old_flags = dst->flags; dst->flags |= LB_DST_STAT_DSBL_FLAG; + + if( dst->flags != old_flags ) { + lb_raise_event(dst); + if( verbose ) + LM_INFO("manually disable destination %d <%.*s> from script\n", dst->id, dst->uri.len, dst->uri.s); + } return 0; } } diff --git a/modules/load_balancer/lb_data.h b/modules/load_balancer/lb_data.h index f2679913315..171f04e7c1f 100644 --- a/modules/load_balancer/lb_data.h +++ b/modules/load_balancer/lb_data.h @@ -101,7 +101,7 @@ int do_lb_reset(struct sip_msg *req, struct lb_data *data); int do_lb_is_started(struct sip_msg *req); -int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data); +int do_lb_disable_dst(struct sip_msg *req, struct lb_data *data, unsigned int verbose); int lb_is_dst(struct lb_data *data, struct sip_msg *_m, pv_spec_t *pv_ip, pv_spec_t *pv_port, int group, int active); diff --git a/modules/load_balancer/load_balancer.c b/modules/load_balancer/load_balancer.c index 79536870eaf..b36771cb38b 100644 --- a/modules/load_balancer/load_balancer.c +++ b/modules/load_balancer/load_balancer.c @@ -667,7 +667,7 @@ static int w_lb_disable_dst(struct sip_msg *req) lock_start_read(ref_lock); /* do lb */ - ret = do_lb_disable_dst(req, *curr_data); + ret = do_lb_disable_dst(req, *curr_data, lb_prob_verbose); lock_stop_read(ref_lock);