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
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 52
 
53 53
    1.1. Set db_url parameter
54 54
    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
55
+   1.3. Set mt_mode parameter
56
+   1.4. Set mt_mode parameter
57
+   1.5. db_insert_mode example
58
+   1.6. Set capture_on parameter
59
+   1.7. Set hep_capture_on parameter
60
+   1.8. Set raw_ipip_capture_on parameter
61
+   1.9. Set raw_moni_capture_on parameter
62 62
    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
63
+   1.11. Set raw_socket_listen parameter
64
+   1.12. Set raw_socket_listen parameter
65
+   1.13. Set hep_capture_on parameter
66
+   1.14. Set raw_moni_bpf_on parameter
67
+   1.15. Set capture_node parameter
66 68
 
67 69
 Chapter 1. Admin Guide
68 70
 
... ...
@@ -78,17 +82,19 @@ Chapter 1. Admin Guide
78 78
 
79 79
         3.1. db_url (str)
80 80
         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)
81
+        3.3. mt_mode (str)
82
+        3.4. hash_source (str)
83
+        3.5. db_insert_mode (integer)
84
+        3.6. capture_on (integer)
85
+        3.7. hep_capture_on (integer)
86
+        3.8. raw_ipip_capture_on (integer)
87
+        3.9. raw_moni_capture_on (integer)
88
+        3.10. raw_socket_listen (string)
89
+        3.11. raw_interface (string)
90
+        3.12. raw_sock_children (integer)
91
+        3.13. promiscuous_on (integer)
92
+        3.14. raw_moni_bpf_on (integer)
93
+        3.15. capture_node (str)
92 94
 
93 95
    4. MI Commands
94 96
 
... ...
@@ -133,17 +139,19 @@ Chapter 1. Admin Guide
133 133
 
134 134
    3.1. db_url (str)
135 135
    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)
136
+   3.3. mt_mode (str)
137
+   3.4. hash_source (str)
138
+   3.5. db_insert_mode (integer)
139
+   3.6. capture_on (integer)
140
+   3.7. hep_capture_on (integer)
141
+   3.8. raw_ipip_capture_on (integer)
142
+   3.9. raw_moni_capture_on (integer)
143
+   3.10. raw_socket_listen (string)
144
+   3.11. raw_interface (string)
145
+   3.12. raw_sock_children (integer)
146
+   3.13. promiscuous_on (integer)
147
+   3.14. raw_moni_bpf_on (integer)
148
+   3.15. capture_node (str)
147 149
 
148 150
 3.1. db_url (str)
149 151
 
... ...
@@ -158,7 +166,8 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
158 158
 
159 159
 3.2. table_name (str)
160 160
 
161
-   Name of the table's name where to store the SIP messages.
161
+   Name of the table's name where to store the SIP messages. Can contain
162
+   multiple tables, separated by "|".
162 163
 
163 164
    Default value is "sip_capture".
164 165
 
... ...
@@ -166,8 +175,37 @@ modparam("sipcapture", "db_url", "mysql://user:passwd@host/dbname")
166 166
 ...
167 167
 modparam("sipcapture", "table_name", "homer_capture")
168 168
 ...
169
+modparam("sipcapture", "table_name", "homer_capture1|homer_capture2");
170
+...
171
+
172
+3.3. mt_mode (str)
173
+
174
+   Name of the mode used for storing data in multiple tables. Modes can be
175
+   "rand" (random), "round_robin" (use a round_robin algorithm) or "hash"
176
+   (use hashing to determine the table to store). These modes are only
177
+   triggered if there is more than one table specified in table_name
178
+   parameter, separated by "|".
179
+
180
+   Default value is "rand".
181
+
182
+   Example 1.3. Set mt_mode parameter
183
+...
184
+modparam("sipcapture", "mt_mode", "hash")
185
+...
186
+
187
+3.4. hash_source (str)
169 188
 
170
-3.3. db_insert_mode (integer)
189
+   The field of the SIP message used for hashing, when mt_mode is set to
190
+   "hash". The value can be "call_id", "to_user" or "from_user".
191
+
192
+   Default value is "call_id".
193
+
194
+   Example 1.4. Set mt_mode parameter
195
+...
196
+modparam("sipcapture", "hash_source", "to_user")
197
+...
198
+
199
+3.5. db_insert_mode (integer)
171 200
 
172 201
    If set to 1, use INSERT DELAYED to store sip message into capture table
173 202
    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 175
 
176 176
    Default value is 0 (no INSERT DELAYED).
177 177
 
178
-   Example 1.3. db_insert_mode example
178
+   Example 1.5. db_insert_mode example
179 179
 modparam("sipcapture", "db_insert_mode", 1)
180 180
 
181
-3.4. capture_on (integer)
181
+3.6. capture_on (integer)
182 182
 
183 183
    Parameter to enable/disable capture globaly (on(1)/off(0))
184 184
 
185 185
    Default value is "0".
186 186
 
187
-   Example 1.4. Set capture_on parameter
187
+   Example 1.6. Set capture_on parameter
188 188
 ...
189 189
 modparam("sipcapture", "capture_on", 1)
190 190
 ...
191 191
 
192
-3.5. hep_capture_on (integer)
192
+3.7. hep_capture_on (integer)
193 193
 
194 194
    Parameter to enable/disable capture of HEP (on(1)/off(0))
195 195
 
196 196
    Default value is "0".
197 197
 
198
-   Example 1.5. Set hep_capture_on parameter
198
+   Example 1.7. Set hep_capture_on parameter
199 199
 ...
200 200
 modparam("sipcapture", "hep_capture_on", 1)
201 201
 ...
202 202
 
203
-3.6. raw_ipip_capture_on (integer)
203
+3.8. raw_ipip_capture_on (integer)
204 204
 
205 205
    Parameter to enable/disable IPIP capturing (on(1)/off(0))
206 206
 
207 207
    Default value is "0".
208 208
 
209
-   Example 1.6. Set raw_ipip_capture_on parameter
209
+   Example 1.8. Set raw_ipip_capture_on parameter
210 210
 ...
211 211
 modparam("sipcapture", "raw_ipip_capture_on", 1)
212 212
 ...
213 213
 
214
-3.7. raw_moni_capture_on (integer)
214
+3.9. raw_moni_capture_on (integer)
215 215
 
216 216
    Parameter to enable/disable monitoring/mirroring port capturing
217 217
    (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 219
 
220 220
    Default value is "0".
221 221
 
222
-   Example 1.7. Set raw_moni_capture_on parameter
222
+   Example 1.9. Set raw_moni_capture_on parameter
223 223
 ...
224 224
 modparam("sipcapture", "raw_moni_capture_on", 1)
225 225
 ...
226 226
 
227
-3.8. raw_socket_listen (string)
227
+3.10. raw_socket_listen (string)
228 228
 
229 229
    Parameter indicate an listen IP address of RAW socket for IPIP
230 230
    capturing. You can also define a port/portrange for IPIP/Mirroring
... ...
@@ -242,49 +280,49 @@ modparam("sipcapture", "raw_moni_capture_on", 1)
242 242
 
243 243
    Default value is "".
244 244
 
245
-   Example 1.8. Set raw_socket_listen parameter
245
+   Example 1.10. Set raw_socket_listen parameter
246 246
 ...
247 247
 modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060-5090")
248 248
 ...
249 249
 modparam("sipcapture", "raw_socket_listen", "10.0.0.1:5060")
250 250
 ...
251 251
 
252
-3.9. raw_interface (string)
252
+3.11. raw_interface (string)
253 253
 
254 254
    Name of the interface to bind on the raw socket.
255 255
 
256 256
    Default value is "".
257 257
 
258
-   Example 1.9. Set raw_socket_listen parameter
258
+   Example 1.11. Set raw_socket_listen parameter
259 259
 ...
260 260
 modparam("sipcapture", "raw_interface", "eth0")
261 261
 ...
262 262
 
263
-3.10. raw_sock_children (integer)
263
+3.12. raw_sock_children (integer)
264 264
 
265 265
    Parameter define how much children must be created to listen the raw
266 266
    socket.
267 267
 
268 268
    Default value is "1".
269 269
 
270
-   Example 1.10. Set raw_socket_listen parameter
270
+   Example 1.12. Set raw_socket_listen parameter
271 271
 ...
272 272
 modparam("sipcapture", "raw_sock_children", 6)
273 273
 ...
274 274
 
275
-3.11. promiscuous_on (integer)
275
+3.13. promiscuous_on (integer)
276 276
 
277 277
    Parameter to enable/disable promiscuous mode on the raw socket. Linux
278 278
    only.
279 279
 
280 280
    Default value is "0".
281 281
 
282
-   Example 1.11. Set hep_capture_on parameter
282
+   Example 1.13. Set hep_capture_on parameter
283 283
 ...
284 284
 modparam("sipcapture", "promiscuous_on", 1)
285 285
 ...
286 286
 
287
-3.12. raw_moni_bpf_on (integer)
287
+3.14. raw_moni_bpf_on (integer)
288 288
 
289 289
    Activate Linux Socket Filter (LSF based on BPF) on the mirroring
290 290
    interface. The structure is defined in linux/filter.h. The default LSF
... ...
@@ -293,18 +331,18 @@ modparam("sipcapture", "promiscuous_on", 1)
293 293
 
294 294
    Default value is "0".
295 295
 
296
-   Example 1.12. Set raw_moni_bpf_on parameter
296
+   Example 1.14. Set raw_moni_bpf_on parameter
297 297
 ...
298 298
 modparam("sipcapture", "raw_moni_bpf_on", 1)
299 299
 ...
300 300
 
301
-3.13. capture_node (str)
301
+3.15. capture_node (str)
302 302
 
303 303
    Name of the capture node.
304 304
 
305 305
    Default value is "homer01".
306 306
 
307
-   Example 1.13. Set capture_node parameter
307
+   Example 1.15. Set capture_node parameter
308 308
 ...
309 309
 modparam("sipcapture", "capture_node", "homer03")
310 310
 ...
... ...
@@ -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 @@
0
+#include "../../sr_module.h"
1
+#include "../../crc.h"
2
+
3
+#include <ctype.h>
4
+
5
+#include "sipcapture.h"
6
+#include "hash_mode.h"
7
+
8
+static int get_source(struct _sipcapture_object *sco, enum hash_source source,
9
+                            str *source_string);
10
+static int get_call_id (struct _sipcapture_object *sco, str *source_string);
11
+static int get_from_user (struct _sipcapture_object *sco, str *source_string);
12
+static int get_to_user (struct _sipcapture_object *sco, str *source_string);
13
+
14
+
15
+static int first_token (str *source_string);
16
+
17
+
18
+int hash_func (struct _sipcapture_object * sco,
19
+                         enum hash_source source, int denominator) {
20
+	int ret;
21
+	unsigned int hash;
22
+	str source_string;
23
+
24
+	if(get_source (sco, source, &source_string) == -1) {
25
+		return -1;
26
+	}
27
+
28
+	LM_DBG("source string: [%.*s]\n", source_string.len, source_string.s);
29
+	crc32_uint(&source_string, &hash);
30
+
31
+	ret = hash % denominator;
32
+	return ret;
33
+}
34
+
35
+static int get_source (struct _sipcapture_object *sco, enum hash_source source,
36
+                             str *source_string) {
37
+	source_string->s = NULL;
38
+	source_string->len = 0;
39
+
40
+	switch (source) {
41
+			case hs_call_id:
42
+			return get_call_id (sco, source_string);
43
+			case hs_from_user:
44
+			return get_from_user(sco, source_string);
45
+			case hs_to_user:
46
+			return get_to_user(sco, source_string);
47
+			default:
48
+			LM_ERR("unknown hash source %i.\n",
49
+			     (int) source);
50
+			return -1;
51
+	}
52
+}
53
+
54
+static int get_call_id (struct _sipcapture_object * sco, str *source_string) {
55
+
56
+	if (!sco->callid.s || !sco->callid.len)
57
+	{
58
+		return -1;
59
+	}
60
+	source_string->s = sco->callid.s;
61
+	source_string->len = sco->callid.len;
62
+	first_token (source_string);
63
+	return 0;
64
+}
65
+
66
+static int get_from_user (struct _sipcapture_object * sco, str *source_string) {
67
+
68
+	if (!sco->from_user.s || !sco->from_user.len)
69
+	{
70
+		return -1;
71
+	}
72
+	source_string->s = sco->from_user.s;
73
+	source_string->len = sco->from_user.len;
74
+	return 0;
75
+}
76
+
77
+
78
+static int get_to_user (struct _sipcapture_object * sco, str *source_string) {
79
+
80
+	if (!sco->to_user.s || !sco->to_user.len)
81
+	{
82
+		return -1;
83
+	}
84
+	source_string->s = sco->to_user.s;
85
+	source_string->len = sco->to_user.len;
86
+	return 0;
87
+}
88
+
89
+
90
+static int first_token (str *source_string) {
91
+	size_t len;
92
+
93
+	if (source_string->s == NULL || source_string->len == 0) {
94
+		return 0;
95
+	}
96
+
97
+	while (source_string->len > 0 && isspace (*source_string->s)) {
98
+		++source_string->s;
99
+		--source_string->len;
100
+	}
101
+	for (len = 0; len < source_string->len; ++len) {
102
+		if (isspace (source_string->s[len])) {
103
+			source_string->len = len;
104
+			break;
105
+		}
106
+	}
107
+	return 0;
108
+}
109
+
110
+
111
+enum hash_source get_hash_source (const char *hash_source){
112
+
113
+	if (strcasecmp ("call_id", hash_source) == 0){
114
+		return hs_call_id;
115
+	}
116
+	else if (strcasecmp("from_user", hash_source) == 0)
117
+	{
118
+		return hs_from_user;
119
+	}
120
+	else if (strcasecmp("to_user", hash_source) == 0)
121
+	{
122
+		return hs_to_user;
123
+	}
124
+	else {
125
+		return hs_error;
126
+	}
127
+
128
+}
0 129
new file mode 100644
... ...
@@ -0,0 +1,61 @@
0
+/*
1
+ * $Id$
2
+ *
3
+ * Copyright (C) 2012 dragos.dinu@1and1.ro, 1&1 Internet AG
4
+ *
5
+ * This file is part of SIP-router, a free SIP server.
6
+ *
7
+ * SIP-router is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * SIP-router is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License 
18
+ * along with this program; if not, write to the Free Software 
19
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
+ *
21
+ */
22
+
23
+
24
+#ifndef HASH_MODE_H
25
+#define HASH_MODE_H 1
26
+
27
+
28
+
29
+
30
+/*
31
+ * Determines from which part of a message will be used to calculate the hash
32
+ * Possible values are:
33
+ * 
34
+ * hs_call_id     the content of the Call-ID header field
35
+ * hs_from_user   the username part of the URI in the From header field
36
+ * hs_to_user     the username part of the URI in the To header field
37
+ * hs_error       no hash specified
38
+*/
39
+enum hash_source {
40
+	hs_call_id = 1,
41
+	hs_from_user,
42
+	hs_to_user,
43
+	hs_error
44
+};
45
+
46
+
47
+/*
48
+ * CRC32 hash function
49
+ * Returns an integer number between 0 and denominator - 1 based on
50
+ * the hash source from the msg. The hash algorithm is CRC32.
51
+*/
52
+int hash_func (struct _sipcapture_object * sco,
53
+                         enum hash_source source, int denominator);
54
+
55
+/*
56
+ * Gets the hash source type.
57
+*/
58
+enum hash_source get_hash_source (const char *hash_source);
59
+
60
+#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 82
 
83 83
 MODULE_VERSION
84 84
 
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 85
 
127 86
 #define ETHHDR 14 /* sizeof of ethhdr structure */
128 87
 
... ...
@@ -149,6 +109,8 @@ static struct mi_root* sip_capture_mi(struct mi_root* cmd, void* param );
149 149
 
150 150
 static str db_url		= str_init(DEFAULT_RODB_URL);
151 151
 static str table_name		= str_init("sip_capture");
152
+static str hash_source		= str_init("call_id");
153
+static str mt_mode			= str_init("rand");
152 154
 static str id_column		= str_init("id");
153 155
 static str date_column		= str_init("date");
154 156
 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 226
 db1_con_t *db_con = NULL; 		/*!< database connection */
227 227
 db_func_t db_funcs;      		/*!< Database functions */
228 228
 
229
+str* table_names = NULL;
230
+unsigned int no_tables = 0;
231
+
232
+/*multiple table mode*/
233
+enum e_mt_mode{
234
+	mode_random = 1,
235
+	mode_hash,
236
+	mode_round_robin,
237
+	mode_error
238
+};
239
+
240
+enum e_mt_mode mtmode = mode_random ;
241
+enum hash_source source = hs_error;
242
+
243
+unsigned int rr_idx = 0;
244
+
229 245
 struct hep_timehdr* heptime;
230 246
 
231 247
 
... ...
@@ -244,6 +222,8 @@ static cmd_export_t cmds[] = {
244 244
 static param_export_t params[] = {
245 245
 	{"db_url",			STR_PARAM, &db_url.s            },
246 246
 	{"table_name",       		STR_PARAM, &table_name.s	},
247
+	{"hash_source",				STR_PARAM, &hash_source.s	},
248
+	{"mt_mode",					STR_PARAM, &mt_mode.s	},
247 249
 	{"id_column",        		STR_PARAM, &id_column.s         },
248 250
 	{"date_column",        		STR_PARAM, &date_column.s       },	
249 251
 	{"micro_ts_column",     	STR_PARAM, &micro_ts_column.s	},
... ...
@@ -337,6 +317,70 @@ struct module_exports exports = {
337 337
 };
338 338
 
339 339
 
340
+static int mt_init(void) {
341
+
342
+	char *p = NULL;
343
+	int i = 0;
344
+
345
+	/*parse and save table names*/
346
+	no_tables = 1;
347
+	p = table_name.s;
348
+
349
+	while (*p)
350
+	{
351
+		if (*p== '|')
352
+		{
353
+			no_tables++;
354
+		}
355
+		p++;
356
+	}
357
+
358
+	table_names = (str*)pkg_malloc(sizeof(str) * no_tables);
359
+	if(table_names == NULL) {
360
+		LM_ERR("no more pkg memory left\n");
361
+		return -1;
362
+	}
363
+	p = strtok (table_name.s,"| \t");
364
+	while (p != NULL)
365
+	{
366
+		LM_INFO ("INFO: table name:%s\n",p);
367
+		table_names[i].s =  p;
368
+		table_names[i].len = strlen (p);
369
+		i++;
370
+		p = strtok (NULL, "| \t");
371
+	}
372
+
373
+	if (strcmp (mt_mode.s, "rand") ==0)
374
+	{
375
+		mtmode = mode_random;
376
+	}
377
+	else if (strcmp (mt_mode.s, "round_robin") ==0)
378
+	{
379
+		mtmode = mode_round_robin;
380
+	}
381
+	else if (strcmp (mt_mode.s, "hash") == 0)
382
+	{
383
+		mtmode = mode_hash;
384
+	}
385
+	else {
386
+		LM_ERR("ERROR: sipcapture: mod_init: multiple tables mode unrecognized\n");
387
+		return -1;
388
+		
389
+	}
390
+
391
+
392
+	if ( mtmode == mode_hash && (source = get_hash_source (hash_source.s) ) == hs_error)
393
+	{
394
+		LM_ERR("ERROR: sipcapture: mod_init: hash source unrecognized\n");
395
+		return -1;
396
+	}
397
+
398
+	srand(time(NULL));
399
+
400
+	return 0;
401
+
402
+}
403
+
340 404
 /*! \brief Initialize sipcapture module */
341 405
 static int mod_init(void) {
342 406
 
... ...
@@ -359,6 +403,8 @@ static int mod_init(void) {
359 359
 
360 360
 	db_url.len = strlen(db_url.s);
361 361
 	table_name.len = strlen(table_name.s);
362
+	hash_source.len = strlen (hash_source.s);
363
+	mt_mode.len = strlen(mt_mode.s);
362 364
 	date_column.len = strlen(date_column.s);
363 365
 	id_column.len = strlen(id_column.s);
364 366
 	micro_ts_column.len = strlen(micro_ts_column.s);
... ...
@@ -421,6 +467,11 @@ static int mod_init(void) {
421 421
 		return -1;
422 422
 	}
423 423
 
424
+	if (mt_init () <0)
425
+	{
426
+		return -1;
427
+	}
428
+
424 429
 
425 430
 	if(db_insert_mode) {
426 431
                 LM_INFO("INFO: sipcapture: mod_init: you have enabled INSERT DELAYED \
... ...
@@ -561,6 +612,10 @@ static int child_init(int rank)
561 561
                 return -1;
562 562
         }
563 563
 
564
+    if (mtmode ==mode_round_robin && rank > 0)
565
+    {
566
+		rr_idx = rank % no_tables;
567
+    }
564 568
 
565 569
 	return 0;
566 570
 }
... ...
@@ -611,6 +666,9 @@ static void destroy(void)
611 611
                 }                		
612 612
 		close(raw_sock_desc);
613 613
 	}
614
+	if (table_names){
615
+		pkg_free(table_names);
616
+	}
614 617
 }
615 618
 
616 619
 
... ...
@@ -793,6 +851,7 @@ static int sip_capture_store(struct _sipcapture_object *sco)
793 793
 	db_val_t db_vals[NR_KEYS];
794 794
 
795 795
 	str tmp;
796
+	int ii = 0;
796 797
 
797 798
 	if(sco==NULL)
798 799
 	{
... ...
@@ -996,9 +1055,25 @@ static int sip_capture_store(struct _sipcapture_object *sco)
996 996
 
997 997
 	db_vals[36].val.blob_val = tmp;
998 998
 
999
-	LM_DBG("homer table: [%.*s]\n", table_name.len, table_name.s);		
1000
-                
1001
-	db_funcs.use_table(db_con, &table_name);
999
+	if (no_tables > 0 ){
1000
+		if ( mtmode == mode_hash ){
1001
+			ii = hash_func ( sco, source , no_tables);
1002
+			LM_DBG ("hash idx is:%d\n", ii);
1003
+		}
1004
+		else if (mtmode == mode_random )
1005
+		{
1006
+			ii = rand() % no_tables;
1007
+			LM_DBG("rand idx is:%d\n", ii);
1008
+		}
1009
+		else if (mtmode == mode_round_robin)
1010
+		{
1011
+			ii = rr_idx;
1012
+			rr_idx = (rr_idx +1) % no_tables;
1013
+			LM_DBG("round robin idx is:%d\n", ii);
1014
+		}
1015
+	}
1016
+	LM_DBG("insert into homer table: [%.*s]\n", table_names[ii].len, table_names[ii].s);
1017
+	db_funcs.use_table(db_con, &table_names[ii]);
1002 1018
 
1003 1019
 	LM_DBG("storing info...\n");
1004 1020
 	
... ...
@@ -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 */