Browse code

dispatcher(k): weight based distribution

- new algorithm 9 for weight based distribution
- new column to hold attributes per destination
- for weight based distribution you have to set for each address in
destination set: weight=value, for example:

[setid address flags priority attributes]

2 sip:10.10.0.1:5080 0 2 weight=40
2 sip:10.10.0.2:5082 0 1 weight=60

- this will send 60% of the traffic to second address
- note that at startup the distribution is randomized, so traffic is
directed to first or second desintation alternatively but keeping
overall percentages

Daniel-Constantin Mierla authored on 11/02/2010 14:20:36
Showing 3 changed files
... ...
@@ -48,6 +48,7 @@
48 48
 #include <stdio.h>
49 49
 #include <string.h>
50 50
 #include <stdlib.h>
51
+#include <time.h>
51 52
 
52 53
 #include "../../ut.h"
53 54
 #include "../../trim.h"
... ...
@@ -58,6 +59,7 @@
58 59
 #include "../../mem/shm_mem.h"
59 60
 #include "../../parser/parse_uri.h"
60 61
 #include "../../parser/parse_from.h"
62
+#include "../../parser/parse_param.h"
61 63
 #include "../../usr_avp.h"
62 64
 #include "../../lib/kmi/mi.h"
63 65
 #include "../../parser/digest/digest.h"
... ...
@@ -73,34 +75,49 @@
73 75
 #define DS_TABLE_VERSION	1
74 76
 #define DS_TABLE_VERSION2	2
75 77
 #define DS_TABLE_VERSION3	3
78
+#define DS_TABLE_VERSION4	4
76 79
 
77 80
 static int _ds_table_version = DS_TABLE_VERSION;
78 81
 
82
+#define DS_DUID_SIZE	16
83
+
84
+typedef struct _ds_attrs
85
+{
86
+	char duid[DS_DUID_SIZE];
87
+	int maxload;
88
+	int weight;
89
+} ds_attrs_t;
90
+
79 91
 typedef struct _ds_dest
80 92
 {
81 93
 	str uri;
82 94
 	int flags;
83 95
 	int priority;
96
+	ds_attrs_t attrs;
84 97
 	struct ip_addr ip_address; 	/*!< IP-Address of the entry */
85 98
 	unsigned short int port; 	/*!< Port of the request URI */
86 99
 	int failure_count;
87 100
 	struct _ds_dest *next;
88
-} ds_dest_t, *ds_dest_p;
101
+} ds_dest_t;
89 102
 
90 103
 typedef struct _ds_set
91 104
 {
92 105
 	int id;				/*!< id of dst set */
93 106
 	int nr;				/*!< number of items in dst set */
94
-	int last;			/*!< last used item in dst set */
95
-	ds_dest_p dlist;
107
+	int last;			/*!< last used item in dst set (round robin) */
108
+	int wlast;			/*!< last used item in dst set (by weight) */
109
+	ds_dest_t *dlist;
110
+	unsigned int wlist[100];
96 111
 	struct _ds_set *next;
97
-} ds_set_t, *ds_set_p;
112
+} ds_set_t;
98 113
 
99 114
 extern int ds_force_dst;
100 115
 
101 116
 static db_func_t ds_dbf;
102 117
 static db1_con_t* ds_db_handle=0;
103
-ds_set_p *ds_lists=NULL;
118
+
119
+ds_set_t **ds_lists=NULL;
120
+
104 121
 int *ds_list_nr = NULL;
105 122
 int *crt_idx    = NULL;
106 123
 int *next_idx   = NULL;
... ...
@@ -110,9 +127,9 @@ int *next_idx   = NULL;
110 127
 
111 128
 void destroy_list(int);
112 129
 
113
-static int ds_print_sets(void)
130
+int ds_print_sets(void)
114 131
 {
115
-	ds_set_p si = NULL;
132
+	ds_set_t *si = NULL;
116 133
 	int i;
117 134
 
118 135
 	if(_ds_list==NULL)
... ...
@@ -124,9 +141,11 @@ static int ds_print_sets(void)
124 141
 	{
125 142
 		for(i=0; i<si->nr; i++)
126 143
 		{
127
-			LM_DBG("dst>> %d %.*s %d %d\n", si->id,
144
+			LM_DBG("dst>> %d %.*s %d %d (%s,%d,%d)\n", si->id,
128 145
 					si->dlist[i].uri.len, si->dlist[i].uri.s,
129
-					si->dlist[i].flags, si->dlist[i].priority);
146
+					si->dlist[i].flags, si->dlist[i].priority,
147
+					si->dlist[i].attrs.duid, si->dlist[i].attrs.maxload,
148
+					si->dlist[i].attrs.weight);
130 149
 		}
131 150
 		si = si->next;
132 151
 	}
... ...
@@ -138,7 +157,7 @@ int init_data(void)
138 157
 {
139 158
 	int * p;
140 159
 
141
-	ds_lists = (ds_set_p*)shm_malloc(2*sizeof(ds_set_p));
160
+	ds_lists = (ds_set_t**)shm_malloc(2*sizeof(ds_set_t*));
142 161
 	if(!ds_lists)
143 162
 	{
144 163
 		LM_ERR("Out of memory\n");
... ...
@@ -162,13 +181,52 @@ int init_data(void)
162 181
 	return 0;
163 182
 }
164 183
 
165
-int add_dest2list(int id, str uri, int flags, int priority, int list_idx,
166
-		int * setn)
184
+int ds_set_attrs(ds_dest_t *dest, str *attrs)
167 185
 {
168
-	ds_dest_p dp = NULL;
169
-	ds_set_p  sp = NULL;
170
-	ds_dest_p dp0 = NULL;
171
-	ds_dest_p dp1 = NULL;
186
+	param_t* params_list = NULL;
187
+	param_hooks_t phooks;
188
+	param_t *pit=NULL;
189
+
190
+	if(attrs==NULL || attrs->len<=0)
191
+		return 0;
192
+	if(attrs->s[attrs->len-1]==';')
193
+		attrs->len--;
194
+	if (parse_params(attrs, CLASS_ANY, &phooks, &params_list)<0)
195
+		return -1;
196
+	for (pit = params_list; pit; pit=pit->next)
197
+	{
198
+		if (pit->name.len==4
199
+				&& strncasecmp(pit->name.s, "duid", 4)==0) {
200
+			if(pit->body.len>=DS_DUID_SIZE)
201
+			{
202
+				LM_ERR("dest unique id too long: %.*s\n",
203
+						pit->body.len, pit->body.s);
204
+				return -1;
205
+			}
206
+			memcpy(dest->attrs.duid, pit->body.s, pit->body.len);
207
+			dest->attrs.duid[pit->body.len] = '\0';
208
+		} else if(pit->name.len==6
209
+				&& strncasecmp(pit->name.s, "weight", 4)==0) {
210
+			str2sint(&pit->body, &dest->attrs.weight);
211
+		} else if(pit->name.len==7
212
+				&& strncasecmp(pit->name.s, "maxload", 7)==0) {
213
+			str2sint(&pit->body, &dest->attrs.maxload);
214
+		} else {
215
+			LM_ERR("unknown dest attribute: %.*s\n",
216
+						pit->name.len, pit->name.s);
217
+			return -1;
218
+		}
219
+	}
220
+	return 0;
221
+}
222
+
223
+int add_dest2list(int id, str uri, int flags, int priority, str *attrs,
224
+		int list_idx, int * setn)
225
+{
226
+	ds_dest_t *dp = NULL;
227
+	ds_set_t  *sp = NULL;
228
+	ds_dest_t *dp0 = NULL;
229
+	ds_dest_t *dp1 = NULL;
172 230
 	
173 231
 	/* For DNS-Lookups */
174 232
 	static char hn[256];
... ...
@@ -193,7 +251,7 @@ int add_dest2list(int id, str uri, int flags, int priority, int list_idx,
193 251
 
194 252
 	if(sp==NULL)
195 253
 	{
196
-		sp = (ds_set_p)shm_malloc(sizeof(ds_set_t));
254
+		sp = (ds_set_t*)shm_malloc(sizeof(ds_set_t));
197 255
 		if(sp==NULL)
198 256
 		{
199 257
 			LM_ERR("no more memory.\n");
... ...
@@ -209,7 +267,7 @@ int add_dest2list(int id, str uri, int flags, int priority, int list_idx,
209 267
 	sp->nr++;
210 268
 
211 269
 	/* store uri */
212
-	dp = (ds_dest_p)shm_malloc(sizeof(ds_dest_t));
270
+	dp = (ds_dest_t*)shm_malloc(sizeof(ds_dest_t));
213 271
 	if(dp==NULL)
214 272
 	{
215 273
 		LM_ERR("no more memory!\n");
... ...
@@ -229,6 +287,12 @@ int add_dest2list(int id, str uri, int flags, int priority, int list_idx,
229 287
 	dp->flags = flags;
230 288
 	dp->priority = priority;
231 289
 
290
+	if(ds_set_attrs(dp, attrs)<0)
291
+	{
292
+		LM_ERR("cannot set attributes!\n");
293
+		goto err;
294
+	}
295
+
232 296
 	/* The Hostname needs to be \0 terminated for resolvehost, so we
233 297
 	 * make a copy here. */
234 298
 	strncpy(hn, puri.host.s, puri.host.len);
... ...
@@ -285,16 +349,56 @@ err:
285 349
 	return -1;
286 350
 }
287 351
 
352
+int dp_init_weights(ds_set_t *dset)
353
+{
354
+	int j;
355
+	int k;
356
+	int t;
357
+
358
+	if(dset==NULL || dset->dlist==NULL)
359
+		return -1;
360
+
361
+	/* is weight set for dst list? (first address must have weight!=0) */
362
+	if(dset->dlist[0].attrs.weight==0)
363
+		return 0;
364
+
365
+	t = 0;
366
+	for(j=0; j<dset->nr; j++)
367
+	{
368
+		for(k=0; k<dset->dlist[j].attrs.weight; k++)
369
+		{
370
+			if(t>=100)
371
+				goto randomize;
372
+			dset->wlist[t] = (unsigned int)j;
373
+			t++;
374
+		}
375
+	}
376
+	j = (t-1>=0)?t-1:0;
377
+	for(; t<100; t++)
378
+		dset->wlist[t] = (unsigned int)j;
379
+randomize:
380
+	srand(time(0));
381
+	for (j=0; j<100; j++)
382
+	{
383
+		k = j + (rand() % (100-j));
384
+		t = (int)dset->wlist[j];
385
+		dset->wlist[j] = dset->wlist[k];
386
+		dset->wlist[k] = (unsigned int)t;
387
+	}
388
+
389
+	return 0;
390
+}
391
+
288 392
 /*! \brief  compact destinations from sets for fast access */
289 393
 int reindex_dests(int list_idx, int setn)
290 394
 {
291 395
 	int j;
292
-	ds_set_p  sp = NULL;
293
-	ds_dest_p dp = NULL, dp0= NULL;
396
+	ds_set_t  *sp = NULL;
397
+	ds_dest_t *dp = NULL, *dp0= NULL;
294 398
 
295
-	for(sp = ds_lists[list_idx]; sp!= NULL;	sp->dlist = dp0, sp = sp->next)
399
+	for(sp = ds_lists[list_idx]; sp!= NULL;	sp = sp->next)
296 400
 	{
297
-		dp0 = (ds_dest_p)shm_malloc(sp->nr*sizeof(ds_dest_t));
401
+		dp0 = (ds_dest_t*)shm_malloc(sp->nr*sizeof(ds_dest_t));
298 402
 		if(dp0==NULL)
299 403
 		{
300 404
 			LM_ERR("no more memory!\n");
... ...
@@ -302,7 +406,7 @@ int reindex_dests(int list_idx, int setn)
302 406
 		}
303 407
 		memset(dp0, 0, sp->nr*sizeof(ds_dest_t));
304 408
 
305
-		/*copy from the old pointer to destination, and then free it*/
409
+		/* copy from the old pointer to destination, and then free it */
306 410
 		for(j=sp->nr-1; j>=0 && sp->dlist!= NULL; j--)
307 411
 		{
308 412
 			memcpy(&dp0[j], sp->dlist, sizeof(ds_dest_t));
... ...
@@ -310,13 +414,16 @@ int reindex_dests(int list_idx, int setn)
310 414
 				dp0[j].next = NULL;
311 415
 			else
312 416
 				dp0[j].next = &dp0[j+1];
313
-	
417
+
418
+
314 419
 			dp = sp->dlist;
315 420
 			sp->dlist = dp->next;
316 421
 			
317 422
 			shm_free(dp);
318 423
 			dp=NULL;
319 424
 		}
425
+		sp->dlist = dp0;
426
+		dp_init_weights(sp);
320 427
 	}
321 428
 
322 429
 	LM_DBG("found [%d] dest sets\n", setn);
... ...
@@ -333,7 +440,8 @@ int ds_load_list(char *lfile)
333 440
 	FILE *f = NULL;
334 441
 	int id, setn, flags, priority;
335 442
 	str uri;
336
-	
443
+	str attrs;
444
+
337 445
 	if( (*crt_idx) != (*next_idx)) {
338 446
 		LM_WARN("load command already generated, aborting reload...\n");
339 447
 		return 0;
... ...
@@ -357,7 +465,7 @@ int ds_load_list(char *lfile)
357 465
 
358 466
 	*next_idx = (*crt_idx + 1)%2;
359 467
 	destroy_list(*next_idx);
360
-	
468
+
361 469
 	p = fgets(line, 256, f);
362 470
 	while(p)
363 471
 	{
... ...
@@ -366,7 +474,7 @@ int ds_load_list(char *lfile)
366 474
 			p++;
367 475
 		if(*p=='\0' || *p=='#')
368 476
 			goto next_line;
369
-		
477
+
370 478
 		/* get set id */
371 479
 		id = 0;
372 480
 		while(*p>='0' && *p<='9')
... ...
@@ -374,7 +482,7 @@ int ds_load_list(char *lfile)
374 482
 			id = id*10+ (*p-'0');
375 483
 			p++;
376 484
 		}
377
-		
485
+
378 486
 		/* eat all white spaces */
379 487
 		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
380 488
 			p++;
... ...
@@ -393,7 +501,7 @@ int ds_load_list(char *lfile)
393 501
 		/* eat all white spaces */
394 502
 		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
395 503
 			p++;
396
-		
504
+
397 505
 		/* get flags */
398 506
 		flags = 0;
399 507
 		priority = 0;
... ...
@@ -405,11 +513,11 @@ int ds_load_list(char *lfile)
405 513
 			flags = flags*10+ (*p-'0');
406 514
 			p++;
407 515
 		}
408
-		
516
+
409 517
 		/* eat all white spaces */
410 518
 		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
411 519
 			p++;
412
-		
520
+
413 521
 		/* get priority */
414 522
 		priority = 0;
415 523
 		if(*p=='\0' || *p=='#')
... ...
@@ -420,9 +528,23 @@ int ds_load_list(char *lfile)
420 528
 			priority = priority*10+ (*p-'0');
421 529
 			p++;
422 530
 		}
423
-		
531
+
532
+		/* eat all white spaces */
533
+		while(*p && (*p==' ' || *p=='\t' || *p=='\r' || *p=='\n'))
534
+			p++;
535
+		attrs.s = 0; attrs.len = 0;
536
+		if(*p=='\0' || *p=='#')
537
+			goto add_destination; /* no priority given */
538
+
539
+		/* get attributes */
540
+		attrs.s = p;
541
+		while(*p && *p!=' ' && *p!='\t' && *p!='\r' && *p!='\n' && *p!='#')
542
+			p++;
543
+		attrs.len = p-attrs.s;
544
+
424 545
 add_destination:
425
-		if(add_dest2list(id, uri, flags, priority, *next_idx, &setn) != 0)
546
+		if(add_dest2list(id, uri, flags, priority, &attrs,
547
+					*next_idx, &setn) != 0)
426 548
 			goto error;
427 549
 					
428 550
 		
... ...
@@ -532,18 +654,22 @@ int ds_load_db(void)
532 654
 	int priority;
533 655
 	int nrcols;
534 656
 	str uri;
657
+	str attrs = {0, 0};
535 658
 	db1_res_t * res;
536 659
 	db_val_t * values;
537 660
 	db_row_t * rows;
538 661
 	
539
-	db_key_t query_cols[4] = {&ds_set_id_col, &ds_dest_uri_col,
540
-								&ds_dest_flags_col, &ds_dest_priority_col};
662
+	db_key_t query_cols[5] = {&ds_set_id_col, &ds_dest_uri_col,
663
+				&ds_dest_flags_col, &ds_dest_priority_col,
664
+				&ds_dest_attrs_col};
541 665
 	
542 666
 	nrcols = 2;
543 667
 	if(_ds_table_version == DS_TABLE_VERSION2)
544 668
 		nrcols = 3;
545 669
 	else if(_ds_table_version == DS_TABLE_VERSION3)
546 670
 		nrcols = 4;
671
+	else if(_ds_table_version == DS_TABLE_VERSION4)
672
+		nrcols = 5;
547 673
 
548 674
 	if( (*crt_idx) != (*next_idx))
549 675
 	{
... ...
@@ -596,7 +722,14 @@ int ds_load_db(void)
596 722
 		if(nrcols>=4)
597 723
 			priority = VAL_INT(values+3);
598 724
 
599
-		if(add_dest2list(id, uri, flags, priority, *next_idx, &setn) != 0)
725
+		attrs.s = 0; attrs.len = 0;
726
+		if(nrcols>=5)
727
+		{
728
+			attrs.s = VAL_STR(values+4).s;
729
+			attrs.len = strlen(attrs.s);
730
+		}
731
+		if(add_dest2list(id, uri, flags, priority, &attrs,
732
+					*next_idx, &setn) != 0)
600 733
 			goto err2;
601 734
 
602 735
 	}
... ...
@@ -641,8 +774,8 @@ int ds_destroy_list(void)
641 774
 
642 775
 void destroy_list(int list_id)
643 776
 {
644
-	ds_set_p  sp = NULL;
645
-	ds_dest_p dest = NULL;
777
+	ds_set_t  *sp = NULL;
778
+	ds_dest_t *dest = NULL;
646 779
 
647 780
 	sp = ds_lists[list_id];
648 781
 
... ...
@@ -1001,9 +1134,9 @@ int ds_hash_pvar(struct sip_msg *msg, unsigned int *hash)
1001 1134
 	return 0;
1002 1135
 }
1003 1136
 
1004
-static inline int ds_get_index(int group, ds_set_p *index)
1137
+static inline int ds_get_index(int group, ds_set_t **index)
1005 1138
 {
1006
-	ds_set_p si = NULL;
1139
+	ds_set_t *si = NULL;
1007 1140
 	
1008 1141
 	if(index==NULL || group<0 || _ds_list==NULL)
1009 1142
 		return -1;
... ...
@@ -1078,7 +1211,7 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1078 1211
 	int i, cnt;
1079 1212
 	unsigned int hash;
1080 1213
 	int_str avp_val;
1081
-	ds_set_p idx = NULL;
1214
+	ds_set_t *idx = NULL;
1082 1215
 
1083 1216
 	if(msg==NULL)
1084 1217
 	{
... ...
@@ -1113,39 +1246,39 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1113 1246
 	hash = 0;
1114 1247
 	switch(alg)
1115 1248
 	{
1116
-		case 0:
1249
+		case 0: /* hash call-id */
1117 1250
 			if(ds_hash_callid(msg, &hash)!=0)
1118 1251
 			{
1119 1252
 				LM_ERR("can't get callid hash\n");
1120 1253
 				return -1;
1121 1254
 			}
1122 1255
 		break;
1123
-		case 1:
1256
+		case 1: /* hash from-uri */
1124 1257
 			if(ds_hash_fromuri(msg, &hash)!=0)
1125 1258
 			{
1126 1259
 				LM_ERR("can't get From uri hash\n");
1127 1260
 				return -1;
1128 1261
 			}
1129 1262
 		break;
1130
-		case 2:
1263
+		case 2: /* hash to-uri */
1131 1264
 			if(ds_hash_touri(msg, &hash)!=0)
1132 1265
 			{
1133 1266
 				LM_ERR("can't get To uri hash\n");
1134 1267
 				return -1;
1135 1268
 			}
1136 1269
 		break;
1137
-		case 3:
1270
+		case 3: /* hash r-uri */
1138 1271
 			if (ds_hash_ruri(msg, &hash)!=0)
1139 1272
 			{
1140 1273
 				LM_ERR("can't get ruri hash\n");
1141 1274
 				return -1;
1142 1275
 			}
1143 1276
 		break;
1144
-		case 4:
1277
+		case 4: /* round robin */
1145 1278
 			hash = idx->last;
1146 1279
 			idx->last = (idx->last+1) % idx->nr;
1147 1280
 		break;
1148
-		case 5:
1281
+		case 5: /* hash auth username */
1149 1282
 			i = ds_hash_authusername(msg, &hash);
1150 1283
 			switch (i)
1151 1284
 			{
... ...
@@ -1163,20 +1296,23 @@ int ds_select_dst(struct sip_msg *msg, int set, int alg, int mode)
1163 1296
 				break;
1164 1297
 			}
1165 1298
 		break;
1166
-		case 6:
1299
+		case 6: /* random selection */
1167 1300
 			hash = rand() % idx->nr;
1168 1301
 		break;
1169
-		case 7:
1302
+		case 7: /* hash on PV value */
1170 1303
 			if (ds_hash_pvar(msg, &hash)!=0)
1171 1304
 			{
1172 1305
 				LM_ERR("can't get PV hash\n");
1173 1306
 				return -1;
1174 1307
 			}
1175 1308
 		break;		
1176
-		case 8:
1177
-			/* use first entry */
1309
+		case 8: /* use always first entry */
1178 1310
 			hash = 0;
1179 1311
 		break;
1312
+		case 9: /* weight based load */
1313
+			hash = idx->wlist[idx->wlast];
1314
+			idx->wlast = (idx->wlast+1) % 100;
1315
+		break;
1180 1316
 		default:
1181 1317
 			LM_WARN("algo %d not implemented - using first entry...\n", alg);
1182 1318
 			hash = 0;
... ...
@@ -1365,7 +1501,7 @@ int ds_mark_dst(struct sip_msg *msg, int mode)
1365 1501
 int ds_set_state(int group, str *address, int state, int type)
1366 1502
 {
1367 1503
 	int i=0;
1368
-	ds_set_p idx = NULL;
1504
+	ds_set_t *idx = NULL;
1369 1505
 
1370 1506
 	if(_ds_list==NULL || _ds_list_nr<=0)
1371 1507
 	{
... ...
@@ -1428,7 +1564,7 @@ int ds_set_state(int group, str *address, int state, int type)
1428 1564
 int ds_print_list(FILE *fout)
1429 1565
 {
1430 1566
 	int j;
1431
-	ds_set_p list;
1567
+	ds_set_t *list;
1432 1568
 		
1433 1569
 	if(_ds_list==NULL || _ds_list_nr<=0)
1434 1570
 	{
... ...
@@ -1474,7 +1610,7 @@ int ds_print_list(FILE *fout)
1474 1610
 int ds_is_from_list(struct sip_msg *_m, int group)
1475 1611
 {
1476 1612
 	pv_value_t val;
1477
-	ds_set_p list;
1613
+	ds_set_t *list;
1478 1614
 	int j;
1479 1615
 
1480 1616
 	memset(&val, 0, sizeof(pv_value_t));
... ...
@@ -1516,7 +1652,7 @@ int ds_print_mi_list(struct mi_node* rpl)
1516 1652
 	int len, j;
1517 1653
 	char* p;
1518 1654
 	char c;
1519
-	ds_set_p list;
1655
+	ds_set_t *list;
1520 1656
 	struct mi_node* node = NULL;
1521 1657
 	struct mi_node* set_node = NULL;
1522 1658
 	struct mi_attr* attr = NULL;
... ...
@@ -1627,7 +1763,7 @@ static void ds_options_callback( struct cell *t, int type,
1627 1763
 void ds_check_timer(unsigned int ticks, void* param)
1628 1764
 {
1629 1765
 	int j;
1630
-	ds_set_p list;
1766
+	ds_set_t *list;
1631 1767
 	uac_req_t uac_r;
1632 1768
 	
1633 1769
 	/* Check for the list. */
... ...
@@ -59,6 +59,7 @@ extern str ds_set_id_col;
59 59
 extern str ds_dest_uri_col;
60 60
 extern str ds_dest_flags_col;
61 61
 extern str ds_dest_priority_col;
62
+extern str ds_dest_attrs_col;
62 63
 
63 64
 extern int ds_flags; 
64 65
 extern int ds_use_default;
... ...
@@ -97,6 +98,7 @@ int ds_set_state(int group, str *address, int state, int type);
97 98
 int ds_mark_dst(struct sip_msg *msg, int mode);
98 99
 int ds_print_list(FILE *fout);
99 100
 int ds_print_mi_list(struct mi_node* rpl);
101
+int ds_print_sets(void);
100 102
 
101 103
 int ds_is_from_list(struct sip_msg *_m, int group);
102 104
 /*! \brief
... ...
@@ -71,6 +71,7 @@ MODULE_VERSION
71 71
 #define DS_DEST_URI_COL			"destination"
72 72
 #define DS_DEST_FLAGS_COL		"flags"
73 73
 #define DS_DEST_PRIORITY_COL	"priority"
74
+#define DS_DEST_ATTRS_COL		"attrs"
74 75
 #define DS_TABLE_NAME			"dispatcher"
75 76
 
76 77
 /** parameters */
... ...
@@ -109,6 +110,7 @@ str ds_set_id_col        = str_init(DS_SET_ID_COL);
109 110
 str ds_dest_uri_col      = str_init(DS_DEST_URI_COL);
110 111
 str ds_dest_flags_col    = str_init(DS_DEST_FLAGS_COL);
111 112
 str ds_dest_priority_col = str_init(DS_DEST_PRIORITY_COL);
113
+str ds_dest_attrs_col    = str_init(DS_DEST_ATTRS_COL);
112 114
 str ds_table_name        = str_init(DS_TABLE_NAME);
113 115
 
114 116
 str ds_setid_pvname   = {NULL, 0};
... ...
@@ -158,6 +160,7 @@ static param_export_t params[]={
158 160
 	{"destination_col", STR_PARAM, &ds_dest_uri_col.s},
159 161
 	{"flags_col",       STR_PARAM, &ds_dest_flags_col.s},
160 162
 	{"priority_col",    STR_PARAM, &ds_dest_priority_col.s},
163
+	{"attrs_col",       STR_PARAM, &ds_dest_attrs_col.s},
161 164
 	{"force_dst",       INT_PARAM, &ds_force_dst},
162 165
 	{"flags",           INT_PARAM, &ds_flags},
163 166
 	{"use_default",     INT_PARAM, &ds_use_default},
... ...
@@ -233,9 +236,11 @@ static int mod_init(void)
233 236
 	{
234 237
 		ds_db_url.len     = strlen(ds_db_url.s);
235 238
 		ds_table_name.len = strlen(ds_table_name.s);
236
-		ds_set_id_col.len     = strlen(ds_set_id_col.s);
237
-		ds_dest_uri_col.len   = strlen(ds_dest_uri_col.s);
238
-		ds_dest_flags_col.len = strlen(ds_dest_flags_col.s);
239
+		ds_set_id_col.len        = strlen(ds_set_id_col.s);
240
+		ds_dest_uri_col.len      = strlen(ds_dest_uri_col.s);
241
+		ds_dest_flags_col.len    = strlen(ds_dest_flags_col.s);
242
+		ds_dest_priority_col.len = strlen(ds_dest_priority_col.s);
243
+		ds_dest_attrs_col.len    = strlen(ds_dest_attrs_col.s);
239 244
 
240 245
 		if(init_ds_db()!= 0)
241 246
 		{
... ...
@@ -250,7 +255,7 @@ static int mod_init(void)
250 255
 			LM_DBG("loaded dispatching list\n");
251 256
 		}
252 257
 	}
253
-	
258
+
254 259
 	if (dst_avp_param.s && dst_avp_param.len > 0)
255 260
 	{
256 261
 		if (pv_parse_spec(&dst_avp_param, &avp_spec)==0