Подключение Asterisk по ОКС-7

d4d2b79555ab4058ba621ac674bad3ab.jpg

Поддержка сигнализации SS7 была анонсирована в chan_dahdi достаточно давно, но реально использовать ее было невозможно из-за ограничений в реализации. Практически единственной альтернативой было использовать драйвер chan_ss7 от компании Netfors (хотя их бесплатная версия и не идеальна, но позволяет собрать хоть какую-нибудь рабочую систему). И вот наконец-то в Asterisk v13+ появилась поддержка SS7, позволяющая выполнять подключения к реальному оборудованию. Итак, рассмотрим последовательность шагов, необходимых для сборки Asterisk, поддерживающего работу с цифровыми каналами связи.

Планирование подключения

Нам надо определиться, будет ли у нас подключение к вышестоящему оператору связи (uplinks), или мы будем заниматься исключительно обслуживанием наших downlinks. От этого будут зависеть как параметры настройки канального уровня (от кого и в каком порядке будет осуществляться синхронизация физических потоков), так и параметры сетевого уровня (см. ниже).

В нашем примере мы будем использовать следующие исходные данные:
— две 4-х портовые интерфейсные платы Digium TE 420;
— на первой плате 4 порта управляются по сигнализации ОКС-7 и собраны в один пучек (linkset). Параметры подключения: «точка-точка», наш pointcode 650, pointcode соседа 599, он же является конечной точкой. Это подключение к «uplink», т. е. физическую синхронизацию будем получать от него.
— на второй плате к первому порту подключается потребитель, работающий по протоколу EuroISDN, которому мы даем 30 соединительных линий (т. е. задействуем все таймслоты в E1). Для этого потребителя мы являемся сетью (NET).
— на второй плате ко второму порту подключается другой потребитель, но также работающий по протоколу EuroISDN. Но ему мы даем только 10 соединительных линий (10 младших таймслотов в E1. Остальные таймслоты в потоке, за исключением сигнального, не задействованы).
— оставшиеся два порта второй платы пока не используются.

Установка интерфейсных плат

Я использую интерфейсные платы производства Digium на 1 (TE 131*), 2 (TE 235*), и 4 (TE 420*) канала. Сейчас в продаже имеются и 8-ми канальные платы, но как-то руки не доходили протестировать их работоспособность.
Перед установкой плат необходимо:

— выставить джамперами требуемый тип интерфейса (T1 или E1) для каждого из портов на плате;
— выставить переключатель, идентифицирующий порядковый номер платы в системе (при установке нескольких плат значения, выставленные на переключателях, должны быть уникальны для каждой карты);
— при установке в систему нескольких карт рекомендуется также соединить их специальным шлейфом, который обеспечит единую синхронизацию для всех портов (хотя в действительности я не заметил каких-либо нарушений работоспособности при отсутствии этого шлейфа даже при передаче факсов между портами, расположенными на разных платах).
Подробнее процесс установки оборудования см. в оригинальных datasheet от Digium.

Сборка драйверов уровня ядра и сопутствующих утилит

Так как мы установили дополнительное интерфейсное оборудование, то для его поддержки потребуются драйвера уровня ядра, которые отсутствуют в стандартных дистрибутивах linux. Поэтому нам придется собрать их самостоятельно, а для этого понадобятся исходные тексты ядра linux. Если использовать исходные тексты именно той версии ядра, которая установлена в системе, то сборка и установка самого ядра нам не потребуется. Если версия не совпадает, то необходимо будет сначала собрать новое ядро, и только после этого собирать драйвера dahdi.

Итак, скачиваем с официального сайта asterisk и распаковываем последнюю версию драйверов dahdi. Кстати сразу же можно скачать и библиотеки libpri и libss7, которые будут необходимы для сборки chan_dahdi. В пакете tools для работы с dahdi есть две полезные утилиты, которые по умолчанию могут и не собраться. Это dahdi_tool (позволяет в консольном режиме посмотреть состояние физических портов E1) и dahdi_pcap (позволяет сохранять трафик, проходящий через порт E1, для дальнейшего его анализа при помощи wireshark). Для сборки dahdi_tool требуется наличие в системе пакета newt-devel, а для dahdi_pcap требуется libpcap-devel.

Для работоспособности утилиты dahdi_pcap до сборки требуется отредактировать файл

dahdi-linux-complete/linux/include/dahdi/dahdi_config.h, в котором надо добавить строку

#define CONFIG_DAHDI_MIRROR

Далее приступаем к сборке и установке собственно драйверов:

cd dahdi-linux-complete
make clean
make
sudo -u root make install

Утилита dahdi_pcap штатной системой сборки в любом случае не собирается, поэтому собираем ее вручную:

cd dahdi-linux-complete/tools
make dahdi_pcap

После этого вручную копируем исполняемый файл dahdi_pcap в нужное нам место.

Создание конфигурации драйверов уровня ядра

Теперь приступаем к конфигурированию драйверов физического уровня. Все конфигурационные файлы находятся в каталоге /etc/dahdi. Нас интересуют /etc/dahdi/modules (список загружаемых модулей) и /etc/dahdi/system.conf (конфигурация канального уровня для всех физических портов).
В /etc/dahdi/modules в каждой строке пишется имя модуля, который подлежит загрузке. Если вы не уверены, какой конкретно модуль поддерживает используемое оборудование, можно запустить утилиту dahdi_genconf, которая проведет проверку установленного оборудования и создаст соответствующий конфигурационный файл. А можно сделать универсальную конфигурацию, просто перечислив в /etc/dahdi/modules все модули, которые были собраны на предыдущем шаге (т. е. файлы *.ko из каталога dahdi-linux-complete/linux/drivers/dahdi, но без пути и расширения .ko).
В моем случае (используются платы Digium TE420*, TE235* и TE131*) в /etc/dahdi/modules достаточно указать только один модуль wct4xxp.

Конфигурации канального уровня для каждого из используемых портов (span), как было указано выше, находятся в файле /etc/dahdi/system.conf.

Пусть мы используем одну 4-х портовую плату для подключения к вышестоящему оператору связи по ОКС-7 (в пучке 4 полных физических потока E1, в каждом из которых имеется сигнальный таймслот), и одну 2-х портовую плату для подключения к нам downlinks по EuroISDN. При этом физическую синхронизацию мы берем от нашего вышестоящего оператора (порядок выбора портов согласуется с ним), а для наших downlinks сами выступаем в качестве источника синхросигнала. При этом один из наших downlinks использует все 30 таймслотов (полный E1), а второму мы даем только 10 первых таймслотов.

Для подключения по протоколу ОКС-7 пример конфигурации выглядит следующим образом:

# CARD 0, SPAN 2
span=1,1,0, ccs, hdb3, yellow
bchan=1–15,17–31
mtp2=16

# CARD 0, SPAN 2
span=2,2,0, ccs, hdb3, yellow
bchan=32–46,48–62
mtp2=47

# CARD 0, SPAN 3
span=3,3,0, ccs, hdb3, yellow
bchan=63–77,79–93
mtp2=78

# CARD 0, SPAN 4
span=4,4,0, ccs, hdb3, yellow
bchan=94–108,110–124
mtp2=109

# CARD 1, SPAN 1 Customer channel, timing master (i.e. far end is a slave)
span=5,0,0, ccs, hdb3, crc4, yellow
bchan=125–139,141–155
dchan=140

# CARD 1, SPAN 2 Customer channel, timing master (i.e. far end is a slave)
span=6,0,0, ccs, hdb3, crc4, yellow
# Но у клиента используется только 10 таймслотов
bchan=156–165
unused=166–170,172–186
dchan=171

# Оставшиеся 2 порта на второй карте не используются, поэтому их описывать не обязательно.

Примечания:

В параметре span первым аргументом идет номер порта (расположение их на интерфейсной плате см. в datasheet). Сами платы располагаются в логическом порядке, соответствующем значению переключателей в порядке возрастания выставленного на них значения).

Вторым аргументом идет значение, определяющее физическую синхронизацию. Значение 0 обозначает, что мы являемся источником синхросигнала для удаленной стороны. Не нулевые значения задают приоритет нашей синхронизации от внешних источников (чем меньше значение, тем более приоритетным будет для нас источник внешнего синхросигнала).

Третьим параметром указывается значение, зависящее от длины кабеля, соединяющего нашу и удаленную системы. Соответствие значения параметра физической длине описано в комментариях в system.conf.

Следующим параметром указывается тип фреймов. Для E1 с сигнализацией ОКС-7 или EuroISDN это будет ccs. Далее указывается способ кодировки данных. Для E1 с сигнализацией ОКС-7 или EuroISDN это будет hdb3.

Следующим параметром (возможно) будет указан crc4, разрешающий контроль целостности принимаемых данных. В любом случае, это значение должно совпадать с тем, что ожидает от нас удаленная сторона.

Последним параметром я выставляю yellow. Это заставляет драйвер передавать состояние «yellow alarm» в случае, когда соответствующий span не открыт прикладной программой (например, Asterisk еще не запущен или он был принудительно остановлен).

После объявления порта (span) идет определение каналов, которые он содержит. В нашем случае каналы будут 3-х типов: сигнальные (HDLC), голосовые (обычно используются для передачи сигнала, кодированного одним из вариантов G.711. Однако для 3GPP эти каналы могут содержать unrestricted raw 64K data, при этом режим работы канала изменяется прикладной программой в зависимости от запросов в канале сигнализации) и не используемые (если в потоке определено меньшее количество каналов, чем имеющееся количество таймслотов).

Для объявления сигнального линка для ОКС-7 мы используем параметр mtp2=канал, а для EuroISDN этот параметр имеет имя dchan=канал. Фактически оба этих значения являются равноценными и определяют указанный канал в качестве HDLC-канала.

Голосовые каналы объявляем при помощи параметра bchan=канал (ы), а не используемые каналы объявляем при помощи параметра unused=канал (ы).

После завершения конфигурации загружаем драйвера командой
/etc/init.d/dahdi start и убеждаемся в работоспособности при помощи утилиты dahdi_tool:

511ca1377fdd450b8951622be77c3217.jpg

На картинке видно, что все 4 порта на первой интерфейсной плате и первые 2 порта на второй интерфейсной плате имеют физическое подключение и синхронизированы с удаленной стороной (т.е. канальный уровень на них поднят). Оставшиеся 2 порта на второй плате имеют состояние «Red alarm» обозначающее, что физическое подключение к ним отсутствует либо не работоспособно (ошибка канального уровня).

Также можно посмотреть состояние конкретного физического порта

4c914fcb78f042aab0d6241f1d790203.jpg

… и проверить отзывчивость системы в целом утилитой dahdi_test:

970d9787a8dd41679b9ebc7408a072a1.jpg

Отметим, что чем больше значение «Average:», тем отзывчивость системы лучше. Если это значение меньше 99.99%, то, скорее всего, возникнут проблемы с передачей факсимильных данных по цифровым каналам. Также возможны искажения звука при использовании функционала аудио-конференций.

Если при попытке запуска dahdi_tool получаем сообщение типа «Unable to open /dev/dahdi/ctl: No such file or directory» то это означает, что драйверы не загружены либо сконфигурированы неправильно. Проверить их загрузку можно стандартной утилитой lsmod:

#lsmod
Module Size Used by Tainted: G
wctc4xxp 32992 0
dahdi_transcode 4566 1 wctc4xxp
wct4xxp 241730 166
dahdi 201849 486 dahdi_transcode, wct4xxp

Проверить наличие и логическое расположение оборудования можно командой lspci:

#lspci -k
00:00.0 Class 0600: 8086:0150
00:02.0 Class 0300: 8086:0162
00:14.0 Class 0c03: 8086:1e31 xhci_hcd
00:16.0 Class 0780: 8086:1e3a
00:16.3 Class 0700: 8086:1e3d serial
00:19.0 Class 0200: 8086:1502 e1000e
00:1a.0 Class 0c03: 8086:1e2d ehci-pci
00:1b.0 Class 0403: 8086:1e20 snd_hda_intel
00:1c. 0 Class 0604: 8086:1e10 pcieport
00:1c. 4 Class 0604: 8086:1e18 pcieport
00:1c. 6 Class 0604: 8086:1e1c pcieport
00:1c. 7 Class 0604: 8086:1e1e pcieport
00:1d.0 Class 0c03: 8086:1e26 ehci-pci
00:1e.0 Class 0604: 8086:244e
00:1f.0 Class 0601: 8086:1e53
00:1f.2 Class 0106: 8086:1e02 ahci
00:1f.3 Class 0c05: 8086:1e22
02:00.0 Class 0604: 104c:8231
03:08.0 Class 0780: d161:1420 wct4xxp
04:00.0 Class 0604: 104c:8231
05:08.0 Class 0780: d161:1420 wct4xxp
06:00.0 Class 0200: 8086:10d3 e1000e

(для оборудования Digium в качестве кода производителя будет значение d161).

Сборка необходимых библиотек для полнофункционального chan_dahdi

Для поддержки сигнализации EuroISDN нам потребуется библиотека libpri, исходные тексты которой мы скачали ранее с сайта asterisk.org. Распаковываем их, выполняем сборку и установку:

cd libpri
make clean
sudo -u root make install

Для поддержки сигнализации ОКС-7 нам потребуется библиотека libss7, исходные тексты которой также есть на asterisk.org. Распаковываем их, выполняем сборку и установку:
cd libss7
make clean
make
sudo -u root make install

Теперь распаковываем исходные тексты самого asterisk и запускаем систему автоматического конфигурирования:

cd asterisk
./configure

Затем мы рекомендуем произвести проверку модулей Asterisk и дабы не перегружать статью описанием этой необходимой процедуры мы выложили ее на отдельном ресурсе.
— Вместе с тем, мы надеемся, что не злоупотребим вашим вниманием и приведем описание проверки целиком.

Проверка модулей Asterisk

Для проверки готовности модулей к сборке запускаем make menuselect

7365679909624ab49e1e7db3c27f2b4d.jpg

Убеждаемся, что драйвер chan_dahdi готов к сборке (система автоматического конфигурирования нашла библиотеки и файлы заголовков для dahdi, библиотек libpri и libss7).

Выполняем компиляцию и установку asterisk:
make
sudo -u root make install
sudo -u root make samples

Последняя команда установит пример конфигурации в каталог /etc/asterisk.

Теперь нам необходимо отредактировать /etc/asterisk/chan_dahdi.conf для определения в нем параметров сетевого уровня для создаваемых подключений.

[trunkgroups]
; Оставляем эту секцию пустой, если только каналы EuroISDN
; не используют схему сборки потоков в транки с указанием идентификатора потока
; в сообщении. Для ОКС-7 эта секция вообще не используется.

[channels]
; Общие параметры для наших EuroISDN-подключений
echocancel=no
faxdetect=incoming

; Контекст приземления входящих вызовов из ISDN-портов
; В нашем случае он один для всех физических портов,
;, но можно использовать и раздельные контексты.
context=landing

Конфигурируем порты EuroISDN:

switchtype=euroisdn

;
; Некоторые специфичные для ISDN параметры опущены, ибо их описание есть
; тема отдельной статьи
;

; Зависит от удаленной системы. Если она не распознает ситуацию, когда
; вы «положили трубку», попробуйте заменить значение на inband (извращенцы!)
priindication = outofband

; CLIP обрабатывать будем
usecallerid=yes

; Да и calling presentation будем посылать на исходящих вызовах. Вдруг кто захочет
; скрыть свой АОН от определения? ;)))
usecallingpres=yes

; Наш downlink, использующий все 30 таймслотов для передачи трафика.
; Физически подключается на первый порт второй потоковой платы.
; Для него мы выступаем как сеть (NET), он для нас является CPE.
; Передача вызова ему производится командой
; Dial (DAHDI/g5/вызываемый_номер)
group=5
callgroup=5

signalling=pri_net

channel => 125–139
channel => 141–155

; Наш downlink, использующий только 10 таймслотов для передачи трафика.
; Физически подключается на второй порт второй потоковой платы.
; Передача вызова ему производится командой
; Dial (DAHDI/g6/вызываемый_номер)
group=6
callgroup=6

signalling=pri_net

; У клиента используется 10 таймслотов
channel => 156–165

Итак, мы имеем 4 физических потока E1, собранных в один пучек, управляемый по сигнализации ОКС-7. В каждом из физических потоков имеется один сигнальный линк (стандартное расположение 16-й таймслот), остальные линки используются для передачи данных. Потоки в пучек собраны начиная с младшего, CIC нумеруются последовательно, начиная с 1. Соответствующий кусок из chan_dahdi.conf:

; Тип сигнализации
signalling=ss7
; Дальше идут общие для различных типов сигнализации параметры
; Врядли вам потребуется их изменять
usecallerid=yes
usecallingpres=yes
callwaitingcallerid=yes
threewaycalling=no
transfer=no
canpark=no
cancallforward=no
echocancel=no
echocancelwhenbridged=no

; Контекст, на который будут приземляться вызовы, пришедшие от удаленной системы
context=landing

; Логическая группа, используемая для отправки вызова на этот пучек. Т.е.
; команда вызова будет иметь вид
; Dial (DAHDI/g1/номер_назначения)
group=1
callgroup=1
; pickupgroup=1

; В Европе (и в России) используется вариант ITU
ss7type = itu

; SS7 Called Nature of Address Indicator
; Для подключений местного/зонового уровня
; можно задать явно ss7_called_nai=National
; Но мы оставляем значение по умолчанию (оно также закомментировано):
; ss7_called_nai=dynamic

; Префиксы также указывать не будем. Мне с ними проще разобраться в диалплане
; ss7_internationalprefix = 00
; ss7_nationalprefix = 0
; ss7_subscriberprefix =
; ss7_unknownprefix =

; На входящих вызовах будем посылать ACM сразу, как только начнется обработка
; диалплана приземления. Т.е. удаленная сторона поймет, что вызов был хоть куда-то
; доставлен. Разрешать этот параметр или нет — дело вкуса.
; ss7_explicitacm=yes

; Автоматическая передача ACM на входящих вызовах, когда он был перенаправлен
; asterisk-ом на другой канал и на этом другом канале возникло состояние вызова
; или ответа. Влияет на передачу early media от стороннего канала на вызывной.
; Либо всегда надо будет вызывать Proceeding () перед Dial ().
; ss7_autoacm=yes

; При инициализации драйвера канала считаем все CIC заблокированными (т. е.
; недоступными для использования). Их разблокировка произойдет автоматически
; после завершения логического тестирования канала связи.
; ss7_initialhwblo=yes

; Управление эходавом. Я оставляю по умолчанию.
; ss7_use_echocontrol=yes
; ss7_default_echocontrol=yes

; Определение пучка (linkset)
linkset = 1

; Для первого потока в пучке SLC=0 (для каждого последующего увеличивается на 1)
; Этот параметр зависит от конфигурации удаленной стороны
slc=0

; Наш pointcode
pointcode = 651

; pointcode удаленной стороны
; Этот параметр зависит от конфигурации удаленной стороны
adjpointcode = 599

; Врядли вы будете использовать STP-маршрутизацию, поэтому конечный pointcode
; совпадает с pointcode удаленной стороны. Но может иметь другое значение, если
; удаленная сторона не является конечной точкой.
; Этот параметр зависит от конфигурации удаленной стороны
defaultdpc = 599

; Значение NI для MTP3. Скорее всего это будет либо national, либо national_spare
; Этот параметр зависит от конфигурации удаленной стороны
networkindicator=national_spare

; Указываем сигнальный канал для 1-го потока
sigchan = 16
; Обязательно определяем таймеры! Их необходимо определять
; после каждого нового сигнального канала
#include ss7.timers

; Определяем соответствие CIC и физическим каналам
cicbeginswith = 1
channel = 1–15
cicbeginswith = 17
channel = 17–31

; По аналогии определяем оставшиеся 3 физических порта, входящих в пучек

slc=1
pointcode = 650
adjpointcode = 599
defaultdpc = 599
networkindicator=national_spare
sigchan = 47
#include ss7.timers

cicbeginswith = 33
channel = 32–46
cicbeginswith = 49
channel = 48–62

slc=2
pointcode = 650
adjpointcode = 599
defaultdpc = 599
networkindicator=national_spare
sigchan = 78
#include ss7.timers

cicbeginswith = 65
channel = 63–77
cicbeginswith = 81
channel = 79–93

slc=3
pointcode = 650
adjpointcode = 599
defaultdpc = 599
networkindicator=national_spare
sigchan = 109
#include ss7.timers

cicbeginswith = 97
channel = 94–108
cicbeginswith = 113
channel = 110–124

Осталось только составить диалплан в extensions.conf и запустить asterisk в консольном режиме:
asterisk -vvvc

— Хотим заверить вас, что тема сигнализации Asterisk будет развиваться в дальнейшем и дополнится новыми материалами.

© Habrahabr.ru