ACC Module - acounting AVPs and headers


Table of Contents

1. Downloads
2. Overview
3. Extra information to be accounted
4. Configuring ACC for extra accounting
5. Configuring the storage for extra accounting
6. The configuration script
7. AVPOPS Module

1. Downloads

- acc-headers.tgz - new acc tarball (whole module)

- acc_headers.patch.gz - gzipped patch

- acc_headers.patch - patch to acc

- acc.html - acc readme in html format

2. Overview

To achive the functionality described in this document you have to apply the above patch to “acc” module from CVS head at November 1, 2004. You can also download the whole module from this site, link provided in “Downloads” section.

This is a basic example about how to account extra data along with the the standard accounted data. It shows how to get the data - mainly from SIP messages - how to configure the “acc” module to store it and where is stored.

The extra accounting facility allows dynamic configurable accounting of data from SIP messages - mainly SIP headers - and from AVP (Attribute Value Pair) - which can contain basically anything.

The example shows how to use the canonical URI for a better accounting - in a configuration with heavier RURI transformations (aliases, speed-dial, prefixes), accounting only input an output uri proves insufficient o correlate the CDRs with the actual user - so, saving the canonical URI (user@domain as subscribed) will not require to apply again the transformations on CDRs to find the actual user.

Along the canonical-URI, the example show how additional information - like source IP of the request and the User-Agent header - can be also included for accounting.

3. Extra information to be accounted

For extra accounting message headers, nothing special needs to be made. For extra accounting AVPs, we need to put the data we want into AVPs. For this the “avpops” module is used, and to make the script more clear we define the following AVP aliases (we recommend the usage of ID AVPs since are much faster than the NAME avps):

...
# "c_uri" (canonical URI) alias to ID AVP 888
# "s_ip"  (source IP) alias to ID AVP 999

modparam("avpops", "avp_aliases", "c_uri=i:888; s_ip=i:999" )
...

To get the date into AVPs, the "avp_write" function has to be used:

...
avp_write( "$src_ip", "$s_ip"); #store the src_ip
avp_write( "$ruri", "$c_uri");  #store the ruri
...

4. Configuring ACC for extra accounting

The extra data to be accounting is specify via “xxx_extra” parameter of “acc” module. For each type of accounting - syslog, database, radius, diameter - another set of extra data can be set.

The example accounts the User-Agent header into syslog, labeled “ua”, and canonical uri and source IP into database, labeled “uuid” and “src_ip”:

...
modparam("acc", "log_extra" ,"ua=hdr/User-Agent")
modparam("acc", "db_extra"  ,"uuid=avp/i:888; src_ip=avp/i:999")
...

5. Configuring the storage for extra accounting

In order to extra account in database, the structure of “acc” and “missed_calls” tables must be extended in order to wrap up the new values. All the extra values are logged as string values, so, in mysql, just do:

...
ALTER TABLE acc ADD uuid varchar(128) NOT NULL default "";
ALTER TABLE acc ADD src_ip varchar(128) NOT NULL default "";

ALTER TABLE missed_calls ADD uuid varchar(128) NOT NULL default "";
ALTER TABLE missed_calls ADD src_ip varchar(128) NOT NULL default "";
...

After these, the “acc” and “missed_calls” tables' structure should be like:

...
+------------+---------------+------+-----+---------------------+-------+
| Field      | Type          | Null | Key | Default             | Extra |
+------------+---------------+------+-----+---------------------+-------+
| sip_from   | varchar(128)  |      |     |                     |       |
| sip_to     | varchar(128)  |      |     |                     |       |
| sip_status | varchar(128)  |      |     |                     |       |
| sip_method | varchar(16)   |      |     |                     |       |
| i_uri      | varchar(128)  |      |     |                     |       |
| o_uri      | varchar(128)  |      |     |                     |       |
| from_uri   | varchar(128)  |      |     |                     |       |
| to_uri     | varchar(128)  |      |     |                     |       |
| sip_callid | varchar(128)  |      | MUL |                     |       |
| username   | varchar(64)   |      | MUL |                     |       |
| domain     | varchar(128)  |      |     |                     |       |
| fromtag    | varchar(128)  |      |     |                     |       |
| totag      | varchar(128)  |      |     |                     |       |
| time       | datetime      |      |     | 0000-00-00 00:00:00 |       |
| timestamp  | timestamp(14) | YES  |     | NULL                |       |
| uuid       | varchar(128)  |      |     |                     |       |
| src_ip     | varchar(128)  |      |     |                     |       |
+------------+---------------+------+-----+---------------------+-------+
...

For accounting to syslog, no modifications are required.

6. The configuration script

The example shows a basic SER script with accounting support. All extra values must be fetched in the proper places, before the accounting process:

  • src_ip” is loaded into AVP immediately as the request is considered valid

  • canonical uri” is loaded into AVP after all the transformations where applied - after doing lookup("aliases"), but before the lookup("location").

The script does accounting for all requests at syslog and database, but reports the missed calls only to database.

...
# **** global configuration parameters ****
debug=9
fork=no
log_stderror=yes

check_via=no
dns=no
rev_dns=no

port=5070
listen=xxx.xxx.xxx.xxx


# **** modules ****

loadmodule "/usr/local/lib/ser/modules/sl.so"
loadmodule "/usr/local/lib/ser/modules/mysql.so"
loadmodule "/usr/local/lib/ser/modules/tm.so"
loadmodule "/usr/local/lib/ser/modules/acc.so"
loadmodule "/usr/local/lib/ser/modules/rr.so"
loadmodule "/usr/local/lib/ser/modules/maxfwd.so"
loadmodule "/usr/local/lib/ser/modules/usrloc.so"
loadmodule "/usr/local/lib/ser/modules/registrar.so"
loadmodule "/usr/local/lib/ser/modules/avpops.so"
loadmodule "/usr/local/lib/ser/modules/textops.so"


# **** module parameters  ****

# don't use databse for usrloc
modparam("usrloc", "db_mode",   0)

# add value to ;lr param
modparam("rr", "enable_full_lr", 1)

# accounting
modparam("acc", "log_flag", 1)
modparam("acc", "db_flag",  3)
modparam("acc", "db_missed_flag",  4)
modparam("acc", "failed_transactions",  1)
modparam("acc", "db_url" , "mysql://ser:heslo@localhost/ser")

# extra accounting - log User-Agent hdr to syslog and AVP ID 888 to database
modparam("acc", "log_extra" ,"ua=hdr/User-Agent")
# extra accounting - log AVP ID 888 as "uuid" and AVP ID 999 as "src_ip"
# to database
modparam("acc", "db_extra"  ,"uuid=avp/i:888; src_ip=avp/i:999")

# avp aliases - define c_uri (canonical uri) as AVP ID 888 and s_ip as ID 999
modparam("avpops", "avp_aliases", "c_uri=i:888; s_ip=i:999" )



# **** routing script ****

route{

	# initial sanity checks 
	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		break;
	};
	if (msg:len >=  max_len ) {
		sl_send_reply("513", "Message too big");
		break;
	};

	# do record-route for non-REGISTER messages
	if (!method=="REGISTER")
		record_route();

	# write the source IP as avp "s_ip" for accounting purposes
	avp_write( "$src_ip", "$s_ip");

	# enable both syslog and db accountings
	setflag(1);
	setflag(3);

	# follow Route headers
	if (loose_route()) {
		# mark routing logic in request
		append_hf("P-hint: rr-enforced\r\n"); 
		route(1);
		break;
	};

	# request is for our domain ?
	if (!uri==myself) {
		append_hf("P-hint: outbound\r\n"); 
	} else {
		# deal with REGISTERs
		if (method=="REGISTER") {
			save("location");
			break;
		};

		lookup("aliases");
		if (!uri==myself) {
			append_hf("P-hint: outbound alias\r\n"); 
			route(1);
			break;
		};

		# write the current RURI as avp "c_uri" for accounting purposes
		avp_write( "$ruri", "$c_uri");

		# native SIP destinations are handled using our USRLOC DB
		if (!lookup("location")) {
			sl_send_reply("404", "Not Found");
			# account the call as missed
			acc_db_request("404 missed call", "missed_calls");
			break;
		};
		# set flag for missed calls accounting
		setflag(4);
		append_hf("P-hint: usrloc applied\r\n");
	};

	# generic forward
	route(1);
}


# generic statefull forward
route[1] {
	if (!t_relay()) {
		sl_reply_error();
	};
}


...

7. AVPOPS Module

The AVPOPS has been introduced into CVS at the beginning of November 2004. A tutorial about its capabilties can be found at http://www.voice-system.ro/docs/avpops/.