Category Archives: pbx

How to automatically extract data from an Avaya Communication Manager

You might call this post “the secret of my success” as a PBX admin for Avaya Communication Manager. Avaya provides some utilities for their techs and business partners, but customers don’t really have a lot of tools to easily extract data. In this post, I’ll show you how to extract ANYTHING from Avaya from a command line so it’s suitable for scripting. In my case, I parse the data further and generate a list of all stations and report of changes to my PBX every 15 minutes. Have you ever wondered who used to have extension 4438? How about that phone for the intern over the summer named “Bodkin Van Horn” that you deleted but now he has been hired and you want to give him the same extension? How about the question “how long has this extension been unplugged”?

Back in mid 00s, I wrote some PHP integrate with CM using telnet. Since I didn’t know much about PHP’s ANSI support, I ended up writing my own ANSI parser of the raw data. Anyway, it was great, but many customers don’t support telnet and want all communication to CM to be through ssh, which is reasonable, right?

Then I found this post from Benjamin Roy where he provided a perl module to do it through ssh. Also, he meticulously reverse-engineered Avaya’s OSSI protocol, which I think is impressive and sounds like fun. But I didn’t use OSSI; I just wanted a way to get data using ssh. So I took Ben’s code and tweaked it a little bit. It’s straight perl code – it’s not a module or anything like that. It does have dependencies on a couple other modules though. You do not need to be a perl developer to use this. It’s really easy. Here is a link to the script. Just save this as “av.pl”. Try to run it with “perl -c av.pl” (the -c means just check to make sure it compiles but do not run it). You might get some errors about missing modules. There are only three, and this is how you install them if you need to:

perl -MCPAN -e "install Expect"
perl -MCPAN -e "install Data::Dumper"
perl -MCPAN -e "install Term::VT102"

I should probably mention here – if you don’t have a Linux server in your environment, you should really get one. Your Virtual Machine team can make one for you – just about any distribution of Lunux will do and they take almost no resources. If you need to justify it, just say something like “utility server for PBX monitoring” or something like that.

Anyway, back to the script. Naturally, it needs to connect to your PBX, so create a little text file like “mypbx.txt” with the contents

10.10.40.89,5022,cmusername,Passw0rd,ssh

Obviously, replace the IP address, username, and password of your PBX.

And then create another file called “commands.txt” with the contents

list trunk
display station 3100

This can contain whatever commands you’d like. list reg, list station, list trunk, list locations, list measurements, stat cdr, etc. It should be any command that can be “paged” through, you know?

And then simply run this line

perl av.pl mypbx.txt commands.txt

The script will connect to the PBX defined in mypbx.txt, run the commands in commands.txt and output the results to STDOUT!

This is the core script to a bunch of stuff I automate in my PBXs. In a later post, I’ll show you how I parse the results with Perl and make use of the data.

I call this “the secret of my success” because I use this data to build a simple html page of all extensions in all of my PBXs every 15 minutes. I keep this page up all the time in a browser tab, which enables me to simply “control-f” for any name in the PBX and I have the extension number and the IP address of the station (or ‘unregistered’ if it’s unplugged). I can see unregistered ‘guest’ numbers, see the station’s history, etc. There’s a lot more I do with this information and I look forward to showing you.

Please let me know what you think! And if there’s anything I can do to help you get it working.

Lastly, if any of you need to do any telephone system testing (capacity, QA, DID number ports, call-flow, queuing, etc), please check out my post about CallsByCloud. If you sign up and use the promotion code ‘roger2015’, you’ll get $10 in credit and a 20% discount on the per-minute rate.

Also, if you hate unsolicited outbound telemarketing, consider subscribing to the Jolly Roger Telephone Company. Your telemarketers will entertain and delight you. Sample recordings here.

Thanks all!

Roger

 

Roger speaks at TEDx Naperville about disrupting the telemarketing industry!

Way back in July of 2014, I wrote about how I stopped telemarketing at my house. Little did I know that my efforts to combat and disrupt unsolicited telemarketers would eventually lead to me giving a TEDx talk about it!

Some of you may know that, in an effort to stop telemarketing, I created a robot to talk to them. It’s an interesting story and I posted some audio at the beginning of 2016. My story was picked up by Gizmodo on February 1, 2016 and things got really crazy from there.

Anyway, Fast forward to November 4, 2016 and I find myself on stage at TEDxNaperville in Illinois speaking in front of about 500 people at a beautiful venue. I’ve never spoken in front of a crowd like that, and it was amazing.

Don’t get me wrong – as a phone guy, I love call centers. But as a phone guy I also love the telephone network. The Public Switched Telephone Network has been around for about 140 years and it is crushed under the burden of unsolicited telemarketing. Blocking doesn’t work. Their predictive dialers simply call the next sucker. I think the only solution (short of abandoning the entire network) is the Jolly Roger Telephone Company. Here is me story about how I’m disrupting the scammers, spammers, and crooks, which make up most of the unsolicited telemarketing industry.

By the way, this goes for cold callers too. If your business is struggling to handle cold callers (ask your receptionists, Investor Relations team, or any admins for your CxOs) then I also have a solution for you. It’s called a Biz-Bot and it will handle all your pesky cold callers for all your employees.

But anyway, here is the talk!

How to parse Avaya CDR into MySQL database with Perl

This is a follow-up to my earlier post about setting up CDR processing with Kiwi Syslog Server. In that post, I discuss how to capture the data to a text file. But of course, if we are capturing CDR, we probably want to analyze it, right?

So this post is dedicated to capturing the data to a MySQL database. It is not for the faint-of-heart though. It requires a little knowledge of MySQL and willingness to read a tiny bit of perl. I am happy to help you set this up, though. Either via this blog as time allows, or I would love to work for you as an hourly contractor – and I love all things telecom!

If you don’t have a Linux server in your network that you can use for your own purposes, I highly recommend one. Any Linux distribution will do, and you probably have a VMWare infrastructure to support it. If you need to justify it, I can help – perhaps even this blog entry will help. Tell your boss you need to perform text analysis of your PBX data. This blog entry assumes you have Linux, but I suppose it will work on Windows with a LAMP stack (but good luck with local firewall rules in Windows).

So first. you must create a MySQL database to store the call records. Let me know if you need help doing this. Since I have to start somewhere with this post, I will assume you have access to a MySQL database. You just need to create a table to store the data. Here is the statement to do that:

drop table if exists cdr_syslog;
create table cdr_syslog (
 id integer auto_increment primary key,
 method varchar(8),
 reported_on datetime,
 deduced_starttime datetime,
 source_ip varchar(32),
 from_number varchar(24),
 to_number varchar(24),
 call_type varchar(12),
 call_time varchar(16),
 direction varchar(3),
 duration_ss integer,
 call_hash varchar(64),
 pbx_time_of_day_hh varchar(2),
 pbx_time_of_day_mm varchar(2),
 pbx_duration_h varchar(1),
 pbx_duration_mm varchar(2),
 pbx_duration_6s varchar(1),
 pbx_condition_code varchar(1),
 pbx_access_code_dialed varchar(4),
 pbx_access_code_used varchar(4),
 pbx_dialed_number varchar(23),
 pbx_calling_number varchar(14),
 pbx_account_code varchar(15),
 pbx_authorization_code varchar(7),
 pbx_frl varchar(1),
 pbx_incoming_ckt varchar(3),
 pbx_outgoing_ckt varchar(3),
 pbx_feature_flag varchar(1),
 pbx_attendant_console varchar(4),
 pbx_incoming_tac varchar(4),
 pbx_node_number varchar(2),
 pbx_ins varchar(5),
 pbx_ixc varchar(3),
 pbx_bcc varchar(1),
 pbx_ma_uui varchar(1),
 pbx_resource_flag varchar(1),
 pbx_packet_count varchar(5),
 source_line varchar(128),
 created_on datetime
);

alter table cdr_syslog add index i_call_hash(call_hash);
alter table cdr_syslog add index i_deduced_starttime(deduced_starttime);
alter table cdr_syslog add index i_from_number(from_number);
alter table cdr_syslog add index i_to_number(to_number);

Those statements create the table and a few indexes to speed things up. The indexes for call_hash and deduced_starttime are used when inserting records. The indexes for from_number and to_number are added since these are probably the most common fields to query. Typically, I will add an index for any field that appears in my ‘where’ clause, but I’m no DBA so there are probably better ways to tune it. However, this works fine for me and should for you as well.

I am using a Kiwi Syslog server to capture the CDR. But the cool thing about Kiwi is that you can “forward” the message along to another server. So I configured mine to send it to my Linux server. This is the screenshot for that forward command within Kiwi:

kiwi-send-logs-out-via-syslog

This simply sends the Syslog message to my server on UDP port 514. This is the typical Syslog port. Then I have a Perl script running on my server. That Perl script has some dependencies

use strict;
use DBI;
use Net::Syslogd;
use Digest::MD5 qw(md5_hex);
use POSIX qw(setsid);

You don’t need to be familiar with Perl to run this script, but you will need to make sure these packages are installed. For example, if I have a script that runs this line:

use Roger::Wilco;

When I try to run the script, I will get this error:

Can't locate Roger/Wilco.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at syslog.pl line 2.
BEGIN failed--compilation aborted at syslog.pl line 2.

So if you try to run my CDR script and you get any kind of “Can’t Locate” error, then you need to install that package. To to this, type this at a command line:

Perl -MCPAN -e shell

And that will get you to the CPAN command line where you can install packages.

# perl -MCPAN -e shell
Terminal does not support AddHistory.

cpan shell -- CPAN exploration and modules installation (v1.9402)
Enter 'h' for help.

cpan[1]>

And from here, you can type

install Net::Syslogd

Or whatever other packages you need to install. Note that case matters, and that’s a double colon between the words. When it asks you a yes/no question, say yes. If all goes well, then it should install fine. CPAN installs all dependencies. If you get errors, the most common is you don’t have a c++ compiler on your machine. I never did figure out how to fix that in Windows. In Linux, there are lots of tutorials. With that in mind, here is the Perl script that will catch the CDR forwarded from Kiwi. Be sure to read my comments at the end.

#!/usr/bin/perl

### Read unformatted CDR data from an Avaya server
### This script uses Net::Syslogd to listen to standard syslog messages
### The Avaya phone systems send to TCP ports. Unfortunately, this script is to listen from 
### A 'proxy' instance of CDR. for example, a Kiwi Syslog Server that forwards syslog messages
### out to another server.
### see my blog http://rogerthephoneguy.com/?p=404 for details


### Usage!
### set the $dir folder to where you store text files from your syslog server
### and run this script with 'perl cdrd.pl file' to tell the script to process files
### or run as 'perl cdrd.pl' to just watch the processing fly by
### or run as 'perl cdrd.pl -d' as a daemon process
### to stop the daemon, just create a file matching $killfile
### Or do a 'ps -ef |grep cdrd.pl to find the PID
### and kill -9 that pid
### not the best way to manage daemons, but we are telephone engineers here, not linux admins, right?

use strict;
use DBI;
use Net::Syslogd;
use Digest::MD5 qw(md5_hex);
use POSIX qw(setsid);

my $db;
my $dir = "/home/roger/avaya/cdr/data/";
my $killfile = "/home/roger/avaya/cdr/cdrd.end";


sub db_open {
        my $dsn = "DBI:mysql:dbname_ie_avaya:localhost";
        my $user = "dbuser";
        my $pass = "dbpassword";
        while (!($db)) {
                $db = DBI->connect($dsn, $user, $pass);
        }
}

sub db_close {
        if($db) {
                $db->disconnect();
        }
        undef($db);
}

sub sql { #check
        my ($sql) = (@_);
        my $sth = $db->prepare($sql);
        if(!($sth->execute())) {
                print "WARNING - unable to execute $sql\n";
        }
        $sth->finish();
}

sub generic_create {
        my ($table, $fields, $values) = (@_);
        my $sql = "insert into $table ($fields) values ($values)";
        my $sth = $db->prepare($sql);
        if(!($sth->execute())) {
                print "WARNING - unable to insert with $sql\n";
        }
        $sth->finish();
}

sub generic_read {
        my ($select, $table, $where) = (@_);
        my @datarow;
        my $sql = "select $select from $table where $where limit 1";
        my $sth = $db->prepare($sql);
        if($sth->execute()) {
                @datarow = $sth->fetchrow_array();
        } else {
                print "unable to execute $sql\n";
        }
        $sth->finish();
        return $datarow[0];
}

sub one {
        my ($sql) = (@_);
        my @datarow;
        my $sth = $db->prepare($sql);
        if($sth->execute()) {
                @datarow = $sth->fetchrow_array();
        } else {
                print "unable to execute $sql\n";
        }
        $sth->finish();
        return $datarow[0];
}

sub process_cdr_line {
    my $cdr = shift;
    chomp($cdr);
    my ($logtime,$facsev,$remoteaddr,$message) = split(/\t/,$cdr);
    my $md5message = md5_hex($message);
    #print "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n$message";
    #here are the start and length of each data point within the message of an "unformatted" cdr line
    #Nobody knows what some of these are. It's a mystery today
    #your condition codes may be different, so you should watch your data closely for several days
    my @parses = (
        0,2,     #time of day hours
        2,2,     #time of day minutes
        4,1,     #duration hours
        5,2,     #duration minutes
        7,1,     #duration tenths
        8,1,     #condition code
        9,4,     #access code dialed
        13,4,    #access code used 
        17,15,     #dialed number
        32,10,     #calling number
        42,15,     #account code
        57,7,     #auth code
        66,1,     #frl
        67,3,     #incoming ckt
        70,3,     #outgoung ckt
        73,1,     #feature flag
        70,4,     #attendant console
        76,4,     #incoming tac
        82,2,     #node number
        84,4,     #INS
        88,3,     #IXC
        92,1,     #BCC
        93,1,     #MAUUI
        94,1,    #Resource flag
        95,4    #packet count
    );
    my $values = '';
    my $insert;
    my $i;
    my $calltime;
    my $duration;
    my $direction = 'unk';
    my $dialed;
    my $calling;
    my $node = '01';
    my $condition;
    for($i=0; $i<25; $i++) { my $start = $parses[$i*2]; my $length = $parses[$i*2+1]; my $part = substr($message,$start,$length); #print "this $i from $start with length $length is '$part'\n"; $part =~ s/^ *//g; $part =~ s/ *$//g; if($i == 0) { #time of day hh $calltime = "$part:"; } elsif($i == 1) { #time of day mm $calltime .= $part; } elsif($i == 2) { #duration h $duration = $part * 60 * 60; } elsif($i == 3) { #duration mm $duration += ($part * 60); } elsif($i == 4) { #duration 1/10 min (6 sec) $duration += ($part * 6); } elsif($i == 5) { #condition code $condition = $part; if($part == 9) { $direction = "in"; } elsif($part == 7) { $direction = "out"; } } elsif($i == 8) { #dialed number $dialed = $part; $dialed =~ s/E$//; if(($dialed ne '6226') && ($dialed =~ /^6[234]\d\d$/)) { $node = '44'; } } elsif($i == 9) { #calling number $calling = $part; $calling =~ s/E$//; if(($dialed ne '6226') && ($dialed =~ /^6[234]\d\d$/)) { $node = '44'; } } elsif($i == 17) { #incoming tac if($part =~ /^#0\d\d/) { $node = '44'; } } elsif($i == 18) { #node number $part = $node; } $values .= "'$part',"; } if($direction eq "in") { my $temp = $dialed; $dialed=$calling; $calling=$temp; } if(($dialed =~ /^\d*$/) && ($calling =~ /^\d*$/)) { #dialed_name and calling_name are filled from a 'display_name' table that is not part of this demo. #for more information, contact me through RogerThePhoneGuy.com and we can chat about how this table is filled my $dialed_name=''; #generic_read("name", "avaya_display_name","station='$dialed'"); my $calling_name=''; #generic_read("name", "avaya_display_name","station='$calling'"); $dialed_name =~ s/'/\\'/g; $calling_name =~ s/'/\\'/g; #print "logtime:$logtime\ncondition $condition\ndirection $direction\ndialed $dialed ($dialed_name)\ncalling $calling ($calling_name)\nduration $duration\n"; $insert = "insert into cdr_syslog values (null,'syslog','$logtime',null,'$remoteaddr','$calling','$calling_name','$dialed','$dialed_name','type','$calltime','$direction',$duration,'$md5message',"; $insert .= "$values '$message',now())"; my $check = one("select count(*) from cdr_syslog where call_hash = '$md5message'"); #print "hash check = $check\n"; if($check == 0) { #We insert the md5 of this line, to prevent double-logging. This allows us to re-process the cdr as much as necessary w/o dups in the database #print "$insert\n"; sql($insert); sql("update cdr_syslog set deduced_starttime = DATE_SUB(reported_on,INTERVAL duration_ss SECOND) where call_hash='$md5message'"); } else { #print "duplicate\n"; } } else { $insert = "insert into pbx_syslog values (null,'$message')"; #sql($insert); } } sub daemonize { #check open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; open STDOUT, '>>/dev/null' or die "Can't write to log: $!";
    open STDERR, '>>/dev/null' or die "Can't write to log: $!";
    defined(my $pid = fork)   or die "Can't fork: $!";
    exit if $pid;
    setsid                    or die "Can't start a new session: $!";
    umask 0;
}

if($ARGV[0] eq "-d") {
    daemonize;
}

db_open();

if($ARGV[0] eq "file") {
    opendir(DH, $dir);
    my @files = readdir(DH);
    closedir(DH);
    foreach my $file (@files) {
        open CDR, "$dir$file";
        my $i = 0;
        while (my $line = ) {
            $i++;
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time);$mon++;$year+=1900;
            $line =~ s/[^!-~\s]//g; #strips unprintable
            process_cdr_line($line);
            #die if($i>2);
        }
        print "$dir$file - $i lines\n";
        close CDR;
        unlink "$dir$file";
    }

} else {
    my $syslogd = Net::Syslogd->new()
      or die "Error creating Syslogd listener: ", Net::Syslogd->error;

    while (!(-e $killfile)) {
        my $message = $syslogd->get_message();
        if (!defined($message)) {
            printf "$0: %s\n", Net::Syslogd->error;
            exit 1;
        } elsif ($message == 0) {
            next
        }

        if (!defined($message->process_message())) {
            printf "$0: %s\n", Net::Syslogd->error
        } else {
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time);$mon++;$year+=1900;
            my $logtime = sprintf("%04d-%02d-%02d %02d:%02d:%02d",$year,$mon,$mday,$hour,$min,$sec);
            my $remoteaddr = $message->remoteaddr;
            my $remoteport = $message->remoteport;
            my $facility = $message->facility;
            my $severity = $message->severity;
            my $time = $message->time;
            my $hostname = $message->hostname;
            my $msg = $message->message;
            my $line = "$logtime\t$facility.$severity\t$remoteaddr\t$msg\n";
            print $line;
            #now $line looks like any line from the CDR files
            #so this next part works via syslog or files
            $line =~ s/[^!-~\s]//g; #strips unprintable
            process_cdr_line($line);
        }
    }
    unlink $killfile;
}

db_close();

There’s a lot in that script. Things you must know:

  1. You’ll need to replace the database name, username, and password in the “db_open” subroutine.
  2. The comments at the top explain how to run it to process files, or to capture syslog live, or even how to run as a daemon.
  3. Each CDR line is hashed and included in the record, so don’t worry about processing the CDR files multiple times. It will NOT insert duplicate records.
  4. When processing files, the script will delete the file when done. So always copy the CDR files into a separate folder before running this script.
  5. I kludged this together from a working Perl script. I removed some identifying information, moved some variables around, and added a bunch of comments. If you get any errors, let me know – it’ll probably be really easy to fix.
  6. For any hobbyist Perl developers out there, this script includes some handy database functions that insert records, return rows, and return one record.
  7. This script is for information purposes only. Naturally, I don’t provide any warranties, guarantees, or assertions that it will work with your systems. Run it at your own risk.
  8. If you’d like me to help set this up, I’d love to work for you. I love telecom and I’m always available for hire as a consultant. I would LOVE to be your telephone guy!

If you’re planning on trying this, then I’m really flattered. Let me know how it goes. Mine has been running for about two years and I cannot tell you how handy it is to have that much CDR data in a MySQL table. I have a PHP script that I use to analyze the data. Do you want to see that?

Thanks all,

Roger

 

Avaya Call Detail Recording to Kiwi syslog server

In a previous post about busy/release of CDR, I asked if anyone was curious about capturing CDR from Avaya Communication Manager using a Kiwi Syslog server. At least one of you was, so here it is.

There are two parts of course. One part is programming the phone system to send CDR. And the other part is programming Kiwi to capture CDR. These can be done in either order, but if you program the phone system first, the CDR buffer will fill as is tries to establish the connection with Syslog.

So let’s start with Kiwi. Your version may differ. In my case, the network team already had a rather powerful installation of Kiwi on some great hardware. All I had to do was configure it to capture Avaya CDR. So when you launch the Kiwi dashboard, click File->Setup and in the “Server Setup” window, scroll to the bottom for “Inputs”.

kiwi-config-0

In the TCP section, tell Kiwi to listen for TCP messages on whatever port you wish. I’m using 5013 – probably because I saw it in an Avaya doc somewhere. But you can use any port.

Then scroll up to the “Rules” section and configure a new rule to match for messages from your Avaya Communication Manager.

kiwi-config-1

In my case, I named my rule “Call Records from LA PBX”. I set a filter by IP address. If you also send any other information to Kiwi from the CMs, then you’ll want to filter by the Priority field. You want the Local7 field to be Debug. I don’t recall why this works. I think I was looking at the data one day to try to separate the CDR from the other syslog messages from Avaya and this seemed the easiest way to do it.

kiwi-config-3

Once you have those two filters – IP address and Local7.Debug, you need to create an action. My action above is a little misleading. All you really need is one that logs to a file, then stops processing. If you’d like, you can also display it to one of the virtual displays in Kiwi. I log to a text file on the local file system:

kiwi-config-2

Now, if we program our PBX correctly, we should get CDR to these text files!

Step 2 – Program the Avaya Communication Manager

Programming the Communication Manager is three steps: Add the node-name, set the ip-services, and change the system-parameters cdr.

To set the node name, ‘change node-name ip’ and create an entry for the IP address of your Kiwi server. This is basically the DNS lookup for the CM. This sets the name and IP address. Any name will do. Enter the IP address of your Kiwi server.

change node-names ip                                            Page   1 of   2
                                  IP NODE NAMES
    Name              IP Address
SL_LSP              10.10.60.10
CHA_LSP             10.10.1.10
Chicago             10.10.148.2
Chicago_LSP         10.30.10.10
DO_LSP              10.20.16.10
Smoot               10.87.176.11
Gateway006          10.46.12.1
LA                  10.10.19.6
LA_ESS              10.44.192.10
LE_ESS              10.58.200.10
LA_SM               10.59.29.16
( 16 of 44   administered node-names were displayed )
Use 'list node-names' command to see all the administered node-names
Use 'change node-names ip xxx' to change a node-name 'xxx' or add a node-name

Next, set the ip-services. I have squeezed all three screens here. The important thing here is page three. We need to set the “Reliable Protocol” to n. I think Avaya defaults this to y and it works great for their pre-packaged CDR partners. For home-grown syslog, we set this to n. It may not hold up in court if there’s ever a dispute.

change ip-services                                              Page   1 of   3

                                   IP SERVICES
 Service     Enabled     Local        Local       Remote      Remote
  Type                   Node         Port        Node        Port
CDR1                 procr            0       la_syslog       5013
CDR2                 procr            0       prognosis       50000

change ip-services                                              Page   2 of   3

                                   IP SERVICES
 Service     Enabled     Local        Local       Remote      Remote
  Type                   Node         Port        Node        Port


change ip-services                                              Page   3 of   3

                              SESSION LAYER TIMERS
  Service     Reliable  Packet Resp   Session Connect  SPDU  Connectivity
   Type       Protocol     Timer       Message Cntr    Cntr     Timer

 CDR1            n         10                3          3         10
 CDR2            n         10                3          3         10


And last step – set the system-parameters for CDR. Here’s the thing. You have lots of options here. You can define fields, separators, etc. But I discovered that there is a line length limit that is not obvious. Also, the caller-id name is surprisingly absent. Rather than customize the CDR, I have gone back to “unformatted” and let further processing figure it out.

change system-parameters cdr                                    Page   1 of   1
                            CDR SYSTEM PARAMETERS

 Node Number (Local PBX ID): 2                     CDR Date Format: month/day
      Primary Output Format: unformatted   Primary Output Endpoint: CDR1
    Secondary Output Format: unformatted Secondary Output Endpoint: CDR2
           Use ISDN Layouts? n                   Enable CDR Storage on Disk? n
       Use Enhanced Formats? n      Condition Code 'T' For Redirected Calls? n
      Use Legacy CDR Formats? y                 Remove # From Called Number? n
Modified Circuit ID Display? n                             Intra-switch CDR? y
                  Record Outgoing Calls Only? n     Outg Trk Call Splitting? y
  Suppress CDR for Ineffective Call Attempts? n       Outg Attd Call Record? y
      Disconnect Information in Place of FRL? y      Interworking Feat-flag? n
 Force Entry of Acct Code for Calls Marked on Toll Analysis Form? n
                                    Calls to Hunt Group - Record: member-ext
Record Called Vector Directory Number Instead of Group or Member? n

     Inc Trk Call Splitting? n
  Record Non-Call-Assoc TSC? n           Call Record Handling Option: warning
      Record Call-Assoc TSC? n   Digits to Record for Outgoing Calls: dialed
   Privacy - Digits to Hide: 0               CDR Account Code Length: 15
Remove '+' from SIP Numbers? y


I have a perl script that parses unformatted cdr. Anyone want to see it?

Anyway, when you have this set up, you can status CDR to make sure the link is up:

status cdr-link
                                CDR LINK STATUS
                   Primary                      Secondary

       Link State: up                           up

      Date & Time: 2016/04/17 08:43:29          2016/05/09 10:12:20
  Forward Seq. No: 0                            0
 Backward Seq. No: 0                            0
CDR Buffer % Full:   0.00                         0.00
      Reason Code: OK                           OK





The good news here is the link state(s) are “up”  and the CDR buffer % full is 0. If you have trouble, you can “busy cdr primary” and “release cdr primary” to close and open the socket. You should see a blip in the Kiwi server when this happens.

Make a call and watch Kiwi! You may need to check the log files rather than rely on the Kiwi display. The extra CR/LF will sometimes make Kiwi look funky but the text file is usually just fine.

Let me know how it goes for you!

Roger

 

Avaya phone reboots, and then doesn’t have dialtone

I have had this problem in three offices starting in 2013. And it just happened to me today in an overseas office. This problem can remain hidden in your telephone system for years and not be a problem because it’s so rare for a phone to get assigned a new IP address via DHCP.

Basically, a phone reboots for some reason. When it comes back up, there’s no dialtone. Or, if you have more than one gateway,  you might get intermittent dialtone.

In my network, these items were also true:

  1. The gateway and the phones are on the same subnet
  2. The phone was assigned a different IP address when it rebooted (this may not be obvious since you don’t always know the phone’s previous IP address)

If you have more than one gateway, the problem might seen intermittent. you can “list trace station” and watch the phone pull dialtone:

12:19:49   G711A ss:off ps:20
           rgn:1 [10.9.10.90]:39798
           rgn:1 [10.9.10.3]:2094

That IP address on the third line – that’s the gateway assigned to serve dialtone for this call. In my case, I have a gateway in the local office, and a gateway in the datacenter. Whenever the user said “hey, there’s no dialtone!”, it had drawn a resource from the local gateway in the same subnet. The phone worked in all other ways – there was just no media.

There are MILLIONS of Avaya forum postings regarding no dialtone, one-way audio, etc. In my case here, the problem was caused by the arp cache in the G450 gateway. That’s pretty obscure. The IP address changed, but the MAC address in the arp cache did not change. So the gateway is trying to feed dialtone to the wrong MAC address.

The fix was simple: log into the G450 and issue these commands:

  • no ip arp inspection‘ (this disables arp caching)
  • clear arp-cache‘ (this clears the arp-cache, which sounds scary but will not affect service)
  • copy run start‘ (this will write the settings to flash memory to survive a reboot)

That fixed the issue of no dialtone. It did not fix the issue of phones rebooting and getting different IP addresses though. I will write a different post for that, since it was a completely unrelated issue.

I hope this helps! Please let me know if this works for you.

Roger

How to load-test your telephone system, IVR, or DID number port

When you work on telephone systems, at some point you need to make some test calls into your trunks. And sometimes it’s not realistic to use the same phone at your desk, since the call may not truly leave your PBX or your carrier’s network. So you end up using your mobile phone,or if you’re remote, then your home phone. However,

  • What if you need to make dozens of calls?
  • What if you need to load up a trunk group?
  • What if you need to test a number port of hundreds of individual DIDs?
  • What if you need to simulate calls from different areas of the country?
  • What if you need to dial an extremely specific sequence of digits once connected, and you need to do this over-and-over-and-over?

About a year ago, I found a great tool called CallsByCloud.com. This is an automated testing framework – completely self service using your browser. I liked it so much I became a business partner recommend it highly to all of you telecom administrators. I even recorded the training videos for them.

It’s very straight-forward to use. You build a “test scenario” that contain simple “scripts” that are use cases for each type of call. If you’re testing a call center IVR, this could be “make payment” or “renew contract” or “queue for customer service”. And if you’re just testing a trunk group, you can dial into your PBX and “hold” the channel for x seconds. This lets you load the trunk group and test overflow.

cbc-script-commands

Once the tests are complete, you can see the call history, channel usage, a spectrogram of the call, and you can listen to or download the audio.

cbc-history

Once you set up a test, you can schedule it to run at a recurring time and alert you if there are any problems with the call.

cbc-qa-schedule

There are other advanced features such as

  • Caller-id manipulation to simulate geographic routing.
  • Detailed logs of the call processing.
  • Number pooling for testing multiple numbers.
  • The ability to set a “disposition” or “goto” a different spot in the script based upon the timing of noise, silence, or DTMF in the channel.
  • The ability to export call records for the tests.

It’s flexible, cost effective, and has made my job so much easier. I recommend it highly to all of you. If you sign up and use the promotion code ‘roger2015’, you’ll get $10 in credit when you sign up and a 20% discount on the per-minute rate.

Check out the training videos and let me know what you think!

Thanks for watching!

Roger

 

How to reboot the Avaya S8300D from the G-Series gateway

I recently had a problem logging into System Platform. I could not connect to the CDOM via the web, nor SSH into DOM0. Fortunately, there is a way to reboot the S8300D from the gateway itself. Log into the gateway as root, then type “configure” to get to the config menu. Then simply type “reset mm v1”, which will reboot the media module in slot V1. Confirm, and the card will reboot. From my understanding, it will cleanly shut down each VM and reboot.

As always, it will take just long enough for you to panic, plus 45 seconds or so.

 

How to unlock a locked Avaya CM / SAT login

Every once in a while, your login may lock out. And if you use just one, or if you have some scripts using one, you might not want to wait for the account to unlock automatically (hopefully it does).

login as: telecom

This system is restricted solely to authorized users for legitimate business 
purposes only. The actual or attempted unauthorized access, use or modifications 
of this system is strictly prohibited. Unauthorized users are subject to company 
disciplinary procedures and or criminal and civil penalties under state, federal 
or other applicable domestic and foreign laws.

The use of this system may be monitored and recorded for administrative and 
security reasons. Anyone accessing this system expressly consents to such 
monitoring and recording, and is advised that if it reveals possible evidence of 
criminal activity, the evidence of such activity may be provided to law 
enforcement officials. All users must comply with all corporate instructions 
regarding the protection of information assets.
Using keyboard-interactive authentication.
Your account is locked. Maximum amount of failed attempts was reached.
Password:

So here are three things that are totally obvious once you’ve done it once.

  1. Have another login handy. Create a second just-in-case. This is easy also, but not completely straightforward.
  2. Check your account lockout policy. This is done via the web interface at Security->Login Account Policy. You can set the number of failed accesses that trigger a lockout and the time the account is locked.
  3. You can manually unlock an account via the web interface at Security->Administrator Accounts. You can “Change Login” and uncheck the “Lock This Account” checkbox, or you can go to Security->Administrator Accounts and select the “Lock/Unlock Login” and it will toggle the locked status.

Here are a couple screenshots showing the lockout policy (at the end of the Login Account Policy screen) and the account lockout screens.

avaya-cm-account-policy

avaya-cm-unlock-login

 

Update – there’s another way to do this. From the SSH command line in your CM, simply type

userlock -u cust unlock

So… should I delete the rest of this post? Probably not. I suppose you may want to teach your helpdesk folks how to use the GUI rather than the terminal. So there you go.

How to “kick” an Avaya Local Survivable Processor without rebooting

I recently had an Avaya Local Survivable Processor (LSP) unregister. There was no indication why – it just went down. I was able to get to its web interface, and it had a minor alarm indicating that it was unregistered. I suppose I could have restarted the whole thing, but my tech talked me through this procedure, which worked great.

Please note that the LSP is typically registered and inactive. This LSP only activates if network connectivity is lost to the site. So if the home site is available through the WAN, it should look like this:

list survivable-processor
                             SURVIVABLE PROCESSORS
 Record Name/            Type         Reg Act         Translations      Net
 Number  IP Address                                   Updated           Rgn
  1     THE_LSP          LSP           y   n          2:02 12/30/2013   10
         10.2.10.110
        No V6 Entry

However, in my case it looked like this!

list survivable-processor
                             SURVIVABLE PROCESSORS
 Record Name/            Type         Reg Act         Translations      Net
 Number  IP Address                                   Updated           Rgn
  1     THE_LSP          LSP           n                                10
         10.2.10.110
        No V6 Entry

No entry to indicate the active status nor the last translation date. I was able to SSH to the LSP and I confirmed the LSP wasn’t active. The media gateway was still connected to my home site. The LSP could ping the home site. Somehow, the LSP was simply lost.

So I confirmed all CM processes were up with the “statapp” command:

telecom@pbx-cm01> statapp
Watchdog         9/ 9 UP SIMPLEX
TraceLogger      3/ 3 UP SIMPLEX
LicenseServer    2/ 2 UP SIMPLEX
SME              6/ 6 UP SIMPLEX
MasterAgent      1/ 1 UP SIMPLEX
MIB2Agent        1/ 1 UP SIMPLEX
MVSubAgent       1/ 1 UP SIMPLEX
LoadAgent        1/ 1 UP SIMPLEX
FPAgent          1/ 1 UP SIMPLEX
INADSAlarmAgent  1/ 1 UP SIMPLEX
GMM              4/ 4 UP SIMPLEX
SNMPManager      1/ 1 UP SIMPLEX
filesyncd        1/ 1 UP SIMPLEX
MCD              1/ 1 UP SIMPLEX
CommunicaMgr    86/86 UP SIMPLEX
telecom@pbx-cm01>

Sure enough, all processes were running fine. So I stopped CM with the command

stop -afcn

This will stop the processes listed above, refreshing as it goes. It’s pretty nice. When all processes have stopped, you can start CM again with

start -ac

Again, it refreshes the screen as the processes start back up. When it’s done, the LSP should re-register. It’s also a good idea to watch the home CM for this register event. About 30 seconds after the CM comes back, you should see it. In your home site, do a

list trace ras ip-a 10.2.10.110

while the LSP processes restarts.

Here is the register event

list trace ras ip-address 10.2.10.110

                                LIST TRACE

time            data

17:45:39 TRACE STARTED 12/30/2013 CM Release String cold-03.0.124.0-21166
17:46:37   rcv RRQ ext
                   endpt  [10.2.10.110]:1719
                   switch [10.1.10.110]:1719
17:46:52   rcv KARRQ ext
                   endpt  [10.2.10.110]:1719
                   switch [10.1.10.110]:1719
17:47:07   rcv KARRQ ext
                   endpt  [10.2.10.110]:1719
                   switch [10.1.10.110]:1719
17:47:20   RAS TRACE COMPLETE ext

Those KARRQ messages are the keepalives.

After this restart, the LSP was registered fine. No service impact at the site, as the LSP is inactive unless the WAN goes down. And much less scary (for me anyway) than restarting the whole LSP.

Happy New Year everyone!

How to integrate Avaya Communication Manager and Session Manager 6.1 with Asterisk

As with most technical documents of this type, I wrote this because I could not find this information no matter how many Google searches I tried. There’s information about connecting Avaya Communication Manager directly with Asterisk using the H.323 channel drivers, there’s information regarding integration with the Avaya SIP Enablement Server, and I did find some information about some older versions of System Manager.

However, even the information I did see was a simple lab assignment. There was no information on actually using the new integration to do cool things. Some of you may have been tasked with integrating the Avaya PBX with Microsoft Lync. This tutorial provides a great proof-of-concept for Lync integration. We can test everything with Asterisk and it all in the telecom sandbox at your company.

This tutorial is for those of you who already have an Avaya Communication Manager and one or more Session Managers already set up – probably because you’re using Modular Messaging 6.x. Therefore, you have all the ingredients you need to add Asterisk to the mix.

Okay, so let’s assume your Communication Manager is already connected to Session Manager. Often this is the case due to the fact that Modular Messaging is now SIP based and uses Session Manager to connect to Communication Manager. I wanted to connect my Avaya Communication Manager to an Asterisk system. To do so, I need to know a few things about my existing infrastructure. You may already know these things about your PBX. If so, skim this part and skip to “Build the Route to Asterisk”

Part 1 – Confirming the current integration

So how is your Communication Manager connected to Session Manager? Let’s follow the rabbit:

First, look at the pilot number for voicemail, you’ll probably see that it’s a hunt group pilot number. Let’s say your voicemail pilot extension is 2000:

list usage extension 2000
                             LIST USAGE REPORT
Used By
Hunt Group           Group Number         5                      Group Ext

Now display that hunt group

display hunt-group 5                                            Page   2 of  60
                                  HUNT GROUP

                      Message Center: sip-adjunct

     Voice Mail Number        Voice Mail Handle         Routing Digits
                                                 (e.g., AAR/ARS Access Code)
     3992000                  sipmm-la                  801

This pilot number dials the AAR feature code, then 3992000. Now list aar:

list aar analysis                                                      Page   1
                           AAR DIGIT ANALYSIS REPORT
                            Location:  all
               Dialed            Total        Route    Call      Node
               String          Min    Max    Pattern   Type     Number
         1010                   4      4      13       aar
         14                     6      6      40       aar
         3990022                7      7      29       aar
         3992000                7      7      92       aar
         4010                   4      4      19       aar
         4099                   4      4      44       aar

And you can see that 3992000 goes to route pattern 92. Now look at route 92

display route-pattern 92                                        Page   1 of   3
                    Pattern Number: 92  Pattern Name: MM -LA
                             SCCAN? n     Secure SIP? n
    Grp FRL NPA Pfx Hop Toll No.  Inserted                             DCS/ IXC
    No          Mrk Lmt List Del  Digits                               QSIG
                             Dgts                                      Intw
 1: 91   0                    3                                         n   user
 2: 92   0                    3                                         n   user
 3: 93   0                    3                                         n   user
 4:                                                                     n   user
 5:                                                                     n   user
 6:                                                                     n   user

In my case, I have three Session Managers. I just care about the first one for now. So note that the first trunk group is 91. Now display trunk group 91:

display trunk-group 91                                          Page   1 of  21
                                TRUNK GROUP

Group Number: 91                   Group Type: sip           CDR Reports: y
  Group Name: MM SIP to LA                COR: 22       TN: 1        TAC: 815
   Direction: two-way        Outgoing Display? n
 Dial Access? n                                   Night Service:
Queue Length: 0
Service Type: tie                   Auth Code? n
                                              Member Assignment Method: auto
                                                       Signaling Group: 91
                                                     Number of Members: 96

And note that this trunk group uses signaling group 91. Now display signaling group 91:

display signaling-group 91 
                                SIGNALING GROUP

 Group Number: 299            Group Type: sip
  IMS Enabled? n        Transport Method: tls
        Q-SIP? n                                             SIP Enabled LSP? n
     IP Video? n                                   Enforce SIPS URI for SRTP? y
  Peer Detection Enabled? y  Peer Server: SM

   Near-end Node Name: procr                 Far-end Node Name: sipmm-la
 Near-end Listen Port: 5061                Far-end Listen Port: 5061
                                        Far-end Network Region: 5

Far-end Domain: corp.abc.com
                                             Bypass If IP Threshold Exceeded? n
Incoming Dialog Loopbacks: eliminate                  RFC 3389 Comfort Noise? n
         DTMF over IP: rtp-payload            Direct IP-IP Audio Connections? y
Session Establishment Timer(min): 3                     IP Audio Hairpinning? n
         Enable Layer 3 Test? y                   Initial IP-IP Direct Media? n
H.323 Station Outgoing Direct Media? n            Alternate Route Timer(sec): 6

And note that this signaling group connects the Communication Manager main processor (procr) to a node name called sipmm-la. Now list node-names:

list node-names all                                                    Page   4

                        NODE NAMES

Type     Name              IP Address
IP       cm-oc01p          10.5.20.131
IP       default           0.0.0.0
IP       iolan-la          10.2.4.21
IP       medpro-la1        10.2.4.22
IP       medpro-la2        10.2.4.23
IP       medpro-la3        10.2.4.24
IP       medpro-la4        10.2.4.25
IP       medpro-ny1        10.7.4.26
IP       medpro-ny2        10.7.4.27
IP       medpro-oc1        10.5.20.51
IP       medpro-oc2        10.5.20.52
IP       procr             10.2.20.20
IP       procr6            ::
IP       sipmm-la          10.5.20.139

And note that the node name is IP address 10.5.20.139. So in a nutshell, when I dial the voicemail pilot number, the call gets routed to my local session manager 10.5.20.139. That’s pretty much all we needed to know from the Communication Manager point of view.

Part 2 – Building the Route to Asterisk via Session Manager

What we really want is to set up a new route with new extensions between Communication Manager and Session Manager. Next we’ll configure Session Manager to understand a new number range and route it over to Asterisk.

In the case of a single pilot number, I could duplicate the hunt group method that is already set up. However, for more flexibility, I wanted a range of numbers to route to Asterisk. Or even if I do want to point individual numbers, I don’t want to create hunt groups for each one – I just want the number to route over to Asterisk through AAR routing.

So in my case, I had a spare DID number range ending in 44xx that I wanted to send over to Asterisk. So in CM, any four-digit number starting with 44 should go to Session Manager. Note that my route pattern 92 above deletes three digits. I don’t want to delete the first three digits of my 44xx extensions, so I will create a new route pattern that points to the same 91 trunk group. In my case, I used 90:

display route-pattern 90                                        Page   1 of   3
                    Pattern Number: 90  Pattern Name: SIP to SM
                             SCCAN? n     Secure SIP? n
    Grp FRL NPA Pfx Hop Toll No.  Inserted                             DCS/ IXC
    No          Mrk Lmt List Del  Digits                               QSIG
                             Dgts                                      Intw
 1: 91   0                                                              n   use

Now I want to point an entire internal number range to this route using AAR. So the first thing I need to do is edit my uniform dial plan so CM will use AAR routing when I dial this range:

list uniform-dialplan start 41                                         Page   2
                      UNIFORM DIAL PLAN TABLE

 Matching Pattern   Len   Del   Insert Digits   Net    Conv   Node Num

 4129                4     0                    ext     n
 4152                4     0                    ext     n
 4156                4     0                    ext     n
 4163                4     0                    ext     n
 4171                4     0                    ext     n
 4232                4     0                    ext     n
 44                  4     0                    aar     n
 4541                4     0                    ext     n
 4552                4     4      2089          ext     n
 4583                4     0                    ext     n
 4596                4     0                    ext     n
 4598                4     0                    ext     n

Fortunately CM is very forgiving with aar vs. ext. If I can digress for one screenshot, note that my dialplan analysis table defines all four-digit patterns that begin with 4 as extensions. However, I am able to override this in the uniform dialplan table and point these to aar in the table entry above.

display dialplan analysis                                       Page   1 of  12
                             DIAL PLAN ANALYSIS TABLE
                                   Location: all            Percent Full: 5

    Dialed   Total  Call     Dialed   Total  Call     Dialed   Total  Call
    String   Length Type     String   Length Type     String   Length Type
   0           4   ext      37          4   ext      77          4   ext
   20          4   ext      4           4   ext      78          4   ext
   21          6   ext      5           4   ext      79          4   ext
   22          6   ext      51          6   ext      888         3   fac
   23          6   ext      64          4   ext      
   24          6   ext      65          4   ext      
   25          6   ext      66          4   ext      
   26          6   ext      67          4   ext      
   27          4   ext      72          4   ext      
   29          6   ext      73          4   ext

So back to CM routing. Now that I have defined 44xx to point to the aar table, let’s create the aar entry we need to send this to Session Manager:

list aar analysis                                                      Page   1
                           AAR DIGIT ANALYSIS REPORT
                            Location:  all
               Dialed            Total        Route    Call      Node
               String          Min    Max    Pattern   Type     Number
         1010                   4      4      1        aar
         14                     6      6      400      aar
         3990022                7      7      298      aar
         3992000                7      7      299      aar
         4010                   4      4      11       aar
         4099                   4      4      44       aar
         44                     4      4      90       aar
         63xx                   4      4      25       aar
         74                     4      4      24       aar
         750                    6      6      299      aar

Now any four digit numbers starting with 44 will route (via route pattern 90) over to my session manager. Next, we need to configure session manager to route these to Asterisk!

Part 3 – Configuring Session Manager via System Manager

Now, I don’t know your experience with System Manager, but it seems that if I turn my back for a few weeks, the Admin password stops working and I have to reset it via SSH. Hopefully you have better luck than I do.

Major Gotcha: The first time I worked on this routing in System Manager, I just couldn’t get the calls to work. They would die in Session Manager with extremely unhelpful errors. After some troubleshooting, I discovered my changes weren’t synchronizing between System Manager and Session Manager. I had to go into Home->Replication and “repair” the replica group. I have done this several times since then and all of my calls during replication route fine. I don’t think it is service-affecting (with my configuration anyway). Your results may vary. Be careful.

avaya-smgr-replica1

 

I’ve worked on PBXs for a long time. Naturally, it can sometimes take a while to get comfortable with the GUI or command line of new systems. System Manager was tough for me. It’s such an abstraction from the actual routing engine (Session Manager) and I don’t get a chance to use a command line. I guess web interfaces drive me crazy for that reason – they’re a front-end to the actual magic, and I like to be closer to the soul of a PBX.

Enough rant – the actual configuration all takes place within Home->Routing. I just went in order down the list on the left. First, I configured a location called “LA-Asterisk”.

avaya-location-asterisk

 

avaya-location-asterisk-details

 

Next I created an Adaptation also called LA-Asterisk. Note in the screenshot below, there is a 4-digit extension pattern defined. We will do this later.

avaya-adaptation1 avaya-adaptation-asterisk

Next, create a SIP Entity. This is where you define your Asterisk server

avaya-sip-entity1

 

Next, create the Entity Link to “connect” your Asterisk and Session Manager together:

avaya-sip-entity-link

 

In my case, I went for simple UDP connectivity. Next I create the Routing Policy for Asterisk:

avaya-routing-policy1

 

Don’t worry about dial patterns or regular expressions on this screen. Just set up a SIP Entity and Time of Day and commit.

Then the Dial Pattern:

avaya-dialpattern-asterisk

 

 

Note in my case, the PBX is sending the full E.164 number to Session Manager. Well, this isn’t entirely accurate. To digress again, the PBX is sending the regular extension, but the Adaptation for Communication Manager defines several digit conversion rules to convert these to E.164 numbers. This allows for a very flexible system within Session Manager. As a result of this digit conversion, the internal routing of the Session Manager uses the E.164 numbers and this is what you see when you trace. Here are my Adaptation rules:

avaya-adaptation-digit-conversion

 

I’ve erased the DID numbers there – I’m not much of a photo editor. You can see how the various extension ranges and lengths translate into E.164. Note that four-digit non-DIDs are translated to +1000000xxxx. This is how Avaya set up this site and I assume the best practice. I work at another site (set up by an Avaya business partner) that was not normalized to E.164 and it’s been kind of a pain to manage as we’ve added DIDs and extensions.

So back to Communication Manager routing: do you remember way back when I mentioned you could use the “hunt group” routing to send calls to Asterisk? I created a hunt group in CM that looks like this:

display hunt-group 9                                            Page   1 of  60
                                  HUNT GROUP

            Group Number: 9                                ACD? n
              Group Name: Asterisk                       Queue? n
         Group Extension: 2022                          Vector? n
              Group Type: ucd-mia                Coverage Path:
                      TN: 1          Night Service Destination:
                     COR: 21                   MM Early Answer? n
           Security Code:               Local Agent Preference? n
 ISDN/SIP Caller Display: mbr-name

display hunt-group 9                                            Page   2 of  60
                                  HUNT GROUP

                      Message Center: sip-adjunct

     Voice Mail Number        Voice Mail Handle         Routing Digits
                                                 (e.g., AAR/ARS Access Code)
     3992022                  ast-la                    888

This hunt group will send calls to 2022 over to Session Manager with a dial pattern of ast-la. You can then create a regular expression in System Manager to match this pattern:
avaya-regular-expression

Why would you want to do this? Well, this is how the Avaya technicians originally set up the routing to Modular Messaging. I suspect it allows the SIP header to retain the original dialed number as it is passed across. There’s a “diversion” header in the SIP invite, and this is how the originally-dialed number gets to Modular Messaging. I happened to set this up in a desperate attempt to get Session Manager to route for me. When I use the traceSM utility in Session Manager, I noticed that Session Manager was not trying to find a match for this pattern. This is when I discovered that the replication wasn’t working between System Manager and Session Manager. Once I fixed the replication, the rest of the routing worked and I left this in place rather than pull it all out. More on traceSM later.

---------------------------------------------------------------------------------------------------------------
         cm01(.30)             192.168.204.39
                       SM100
---------------------------------------------------------------------------------------------------------------
16:03:51,290 |   Dial Pattern route parameters   | URI Domain: abc.com  Location: LA-MAIN-CM
16:03:51,290 |   Dial Pattern route parameters   | URI Domain: null  Location: LA-MAIN-CM
16:03:51,290 |     Trying Dial Pattern route     | Domain: null  Location: LA-MAIN-CM
16:03:51,290 |   Dial Pattern route parameters   | URI Domain: corp.abc.com  Location: null
16:03:51,290 |     Trying Dial Pattern route     | Domain: corp.abc.com  Location: null
16:03:51,290 |   Dial Pattern route parameters   | URI Domain: abc.com  Location: null
16:03:51,290 |   Dial Pattern route parameters   | URI Domain: null  Location: null
16:03:51,290 |     Trying Dial Pattern route     | Domain: null  Location: null
16:03:51,290 |  Request Regular Expression rout  | for: sip:ast-la@corp.abc.com
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-ny.*  for: sip:ast-la@abc.corp
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-la.*  for: sip:ast-la@abc.corp
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-oc.*  for: sip:ast-la@abc.corp
16:03:51,291 |  Trying Regular Expression route  | pattern: ast-la.*  for: sip:ast-la@abc.corp
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-ny.*  for: ast-la@corp.abc.com
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-la.*  for: ast-la@corp.abc.com
16:03:51,291 |  Trying Regular Expression route  | pattern: sipmm-oc.*  for: ast-la@corp.abc.com
16:03:51,291 |  Trying Regular Expression route  | pattern: ast-la.*  for: ast-la@corp.abc.com
16:03:51,291 |     Regular Expression found      | pattern: ast-la.*  for: ast-la@corp.abc.com  RoutePolicyList
16:03:51,291 |            Route found            | for: sip:ast-la@corp.abc.com  SIPEntity: asterisk-la01p
16:03:51,291 |         Entity Link found         | SIPEntity: asterisk-la01p  EntityLink: sip-oc1->UDP, b
16:03:51,291 |     Entity Link to another SM     | To: sip-oc1  MyInstance: sip-la1
16:03:51,291 |         Entity Link found         | SIPEntity: sip-oc1  EntityLink: sip-la1->TLS, biD
16:03:51,291 |        Request Adaptation         | Adapter: LA-MAIN-CM
16:03:51,292 |     Applied egress Adaptation     | P-Asserted-Identity="Roger Ramjet" <sip:2135552245@abc.corp 16:03:51,292 |        Routing SIP request        | SipEntity: asterisk-la1  EntityLink: sip-oc01->UDP:50
16:03:51,292 |         Entity Link found         | SIPEntity: sip-oc1  EntityLink: sip-la1->TLS, biD
16:03:51,293 |  No hostname resolution required  | Routing to: sip: 10.5.20.139;transport=tls;lr;sm-routethru
16:03:51,294 |           |--INVITE-->|           | (8) T:ast-la F:+12135552245 U:ast-la P:terminating
16:03:51,342 |           |<--Trying--|           | (8) 100 Trying
16:03:52,419 |           |

Once you create a regular expression in System Manager, you should see an attempt to match it in traceSM. I wasn’t seeing my new patterns in this “Trying…” list. If you don’t see your patterns, it may be time to repair the replication.

Part 4 – Configure Asterisk to accept inbound calls from Communication Manager

Ok, so you finally have CM configured, and you think you have Session Manager/System Manager configured. Now for the last step. In my case, I was happy to finally get to Asterisk. Getting back to my rant about Session Manager, I like Asterisk because it’s completely command line and config files. This allows you to get very close to the inner workings of Asterisk.

Asterisk was a simple two step configuration: sip.conf and extensions.conf.

Just add these lines to /etc/asterisk/sip.conf

[avayaLA]
type=peer
qualify=yes
fromdomain=corp.abc.com
host=192.168.24.39
disallow=all
allow=ulaw
allow=g729
dtmfmode=rfc2833
canreinvite=yes

And add these lines to /etc/asterisk/extensions.conf. Note that we’re creating a context for our Avaya Session Manager and adding it to the default context. Later you can pull this out, but for now it provides a nice way to test incoming calls by sending them to the “congratulations” demo that came with Asterisk.

[avaya-la]
exten => ast-la,1,noop
exten => ast-la,n,goto(demo,1000,1)
exten => 4498,1,goto(demo,1000,1)
exten => 4499,1,meetme(4499,1)

[default]
;
; By default we include the demo.  In a production system, you
; probably don't want to have the demo there.
;
include => demo
include => internal
include => avaya-la

So now let’s test. We should have these things in place:

  1. Connectivity between Communication Manager and Session Manager
  2. Connectivity between Session Manager and Asterisk
  3. Routes built from Communication Manager through Session Manager to Asterisk

Now when I call a 44xx extension, the Communication Manager will send it via AAR to Asterisk. Let’s look at that call within Communication Manager:

list trace station 2245                                                Page   1
                                LIST TRACE
time            data
13:12:11 TRACE STARTED 03/19/2012 CM Release String cold-00.1.510.1-19100
13:12:13     active station      2245 cid 0x11c3
13:12:13     G711MU ss:off ps:20
             rgn:1 [172.25.114.8]:11394
             rgn:1 [172.25.24.124]:59628
13:12:15 SIP>INVITE sip:4498@corp.abc.com SIP/2.0
13:12:15     Call-ID: 801ecff7b275e11f7724f24def200
13:12:15     dial 4498 route:UDP|AAR
13:12:15     term trunk-group 91      cid 0x11c3
13:12:15     dial 4498 route:UDP|AAR
13:12:15     route-pattern  90 preference 1 location 1/ALL  cid 0x11c3
13:12:15     seize trunk-group 91 member 6    cid 0x11c3
13:12:15     Setup digits 4498
13:12:15     Calling Number & Name *12135552245 Roger Ramjet
13:12:15 SIP<SIP/2.0 100 Trying
13:12:15     Call-ID: 801ecff7b275e11f7724f24def200
13:12:15     Proceed trunk-group 91 member 6    cid 0x11c3
13:12:15 SIP<SIP/2.0 180 Ringing
13:12:15     Call-ID: 801ecff7b275e11f7724f24def200
13:12:15     Alert trunk-group 91 member 6    cid 0x11c3

We can see from this trace that the call to 4498 goes over route 90 to trunk group 91. Perfect. Now let’s watch Session Manager. If you haven’t had the chance, you can trace calls within Session Manager via a tool called traceSM. At first I wasn’t sure about it, but I’ve come to really like it. SSH into your session manager (the management interface, not the traffic interface) and login as ‘craft’. If you know your Avaya systems, you’ll know the default password. Then type ‘traceSM’. After a few seconds of loading the log file, you’ll be ready to trace.

If your system has a lot of traffic, you’ll probably want to filter your results. Type ‘f’ at the screen and filter by your test extension.

/----------------------------------------------------------------------\
|Filter Usage:                                                         |
|  -u   Filter calls that contain  in          |
|                   the 'From' or 'To' field.                          |
|  -i           Filter SIP messages from/to  address.                  |
|  -c      Filter based on the SIP 'Call-ID' header field.             |
|  -g = Filter SIP header field  for value .                           |
|  -or              Use a logical OR operator instead of the implicit  |
|                   AND when using multiple filter options.            |
|  -nr              Do not display REGISTER messages.                  |
|  -ns              Do not display SUBSCRIBE/NOTIFY messages.          |
|  -no              Do not display OPTIONS messages.                   |
|  -na              Do not display SM related messages.                |
|Filter examples:                                                      |
| To display a call to/from 3035556666 and not REGISTER messages:      |
|    -u 3035556666 -nr                                                 |
| To display SIP messages from/to 1.1.1.1 and 2.2.2.2:                 |
|    -i "1.1.1.1|2.2.2.2"                                              |
|                                                                      |
|Current Filter:                                                       |
|New Filter: -u 4498                         |
|                                                                      |
\----------------------------------------------------------------------/

Press enter and traceSM will re-process the log file. Then press ‘c’ to clear the results, then press ‘s’ to start the trace. Now when I re-dial extension 4498 and I can see the call pass through Session Manager:

---------------------------------------------------------------------------------------------------------------------------------
       172.25.204.30           172.25.14.131
                       SM100
---------------------------------------------------------------------------------------------------------------------------------
13:39:33,115 |--INVITE-->|           |           | (1) T:4498 F:+12135552245 U:4498 P:terminating
13:39:33,117 |<--Trying--|           |           | (1) 100 Trying
13:39:33,118 |      Remote host is trusted       | Trusted
13:39:33,118 |        Request Adaptation         | Adapter: LA-MAIN-CM
13:39:33,119 |    Applied ingress Adaptation     | Request-URI=sip:+12135554498@corp.abc.com, History-Info=<sip:+12135554498@corp.abc.com>;index=1,"4498" UDP, biDirId=null:5060
13:39:33,121 |        Request Adaptation         | Adapter: LA-MAIN-CM
13:39:33,121 |     Applied egress Adaptation     | P-Asserted-Identity="Roger Ramjet" <sip:2135552245@corp.abc.com>, Request-URI=sip:4498@corp.abc.com;rout
13:39:33,121 |        Routing SIP request        | SipEntity: asterisk-la01p  EntityLink: sm-sip-la01p->UDP:5060
13:39:33,123 |  No hostname resolution required  | Routing to: sip:172.25.4.231;lr;phase=terminating
13:39:33,124 |           |--INVITE-->|           | (1) T:4498 F:+12135552245 U:4498 P:terminating
13:39:33,195 |           |<--Trying--|           | (1) 100 Trying
13:39:33,209 |           |<--Ringing-|           | (1) 180 Ringing
13:39:33,211 |        Request Adaptation         | Adapter: LA-MAIN-CM
13:39:33,211 |        Request Adaptation         | Adapter: LA-MAIN-CM
13:39:33,212 |<--Ringing-|           |           | (1) 180 Ringing 13:39:34,455 |--CANCEL-->|           |           | (1) sip:4498@corp.abc.com
13:39:34,455 ||           | (1) sip:4498@corp.abc.com
13:39:34,496 |           ||           | (1) sip:4498@corp.abc.com
13:39:34,499 |<--Request-|           |           | (1) 487 Request Terminated 13:39:34,548 |----ACK--->|           |           | (1) sip:4498@corp.abc.com

You can see the SIP INVITE from Communication Manager. You can see Session Manager process it using the various rules in the routing engine, and you can see the INVITE passed along to Asterisk. You can use the arrow keys to highlight the INVITE and press enter to see the details:

/--------------------------------------------------------------------------------\
|INVITE sip:4498@corp.abc.com;routeinfo=0-0 SIP/2.0                              |
|Record-Route: <sip:192.168.214.8:15060;lr;sap=865602204*1*016asm-callprocessing | 
|.sar634103744~1332189573117~-1715763735~1>                                      |
|From: "Roger Ramjet" <sip:+12135552245@corp.abc.com>;tag=0f617ceb675e1123764f2  |
|4def200                                                                         |
|To: <sip:4498@corp.abc.com>                                                     |
|Call-ID: 0f617ceb675e1124764f24def200                                           |
|CSeq: 1 INVITE                                                                  |
|Via: SIP/2.0/UDP 192.168.24.8:15070;branch=z9hG4bKC0A8CC2608E7B337012365250     |
|Via: SIP/2.0/UDP 192.168.24.8:15070;branch=z9hG4bKC0A8CC2608E7B337112365248     |
|Via: SIP/2.0/UDP 192.168.24.8:15070;branch=z9hG4bKC0A8CC2608E7B337112365247     |
|Via: SIP/2.0/TLS 192.168.24.9;branch=z9hG4bK0f617ceb675e1125764f24def200-AP;ft  |
|=23826                                                                          |
|Via: SIP/2.0/TLS 172.25.24.30;branch=z9hG4bK0f617ceb675e1125764f24def200        |
|Supported: 100rel,histinfo,join,replaces,sdp-anat,timer                         |
|Allow: INVITE,ACK,OPTIONS,BYE,CANCEL,SUBSCRIBE,NOTIFY,REFER,INFO,PRACK,PUBLISH  |
|User-Agent:  Avaya CM/R016x.00.1.510.1 AVAYA-SM-6.1.1.0.611023                  |
|Contact: "Roger Ramjet" <sip:+12135552245@172.25.24.30:5061;transport=tls>      |
|Alert-Info: <cid:internal@corp.abc.com>;avaya-cm-alert-type=internal            |
|Min-SE: 1200                                                                    |
|Record-Route: <sip:559ae004@192.168.24.39;transport=tls;lr>                     |
|Record-Route: <sip:172.25.24.30:5061;transport=tls;lr>                          |
|Session-Expires: 1200;refresher=uac                                             |
|P-Charging-Vector: icid-value="AAS:5279-ce17f6001e175b6244f7622f2de"            |
|Content-Type: application/sdp                                                   |
|Content-Length: 210                                                             |
|P-Asserted-Identity: "Roger Ramjet" <sip:2135552245@corp.abc.com>               |
|History-Info: <sip:2135554498@corp.abc.com>;index=1,"4498" <sip:2135554498@corp.abc.com>;index=1.1                                                              |
|Route: <sip:192.168.204.39;lr>                                                  |
|Route: <sip:172.25.4.31;lr;phase=terminating>                                   |
|P-AV-Transport: AP;fe=172.25.24.30:34534;ne=192.168.24.39:5061;tt=TLS;th;timer  |
|B=4                                                                             |
|P-Location: SM;origlocname="LA-MAIN-CM";termlocname="LA-Asterisk"               |
|Max-Forwards: 68                                                                |
|                                                                                |
|v=0                                                                             |
|o=- 1332189580 1 IN IP4 172.25.24.30                                            |
|s=-                                                                             |
|c=IN IP4 172.25.24.54                                                           |
|b=AS:64                                                                         |
|t=0 0                                                                           |
|a=avf:avc=n prio=n                                                              |
|a=csup:avf-v0                                                                   |
|m=audio 65044 RTP/AVP 0 127                                                     |
|a=rtpmap:0 PCMU/8000                                                            |
|a=rtpmap:127 telephone-event/8000                                               |
\--------------------------------------------------------------------------------/

This confirms that your dial request to 4498 is passing through the Session Manager over to Asterisk. Now let’s look at Asterisk:

exten => 4498,1,goto(demo,1000,1)

Because our extensions.conf file contains the line above, the calls that come in should go to the Asterisk demo application. Let’s watch from the CLI when I call 4498 again:

localhost*CLI>
  == Using SIP RTP CoS mark 5
    -- Executing [4498@default:1] Goto("SIP/avayaLA-00000037", "demo,1000,1") in new stack
    -- Goto (demo,1000,1)
    -- Executing [1000@demo:1] Goto("SIP/avayaLA-00000037", "default,s,1") in new stack
    -- Goto (default,s,1)
    -- Executing [s@default:1] Wait("SIP/avayaLA-00000037", "1") in new stack
    -- Executing [s@default:2] Answer("SIP/avayaLA-00000037", "") in new stack
    -- Executing [s@default:3] Set("SIP/avayaLA-00000037", "TIMEOUT(digit)=5") in new stack
    -- Digit timeout set to 5.000
    -- Executing [s@default:4] Set("SIP/avayaLA-00000037", "TIMEOUT(response)=10") in new stack
    -- Response timeout set to 10.000
    -- Executing [s@default:5] BackGround("SIP/avayaLA-00000037", "demo-congrats") in new stack
    -- <SIP/avayaWLA-00000037> Playing 'demo-congrats.slin' (language 'en')
  == Spawn extension (default, s, 5) exited non-zero on 'SIP/avayaWLA-00000037'
localhost*CLI>

And if you could hear what I hear, you’d enjoy Allison Smith’s congratulations message also! We have inbound calls to Asterisk.

Part 5 – Configure Asterisk to send outbound calls to Communication Manager

This one is a little easier. To send internal calls to Avaya, just create an extension match in extensions.conf to match your internal number ranges. However, don’t forget that you are probably sending some numbers from Communication Manager to Asterisk. Be sure not to send these number ranges back to Communication Manager! In my case, Communication Manager is sending 44xx to Asterisk so I make sure I keep those numbers internal to Asterisk by dialing any registered SIP phones (more on this later).

[losangeles]
;these are LA extensions registered through softphones
exten => _44XX,1,Dial(SIP/${EXTEN}) ; these stay internal to Asterisk
exten => _91XXXXXXXXXX,1,dial(SIP/${EXTEN}@avayaLA) ; external – leave the 9 in place
exten => _[245]XXX,1,dial(SIP/${EXTEN}@avayaLA) ; 4 digits starting with 0, 4, or 5

To test this, you can issue an ‘originate’ command right from the Asterisk CLI.

localhost*CLI> originate SIP/2245@avayaWLA extension 1000
  == Using SIP RTP CoS mark 5
    -- Executing [1000@default:1] Goto("SIP/avayaLA-00000049", "default,s,1") in new stack
    -- Goto (default,s,1)
    -- Executing [s@default:1] Wait("SIP/avayaLA-00000049", "1") in new stack
    -- Executing [s@default:2] Answer("SIP/avayaLA-00000049", "") in new stack
    -- Executing [s@default:3] Set("SIP/avayaLA-00000049", "TIMEOUT(digit)=5") in new stack
    -- Digit timeout set to 5.000
    -- Executing [s@default:4] Set("SIP/avayaLA-00000049", "TIMEOUT(response)=10") in new stack
    -- Response timeout set to 10.000
    -- Executing [s@default:5] BackGround("SIP/avayaLA-00000049", "demo-congrats") in new stack
    -- <SIP/avayaWLA-00000049> Playing 'demo-congrats.slin' (language 'en')
  == Spawn extension (default, s, 5) exited non-zero on 'SIP/avayaWLA-00000049'
localhost*CLI>

The command above causes Asterisk to launch a call to 2245 through the avayaLA peer and send the call to extension 1000. You should get a call and when you answer, you’ll hear the demo. Likewise, external calls should include the ‘9’ when sent to Communication Manager. Your system will probably pass this through Session Manager to Communication Manager just fine since Modular Messaging needs to dial out sometimes (for find-me/follow-me features).

So that’s it! You now have an Avaya Communication Manager sending and receiving calls to Asterisk via Session Manager! This is a great proof-of-concept for you to start your Lync integration. I’ll write up a separate article for Lync. There’s an amazing amount of politics involved in a Lync project. I’d love to hear from you about it.