8 Call Merging Algorithms

Oracle Communications Operations Monitor has the ability to find the call legs of the same call. This is an essential feature for troubleshooting and for providing deep device visibility and accurate statistics. While in the case of some SIP devices (like Proxies and B2BUAs that keep the Call-ID header) finding the matching call legs is easy, many other devices change most of the fields from the incoming leg for purposes like topology hiding, decoupling, and interoperability. This makes the call merging problem hard and impossible to solve in all cases with a single algorithm.

Operations Monitor gives the network operator the power to adjust the call merging algorithm by providing a comprehensive list of tests and a flexible way to combine them in call merging algorithms. This section describes the available tests and how to write the algorithms. The resulting scripts can be entered in the Platform Devices section for SBC/B2BUA devices by choosing the Use custom algorithm option.

The call merge algorithms always return a single Boolean value: true if the call legs are part of the same call, and false otherwise. They provide ordered tests, tests with parameters, and nested decisions trees. To keep the real-time nature of Operations Monitor, the tests are implemented natively in the Operations Monitor core, and the algorithms are compiled to an internal representation which can be executed with maximum performance.

This chapter also contains links to KM notes that describe how to enable various types of call merging and call correlation. For more information, see "Merging and Correlating Calls".

Note:

When call correlation is based on the correlation algorithm of a device, an incoming leg can be correlated with multiple outgoing legs. An outgoing leg, however, can be correlated to only one incoming leg.

For global call correlation based on the SIP Call ID, the restriction for outgoing legs does not apply. Call ID based correlation can be enabled with the Merge globally by Call ID setting in System Settings under System Management on the Settings page. For more information on this setting, see "Merge globally by Call-ID".

Merging and Correlating Calls

This section contains links to KM notes that describe how to enable various types of call merging and call correlation. For more information, see the KM note located at: https://support.oracle.com/epmos/faces/DocumentDisplay?id=1638050.1

For information on call merging and call correlation using the Replaces parameter, see the KM note at: https://support.oracle.com/epmos/faces/DocumentDisplay?id=2012218.1

Syntax

Syntax wise, they are formed from a single LISP expression. Apart from the tests, there is only the special function cond, and two terminals:

  • #t for true.

  • #f for false.

The LISP cond function accepts an arbitrary number of arguments. Each argument is a list of two elements: a condition and a result.

(cond
    (condition1 result1)
    (condition2 result2)
    ...
    (conditionN resultN)
)
  

The conditions are evaluated in order, and for the first being true, the result is returned:

if condition1 is true return result1, else if condition2 is true return result2, else if ...; else if conditionN is true return resultN.

If none of the conditions is true, then false is returned for the whole expression, as a convenience.

Usually in call merging algorithms, the conditions are tests and the results are terminals:

(cond
    (test1 #t)
    (test2 #t)
    (test3 #f)
    (test4 #t)
)
  

But the result does not have to be a terminal. For example, this is a possible AND statement:

(cond
    (test1 test2)
)
  

The result part can also be another cond expression for providing nested tests:

(cond
    (test1 (cond
                (test2 #t)
                (test3 #t)
           )
    )
    (test4 #t)
)
  

The above example translates in the following pseudo-code:

if test1:
    if test2:
        return True
    elif test3:
        return True
    else:
        return False
elif test4:
    return True
else:
    return False
  

The tests can accept an arbitrary number of parameters which have to be provided right after the test name, for example:

(cond
    (test1 param1 param2)
)
  

translates to:

if test1(param1, param2):
    return True
else:
    return False
  

The parameters can be strings, integers, or list of strings:

(test "string" 12 ("list" "of" "parameters"))
  

Line comments can be inserted by using the semicolon symbol:

; this is a comment

Tests Reference

This section lists the tests available for custom call merging algorithms.

call_id ([suffix])

Returns #t if the Call-ID headers of the two call legs are equal.

Parameters:

suffix - If this parameter is provided and it is non-zero, then only the last suffix characters are compared from the two Call-ID headers, and if they are equal, it returns #t.

Example:

(call_id 12)
  

returns #t if the last 12 characters from the Call-ID headers are equal.

hf_equals (header)

Returns #t if the values of the header whose name is given as a parameters are equal in the two call legs. The header name is case-insensitive.

For example, the following snippet returns #t, if the INVITE messages from both call legs contain a header named Session-ID and their values are equal:

(hf_equals "Session-ID")

hf_any_equals (headers)

Like hf_equals, but compares any header value in headers list with any header value from the second call; for a more complete example what this means see also uri_user.

hf_any_equals_all (headers)

This function is like hf_any_equals, but differs in the way that it treats the case where a header field contains a list of values, either separated by commas or in several header field rows with the same field name. In that case hf_any_equals will use only the first header field row with a given field name and use the entire row as one value, whereas hf_any_equals_all will try to match each individual element of the list.

hf_equals_prefix (length, header)

Limits the comparison performed by hf_equals to length characters from the beginning of the header value.

hf_param_equals (header, param)

Works like hf_equals but compares only the value of the named param.

sdp_media_ip_port ()

Returns #t if the SDP bodies from the initial INVITE messages of the two call legs contain the same media IP address and UDP port number in the first media description.

This is usually a good indicator, if the B2BUA device does not relay media.

sdp_session_id ()

Returns #t if the SDP bodies from the initial INVITE messages of the two call legs contain the same non-zero session ID.

time_diff (interval1, interval2)

Returns #t if the time difference between the two legs is larger than the accepted intervals.

Parameters:

  • interval1 - The minimum time difference between the initial INVITE message of incoming call leg and the initial INVITE of the outgoing call leg.

  • interval2 - The minimum time difference between the initial INVITE message of outgoing call leg and the initial INVITE of the incoming call leg.

For example, the following code returns #t if the outgoing leg comes after the incoming leg with more than 15 seconds, or if the incoming leg comes after the outgoing leg with more than 2 seconds:

(time_diff 15000 2000)

Important:

The maximum value that you can use for the time_diff function is the same as the Operations Monitor system settings. Where,
  • The maximum value for B2B incoming backlog search for merging is 5 seconds.

  • The maximum value for B2B outgoing backlog search for merging is 1800 seconds.

If you do not include the time_diff function in your algorithm, your Operations Monitor B2B incoming backlog search for merging and B2B outgoing backlog search for merging system settings are used.

Note:

The time_diff function is treated differently than the others within the call correlation algorithm. It is considered for each correlation regardless of its position inside the algorithm.

uri_user (suffix, list_of_headers)

Returns #t if the user part of any of the URIs is specified in the list_of_headers matches.

Parameters:

  • suffix - If non-zero, only the last suffix characters from each URI is compared with the rest. URI length must be at least this size.

  • list_of_headers - A list containing the headers from which to extract the URI usernames to compare. A set of shortcuts are defined:

    • ruri - Request-URI.

    • from - From header URI.

    • to - To header URI.

    • diversion - Diversion header URI.

    • pai - P-Asserted-Identity URI.

    • ppid - P-Preferred-Identity URI.

    • rpid - Remote-Party-ID URI.

The URIs are compared in all possible permutations. For example, this snippet:

(uri_user 6 ("from" "pai"))
  

compares:

  • The From user from leg 1, with the From user from leg 2.

  • The From user from leg 1, with the P-Asserted-Identity user from leg 2.

  • The P-Asserted-Identity user from leg 1, with the From user from leg 2.

  • The P-Asserted-Identity user from leg 1, with the P-Asserted-Identity user from leg 2.

Similarly, the following snippet makes at most 9 comparisons:

(uri_user 6 ("to" "ruri" "diversion"))
  

In addition to the specified shortcut header names, URIs can be also specified by the name of the header containing them.

For example, the following expression returns #t if the last 7 characters from the username of the first Contact header from both calls are equal:

(uri_user 7 ("Contact"))
  

The header name is case-insensitive.

uri_user_max (suffix, list_of_headers)

The same as uri_user function, but it tries to match the call if a string is shorter than the suffix. For example, phone numbers 5551234 and 1234 will match, even if the suffix is 6.

uri_user_all (suffix, list_of_headers)

This function behaves in the same way as uri_user , except that if one of the relevant headers of one the call legs contains more than one URI, then all of these URIs are used for comparison, whereas uri_user would only use the first. Therefore if in the example:

(uri_user 6 ("from" "pai"))
  

one leg contains one P-Asserted-Identity and the other three, then up to 8 comparisons will be performed.

uri_user_all_max (suffix, list_of_headers)

As uri_user_max , but treats lists in header fields in the same way as uri_user_all.

cxpn_uri (suffix, list_of_headers)

Matches an in- with an out-going call comparing all possible header permutations like uri_user. It also supports ISUP cdpn and cgpn and allows for cross matching of SIP and ISUP calls.

Parameters:

  • suffix - If non-zero, only the last suffix characters from each URI is compared with the rest. URI length must be at least this size.

  • list_of_headers - In addition to the values supported by uri_user, cxpn_uri also supports:

    • cdpn - Matching on the callee.

    • cgpn - Matching on the caller.

cxpn_uri_max (suffix, list_of_headers)

The same as cxpn_uri function, but it tries to match the call if a string is shorter than the suffix. For example, phone numbers 5551234 and 1234 will match, even if suffix is 6.

cxpn_uri_all (suffix,list_of_headers)

Variants of cxpn_uri that use all URIs if a header of the SIP leg contains several, just as uri_user_all.

cxpn_uri_all_max (suffix,list_of_headers)

Same as cxpn_uri_max, but treats lists in header fields in the same way as uri_user_all.

cdpn (suffix)

Like uri_user, but matches only on the callee.

cgpn (suffix)

Like uri_user, but matches only on the caller.

Test Usage Limitations

Depending on the kind of device that is used for matching, different sets of test functions are available:

  • B2BUA

    Supports SIP matching which comprises these tests: call_id , uri_user, time_diff, the hf_equals family of tests and sdp_session_id as well as sdp_media_ip_port.

  • STP

    Supports ISUP call matching with cdpn, cgpn and time_diff as tests.

  • SGW

    Supports all the tests available for the other two device types and the cxpn_uri test.

Examples

The following examples describe how to create an algorithm using the test references.

Match by the Caller and the Callee

The following algorithm matches two call legs if:

  • The last 6 characters of caller are equal, as found in either the From header or in the P-Asserted-Identity,

  • And the last 6 characters of the callee are equal, as found in either the To header or in the Request-URI.

(cond
    ((uri_user 6 ("from" "pai"))
        (uri_user 6 ("to" "ruri"))
    )
)
  

The following example modifies the one above to return true, if either the caller or the callee matches:

(cond
    ((uri_user 6 ("from" "pai")) #t)
    ((uri_user 6 ("to" "ruri")) #t)
)

Match by Generic Algorithm

The following algorithm is an example of a generic algorithm, which should give good results for a wide range of SIP devices.

(cond
    ((call_id 0) #t)
    ((sdp_media_ip_port) #t)
  
    ; custom header
    ((hf_equals "session-id") #t)
  
    ((time_diff 15000 2000) #f)
   
    ; Matching by from and to
    ((uri_user 6 ("from" "pai" "rpid" "ppid"))
        (cond
            ((uri_user 6 ("to" "ruri" "diversion")) #t)
            (#t #f)
        )
    )
  
    ; nothing matched, return false
    (#t #f)
)
  

The above algorithm:

  • Checks first the Call-ID. If the two call legs have the same Call-ID header, then it returns true.

  • Checks the SDP bodies. If the two call legs have the same media IP and port number, or if the session ID are equal, then it returns true.

  • Checks if the custom Session-ID header is present in both call legs, and if their values are equal, then it returns true.

  • Checks if the start time stamps of the two call legs are too far one from each other, and if so, returns false.

  • Checks if both the caller and the callee match, by comparing the URIs from several headers. If a match is found for both of them, it returns true.

If none of the above is true, it returns false.