[Kamailio-Devel] [SR-Dev] [Serdev] AVPs
Jan Janak
jan at ryngle.com
Tue Dec 16 14:39:43 CET 2008
On 16-12 10:52, Daniel-Constantin Mierla wrote:
> On 12/16/08 10:15, Andrei Pelinescu-Onciul wrote:
>> On Dec 16, 2008 at 00:36, Daniel-Constantin Mierla <miconda at gmail.com> wrote:
>>
>>> Hello,
>>>
>>> On 12/12/08 17:22, Jan Janak wrote:
>>>
>>>> On 12-12 00:25, Daniel-Constantin Mierla wrote:
>>>>
>>>>> Hello,
>>>>>
>>>>> I think we need to decide about AVPs. Although not deeply
>>>>> investigated, ser seems to have couple of AVPs lists. In
>>>>> kamailio/openser it is one list.
>>>>>
>>>>> Can a ser developer describe a bit the AVP implementation as it
>>>>> is now there?
>>>>>
>>>> A long time ago we started using AVPs to store all kinds of configuration
>>>> information. We needed some sort of general configuration mechanism because
>>>> real-world scripts were getting too complex and at that time the AVPs were
>>>> readily available.
>>>>
>>>> We started by loading attribute names and value from a database table into
>>>> AVPs. This mechanism was/is same as in k. We would always load a set of
>>>> attributes this way for a particular user (identified by username and domain
>>>> from his/her SIP URI). With this mechanism in place, we were able to load a
>>>> generic set of configuration options for a particular user of the server, I
>>>> guess you have the same.
>>>>
>>>> To make the AVPs easily accessible from the configuration script, we added
>>>> support for AVP identifiers in the config script, so that you can access AVP
>>>> with name foo as $foo.
>>>>
>>>> As we migrated more and more configuration options to AVPs, it became clear
>>>> that having just one set of AVPs was not enough. Although we could load all
>>>> the config options for the caller (From URI) from the database into a set of
>>>> AVPs, we could not do the same for the callee (Request-URI) at the same
>>>> time. We could not do it because they would conflict with the
>>>> AVPs of the caller as both users could have AVPs with same names
>>>> but different values.
>>>>
>>>> To get around this issue we added another list of AVPs. The new AVP list
>>>> works the same way, it can contain AVPs with same names as AVPs in the
>>>> original list and they do not conflict. All functions that work with lists
>>>> of AVPs now take the list to work on as parameter.
>>>>
>>>> To make both AVP lists available in the configuration script, we extended
>>>> the syntax of AVPs identifiers so the script write can choose the AVP list
>>>> to work with. SO instead of just $foo you can write either
>>>>
>>>> $f.foo or $t.foo
>>>>
>>>> $f refers to the original AVP list which is commonly associated with the
>>>> caller. The address/uid of the caller is taken from From header, hence the
>>>> 'f' in the identifier. $t refers to the AVP list which contains
>>>> configuration settings of the callee. The address/uid of the calle can be
>>>> taken either from the Request-URI or To headers, hence the 't' in the
>>>> identifier.
>>>>
>>>> The original syntax without any list identifier is still available, in other
>>>> words you can still write $foo, this is defined as a shorthand for
>>>> $f.foo. If you do not specify the AVP list to be used then you are referring
>>>> to the list containing AVPs of the caller (From).
>>>>
>>>> It also turned out that in some cases we would be having too many attributes
>>>> in the database table storing AVPs. This can happen in bigger setups, having
>>>> tens or hundreds of thousands users or serving multiple domains. This can
>>>> slow the database down and makes SER load too much data. Based on my
>>>> observations it is common that a large number of users have AVPs with same
>>>> values. If ten thousands of users have attribute named 'foo' with value
>>>> 'bar' then the attribute will be stored in the database ten thousand times.
>>>>
>>>> As a remedy for this problem, we introduced the concept of AVP levels. The
>>>> AVPs described so far and stored in user_attrs table are called user-level
>>>> attributes and they store configuration specific to particular users. Then
>>>> we added another two AVP lists to store so called domain-level AVPs.
>>>>
>>>> Domain-level AVPs are used to store configuration information that is shared
>>>> by a group of users. Domain-level AVPs are stored in a separate database
>>>> table, the name of the table is domain_attrs and its contents is cached in
>>>> memory by 'domain' SER module. This is an important difference, while
>>>> user-level AVPs need to be loaded every time a SIP request is processed,
>>>> domain-level AVPs are only loaded when the contents of domain_attrs table
>>>> has changed.
>>>>
>>>> The domain-level AVPs are called 'domain' because they are tied to a
>>>> particular domain handled by the SIP server. That could be 'iptel.org',
>>>> 'sip-router.org', and so on. This mainly useful for multi-domain
>>>> setups. There are two domain-level AVP lists because it is common that SER
>>>> works with two domains at the same time, the domain from From header
>>>> (caller's domain) and the domain from Request-URI or To (callee's domain).
>>>>
>>>> Again, we extended the syntax of AVP identifiers in the configuration
>>>> file. So you can write:
>>>>
>>>> $fu.foo -- this way you are asking for the value of the user-level foo AVP.
>>>> $fd.foo -- This will return the value of the domain-level foo AVP.
>>>>
>>>> And similarly there is $tu and $td for callee's user-level and domain-level
>>>> AVPs. If you specify 'u' in the AVP identifiers then SER searches only the
>>>> list of user-level attributes. If you specify 'd' then SER searches only the
>>>> list of domain-level attributes.
>>>>
>>>> This behavior changes if you do NOT specify the level to be searched. In
>>>> that case SER searches the user-level list first and if no match is found
>>>> then the domain-level list will be searched. Thus if you write:
>>>>
>>>> $f.foo
>>>>
>>>> then you are telling SER to search for the value of 'foo' AVP in the
>>>> user-level list and continue with the domain-level list if no match is
>>>> found. In other words, user-level AVPs have higher priority than
>>>> domain-level AVPs. With this system you can efficiently set a configuration
>>>> option for all users within a domain by creating a domain-level attribute
>>>> and yet you can override that option with user-level attributes for
>>>> particular users within that domain.
>>>>
>>>> Then there are the global AVPs. Global AVPs can be used to store settings
>>>> applicable to the whole SIP server and all domains on that server. Global
>>>> AVPs are stored in global_attrs table and the contents of that table is
>>>> cached in memory by gflags module. There is only one list of global
>>>> AVPs. Global AVPs can be accessed with:
>>>>
>>>> $g.foo
>>>>
>>>> (note that there is no 'f' or 't' in the identifier). The list of global
>>>> AVPs is searched after the list of domain-level AVPs. So if you write:
>>>>
>>>> $f.foo
>>>>
>>>> Then SER searches user-level AVPs first, then domain-level and then the
>>>> global AVPs.
>>>>
>>>> And finally there are also so called URI-level AVPs. They work just
>>>> like user-level AVPs, but a single user can have multiple sets of
>>>> uri-level AVPs. They are tied to SIP URIs of that user. Uri-level AVPs are
>>>> denoted by 'r' in the AVP identifier, for example:
>>>>
>>>> $fr.foo
>>>>
>>> so, if I understood correctly, there are couple of combinations
>>> between the dot, with one or two letters, right?
>>>
>>> Like:
>>>
>>> $xy.name
>>>
>>> where x = f|t|g and y may be missing or u|d|r
>>>
>>
>> x = f|t ("track" in ser avp terminology
>> y= r|u|d|g ("class")
>>
>> g is a special case (it cannot be combined with f or t).
>>
>>
>> Here is the parse_avp_ident() usage comment:
>>
>> /** parse an avp indentifier.
>> *
>> * Parses the following avp indentifier forms:
>> * - "i:<number>" - old form, deprecated (e.g. i:42)
>> * - "s:<string>" - old form, deprecated (e.g. s:foo)
>> * - "<track>.<name>" (e.g.: f.bar)
>> * - "<track>.<name>[<index>]" (e.g.: f.bar[1])
>> * - "<track><class>.<name>" (e.g: tu.bar)
>> * - "<track><class>.<name>[<index>]" (e.g: fd.bar[2])
>> * - "<string>" (e.g.: foo)
>> * Where:
>> * <string> = ascii string
>> * <id> = ascii string w/o '[', ']', '.' and '/'
>> * <name> = <id> | '/' regex '/'
>> * (Note: regex use is deprecated)
>> * <track> = 'f' | 't'
>> * (from or to)
>> * <class> = 'r' | 'u' | 'd' | 'g'
>> * (uri, user, domain or global)
>> * <index> = <number> | '-' <number> | ''
>> * (the avp index, if missing it means AVP_INDEX_ALL, but
>> * it's use is deprecated)
>> * More examples:
>> * "fr.bar[1]" - from track, uri class, avp "bar", the value 1.
>> * "tu./^foo/" - to track, user class, all avps for which the name
>> * starts with foo (note RE in avp names are deprecated).
>> * "t.did" - to track, "did" avp
>> *
>> * @param name - avp identifier
>> * @param *attr - the result will be stored here
>> * @return 0 on success, -1 on error
>> */
>>
>>
>>> Then we can get rid of overlapping in the namespace if we enforce
>>> usage of $f.foo for $foo . In K there are couple of PV that use dot
>>> in classname (a PV can be $classname or $classname(innername)), but
>>> they are proposed to be removed.
>>>
>>
>> For the time being in sip-router this is handled in the following way:
>>
>> $(...) -> pvar
>> $foo(...) -> pvar
>> $foo[...] -> avp
>> $bar.foo -> avp (if it has a dot in it -> avp)
>> $foo (no dot, [] or ()) -> try first to resolve it as pvar and if it
>> fails consider it an avp.
>>
>> For the current version I think this is the most compatible way.
> yes, indeed, thanks!
>
>> I'll
>> use the same approach for ser module fixups (so all ser module that use
>> core fixup functions will be able to use also pvars).
>> One could also force kamailio or ser behaviour, by starting the
>> script with #!KAMAILIO or #!SER.
>>
>> For future versions we should rethink how everything is accessed.
>> For example I would use $foo for script variables and some other form
>> for avps or the current pvar $foo. Also we would have to unify selects
>> with the select like part of the pvars.
>> (Note for ser users: pvars in kamailio are used to access script vars,
>> avps, message headers and something which is kind of similar to ser
>> selects.).
>>
> Perhaps select implementations can be moved in modules, as well.
> Integration has to be done at some point anyhow.
It already is, the core contains the core selects and shared parts.
Jan.
More information about the Devel
mailing list