Browse code

modules/sipcapture: Extended sipcapture to support multiple tables

The sipcapture module can support storing the information to multiple sql tables.
Tests have shown that a major bottleneck against scalability on multi core CPU of
the capture node instance was caused by using a single MySQL Table.
The frontend (HOMER) will be soon patched to support retrieval of data from multiple
sources.

The decision to select witch table is written to, can be configured from random,
round robin or hashing via username or callid.

Dragos Dinu authored on 20/07/2012 07:48:48 • Marius Zbihlei committed on 20/07/2012 07:48:48
Showing 6 changed files
... ...
@@ -29,17 +29,19 @@ Alexandr Dubovikov
29 29
 
30 30
               3.1. db_url (str)
31 31
               3.2. table_name (str)
32
-              3.3. db_insert_mode (integer)
33
-              3.4. capture_on (integer)
34
-              3.5. hep_capture_on (integer)
35
-              3.6. raw_ipip_capture_on (integer)
36
-              3.7. raw_moni_capture_on (integer)
37
-              3.8. raw_socket_listen (string)
38
-              3.9. raw_interface (string)
39
-              3.10. raw_sock_children (integer)
40
-              3.11. promiscuous_on (integer)
41
-              3.12. raw_moni_bpf_on (integer)
42
-              3.13. capture_node (str)
32
+              3.3. mt_mode (str)
33
+              3.4. hash_source (str)
34
+              3.5. db_insert_mode (integer)
35
+              3.6. capture_on (integer)
36
+              3.7. hep_capture_on (integer)
37
+              3.8. raw_ipip_capture_on (integer)
38
+              3.9. raw_moni_capture_on (integer)
39
+              3.10. raw_socket_listen (string)
40
+              3.11. raw_interface (string)
41
+              3.12. raw_sock_children (integer)
42
+              3.13. promiscuous_on (integer)
43
+              3.14. raw_moni_bpf_on (integer)
44
+              3.15. capture_node (str)
43 45
 
44 46
         4. MI Commands
45 47
 
... ...
@@ -52,17 +54,19 @@ Alexandr Dubovikov
52 54
 
53 55
    1.1. Set db_url parameter
54 56
    1.2. Set sip_capture parameter
55
-   1.3. db_insert_mode example
56
-   1.4. Set capture_on parameter
57
-   1.5. Set hep_capture_on parameter
58
-   1.6. Set raw_ipip_capture_on parameter
59
-   1.7. Set raw_moni_capture_on parameter
60
-   1.8. Set raw_socket_listen parameter
61
-   1.9. Set raw_socket_listen parameter
57
+   1.3. Set mt_mode parameter
58
+   1.4. Set mt_mode parameter
59
+   1.5. db_insert_mode example
60
+   1.6. Set capture_on parameter
61
+   1.7. Set hep_capture_on parameter
62
+   1.8. Set raw_ipip_capture_on parameter
63
+   1.9. Set raw_moni_capture_on parameter
62 64
    1.10. Set raw_socket_listen parameter
63
-   1.11. Set hep_capture_on parameter
64
-   1.12. Set raw_moni_bpf_on parameter
65
-   1.13. Set capture_node parameter
65
+   1.11. Set raw_socket_listen parameter
66
+   1.12. Set raw_socket_listen parameter
67
+   1.13. Set hep_capture_on parameter
68
+   1.14. Set raw_moni_bpf_on parameter
69
+   1.15. Set capture_node parameter
66 70
 
67 71
 Chapter 1. Admin Guide
68 72
 
... ...
@@ -78,17 +82,19 @@ Chapter 1. Admin Guide
78 82
 
79 83
         3.1. db_url (str)
80 84
         3.2. table_name (str)
81
-        3.3. db_insert_mode (integer)
82
-        3.4. capture_on (integer)
83
-        3.5. hep_capture_on (integer)
84
-        3.6. raw_ipip_capture_on (integer)
85
-        3.7. raw_moni_capture_on (integer)
86
-        3.8. raw_socket_listen (string)
87
-        3.9. raw_interface (string)
88
-        3.10. raw_sock_children (integer)
89
-        3.11. promiscuous_on (integer)
90
-        3.12. raw_moni_bpf_on (integer)
91
-        3.13. capture_node (str)
85
+        3.3. mt_mode (str)
86
+        3.4. hash_source (str)
87
+        3.5. db_insert_mode (integer)
88
+        3.6. capture_on (integer)
89
+        3.7. hep_capture_on (integer)
90
+        3.8. raw_ipip_capture_on (integer)
91
+        3.9. raw_moni_capture_on (integer)
92
+        3.10. raw_socket_listen (string)
93
+        3.11. raw_interface (string)
94
+        3.12. raw_sock_children (integer)
95
+        3.13. promiscuous_on (integer)
96
+        3.14. raw_moni_bpf_on (integer)
97
+        3.15. capture_node (str)
92 98
 
93 99
    4. MI Commands
94 100
 
... ...
@@ -133,17 +139,19 @@ Chapter 1. Admin Guide
133 139
 
134 140
    3.1. db_url (str)
135 141
    3.2. table_name (str)
136
-   3.3. db_insert_mode (integer)
137
-   3.4. capture_on (integer)
138
-   3.5. hep_capture_on (integer)
139
-   3.6. raw_ipip_capture_on (integer)
140
-   3.7. raw_moni_capture_on (integer)
141
-   3.8. raw_socket_listen (string)
142
-   3.9. raw_interface (string)
143
-   3.10. raw_sock_children (integer)
144
-   3.11. promiscuous_on (integer)
145
-   3.12. raw_moni_bpf_on (integer)
146
-   3.13. capture_node (str)
142
+   3.3. mt_mode (str)
143
+   3.4. hash_source (str)
144
+   3.5. db_insert_mode (integer)
145
+   3.6. capture_on (integer)
146
+   3.7. hep_capture_on (integer)
147
+   3.8. raw_ipip_capture_on (integer)
148
+   3.9. raw_moni_capture_on (integer)
149
+   3.10. raw_socket_listen (string)
150
+   3.11. raw_interface (string)
151
+   3.12. raw_sock_children (integer)
152
+   3.13. promiscuous_on (integer)
153
+   3.14. raw_moni_bpf_on (integer)
154
+   3.15. capture_node (str)
147 155
 
148 156
 3.1. db_url (str)
149 157
 
... ...
@@ -158,7 +166,8 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
158 166
 
159 167
 3.2. table_name (str)
160 168
 
161
-   Name of the table's name where to store the SIP messages.
169
+   Name of the table's name where to store the SIP messages. Can contain
170
+   multiple tables, separated by "|".
162 171
 
163 172
    Default value is "sip_capture".
164 173
 
... ...
@@ -166,8 +175,37 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
166 175
 ...
167 176
 modparam("sipcapture", "table_name", "homer_capture")
168 177
 ...
178
+modparam("sipcapture", "table_name", "homer_capture1|homer_capture2");
179
+...
180
+
181
+3.3. mt_mode (str)
182
+
183
+   Name of the mode used for storing data in multiple tables. Modes can be
184
+   "rand" (random), "round_robin" (use a round_robin algorithm) or "hash"
185
+   (use hashing to determine the table to store). These modes are only
186
+   triggered if there is more than one table specified in table_name
187
+   parameter, separated by "|".
188
+
189
+   Default value is "rand".
190
+
191
+   Example 1.3. Set mt_mode parameter
192
+...
193
+modparam("sipcapture", "mt_mode", "hash")
194
+...
195
+
196
+3.4. hash_source (str)
169 197
 
170
-3.3. db_insert_mode (integer)
198
+   The field of the SIP message used for hashing, when mt_mode is set to
199
+   "hash". The value can be "call_id", "to_user" or "from_user".
200
+
201
+   Default value is "call_id".
202
+
203
+   Example 1.4. Set mt_mode parameter
204
+...
205
+modparam("sipcapture", "hash_source", "to_user")
206
+...
207
+
208
+3.5. db_insert_mode (integer)
171 209
 
172 210
    If set to 1, use INSERT DELAYED to store sip message into capture table
173 211
    when the DB driver has support for it. If no INSERT DELAYED support is
... ...
@@ -175,43 +213,43 @@ modparam("sipcapture", "table_name", "homer_capture")
175 213
 
176 214
    Default value is 0 (no INSERT DELAYED).
177 215
 
178
-   Example 1.3. db_insert_mode example
216
+   Example 1.5. db_insert_mode example
179 217
 modparam("sipcapture", "db_insert_mode", 1)
180 218
 
181
-3.4. capture_on (integer)
219
+3.6. capture_on (integer)
182 220
 
183 221
    Parameter to enable/disable capture globaly (on(1)/off(0))
184 222
 
185 223
    Default value is "0".
186 224
 
187
-   Example 1.4. Set capture_on parameter
225
+   Example 1.6. Set capture_on parameter
188 226
 ...
189 227
 modparam("sipcapture", "capture_on", 1)
190 228
 ...
191 229
 
192
-3.5. hep_capture_on (integer)
230
+3.7. hep_capture_on (integer)
193 231
 
194 232
    Parameter to enable/disable capture of HEP (on(1)/off(0))
195 233
 
196 234
    Default value is "0".
197 235
 
198
-   Example 1.5. Set hep_capture_on parameter
236
+   Example 1.7. Set hep_capture_on parameter
199 237
 ...
200 238
 modparam("sipcapture", "hep_capture_on", 1)
201 239
 ...
202 240
 
203
-3.6. raw_ipip_capture_on (integer)
241
+3.8. raw_ipip_capture_on (integer)
204 242
 
205 243
    Parameter to enable/disable IPIP capturing (on(1)/off(0))
206 244
 
207 245
    Default value is "0".
208 246
 
209
-   Example 1.6. Set raw_ipip_capture_on parameter
247
+   Example 1.8. Set raw_ipip_capture_on parameter
210 248
 ...
211 249
 modparam("sipcapture", "raw_ipip_capture_on", 1)
212 250
 ...
213 251
 
214
-3.7. raw_moni_capture_on (integer)
252
+3.9. raw_moni_capture_on (integer)
215 253
 
216 254
    Parameter to enable/disable monitoring/mirroring port capturing
217 255
    (on(1)/off(0)) Only one mode on raw socket can be enabled! Monitoring
... ...
@@ -219,12 +257,12 @@ modparam("sipcapture", "raw_ipip_capture_on", 1)
219 257
 
220 258
    Default value is "0".
221 259
 
222
-   Example 1.7. Set raw_moni_capture_on parameter
260
+   Example 1.9. Set raw_moni_capture_on parameter
223 261
 ...
224 262
 modparam("sipcapture", "raw_moni_capture_on", 1)
225 263
 ...
226 264
 
227
-3.8. raw_socket_listen (string)
265
+3.10. raw_socket_listen (string)
228 266
 
229 267
    Parameter indicate an listen IP address of RAW socket for IPIP
230 268
    capturing. You can also define a port/portrange for IPIP/Mirroring
... ...
@@ -242,49 +280,49 @@ modparam("sipcapture", "raw_moni_capture_on", 1)
242 280
 
243 281
    Default value is "".
244 282
 
245
-   Example 1.8. Set raw_socket_listen parameter
283
+   Example 1.10. Set raw_socket_listen parameter
246 284
 ...
247 285
 modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060-5090")
248 286
 ...
249 287
 modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060")
250 288
 ...
251 289
 
252
-3.9. raw_interface (string)
290
+3.11. raw_interface (string)
253 291
 
254 292
    Name of the interface to bind on the raw socket.
255 293
 
256 294
    Default value is "".
257 295
 
258
-   Example 1.9. Set raw_socket_listen parameter
296
+   Example 1.11. Set raw_socket_listen parameter
259 297
 ...
260 298
 modparam("sipcapture", "raw_interface", "eth0")
261 299
 ...
262 300
 
263
-3.10. raw_sock_children (integer)
301
+3.12. raw_sock_children (integer)
264 302
 
265 303
    Parameter define how much children must be created to listen the raw
266 304
    socket.
267 305
 
268 306
    Default value is "1".
269 307
 
270
-   Example 1.10. Set raw_socket_listen parameter
308
+   Example 1.12. Set raw_socket_listen parameter
271 309
 ...
272 310
 modparam("sipcapture", "raw_sock_children", 6)
273 311
 ...
274 312
 
275
-3.11. promiscuous_on (integer)
313
+3.13. promiscuous_on (integer)
276 314
 
277 315
    Parameter to enable/disable promiscuous mode on the raw socket. Linux
278 316
    only.
279 317
 
280 318
    Default value is "0".
281 319
 
282
-   Example 1.11. Set hep_capture_on parameter
320
+   Example 1.13. Set hep_capture_on parameter
283 321
 ...
284 322
 modparam("sipcapture", "promiscuous_on", 1)
285 323
 ...
286 324
 
287
-3.12. raw_moni_bpf_on (integer)
325
+3.14. raw_moni_bpf_on (integer)
288 326
 
289 327
    Activate Linux Socket Filter (LSF based on BPF) on the mirroring
290 328
    interface. The structure is defined in linux/filter.h. The default LSF
... ...
@@ -293,18 +331,18 @@ modparam("sipcapture", "promiscuous_on", 1)
293 331
 
294 332
    Default value is "0".
295 333
 
296
-   Example 1.12. Set raw_moni_bpf_on parameter
334
+   Example 1.14. Set raw_moni_bpf_on parameter
297 335
 ...
298 336
 modparam("sipcapture", "raw_moni_bpf_on", 1)
299 337
 ...
300 338
 
301
-3.13. capture_node (str)
339
+3.15. capture_node (str)
302 340
 
303 341
    Name of the capture node.
304 342
 
305 343
    Default value is "homer01".
306 344
 
307
-   Example 1.13. Set capture_node parameter
345
+   Example 1.15. Set capture_node parameter
308 346
 ...
309 347
 modparam("sipcapture", "capture_node", "homer03")
310 348
 ...
... ...
@@ -104,7 +104,7 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
104 104
 	<section>
105 105
 		<title><varname>table_name</varname> (str)</title>
106 106
 		<para>
107
-		Name of the table's name where to store the SIP messages. 
107
+		Name of the table's name where to store the SIP messages. Can contain multiple tables, separated by "|".
108 108
 		</para>
109 109
 		<para>
110 110
 		<emphasis>
... ...
@@ -117,7 +117,46 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
117 117
 ...
118 118
 modparam("sipcapture", "table_name", "homer_capture")
119 119
 ...
120
-
120
+modparam("sipcapture", "table_name", "homer_capture1|homer_capture2");
121
+...
122
+</programlisting>
123
+		</example>
124
+	</section>
125
+	<section>
126
+		<title><varname>mt_mode</varname> (str)</title>
127
+		<para>
128
+		Name of the mode used for storing data in multiple tables. Modes can be "rand" (random), "round_robin" (use a round_robin algorithm) or "hash" (use hashing to determine the table to store). These modes are only triggered if there is more than one table specified in table_name parameter, separated by "|". 
129
+		</para>
130
+		<para>
131
+		<emphasis>
132
+			Default value is "rand".
133
+		</emphasis>
134
+		</para>
135
+		<example>
136
+		<title>Set <varname>mt_mode</varname> parameter</title>
137
+		<programlisting format="linespecific">
138
+...
139
+modparam("sipcapture", "mt_mode", "hash")
140
+...
141
+</programlisting>
142
+		</example>
143
+	</section>
144
+	<section>
145
+		<title><varname>hash_source</varname> (str)</title>
146
+		<para>
147
+		The field of the SIP message used for hashing, when mt_mode is set to "hash". The value can be "call_id", "to_user" or "from_user".
148
+		</para>
149
+		<para>
150
+		<emphasis>
151
+			Default value is "call_id".
152
+		</emphasis>
153
+		</para>
154
+		<example>
155
+		<title>Set <varname>mt_mode</varname> parameter</title>
156
+		<programlisting format="linespecific">
157
+...
158
+modparam("sipcapture", "hash_source", "to_user")
159
+...
121 160
 </programlisting>
122 161
 		</example>
123 162
 	</section>
124 163
new file mode 100644
... ...
@@ -0,0 +1,129 @@
1
+#include "../../sr_module.h"
2
+#include "../../crc.h"
3
+
4
+#include <ctype.h>
5
+
6
+#include "sipcapture.h"
7
+#include "hash_mode.h"
8
+
9
+static int get_source(struct _sipcapture_object *sco, enum hash_source source,
10
+                            str *source_string);
11
+static int get_call_id (struct _sipcapture_object *sco, str *source_string);
12
+static int get_from_user (struct _sipcapture_object *sco, str *source_string);
13
+static int get_to_user (struct _sipcapture_object *sco, str *source_string);
14
+
15
+
16
+static int first_token (str *source_string);
17
+
18
+
19
+int hash_func (struct _sipcapture_object * sco,
20
+                         enum hash_source source, int denominator) {
21
+	int ret;
22
+	unsigned int hash;
23
+	str source_string;
24
+
25
+	if(get_source (sco, source, &source_string) == -1) {
26
+		return -1;
27
+	}
28
+
29
+	LM_DBG("source string: [%.*s]\n", source_string.len, source_string.s);
30
+	crc32_uint(&source_string, &hash);
31
+
32
+	ret = hash % denominator;
33
+	return ret;
34
+}
35
+
36
+static int get_source (struct _sipcapture_object *sco, enum hash_source source,
37
+                             str *source_string) {
38
+	source_string->s = NULL;
39
+	source_string->len = 0;
40
+
41
+	switch (source) {
42
+			case hs_call_id:
43
+			return get_call_id (sco, source_string);
44
+			case hs_from_user:
45
+			return get_from_user(sco, source_string);
46
+			case hs_to_user:
47
+			return get_to_user(sco, source_string);
48
+			default:
49
+			LM_ERR("unknown hash source %i.\n",
50
+			     (int) source);
51
+			return -1;
52
+	}
53
+}
54
+
55
+static int get_call_id (struct _sipcapture_object * sco, str *source_string) {
56
+
57
+	if (!sco->callid.s || !sco->callid.len)
58
+	{
59
+		return -1;
60
+	}
61
+	source_string->s = sco->callid.s;
62
+	source_string->len = sco->callid.len;
63
+	first_token (source_string);
64
+	return 0;
65
+}
66
+
67
+static int get_from_user (struct _sipcapture_object * sco, str *source_string) {
68
+
69
+	if (!sco->from_user.s || !sco->from_user.len)
70
+	{
71
+		return -1;
72
+	}
73
+	source_string->s = sco->from_user.s;
74
+	source_string->len = sco->from_user.len;
75
+	return 0;
76
+}
77
+
78
+
79
+static int get_to_user (struct _sipcapture_object * sco, str *source_string) {
80
+
81
+	if (!sco->to_user.s || !sco->to_user.len)
82
+	{
83
+		return -1;
84
+	}
85
+	source_string->s = sco->to_user.s;
86
+	source_string->len = sco->to_user.len;
87
+	return 0;
88
+}
89
+
90
+
91
+static int first_token (str *source_string) {
92
+	size_t len;
93
+
94
+	if (source_string->s == NULL || source_string->len == 0) {
95
+		return 0;
96
+	}
97
+
98
+	while (source_string->len > 0 && isspace (*source_string->s)) {
99
+		++source_string->s;
100
+		--source_string->len;
101
+	}
102
+	for (len = 0; len < source_string->len; ++len) {
103
+		if (isspace (source_string->s[len])) {
104
+			source_string->len = len;
105
+			break;
106
+		}
107
+	}
108
+	return 0;
109
+}
110
+
111
+
112
+enum hash_source get_hash_source (const char *hash_source){
113
+
114
+	if (strcasecmp ("call_id", hash_source) == 0){
115
+		return hs_call_id;
116
+	}
117
+	else if (strcasecmp("from_user", hash_source) == 0)
118
+	{
119
+		return hs_from_user;
120
+	}
121
+	else if (strcasecmp("to_user", hash_source) == 0)
122
+	{
123
+		return hs_to_user;
124
+	}
125
+	else {
126
+		return hs_error;
127
+	}
128
+
129
+}
0 130
new file mode 100644
... ...
@@ -0,0 +1,61 @@
1
+/*
2
+ * $Id$
3
+ *
4
+ * Copyright (C) 2012 dragos.dinu@1and1.ro, 1&1 Internet AG
5
+ *
6
+ * This file is part of SIP-router, a free SIP server.
7
+ *
8
+ * SIP-router is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * SIP-router is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License 
19
+ * along with this program; if not, write to the Free Software 
20
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
+ *
22
+ */
23
+
24
+
25
+#ifndef HASH_MODE_H
26
+#define HASH_MODE_H 1
27
+
28
+
29
+
30
+
31
+/*
32
+ * Determines from which part of a message will be used to calculate the hash
33
+ * Possible values are:
34
+ * 
35
+ * hs_call_id     the content of the Call-ID header field
36
+ * hs_from_user   the username part of the URI in the From header field
37
+ * hs_to_user     the username part of the URI in the To header field
38
+ * hs_error       no hash specified
39
+*/
40
+enum hash_source {
41
+	hs_call_id = 1,
42
+	hs_from_user,
43
+	hs_to_user,
44
+	hs_error
45
+};
46
+
47
+
48
+/*
49
+ * CRC32 hash function
50
+ * Returns an integer number between 0 and denominator - 1 based on
51
+ * the hash source from the msg. The hash algorithm is CRC32.
52
+*/
53
+int hash_func (struct _sipcapture_object * sco,
54
+                         enum hash_source source, int denominator);
55
+
56
+/*
57
+ * Gets the hash source type.
58
+*/
59
+enum hash_source get_hash_source (const char *hash_source);
60
+
61
+#endif
... ...
@@ -74,6 +74,7 @@
74 74
 #include "../../resolve.h"
75 75
 #include "../../receive.h"
76 76
 #include "sipcapture.h"
77
+#include "hash_mode.h"
77 78
 
78 79
 #ifdef STATISTICS
79 80
 #include "../../lib/kcore/statistics.h"
... ...
@@ -82,47 +83,6 @@
82 83
 
83 84
 MODULE_VERSION
84 85
 
85
-struct _sipcapture_object {
86
-	str method;
87
-	str reply_reason;
88
-	str ruri;
89
-	str ruri_user;
90
-	str from_user;
91
-	str from_tag;
92
-	str to_user;
93
-	str to_tag;
94
-	str pid_user;
95
-	str contact_user;
96
-	str auth_user;
97
-	str callid;
98
-	str callid_aleg;
99
-	str via_1;
100
-	str via_1_branch;
101
-	str cseq;
102
-	str diversion;
103
-	str reason;
104
-	str content_type;
105
-	str authorization;
106
-	str user_agent;
107
-	str source_ip;
108
-	int source_port;
109
-	str destination_ip;
110
-	int destination_port;
111
-	str contact_ip;
112
-	int contact_port;
113
-	str originator_ip;
114
-	int originator_port;
115
-	int proto;
116
-	int family;
117
-	str rtp_stat;
118
-	int type;
119
-        long long tmstamp;
120
-	str node;	
121
-	str msg;	
122
-#ifdef STATISTICS
123
-	stat_var *stat;
124
-#endif
125
-};
126 86
 
127 87
 #define ETHHDR 14 /* sizeof of ethhdr structure */
128 88
 
... ...
@@ -149,6 +109,8 @@ static struct mi_root* sip_capture_mi(struct mi_root* cmd, void* param );
149 109
 
150 110
 static str db_url		= str_init(DEFAULT_RODB_URL);
151 111
 static str table_name		= str_init("sip_capture");
112
+static str hash_source		= str_init("call_id");
113
+static str mt_mode			= str_init("rand");
152 114
 static str id_column		= str_init("id");
153 115
 static str date_column		= str_init("date");
154 116
 static str micro_ts_column 	= str_init("micro_ts");
... ...
@@ -226,6 +188,22 @@ static struct sock_filter BPF_code[] = { { 0x28, 0, 0, 0x0000000c }, { 0x15, 0,
226 188
 db1_con_t *db_con = NULL; 		/*!< database connection */
227 189
 db_func_t db_funcs;      		/*!< Database functions */
228 190
 
191
+str* table_names = NULL;
192
+unsigned int no_tables = 0;
193
+
194
+/*multiple table mode*/
195
+enum e_mt_mode{
196
+	mode_random = 1,
197
+	mode_hash,
198
+	mode_round_robin,
199
+	mode_error
200
+};
201
+
202
+enum e_mt_mode mtmode = mode_random ;
203
+enum hash_source source = hs_error;
204
+
205
+unsigned int rr_idx = 0;
206
+
229 207
 struct hep_timehdr* heptime;
230 208
 
231 209
 
... ...
@@ -244,6 +222,8 @@ static cmd_export_t cmds[] = {
244 222
 static param_export_t params[] = {
245 223
 	{"db_url",			STR_PARAM, &db_url.s            },
246 224
 	{"table_name",       		STR_PARAM, &table_name.s	},
225
+	{"hash_source",				STR_PARAM, &hash_source.s	},
226
+	{"mt_mode",					STR_PARAM, &mt_mode.s	},
247 227
 	{"id_column",        		STR_PARAM, &id_column.s         },
248 228
 	{"date_column",        		STR_PARAM, &date_column.s       },	
249 229
 	{"micro_ts_column",     	STR_PARAM, &micro_ts_column.s	},
... ...
@@ -337,6 +317,70 @@ struct module_exports exports = {
337 317
 };
338 318
 
339 319
 
320
+static int mt_init(void) {
321
+
322
+	char *p = NULL;
323
+	int i = 0;
324
+
325
+	/*parse and save table names*/
326
+	no_tables = 1;
327
+	p = table_name.s;
328
+
329
+	while (*p)
330
+	{
331
+		if (*p== '|')
332
+		{
333
+			no_tables++;
334
+		}
335
+		p++;
336
+	}
337
+
338
+	table_names = (str*)pkg_malloc(sizeof(str) * no_tables);
339
+	if(table_names == NULL) {
340
+		LM_ERR("no more pkg memory left\n");
341
+		return -1;
342
+	}
343
+	p = strtok (table_name.s,"| \t");
344
+	while (p != NULL)
345
+	{
346
+		LM_INFO ("INFO: table name:%s\n",p);
347
+		table_names[i].s =  p;
348
+		table_names[i].len = strlen (p);
349
+		i++;
350
+		p = strtok (NULL, "| \t");
351
+	}
352
+
353
+	if (strcmp (mt_mode.s, "rand") ==0)
354
+	{
355
+		mtmode = mode_random;
356
+	}
357
+	else if (strcmp (mt_mode.s, "round_robin") ==0)
358
+	{
359
+		mtmode = mode_round_robin;
360
+	}
361
+	else if (strcmp (mt_mode.s, "hash") == 0)
362
+	{
363
+		mtmode = mode_hash;
364
+	}
365
+	else {
366
+		LM_ERR("ERROR: sipcapture: mod_init: multiple tables mode unrecognized\n");
367
+		return -1;
368
+		
369
+	}
370
+
371
+
372
+	if ( mtmode == mode_hash && (source = get_hash_source (hash_source.s) ) == hs_error)
373
+	{
374
+		LM_ERR("ERROR: sipcapture: mod_init: hash source unrecognized\n");
375
+		return -1;
376
+	}
377
+
378
+	srand(time(NULL));
379
+
380
+	return 0;
381
+
382
+}
383
+
340 384
 /*! \brief Initialize sipcapture module */
341 385
 static int mod_init(void) {
342 386
 
... ...
@@ -359,6 +403,8 @@ static int mod_init(void) {
359 403
 
360 404
 	db_url.len = strlen(db_url.s);
361 405
 	table_name.len = strlen(table_name.s);
406
+	hash_source.len = strlen (hash_source.s);
407
+	mt_mode.len = strlen(mt_mode.s);
362 408
 	date_column.len = strlen(date_column.s);
363 409
 	id_column.len = strlen(id_column.s);
364 410
 	micro_ts_column.len = strlen(micro_ts_column.s);
... ...
@@ -421,6 +467,11 @@ static int mod_init(void) {
421 467
 		return -1;
422 468
 	}
423 469
 
470
+	if (mt_init () <0)
471
+	{
472
+		return -1;
473
+	}
474
+
424 475
 
425 476
 	if(db_insert_mode) {
426 477
                 LM_INFO("INFO: sipcapture: mod_init: you have enabled INSERT DELAYED \
... ...
@@ -561,6 +612,10 @@ static int child_init(int rank)
561 612
                 return -1;
562 613
         }
563 614
 
615
+    if (mtmode ==mode_round_robin && rank > 0)
616
+    {
617
+		rr_idx = rank % no_tables;
618
+    }
564 619
 
565 620
 	return 0;
566 621
 }
... ...
@@ -611,6 +666,9 @@ static void destroy(void)
611 666
                 }                		
612 667
 		close(raw_sock_desc);
613 668
 	}
669
+	if (table_names){
670
+		pkg_free(table_names);
671
+	}
614 672
 }
615 673
 
616 674
 
... ...
@@ -793,6 +851,7 @@ static int sip_capture_store(struct _sipcapture_object *sco)
793 851
 	db_val_t db_vals[NR_KEYS];
794 852
 
795 853
 	str tmp;
854
+	int ii = 0;
796 855
 
797 856
 	if(sco==NULL)
798 857
 	{
... ...
@@ -996,9 +1055,25 @@ static int sip_capture_store(struct _sipcapture_object *sco)
996 1055
 
997 1056
 	db_vals[36].val.blob_val = tmp;
998 1057
 
999
-	LM_DBG("homer table: [%.*s]\n", table_name.len, table_name.s);		
1000
-                
1001
-	db_funcs.use_table(db_con, &table_name);
1058
+	if (no_tables > 0 ){
1059
+		if ( mtmode == mode_hash ){
1060
+			ii = hash_func ( sco, source , no_tables);
1061
+			LM_DBG ("hash idx is:%d\n", ii);
1062
+		}
1063
+		else if (mtmode == mode_random )
1064
+		{
1065
+			ii = rand() % no_tables;
1066
+			LM_DBG("rand idx is:%d\n", ii);
1067
+		}
1068
+		else if (mtmode == mode_round_robin)
1069
+		{
1070
+			ii = rr_idx;
1071
+			rr_idx = (rr_idx +1) % no_tables;
1072
+			LM_DBG("round robin idx is:%d\n", ii);
1073
+		}
1074
+	}
1075
+	LM_DBG("insert into homer table: [%.*s]\n", table_names[ii].len, table_names[ii].s);
1076
+	db_funcs.use_table(db_con, &table_names[ii]);
1002 1077
 
1003 1078
 	LM_DBG("storing info...\n");
1004 1079
 	
... ...
@@ -29,6 +29,47 @@ typedef uint16_t u_int16_t;
29 29
 #define IPPROTO_IPIP IPPROTO_ENCAP /* Solaris IPIP protocol has name ENCAP */
30 30
 #endif
31 31
 
32
+struct _sipcapture_object {
33
+	str method;
34
+	str reply_reason;
35
+	str ruri;
36
+	str ruri_user;
37
+	str from_user;
38
+	str from_tag;
39
+	str to_user;
40
+	str to_tag;
41
+	str pid_user;
42
+	str contact_user;
43
+	str auth_user;
44
+	str callid;
45
+	str callid_aleg;
46
+	str via_1;
47
+	str via_1_branch;
48
+	str cseq;
49
+	str diversion;
50
+	str reason;
51
+	str content_type;
52
+	str authorization;
53
+	str user_agent;
54
+	str source_ip;
55
+	int source_port;
56
+	str destination_ip;
57
+	int destination_port;
58
+	str contact_ip;
59
+	int contact_port;
60
+	str originator_ip;
61
+	int originator_port;
62
+	int proto;
63
+	int family;
64
+	str rtp_stat;
65
+	int type;
66
+        long long tmstamp;
67
+	str node;	
68
+	str msg;	
69
+#ifdef STATISTICS
70
+	stat_var *stat;
71
+#endif
72
+};
32 73
 
33 74
 struct hep_hdr{
34 75
     u_int8_t hp_v;            /* version */